Developer: Architecture

Extend Your J2EE Application Server for Instant Messaging
by Prabhu Kapaleeswaran

Link an instant messaging subsystem to your J2EE middleware using J2EE Connector Architecture (JCA)

Downloads for this Article
· Source code
· OracleAS Containers for J2EE 10g
· JMSN (open source MSN messenger clone)

J2EE application servers have become a vital enterprise component recently, with users frequently interacting with them to get the data they need. These "self-service" enterprise systems are often further improved by extending the availability of data to the right people at the right time via email. Email, however, although reliable, is a passive channel that allows the end user to decide when he or she should receive data.

Recently we have seen the emergence of much more active (push-driven) channels, such as desktop instant messengers and GSM handsets and other handheld devices. Extending data transmission actively through such channels would establish a true hub-and-spokes model for the J2EE enterprise wherein business systems (hubs) transmit data to the right people through any or all of these active channels (spokes).

However, although many open-source APIs are available to interact with various instant messengers and wireless service centers, historically there has been no common way to bind these systems to the J2EE application server to take advantage of active media.

In this article, I'll explain how you can apply the J2EE Connector Architecture (JCA) to instant messaging by treating the latter like a J2EE resource adapter. I'll also show you how to design your applications so they can transmit data to instant messengers. I've provided ready-to-use code you can use to extend data transmission to these active channels.

We will use Oracle Application Server Containers for J2EE (OC4J) 10g (9.0.4) to bind the resource adapters, and the JMSN open-source MSN messenger clone to simulate a real-world IM implementation. Of course, you can try to link other instant messengers the same way by utilizing other instant messaging APIs.

Understanding JCA

JCA introduces the concept of the J2EE resource adapter, a software component that can integrate one kind of system with another. Consider the electrical adapter metaphor: Every country has a different kind of socket configuration, so the adapter connects a socket of one kind to another by allowing electricity to flow. The resource adapter plays a similar role in the enterprise: It adapts enterprise information systems (EISs) to the J2EE paradigm, allowing data to flow there from the J2EE-compliant business layer. In our case, this resource adapter would be utilized in transmitting information to a public domain instant messaging layer.

JCA integrates these two systems—the application server layer and the EIS layer—by defining two corresponding contracts:

  • System Contract, or service provider interface, specifies the interfaces the adapter needs to implement in order to plug into the application server.
  • Client Contract, or Common Client interface, specifies the interfaces the adapter needs to implement to plug into the EIS layer.

Let's examine each type of contract in more detail.

System Contracts

The application server provides various housekeeping and transaction services to the resource adapter. These services can be categorized into three categories: connection pooling, transaction management, and security. For our purposes here, only the first category is relevant.

Creating connections to the backend EIS is a fairly expensive task in terms of time and resources. This is not only true for the legacy EIS but also for databases, which is why the connections are pre-created at startup time or runtime and then cached. The connection pooling service is the equivalent of the database connection pool. But in our case, it is used for the EIS—that is, the instant messaging service. Connection pooling is handled inside the application server through javax.resource.spi.ConnectionManager.

Client Contracts

These contracts define how a service can interact with EIS. In a way, the services that need to interact with the EIS are the clients, and this contract defines a common API for the clients of the EIS—hence the name "common client interface." The different parts of the contract are described below.

Components: Static View

First, let's define the class-level components in our system. This level represents the static view, or how the various components are organized.

Many resources about JCA are available, so we will concentrate on the following essential interfaces and contracts here.

  • ManagedConnectionFactory (javax.resource.spi.ManagedConnectionFactory) - logically resides inside the application server/managed environment. It is the factory used to create ManagedConnection, the interface for connecting to the underlying EIS.
  • ManagedConnection (javax.resource.spi.ManagedConnection) - the physical connection to the EIS. It is the connection that is pooled inside the application server.
  • ConnectionEventListener (javax.resource.spi.ConnectionEventListener) - used by the ManagedConnection and ConnectionManager to signal various lifecycle events of the connection to the EIS.
  • ConnectionFactory (javax.resource.cci.ConnectionFactory) - logically resides outside the application server/managed environment. Part of the common client interface, this is the component used for creating the physical connection to the EIS.
  • Connection (javax.resource.cci.Connection) - the application-level handle that the clients use to interact with EIS. Our Connection implementation has a ManagedConnection to request that housekeeping activities be performed by the application server. The EJB interacts with this connection to interact with the EIS.

I recommend that you consult the javadoc for these classes to learn how they relate to each in more detail.

Components: Dynamic View

The dynamic view is used to describe the interaction between various components described in the static view. As an example, let's consider a sample use case: an EJB trying to send an instant message using the instant messenger connector. Here is the sequence of events:

  1. EJB looks up the JNDI for the instant messenger Java Connector. This returns the javax.cci.ConnectionFactory.
  2. EJB then requests a connection from the ConnectionFactory.
  3. ConnectionFactory utilizes the ConnectionManager to request for a connection.
  4. The ConnectionManager checks to see if there are any pooled connections. If there are none, it uses the ManagedConnectionFactory to create a ManagedConnection.
  5. The application server creates a Connection using the ManagedConnection.
  6. The application server sets up the event listener on the Connection.
  7. The application server returns Connection to the ConnectionFactory.
  8. The ConnectionFactory returns the Connection to the EJB.
  9. EJB calls the send method on the Connection to send an instant message to another user.
  10. EJB closes the Connection.
  11. Connection informs the ManagedConnection so that it can be returned to the pool by ConnectionManager.

Now that we've overviewed the JCA at a conceptual level, let's design our system.

Implementing the Resource Adapter

Getting access to the instant messaging resource adapter is a two-step process: Getting the connection factory through JNDI lookup (ConnectionFactory), and then creating the connection for instant messaging (Connection).

The source code for the files described below is provided in connector_src.zip. I recommend that you extract its contents to your root directory (For example, C:/ for Win 32 environment). The unzipped directory structure and their corresponding semantics are explained below.

Note: IMJ2C_INSTALLATION_ROOT/imj2c is the root directory where the build script exists. You will need to be in this directory if you want to issue your Ant commands.

/bin directory for all the batch files. You will need to be in this directory if you want to execute these batch files.
/lib directory for all the libraries that are needed for the imj2c. Since we are talking to public domain instant messaging system like Yahoo and MSN, I have included the hamsam.jar. Hamsam is the binary protocol implementation for connecting these instant messaging services.
/src root directory for all the source files
/build root directory for all the class files
/dist directory that has the final distributable .jar, .rar, and .ear files
/meta-infdirectory for the config files or the descriptor files; in our case, this directory will house the ra.xml file. The ra.xml file (described later) specifies the various components of the resource adapter.
/client client war file that can be used to test this application

Now that we've defined the functionality of the client through a class contract, let's implement the main interfaces.

Description of the ConnectionFactory

The ConnectionFactory is the primary interface the clients use to instantiate the appropriate connector. In a way the ConnectionFactory can be compared with the Home interface of EJB that is used to instantiate the Remote instance of the EJB. Our ConnectionFactory exposes 2 methods to get the java connector.

  • getConnection(String userName, String password) - Gets a connection to the specified instant messaging system for the specific user.
  • getConnection() - Gets any connection to the specified instant messaging system. Because no specific user is specified, the IMConnectionFactory will return the first such connection it finds.

package com.prerna.jca.sample.cci;

public class IMConnectionFactory
{
	/* Gets a connection to the specified instant messaging system (imType) for the specific user. 
	* @param userName - username to authenticate to instant messaging subsystem
	* @param password - password to authenticate to instat messaging subsystem
	*/
	public IMConnection getConnection(String userName, String password);

	/* Gets a default connection to the specified instant messaging subsystem
	*/
	public IMConnection getConnection()
}

Description of the Connection Interface

IMConnectionFactory is the EIS factory that is used to create the Connection (IMConnection). In order for the ConnectionFactory to make effective use of connection pooling and other housekeeping resources, it is important for the ConnectionFactory to have references to the ConnectionManager that is provided by the application server. When a client layer needs to communicate with the instant messaging system, it uses the IMConnectionFactory to get the appropriate connection. IMConnectionFactory in turn uses the ConnectionManager to get the appropriate connection from the pool or creates a connection through the ConnectionManager and ManagedConnectionFactory to create a connection in the pool and return it.

package com.prerna.jca.sample.cci;
import javax.resource.spi.ManagedConnection;
public class IMConnection
{
		/*
		* this method is used to login into the instant messaging system
		*/
		public boolean login();

		/*
		*	this method is used to logout from the instant messaging system
		*/
		public void logout();

		/*
		* this method is used to load a properties file and to configure this J2EE Resource Adapter
		* the properties file has all the necessary attributes needed for the system 
		* this includes
		* @param username - the username used to login
		* @param password - the password for the user
		*/
		public void config(String userName, String password);

		/*
		* Used to send instant message to the user
		* @param recipientUser - the user to which the instant message needs to be sent
		* @param message - the message being sent to the user
		*/
		public void sendMessage(String recipientUser, String message);

		/*
		* Used to send instant messages to multiple user
		* @param recipientUserList - list of users to whom the information need to be sent
		* @param message - the message being sent to the user
		*/
		public void sendMessage(ArrayList recipientUserList, String message);

		/*
		* Checks to see if this im is still connected to the system
		* @return - true if this im connection is open, false otherwise
		*/
		public boolean isConnected();

		/*
		* Indicate to the IMConnection that the work is done
		* this will be used to signal to the application server 
		* so that it can put back on the pool
		*/
		public void closeConnection();
	}

Now, let's take a look at how to build these interfaces.

ManagedConnectionFactory

We will realize this interface by implementing the IMManagedConnectionFactory. At this point, I recommend that you bring up the source code for it by opening the IMManagedConnectionFactory located in the IMJ2C_INSTALLATION_ROOT/imj2c/ src/com/prerna/jca/sample/spi folder. This will you relate quickly to what is being described below.

The ManagedConnectionFactory would be used by the ConnectionManager to create the IMConnectionFactory (javax.resource.cci.ConnectionFactory) and the IMManagedConnection (javax.resource.spi.ManagedConnection). It has ConnectionFactory creation function in two flavors.

  • Object createConnectionFactory() - We will not be using this flavor because we would like to utilize the ConnectionManager to cache and serve our connections.
  • Object createConnectionFactory(ConnectionManager cm) - We will be supporting this operation. It would be used to create IMConnectionFactory (described below).

ManagedConnection

We will create this interface by implementing the IMManagedConnection. At this point I recommend that you bring up the source code for it by opening the IMManagedConnection located in the IMJ2C_INSTALLATION_ROOT/imj2c/src/com/ prerna/jca/sample/spi folder.

The ManagedConnection would be used to create IMConnection (javax.resource.cci.Connection). The ManagedConnection can choose to be transaction sensitive. The application server pools the ManagedConnection. It attaches ConnectionEventListener to every ManagedConnection that exists in the application server. The IMConnection internally uses the ManagedConnection to signal the events to the application server.

Connection

We will create this interface by implementing the IMConnection interface. At this point, bring up the source code by opening the IMConnection.java located in the IMJ2C_INSTALLATION_ROOT/imj2c/src/com/ prerna/jca/sample/cci folder.

IMConnection exposes the various operations that can be performed on instant messaging system. IMConnection is responsible for logging into the instant messaging system and sending message to the appropriate user in the specific instant messaging system. I will realize the IMConnection interface through the IMConnectionImpl class.

ConnectionFactory

We will create this interface by implementing the IMConnectionFactoryImpl. The IMConnectionFactoryImpl will also implement IMConnectionFactory interface. Bring up the source code for it by opening the IMConnection.java located in IMJ2C_INSTALLATION_ROOT/imj2c/src/com/ prerna/jca/sample/cci folder. This will help the reader to relate quickly to what is being described below.

Now that we have implemented bare minimum for the four required interfaces for our resource adapter, let's test this application.

Building the Source

You can build the source by executing

> build compile 

from the IMJ2C_INSTALLATION_ROOT/imj2c directory. This command will run the build.bat file located in the /bin directory.

If you are familiar with Ant and have the Ant environment setup for yourself, you can achieve the same by executing

> ant compile 

from the IMJ2C_INSTALLATION_ROOT/imj2c directory. This runs the imj2c target located in the build.xml.

Go ahead, feel free to change the source code—add your own debug statements and build it.

Packaging the rar File

The resource adapter is packaged into a jar file (much like a zip file) with a .rar extension; "rar" is acronymic for Resource ARchive.

Any rar file has two important components: the class files that implement the resource adapter, and the deployment descriptor file, ra.xml.

The class files are packaged as a separate jar file. You can package this jar file by executing

> build jar

from the IMJ2C_INSTALLATION_ROOT/imj2c directory. The output jar file imj2c.jar can be located in the dist directory.

We can build the rar file by executing

> build rar

from the IMJ2C_INSTALLATION_ROOT/imj2c directory. The output rar file imj2c.rar can be located in the dist directory.

Now, let's examine how to edit the ra.xml file.

Understanding the ra.xml File

The ra.xml resource adapter descriptor document is valid XML. It must conform to the DTD specified by Sun for the resource adapter. The DTD for the resource adapter can be found at the JCA webpage.

The resource adapter is specified using the following element.

<!ELEMENT resourceadapter (
managedconnectionfactory-class, connectionfactory-interface, 
connectionfactory-impl-class, connection-interface, 
connection-impl-class, transaction-support, config-property*, 
authentication-mechanism*, reauthentication-support, security-permission*
)>

Here are the descriptions of the mandatory individual elements in the file and how they are specified for the instant messaging resource adapter.

The final ra.xml is available in the meta-inf directory. I recommended that you inspect this file in order to understand how different components are structured.

Deploying the rar File

Now that we have successfully built the rar file, we will need to deploy and test it. In order for the resource adapter to be available to the client layer, it needs to be deployed and bound into the JNDI tree. This approach will allow the client layer to look up our resource adapter and interact with it.

Our instant messaging resource adapter will be made available through the eis/imEIS JNDI name. To deploy the rar, you will first need to start-up OC4J. When you have the OC4J server listening, you can deploy the rar by executing the following command from OC4J_INSTALL_ROOT/oc4j/j2ee/home:


> java -jar admin.jar ormi://localhost admin <password> -deployconnector -file IMJ2C_INSTALLATION_ROOT/dist/imj2c.rar -name imj2c

This command will deploy the rar as a standalone with name imj2c and add a reference in the OC4J_INSTALL_ROOT/oc4j/j2ee/home/config/oc4j-connectors.xml file. The following snippet will be added to this file.

<connector name="imj2c" path="imj2c.rar"></connector>

The resource adapter itself is deployed in OC4J_INSTALL_ROOT /oc4j /j2ee /home /connectors directory. When the adapter has been deployed, it has to be configured to bind it to the OC4J JNDI. The name for binding the adapter to the JNDI can be specified through the OC4J_INSTALL_ROOT/oc4j/j2ee/home/application-deployments/default/imj2c/oc4j-ra.xml file.

The location attribute of the connection-factory element reflects the name that would be used to bind this resource adapter to the OC4J JNDI tree. We need to specify eis/imEIS here. The resulting snippet of the oc4j-ra.xml file is shown below.

<?xml version="1.0"?>
<!DOCTYPE oc4j-connector-factories PUBLIC "-//Oracle//DTD Oracle Connector 9.04//EN" "http://xmlns.oracle.com/ias/dtds/oc4j-connector-factories-9_04.dtd">

<oc4j-connector-factories>
    <connector-factory location="eis/imEIS" connector-name="IM Connection Adapter">
	</connector-factory>
</oc4j-connector-factories>

Next, the library files needed to connect to the instant messaging subsystem are copied into the OC4J_INSTALL_ROOT/oc4j/j2ee/home/applib directory. In our case, you will need to copy IMJ2C_INSTALLATION_ROOT/imj2c/lib/msnm.jar and IMJ2C_INSTALLATION_ROOT/imj2c/jmsn.jar. We need to restart the OC4J container for this resource adapter to take effect.

Deploying the Client Application

The client directory within the root directory has the war file that can be used to test our resource adapter. The war file contains JSP as well as Servlet code to access the resource adapter. You will need to deploy the IMConnectorServlet into the default-web-app web application. This will be accomplished through three steps:

  • Copy IMConnectorServlet into the classes directory. You can copy the IMConnectorServlet from the IMJ2C_INSTALLATION_ROOT/imj2c/client/imj2c-client/WEB-INF/classes and place it in the OC4J_INSTALL_ROOT/oc4j/j2ee/home/default-web-app/WEB-INF/classes.
  • Copy SendMessage.html from IMJ2C_INSTALLATION_ROOT/imj2c/client/imj2c-client and place it in the OC4J_INSTALL_ROOT/oc4j/j2ee/home/default-web-app directory.
  • Modify the OC4J_INSTALL_ROOT/oc4j/j2ee/home/default-web-app/WEB-INF/web.xml to include the following details:

  <servlet>
        <servlet-name>IMJCATest</servlet-name>
        <servlet-class>pratest.web.IMConnectorServlet</servlet-class>
  </servlet>

	<servlet-mapping>
        <servlet-name>IMJCATest</servlet-name>
        <url-pattern>/imj2c</url-pattern>
  </servlet-mapping>

  <resource-ref>
    <res-ref-name>eis/imEIS</res-ref-name>
    <res-type>com.prerna.jca.sample.cci.IMConnectionFactory</res-type>
    <res-auth>Application</res-auth>
  </resource-ref>

You can also deploy the war through the regular procedure. It is available inside the IMJ2C_INSTALLATION_ROOT/imj2c/client directory.
Resources

JMSN Homepage

JCA Homepage

Java Connector DTD

OC4J 10g (9.0.4) Download

You can access the servlet at

http://your_server_name:server_port/SendMessage.html

Example:

http://localhost:8888/SendMessage.html

You can also modify the IMConnectorServlet and build it by executing the

> build ear 

command from the IMJ2C_INSTALLATION_ROOT/imj2c directory.

The portion of the code that accesses the factory and then sends a message is shown below.

 // Get the recipient and message
 String recipient = request.getParameter("recipient");
 String message = request.getParameter("message");

// Get the Naming Context
 Context ic = new InitialContext();
 System.out.println("Got the context ");

// Look up the connector from the context
 String name = "java:comp/env/eis/imEIS";
 IMConnectionFactory icf = (IMConnectionFactory)ic.lookup(name);
 System.out.println("Look up succeeded ");

// Create a connection by passing the username and password
// The connection here uses the Yahoo Instant Messenger
// Use your sample username and password to get the connection
 IMConnection imconn = icf.getConnection("prabhuk", "bingo");

// Send message to the intended recipient
 System.out.println("Trying to send message now ");
 imconn.sendMessage(recipient, "Hello World IM from J2EE ");

// Close the connection. This is important since this indicates to the
ConnectionManager that this connection is no longer in use and can be put back
on the pool
 imconn.closeConnection();

Note: The username and the password given in the IMConnectorServlet will not work. You will need to use your own MSN id.

Congratulations! You have now linked an instant messenger subsystem to J2EE middleware through the JCA.


Prabhu Kapaleeswaran [appserv@yahoo.com] is technical architect currently consulting for one of the world's largest financial corporations. He has extensive hands-on experience in developing access integration solutions on various portal servers. He has also worked on architecting solutions to extend access to mobile devices and multi-threaded servers in .NET (C#) and Java.


Please rate this document:

Excellent Good Average Below Average Poor


Send us your comments

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy