Use JClaim libraries to write IM-enabled applications

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:

  1. Grab a Subversion client you would like to use (Tortoise, IntelliJ, Eclipse (with a plugin), see Resources)
  2. Check out the whole tree into a subfolder
  3. Locate an install Ant
  4. Use ant jar command to compile the tree
  5. 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:

PackageDescription
com.itbs.aimcer.beanThis package contains basic interfaces responsible for the state machine and for passing objects around. The names (hopefully) are quite self-explanatory.
com.itbs.aimcer.communeThis package contains all the communication interfaces and a couple of abstractions.
com.itbs.aimcer.commune.*These packages are responsible for implementing the functionality for a particular medium.
Class in com.itbs.aimcer.communeDescription
ConnectionPrimary interface of all connection classes. Contains methods needed for any connection class.
MessageSupport (and other support interfaces)Provides starter methods needed for specific functionality. Using feature-specific interfaces in conjunction with instanceof allows us to cast the right connection to an interface that provides the features supported by that connection. Keeps the classes clean and minimizes boolean isFooSupported() calls or the use of reflection.
AbstractConnection, AbstractMessageConnectionProvide starter implementation for appropriate interfaces. We will not be using these directly, but these classes are good to know about.
ConnectionEventListenerListener pattern. Create your own and pass it in to receive events from a connection.


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.

About the author

Alex Rass has been working in the computer field for more than 10 years and has been working in Java for 7 years. He holds a MS in computer science from Stevens Institute of Technology, New Jersey. Currently, he is a tech lead and a senior architect working for Bloomberg LP. Alex Leshinsky has a master's degree in computer science and has been programming on various kinds of computers, and teaching other people how to do so, since the punch-card days. He works for a leading financial firm in Philadelphia, writing software, mainly using Java. R. A. Reutter is a professional writer whose work has recently led to a number of technical writing projects in the financial industry. He has been published in Contents Under Pressure, an avant-garde literary magazine, where he also served as a member of the editorial staff. Several of his theatrical works have been performed on the college level, and his experience also extends to collaboration on stage plays for Philadelphia's Novel Stages. His first novel, Lycanthropes & Leeches, is currently in publication. Pankaj Agnihotri is currently a CIO and has been working in the computer industry for more than 10 years.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值