Developing XMPP Components – The Service
October 8, 2010 22 Comments
In the first part of this blog, I talked about XMPP component, server configurations (subdomain name and secret key) and also about setting up the build environment for Whack.
At the most basic level, developing XMPP components (XEP-0114) with Smack consists of the following Java classes
- A ‘main‘ class – This is the class that
- Creates the XMPP component; this is the service
- Connects and performs handshaking with a Jabber server
- Keeps the XMPP component alive by going into an infinite loop
- The XMPP component class – This class either implements Component or extends AbstractComponent. The difference between the two is how much do you want to write viz. AbstractComponent provides a simple framework to handle various message type while Component you must implement all these yourself. I will go into this in greater detail in my next blog. For the time being, we will just go with Component
We will implement a simple uppercase service, where any message that you send to the service, the service will echo it back to you in uppercase. The following is the main class
import java.util.logging.*;
import org.jivesoftware.whack.*;
import org.xmpp.component.*;public class Main {
public static void main(String[] args) {
ExternalComponentManager mgr = new ExternalComponentManager(“myserver”, 5275);
mgr.setSecretKey(“landofthegiants”, “uppercase”);
try {
mgr.addComponent(“landofthegiants”, new UpperCaseComponent());
} catch (ComponentException e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, “main”, e);
System.exit(-1);
}
//Keep it alive
while (true)
try {
Thread.sleep(10000);
} catch (Exception e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, “main”, e);
}
}
}
Some salient points about the above code
- You create an instance of ExternalComponentManager. This class will be responsible for all components connecting to a particular server. In this case its myserver. Note that 5275 is the standard port
- What you need to do next is to associate a secret key (uppercase) with the subdomain (landofthegiants) of your component. The secret key and subdomain must first be defined on the XMPP server. See part 1.
- Next you create an instance of your component and add that to ExternalComponentManager; the component is associated with the subdomain name. UpperCaseComponent must either implements Component or extends AbstractComponent.
- Finally keep your ‘server’ alive with an infinite loop.
The following class shows UpperCaseComponent
import org.xmpp.component.*;
import org.xmpp.packet.*;public class UpperCaseComponent implements org.xmpp.component.Component {
private ExternalComponentManager mgr = null;public String getName() {
return (“Upper case”);
}public String getDescription() {
return (“Echos your message back to you in upper case”);
}public void processPacket(Packet packet) {
if (packet instanceof Message) {
org.xmpp.packet.Message original = (Message) packet;
org.xmpp.packet.Message response = original.createCopy();
//Swap the sender/recipient fields
response.setTo(original.getFrom());
response.setFrom(original.getTo());
//Convert the text to upper case
response.setBody(original.getBody().toUpperCase());
mgr.sendPacket(this, response);
}
}public void initialize(JID jid, ComponentManager componentManager) throws ComponentException {
mgr = (ExternalComponentManager) componentManager;
}public void start() { }
public void shutdown() { }
}
As you can see, implementing a component is quite simple. getName(), getDescription(), start() and shutdown() are pretty self explanatory. The initialize() method is called before start(). In the initalize() method, the component will be passed its JID; this will be the subdomain plus the domain. for example the JID of this component will be landofthegiants.myserver.com. The other thing that gets pass into the component via initialize() is the instance of the ComponentManager that created the component. Hold a reference of this because the component manager is the key to communicating with the outside world eg. sendPacket().
The processPacket() is the meat of the component; all packets to landofthegiants.myserver.com subdomain are routed to this method. So what you have to do is check if packet parameter is one of the 3 types of message: Message, IQ or Presence, and cast packet appropriately.
In the final part of my blog in this series, I’ll talk about using AbstractComponent, Smack versus org.xmpp API and advertising your component.
Hello oneminutedistraction.
I read 3 thread. But i am not successful.
Download whack source, build it.
Write Main, UpperCaseComponent class. Compile not error. But when i run it, has error: java.lang.ClassNotFoundException: com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap$Builder
java.lang.ClassNotFoundException: gnu.inet.encoding.IDNA
Please help me to run this example and guide how to use it.
Thanks!
All the runtime JARs are in $WHACK_SRC/build/lib (dist and merge)
Thanks for your reply.
It run ok.
But i don’t know how to use my component (example UpperCaseComponent).
Additional, can you explore me about “disco#info”?
This is not the right place to go through XMPP concepts. I suggest you get the O’Reilly book XMPP: The Definitive Guide. Look at Component Developer Guide.
Thank you for a very useful sample code. One question: How would one send the same message to multiple JIDs?
Thanks and I would love to see more component oriented posts.
Hi I don’t think there is a standard for that. You will have to send the same message multiple times or if you are in a chat room
start() and shutdown () have no definition???
Hi,
I followed the tutorial but I have got an exception. So far I could not solve it. I will be grateful if you can give some hints on the issue.
Exception in thread “main” java.lang.NoClassDefFoundError: org/xmpp/component/Log
at itm.stage.xmpp.services.UppercaseService.main(UppercaseService.java:22)
Caused by: java.lang.ClassNotFoundException: org.xmpp.component.Log
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
… 1 more
P.S. I am running your code with out changes. I have referenced the whack.jar in my eclipse project.
Than ks a lot,
B.
I forgot to mention that the exception comes from this line: ExternalComponentManager mgr = new ExternalComponentManager(“localhost”, 5275);
See http://community.igniterealtime.org/thread/41142
I have tried different solutions but only managed to solve the problem by checking the Whack svn and then reference all jar files in the lib/merge folder in the weather example. I hope this hint may help others!
Cheers,
B.
Hi thanks for your comment. I’ve actually mentioned this in my previous blog. See Developing XMPP Components – The Setup. You can also use Vorpal framework to develop external component.
Thanks for reading.
Regards
Is the ComponentManager.sendPacket() function threadsafe?
Yes it is
Is it possible developing external component by tinder?
If so, where can I find sample?
Download whack source http://www.igniterealtime.org/downloads/source.jsp. There is an example in there or you can use my framework
Its an excellent BLOG for component creation, I complied and added the uppercase component to the server. Can you please tell me how can I send message to this service?
I need to send some messages to this service to test it.
The component is registered to a subdomain in your XMPP domain. Eg in the example the subdomain is landofthegiants. So if your XMPP domain is spindrift.com, then the component’s domain is landofthegiants.spindrift.com. So you just send a message eg. steveburton@landofthegiants.spindrift.com and your component should receive it.
HTH
Thanks a lot for prompt reply, It is working now. I was trying to chat with the user but not using send message option.
Thanks a lot for prompt reply, It is working now. I was trying to chat with the user but not using send message option.
How can i run multiple instances of XMPP component in a cluster using Whack and Ejabberd ?
I’m not familiar with Ejabberd. But if you’re using Openfire, there is a connection manager (https://www.igniterealtime.org/projects/openfire/connection_manager.jsp) which clusters the XMPP server instances. Having said that connection manager has not been updated for a long time. I’ve not used this.
There is also a cluster module (https://www.igniterealtime.org/projects/openfire/plugins/hazelcast/readme.html) based on Hazelcast. Have a look at that.
External components are connection oriented. Even though you can cluster the server, the client needs to perform reconnection when the connection fails/drops.