Ilias Tsagklis

About Ilias Tsagklis

Ilias Tsagklis is a senior software engineer working in the telecom domain. He is an applications developer in a wide variety of applications/services. Ilias is co-founder and Executive Editor at Java Code Geeks.

XMPP IM with Smack for Java applications – Infrastructure for Instant Messaging

This tutorial is the third part of the “Setting up an infrastructure for Instant Messaging” article series. In my previous tutorials, I showed you how to setup the Openfire IM Server and how to configure the Spark client in order to connect to that server. In this tutorial, I will show you how to add XMPP messaging capabilities to your own application.

I will use the Smack library, an Open Source XMPP (Jabber) client library for instant messaging and presence. Smack is a pure Java library and can be embedded into your applications to create anything from a full XMPP client to simple XMPP integrations.

XMPP is a simple XML protocol. Under the hood, XML messages are transmitted from the server to the client and vice versa. However, you don’t have to deal with those low level details, unless you want to. Smack hides all these via a well designed API. You can take a first hint of how the API works by reading the article “Instant Messaging in Java Made Easy: The Smack API”. I believe that you are familiar with the concept of instant messaging in general, so we are ready to write some code.

First download the library from the Ignite Realtime site. Since Smack is written in Java, it is cross-platform. The current version is 3.1.0 and I downloaded the tar.gz version (direct download here). After you extract the bundle file, you will find the library JARs along with the corresponding Javadocs. The online Javadocs can be found here (bookmark it to your favorite browser).

Create a new Eclipse project, let’s say under the name “XMPPProject”, and add the “smack.jar” and “smackx.jar” files into your classpath.

The main class that your client will use is XMPPConnection. As the name implies, it represents an XMPP connection to a remote server. Creating a connection and performing a login is as simple as the following code snippet:

// Create a connection to the igniterealtime.org XMPP server.
XMPPConnection connection = new XMPPConnection("myxmppserver.com");
// Connect to the server
connection.connect();
// Most servers require you to login before performing other tasks.
connection.login("myuser", "mypass");

Of course, a more sophisticated configuration of the connection attributes is possible and that can be achieved by using the ConnectionConfiguration class. There are multiple parameters that can be configured, with the most significant being the server host and port and various security (encryption) issues. You can also configure the internal Smack stack by using the SmackConfiguration class.

ConnectionConfiguration config = 
     new ConnectionConfiguration(serverHost, serverPort);
XMPPConnection connection = new XMPPConnection(config);
connection.connect();
connection.login("myuser", "mypass");

From a valid XMPPConnection, you can retrieve a ChatManager object. This one keeps track of references to all current chats and allows you to create Chat instances, i.e. series of messages sent between two users. Chat object are able of sending messages to other chat participants. You can use plain strings or construct XMPP message packets, represented by the Message class. Message class provides direct access to all of the message attributes, such as the message type. For processing incoming messages, you have to implement the MessageListener interface and attach it to a chat.

ChatManager chatManager = connection.getChatManager();
Chat chat = chatManager.createChat("mybuddy", new MyMessageListener());
chat.sendMessage(message);

You can also set your online status, also known as presence, by using the Presence class.

Presence presence = new Presence(Presence.Type.available);
presence.setStatus("What's up everyone?");
connection.sendPacket(presence);

A new buddy can be added to your list by using the Roster class. A user’s roster is a collection of users a person receives presence updates for. A user can be associated with groups, but in the following example the new roster entry won’t belong to a group.

Roster roster = connection.getRoster();
roster.createEntry(user, name, null);

The main class I created is named “XmppManager” and the source code is the following:

package com.javacodegeeks.xmpp;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;

public class XmppManager {
    
    private static final int packetReplyTimeout = 500; // millis
    
    private String server;
    private int port;
    
    private ConnectionConfiguration config;
    private XMPPConnection connection;

    private ChatManager chatManager;
    private MessageListener messageListener;
    
    public XmppManager(String server, int port) {
        this.server = server;
        this.port = port;
    }
    
    public void init() throws XMPPException {
        
        System.out.println(String.format("Initializing connection to server %1$s port %2$d", server, port));

        SmackConfiguration.setPacketReplyTimeout(packetReplyTimeout);
        
        config = new ConnectionConfiguration(server, port);
        config.setSASLAuthenticationEnabled(false);
        config.setSecurityMode(SecurityMode.disabled);
        
        connection = new XMPPConnection(config);
        connection.connect();
        
        System.out.println("Connected: " + connection.isConnected());
        
        chatManager = connection.getChatManager();
        messageListener = new MyMessageListener();
        
    }
    
    public void performLogin(String username, String password) throws XMPPException {
        if (connection!=null && connection.isConnected()) {
            connection.login(username, password);
        }
    }

    public void setStatus(boolean available, String status) {
        
        Presence.Type type = available? Type.available: Type.unavailable;
        Presence presence = new Presence(type);
        
        presence.setStatus(status);
        connection.sendPacket(presence);
        
    }
    
    public void destroy() {
        if (connection!=null && connection.isConnected()) {
            connection.disconnect();
        }
    }
    
    public void sendMessage(String message, String buddyJID) throws XMPPException {
        System.out.println(String.format("Sending mesage '%1$s' to user %2$s", message, buddyJID));
        Chat chat = chatManager.createChat(buddyJID, messageListener);
        chat.sendMessage(message);
    }
    
    public void createEntry(String user, String name) throws Exception {
        System.out.println(String.format("Creating entry for buddy '%1$s' with name %2$s", user, name));
        Roster roster = connection.getRoster();
        roster.createEntry(user, name, null);
    }
    
    class MyMessageListener implements MessageListener {

        @Override
        public void processMessage(Chat chat, Message message) {
            String from = message.getFrom();
            String body = message.getBody();
            System.out.println(String.format("Received message '%1$s' from %2$s", body, from));
        }
        
    }
    
}

Note that no security authentication is used and that the security mode is disabled. That means that there is no protection on the credentials exchange and that the messages are not secured. Smack API supports encryption, but I did not use it since I wanted to keep this tutorial simple.

Ok, let’s see how all the above can be combined in order to create a simple IM application. I will be using the Openfire server installed in a previous tutorial, along with the two users that were created.

First, I use my Spark client to login as user “testuser2”. Nothing special here. Next, I am creating a test class that uses “XmppManager”, connects to my Openfire server, logins as user “testuser1”, sets the online status to “available”, adds the “testuser2” to the roster and finally sends a message. Note that I created an infinite loop so that I can send messages from the Spark client and see them to my console. I am using the “isRunning” boolean to continue the looping. In a real application, this would be set to false if the program was to exit. Make sure you set the thread to sleep for some time, else your machine’s CPU will hit the roof. The test class is the following:

package com.javacodegeeks.xmpp;

public class XmppTest {
    
    public static void main(String[] args) throws Exception {
        
        String username = "testuser1";
        String password = "testuser1pass";
        
        XmppManager xmppManager = new XmppManager("myserver", 5222);
        
        xmppManager.init();
        xmppManager.performLogin(username, password);
        xmppManager.setStatus(true, "Hello everyone");
        
        String buddyJID = "testuser2";
        String buddyName = "testuser2";
        xmppManager.createEntry(buddyJID, buddyName);
        
        xmppManager.sendMessage("Hello mate", "testuser2@myserver");
        
        boolean isRunning = true;
        
        while (isRunning) {
            Thread.sleep(50);
        }
        
        xmppManager.destroy();
        
    }

}

Make sure you select the appropriate username/password and server settings.

If you run the program, you should see the incoming message to the Spark client. Answer to that message and then check your Eclipse console to ensure that the message was printed.

Note that “testuser2” received the message even though he hadn’t added “testuser1” as his buddy. This is the default behavior. Add the other user by hitting the “Add a Contact” button.

After the account is added, you will be able to see if the user is online and his current status as well.

Finally, you can retrieve the user’s roster and check the status of the existing contacts.

public void printRoster() throws Exception {
 Roster roster = connection.getRoster();
 Collection<RosterEntry> entries = roster.getEntries();  
 for (RosterEntry entry : entries) {
  System.out.println(String.format("Buddy:%1$s - Status:%2$s", 
      entry.getName(), entry.getStatus()));
 }
}

That’s all! As always, the Eclipse project created can be found here.

Happy coding!!!

Related Articles :
Related Whitepaper:

Java Essential Training

Author David Gassner explores Java SE (Standard Edition), the language used to build mobile apps for Android devices, enterprise server applications, and more!

The course demonstrates how to install both Java and the Eclipse IDE and dives into the particulars of programming. The course also explains the fundamentals of Java, from creating simple variables, assigning values, and declaring methods to working with strings, arrays, and subclasses; reading and writing to text files; and implementing object oriented programming concepts. Exercise files are included with the course.

Get it Now!  

23 Responses to "XMPP IM with Smack for Java applications – Infrastructure for Instant Messaging"

  1. Pavel Vik says:

    nice work, please could you explain me how to get received messages from xmppManager and function processMessage, I don¨t understant it very well

  2. prasanna jatla says:

    i dnt have eclipse ide so,plzz can any one help me ,how to add this zar files to java .plzzz rpy aeap 

    • shanthi says:

      if u have netbeans, u can upload the jar files….

      • ankaraju says:

        HI

        can U tell me how to get reply msg using this same code.

        Installed openfire server in my local Machine, and I am using same code.
        when I run this main prgrm.. I am able to connect to server well but I am getting below issue.

        Revived Message “null” from “user1@test.com”

        Help me ..it’s is very important for me.

        Regards,
        Raju

  3. Rohit Kelkar says:

    Hi, I have installed the openfire server, spark client and have also installed the code + smack API to work with eclipse.
    When I run the XMPPTest.java, I can see the testuser1 logging in through the spark client, however the sample message “Hello Mate” is not received my testuser2 in spark. Also, any messages sent from spark are not displayed for testuser1 on eclipse console.
    The only change I have done from the sample code displayed above is that I have commented the “override” call in class MyMessageListner (was getting compilation errors).

    class MyMessageListener implements MessageListener { // @Override
    public void processMessage(Chat chat, Message message) {

  4. shanthi says:

    I am trying this mechanism from past 3days, after executing the code, what am waiting for output is came… Thank you soo much, and u r brilliant, what ever you provide the article is cristal clear….

  5. Vyoma Suthar says:

    hi.. can u suggest how can i achieve same in android.. & main concern is to receive chat msg even if i am out of my chat application.

    • Andy says:

      The messages sent from the other person will be stored on a database on your open fire server.
      all you have to do is check for new messages by date or something like that.

      Im still in dilemma how do we keep the chat session alive and the listener instances active for each p2p conversation session.

  6. Dinh Duong Mai says:

    Hi, man

    I installed openfire, Spark on my computer (server name: duong2179-pc, static public ip: 20x.25x.xx.xx). I also programmed a small chat application using Smack (according to this article).
    On Spark, I used testuser1 as username and 20x.25x.xx.xx as server, I got it log in.
    On the Java application I also used 20x.25x.xx.xx as HOST and testuer2 as USERNAME. I got it log in.

    From Spark, I could send messages to the Java application normally.
    But here is the issue:
    In my Java code, if I use:
    sendMessage(message, “testuser1@20x.25x.xx.xx”);
    I cannot send messages to Spark.
    But if I changes a little bit, like this:
    sendMessage(message, “testuser1@duong2179-pc”);
    Now, it works very well.
    * Notice that:
    – Both of them run on the same computer (openfire server).
    – If I run the Java app on another computer (also another network, it still get loging in well).

    So, what happened here?

  7. anakrajuy says:

    HI

    same coding I am using in my own application, I started openfire server and I created two users.

    when I run this above prgrm with created user ..I am able to connect but I am unable to get another one rply.

    —1st time user1 sending to user2

    sendMessage(message, “user2@test.com”); —> msg sending succsess

    Received Message “null” from user2@test.com

    —1st time user2 sending to user1

    sendMessage(message, “user1@test.com”); —> msg sending succsess

    Received Message “null” from user1@test.com

    So How can I get Received message………………….Help me

    can any one help me on this same.

    Advance thanks to All…

    Reagrds,
    raju

  8. Phaneendra Hari says:

    I want to develop a Chat Engine but I am stuck at the search feature. My code and the error are posted here:
    http://stackoverflow.com/questions/19808663/search-for-users-on-ejabberd2-using-smack-fails

    Can you please look at it and tell me what I am doing wrong? Thanx a lot in advance!

  9. chakri says:

    very nice….

  10. isaac says:

    hi guys,

    can anyone show me steps to add in smack.jar into eclipse? thanks.

    • Phaneendra Hari says:

      You need to copy the Smack.jar and paste it into the libs folder of your Project AND add it into the Java Buildpath as an external jar files.

  11. anupama says:

    can anyone provide me wit some java codes tat capture xampp packets?

  12. jigar says:

    i got following errr
    Exception in thread “main” Connection failed. No response from server.:
    at org.jivesoftware.smack.PacketReader.startup(PacketReader.java:121)
    at org.jivesoftware.smack.XMPPConnection.initConnection(XMPPConnection.java:636)
    at org.jivesoftware.smack.XMPPConnection.connectUsingConfiguration(XMPPConnection.java:596)
    at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:1010)
    at com.xmppconfig.XmppTest.main(XmppTest.java:23)

  13. Mukhtar says:

    thanks very much

  14. drakgoku1 says:

    In 2014

    Not work

    U need register listener or not work !

    NEVER CALL

    messageListener = new MyMessageListener();
    Chat chat = chatManager.createChat(buddyJID, messageListener);

    messageListener “NEVER CALL MyMessageListener ”

    class MyMessageListener implements MessageListener {

    @Override
    public void processMessage(Chat chat, Message message) {
    String from = message.getFrom();
    String body = message.getBody();
    System.out.println(String.format(“Received message ‘%1$s’ from %2$s”, body, from));
    }

    }

  15. Minal says:

    Thanks for this easy tutorial. It is very helpful.
    I am building a chat aap for android and would like to know how can I implement this in android.

  16. Ankit Mathur says:

    Hello to all,

    I have set up the openfire server and now connecting it with the java application, still I am unable to connect to the openfire server.
    My code for the java side configuration is :

    package com.connectionmanager;

    import java.io.IOException;

    import javax.security.sasl.SaslException;

    import org.jivesoftware.smack.*;
    import org.jivesoftware.smack.SmackException.NotConnectedException;
    import org.jivesoftware.smack.packet.Packet;

    public class ConnectionManager {

    private static final String host=”http://127.0.0.1:9090″;
    private static final int port=5223;
    public static void main(String[] args) throws Exception{
    System.out.println(“This is a demo for connection to openfire”);

    ConnectionConfiguration config=new ConnectionConfiguration(host, port);
    XMPPConnection con=new XMPPConnection(config) {

    @Override
    protected void shutdown() {
    // TODO Auto-generated method stub

    }

    @Override
    protected void sendPacketInternal(Packet arg0) throws NotConnectedException {
    // TODO Auto-generated method stub

    }

    @Override
    public void loginAnonymously() throws XMPPException, SmackException,
    SaslException, IOException {
    // TODO Auto-generated method stub

    }

    @Override
    public void login(String arg0, String arg1, String arg2)
    throws XMPPException, SmackException, SaslException, IOException {
    // TODO Auto-generated method stub

    }

    @Override
    public boolean isUsingCompression() {
    // TODO Auto-generated method stub
    return false;
    }

    @Override
    public boolean isSecureConnection() {
    // TODO Auto-generated method stub
    return false;
    }

    @Override
    public boolean isConnected() {

    return false;
    }

    @Override
    public boolean isAuthenticated() {
    // TODO Auto-generated method stub
    return false;
    }

    @Override
    public boolean isAnonymous() {
    // TODO Auto-generated method stub
    return false;
    }

    @Override
    public String getUser() {
    // TODO Auto-generated method stub
    return null;
    }

    @Override
    public String getConnectionID() {
    // TODO Auto-generated method stub
    return null;
    }

    @Override
    protected void connectInternal() throws SmackException, IOException,
    XMPPException {
    // TODO Auto-generated method stub

    }
    };

    con.connect();
    if (con.isConnected()) {
    System.out.println(“Connected to server “+con.getHost());
    } else {
    System.out.println(“cannot connect to server”);
    }
    }
    }

    Please reply if any error above:

  17. Sarthak Mehta says:

    Dude great work, thanks but 3 error get poped up when i copy paste your program
    compiler is not able to find some methods like ‘config.setSASLAuthenticationEnabled(false);’
    also having error in ->XMPPConnection connection = new XMPPConnection(config); and -> ChatManager chatManager = connection.getChatManager();

    makes me to override method but still its useless

    if got ANY IDEA ABOUT it PLZZZZ REPLY ASAP!!!

    ONCE AGAIN THANKS FOR TUTORIALS…!!!

  18. Mohit says:

    Hii can u please give the code for file transfer. I have searched a lot on internet but not able to transfer a file.

  19. Khan says:

    Hi,
    can you please provide me the link of other tutorials.

    Please.

Leave a Reply


+ five = 6



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close