In many ways, email is convenient for inter-client communication, but is quite slow. Due to the pervasiveness of spam, more and more restrictions are being imposed upon email accounts, such as size and number of recipients.
Utilizing instant messaging (IM) promotes fast communication—both direct and indirect. For most clients, direct communication is not a necessity. Despite the fact that some protocols do not allow large messages, relaying substantial correspondences may be expedited as file transfers through IM. Delivery is instant, and most firewalls will pass IM traffic. Essentially, even if a user's primary intent is not to send messages, IM protocols still prove useful in the automation of a P2P environment as they provide a ready platform as well as some inherent anonymity.
Supporting email in your Java application is as simple as including mail.jar in your classpath. Fortunately, you only have to worry about one protocol: SMTP (Simple Mail Transfer Protocol). In the IM world, because of the multitude of different protocols, things are not quite as simple. Nevertheless, we need only one project: JClaim, a set of components for IM communication. It includes not only an interactive client, but also a library of classes and interfaces that together make up a flexible framework that supports AIM (AOL Instant Messager), ICQ, Yahoo, MSN (Microsoft Network), Jabber, and GoogleTalk. Other protocols can be added quickly and easily.
This article shows you how to incorporate IM into your application using JClaim. We will write a bot that responds with the current date and time. A bot is an auto-responder used to automate repetitive tasks and is the simplest use of a communication library that we could think of.
Building the JClaim tree is easy. Source code for JClaim can be found on the JClaim Website, in Subversion. For this article, we will only be concerned with the IM API residing in the java/core directory. Supporting JARs are located in the lib folder at the root of the repository.
If you would like to avoid the steps for building the jar files, simply grab the jar files referenced in Resources, add them to your classpath and proceed to the next section of this article. Please note that many other jar files are needed to use JClaim features not addressed in this article. For that, you should look into how to build the project source tree.
To compile the tree:
- Grab a Subversion client you would like to use (Tortoise, IntelliJ, Eclipse (with a plugin), see Resources)
- Check out the whole tree into a subfolder
- Locate an install Ant
- Use
ant jar
command to compile the tree - Examine the run target to create your own or configure your IDE
Model
The figure below illustrates the object model behind the JClaim communication libraries. Start tracing from the Connection
interface to make better sense of it all.
JClaim object model. Click on thumbnail to view full-sized image.
Here is a quick look at the JClaim API:
|
|
Let's start with an empty class and add some code as we go.
Though we do not need a group to make things work, once connected, the API will use groups and contacts to organize and maintain a session. As a result, it is necessary to provide some implementation:
static class GroupImplFactory implements GroupFactory {
public Group create(String group) {
return new GroupImpl();
}
public Group create(Group group) {
return new GroupImpl();
}
}
static class GroupImpl implements Group {
public int size() { return 0; }
public void clear(Connection connection) { }
public Nameable get(int index) { return null; }
public Nameable add(Nameable contact) { return null; }
public boolean remove(Nameable contact) { return false; }
public String getName() { return "Group"; }
}
static class ContactImplFactory implements ContactFactory {
public Contact create(Nameable buddy, Connection connection) {
return create(buddy.getName(), connection);
}
public Contact create(String name, Connection connection) {
return new ContactImpl(connection, name);
}
public Contact get(String name, Connection connection) {
return new ContactImpl(connection, name);
}
}
static class ContactImpl implements Contact {
private final Status status = new StatusImpl(this);
private final Connection connection;
private final String name;
public ContactImpl(Connection connection, String name) {
this.connection = connection;
this.name = name;
}
public void statusChanged() {}
public Icon getIcon() { return null; }
public void setIcon(Icon icon) {}
public Icon getPicture() { return null; }
public void setPicture(Icon icon) { }
public String getDisplayName() { return name; }
public void setDisplayName(String name) {}
public Status getStatus() { return status; }
public Connection getConnection() { return connection; }
public String getName() { return name; }
}
For a robust, "production-worthy" implementation, you'll want to cache contacts and groups to maintain and preserve state, which could easily be done by, for instance, using a concurrent map and list, respectively. Here, however, we skip this step for the sake of clarity and to concentrate on the subject at hand. Note that the classes are static so we can dump them all into one file; if you intend to put each one into its own .java
file, you should remove the static modifier.
Here is the gist of the connection code:
public static void main(String[] args) throws Exception {
MessageSupport conn = new OscarConnection();
conn.assignGroupFactory(new GroupImplFactory());
conn.assignContactFactory(new ContactImplFactory());
conn.setUserName(LOGIN);
conn.setPassword(PASSWORD);
try {
conn.addEventListener(new BotEventHandler());
conn.connect();
} catch (Exception e) {
System.out.println("Failed to create required pieces. Shutting down.");
e.printStackTrace();
return; // No point waiting if connection isn't available
}
while (true) { // Simplified version of "stick around" wait
GeneralUtils.sleep(60*60*1000);
}
} // main()
The new OscarConnection()
method can be replaced with any (or a list of several) connection(s) available from the library. Choose any of the com.itbs.aimcer.commune.*
subpackages. You can use conn.addEventListener()
to add more than one listener. Each listener can provide a new service (logging, messaging, etc.).
So far, this article's code serves setup purposes only. For our intentions, the actual logic is housed in the BotEventHandler
class shown below. Messaging is implemented asynchronously, so all we have to do is react to events, most of which will be irrelevant to our simple example. We only show here the methods that contain the real code:
public class BotEventHandler implements ConnectionEventListener {
public boolean messageReceived(MessageSupport connection, Message message) {
if (message.isOutgoing()) // Not doing anything with outgoing messages
return true;
System.out.println("Message arrived");
try {
String line = GeneralUtils.stripHTML(message.getText());
if (line.startsWith("status")) {
connection.sendMessage(new MessageImpl(message.getContact(), true, "up! " + new Date()));
} else if (line.equals("shutdown")) {
connection.sendMessage(new MessageImpl(message.getContact(), true, "shutting down."));
Thread.sleep(1000); // Let it finalize comminications.
connection.disconnect(true);
System.exit(1);
} // else
} catch (InterruptedException e) {
System.out.println("Failed while processing a message.");
e.printStackTrace();
}
return true;
} // Message received.
// Rest of the calls are blank. You may also want to implement connectionLost() to provide
//reconnect capabilities.
}
As messages come in, they are parsed for commands and replies are sent appropriately.
Conclusion
Yes, it is that easy to connect to virtually any service via any IM protocol using JClaim. For more details, read through JClaim's documentation and look through the UI code to see how to do things.
To add your own protocol, simply inherit from the right abstract class or interface and follow the examples provided by other mediums.
Where do you go from here? Having tools like these, it is simply a matter of imagination. You could implement a P2P communication, which does not rely on a Web browser and isn't limited by a specific medium. Setting up a Web service or enhancing the (already built-in) Web client to support multiple users would not prove difficult. Consider the collaboration software, monitoring tools, or delivery mechanisms that could be written. Much of the software that uses email could be improved with IM communication when the contact is online. With JClaim, the possibilities are endless.