Communications

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 :

Ilias Tsagklis

Ilias is a software developer turned online entrepreneur. He is co-founder and Executive Editor at Java Code Geeks.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

50 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Pavel Vik
Pavel Vik
12 years ago

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

prasanna jatla
prasanna jatla
11 years ago

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

shanthi
shanthi
11 years ago
Reply to  prasanna jatla

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

ankaraju
ankaraju
10 years ago
Reply to  shanthi

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.com”

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

Regards,
Raju

Pradeep Agrawal
Pradeep Agrawal
6 years ago
Reply to  ankaraju

How to install openfire server on local machine? plzz help me

Rohit Kelkar
Rohit Kelkar
11 years ago

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… Read more »

shanthi
shanthi
11 years ago

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….

Vyoma Suthar
Vyoma Suthar
10 years ago

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
Andy
10 years ago
Reply to  Vyoma Suthar

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.

Dinh Duong Mai
Dinh Duong Mai
10 years ago

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… Read more »

anakrajuy
anakrajuy
10 years ago

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@wong wong.com”); —> msg sending succsess Received Message “null” from user2@wong wong.com —1st time user2 sending to user1 sendMessage(message, “user1@wong wong.com”); —> msg sending succsess Received Message “null” from user1@wong wong.com So How can I get Received message………………….Help me can any one help me on this same. Advance thanks to All…… Read more »

Phaneendra Hari
Phaneendra Hari
10 years ago

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!

chakri
chakri
10 years ago

very nice….

isaac
isaac
10 years ago

hi guys,

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

Phaneendra Hari
Phaneendra Hari
10 years ago
Reply to  isaac

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.

Ali Ashiq
9 years ago

Sir i am also developing chat base application using xmpp, i am able to send presence but how can i add friends in roaster or send friend request will u guide me how could i do Arora @Prabuddha i am able to get my roaster entries like this

Roster roster = connection.getRoster();
Collection entries = roster.getEntries();
for (RosterEntry entry : entries) {
System.out.println(entry);
now i want to send friend request how could i

anupama
anupama
10 years ago

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

jigar
jigar
10 years ago

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)

shivam
shivam
8 years ago
Reply to  jigar

user port 5222 instead of 5280

Mukhtar
Mukhtar
9 years ago

thanks very much

drakgoku1
9 years ago

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));
}

}

Minal
Minal
9 years ago

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.

Ankit Mathur
Ankit Mathur
9 years ago

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… Read more »

Sarthak Mehta
Sarthak Mehta
9 years ago

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…!!!

Mohit
Mohit
9 years ago

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

Khan
Khan
9 years ago

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

Please.

Dan
Dan
9 years ago

This example is outdated because the newer Smack API has a number of changes.
For example XMPPConnection is now an abstract class and therefore you need XMPPTCPConnection to create an instance. There are many other such changes.

Surya
Surya
9 years ago
Reply to  Dan

Can you provide with a complete source code, am a beginner but not a newbie to android, since this is my first chat application

Back to top button