Use JMS to build a unified user management framework within your enterprise The importance of maintaining an accurate list of an enterprise’s customer and user profiles cannot be overemphasized. Most enterprises today use business applications like enterprise resource planning (ERP), customer relationship management (CRM), supply chain management (SCM), and some homegrown applications for e-commerce. A common communication infrastructure is required to maintain a synchronized list of user profile information among these diverse applications. Any system providing such an infrastructure must ensure that communication among these applications is reliable (even over unreliable networks) so that user information is not lost; user information is accurate and consistent within these applications; and the solution can scale well as new users and applications are added.Given these stringent requirements, protocols like HTTP, FTP, remote procedure call (RPC), and Remote Method Invocation (RMI) are ruled out. These are synchronous protocols, which, by definition, require an active physical connection between the client and server to function reliably. Certainly, a more robust solution is required. Messaging provides the ability for the client and server to operate asynchronously in a disconnected manner, just like email. At the same time, messaging systems like Java Message Service (JMS) offer native support for reliable, guaranteed message delivery. Clearly, if we can send user profile updates to interested applications via messages, we have a solution for our problem.Regarding the messages’ data format, we use XML for message delivery because it is easily understood by diverse applications; it is a self-describing, extensible format that should accommodate any future applications without modifying existing ones; XML content is easily searchable; and XML parsers are readily available and easy to use. This article assumes an introductory knowledge of JMS or other message-queuing systems. Rather than describe JMS capabilities, we focus more on our framework’s architecture and design. We provide a system architecture overview, a class diagram, a sequence diagram, and Java code to clearly describe the solution we developed. The solution was deployed on BEA’s WebLogic Server 5.1.0 SP8 (Service Pack 8), which implements Sun Microsystems’ JMS 1.0.1.Note: You can download this article’s source code from Resources.System architectureFigure 1 shows our system’s architecture. The system consists of a Web interface for user administration. An administrator uses this interface to change a user’s profile. This Web interface uses a custom API, which we call UserInfo API for convenience, to handle updates to user profiles. Each time a user profile is modified, UserInfo first updates the master database. The master database is updated first so that in the (rare) case of a transmission failure, the data can be published again using information just saved in the master database. Once the master database has been updated, the JMS publisher is notified. The publisher then publishes the changes to the JMS topic. The various registered application subscribers then asynchronously receive these changes. One JMS subscriber is assigned to each business application that needs to locally maintain user profile information. In the accompanying architecture diagram, JMS subscribers are provided for an ERP application, a CRM application, and a future application (that we call XYZ application). Each subscriber updates the user profile information directly in its corresponding application, either via an API to the application (in which case the application must be Java-based), or by manipulating the tables in the application (in which case the application need not be Java-based).Users can modify their own profiles through a personalized My Profile page. All changes made by users to their profiles are also sent to the publisher so it can notify the subscribers.Prepare the messageThe javax.jms.TextMessage object updates the user profiles. Each TextMessage encapsulates an XML document as a Java String that contains updates to a user’s profile. The XML document specifies the operation to be performed, the username on which the operation will be performed, and the updated user information. For example, the following XML message adds a new user to the system: <UserProfiles> <User> <Action>Create</Action> <Username>tbrown</Username> <FirstName>Timothy</FirstName> <LastName>Brown</LastName> <Email>tbrown@somewhere.com</Email> </User> </UserProfiles> The following XML message deletes a user’s profile from the system: <UserProfiles> <User> <Action>Delete</Action> <Username>tbrown</Username> </User> </UserProfiles> The publication mechanismWe use the publish-subscribe messaging model defined by the JMS specification to deliver user profile updates to the various subscriber applications. In this model, publishers send messages to a topic, and all subscribers to that topic receive all messages sent to that topic. The publishers and the subscribers need not be aware of each other—the JMS implementation distributes the messages arriving from a topic’s publisher to its multiple subscribers. The default message delivery mode is persistent, which ensures that messages are not lost in case of a JMS provider failure; and the subscriptions can be made durable, which ensures that if a subscriber is inactive, the persisted message is not lost, but rather, is delivered when the subscriber becomes active again. That guarantees message delivery. We use the publish-subscribe model because each message must be consumed by multiple recipients, and these recipients can be added and removed at will. We use nondurable subscribers instead of durable subscribers because according to the JMS specification, only one durable subscriber can be active at one time; we need to maintain multiple subscribers. Nondurable subscribers do not pose a problem for our application because we expect active subscribers at all times. However, it is important we use persistent message delivery mode to ensure that messages always reach the subscribers. In the persistent delivery mode, a message is not considered published until it has been successfully written to a (properly configured) database or file system.Class structureFigure 2 shows our framework’s class diagram. The diagram’s various components are explained below. UserInfo API: The Web application uses this API to communicate with the messaging system. It is a generic API—it does not assume anything about the underlying implementation. Any other implementation can easily be supported as long as it conforms to the interface provided by this API.UserServiceFactory: This class implements the popular Factory pattern. It returns an implementation of IUserService (in this case JMSUserService).IUserService: This interface to JMSUserService decouples the application from the specifics of a particular implementation.JMSUserService: This class handles the user profile data. It prepares XML messages for publication to the topic and uses JMSClientManager to publish them.ServicesStartup: This class is called by the application server when the server starts up. ServicesStartup calls JMSClientManager, which creates the publisher and subscribers, so the publisher and subscribers are set up before the server begins to listen on its designated port.JMSClientManager: This singleton class creates one Publisher object and all the Subscriber objects. It registers the subscribers as listeners to the JMS topic.Publisher: Created by JMSClientManager, this class publishes data to the JMS topic.Subscriber: This is the parent class of all application subscribers. JMSClientManager expects an instance of this class while registering a subscriber. Subscriber implements javax.jms.MessageListener.The subscribersThe subscriber classes (ERPSubscriber, CRMSubscriber, etc.) are subscribers for any enterprise applications needing updates to user profiles. They receive user profile changes from the JMS topic in the form of XML messages and then update these profiles in the applications to which they are bound.These classes use instanceof to ensure they have received a message of type TextMessage. They ignore all other message types.These classes inherit from Subscriber, which means they must override the onMessage() method. The onMessage() callback is an event-driven message handler that the JMS provider asynchronously invokes when a new message arrives. This method extracts the message’s content and reconstructs it into a meaningful transaction for updating a user’s profile. We provide a template for the onMessage() method implemented by ERPSubscriber below: public void onMessage(Message message) { try { // Message must be of type TextMessage. // Ignore other message types. if (message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; String profileXML = textMessage.getText(); // One of the elements in the document must be 'Username', // so we know which user's profile needs to be updated. // Also, one of the elements in the document must be 'Action', // so we know what action is to be performed on the user profile // (Create, Update, or Delete). // Retrieve the following from the XML document: // 1) Username whose profile needs to be updated // 2) Action to take with the user profile // 3) Parameters that need to be updated, // e.g., address, phone number, etc. ... ... // Update ERP system with new user data. ... ... } } else { System.out.println("Message not recognized."); return; } } catch (JMSException e) { e.printStackTrace(); } } Set up the publisher and subscribersSome session objects must be created as part of the publisher-subscribers setup. Exercise caution while developing these session objects. If you look at JMSClientManager, you notice we create one session for the publisher and one session for each subscriber. (It’s a different matter that we create all our subscriber sessions with the same TopicSession object (subSession).) For example, the code below creates a new TopicSession every time a new subscriber is added to the JMS topic: // This method is extracted from JMSClientManager.java public void registerSubscriber(Subscriber subscriber) { try { // Create a new TopicSession object for every subscriber subSession = topicConnection.createTopicSession( false, Session.AUTO_ACKNOWLEDGE); topicSubscriber = subSession.createSubscriber(topic); topicSubscriber.setMessageListener(subscriber); } catch(Exception e) { e.printStackTrace(); } } Since we have one publisher and three subscribers, we create four different sessions rather than have all objects use the same session. This is because, according to the JMS specification, TopicSession does not support multiple threads. In our application, each subscriber uses a different thread, and the publisher uses a different thread (which is the main application thread). Since the invocation of the onMessage() handler is asynchronous, it can be called while the publisher is publishing messages in another thread. If the same session creates the publisher and subscribers, the two would operate in the same session concurrently—a condition not supported by the JMS specification. For the same reason, each subscriber must also operate in a different session. Since the invocation of the onMessage() handler is asynchronous, two subscriber threads can become active at the same time, so they should not use the same session.Set up the publisher and subscribers following these steps: Using Java Directory and Naming Interface (JNDI), look up a TopicConnectionFactory for the JMS provider that hosts the desired topic. Since TopicConnectionFactory is an administered object, a system administrator must provide the JNDI name for this object. A TopicConnectionFactory‘s sole purpose is to create connections.Use this TopicConnectionFactory object to create a TopicConnection, which represents a direct connection to the JMS server.Create a JMS TopicSession. This object creates message producers and consumers (publishers and subscribers) and manages the flow of messages.Look up a JMS Topic with JNDI. Like TopicConnectionFactory, Topic is an administered object, so a system administrator must provide the JNDI name for it.Create a publisher to the topic just set up in Step 4.Create the individual JMS subscribers for ERP, CRM, and other applications, and set these subscribers as message listeners to the topic obtained in Step 4.The TopicConnection created in Step 2 is initially stopped. Start the connection by calling its start() method.Publish updatesThe sequence diagram shown in Figure 3 illustrates the process of updating user profiles.Figure 3. Publish updates to user profiles. Click on thumbnail to view full-size image.The update process is as follows:Obtain a singleton instance of UserServiceFactory.Use this factory object to obtain an IUserService interface to JMSUserService by calling the getService() method on UserServiceFactory.Pass user profile parameters that need updates to the IUserService object.IUserService prepares an XML string representing the action to be performed and the user profile parameters involved (as explained in the section, “Prepare the Message”).IUserService gets a singleton instance of JMSClientManager.From this instance, IUserService gets a reference to Publisher and sends the XML string to it for publication.Publisher encapsulates the XML message into a javax.jms.TextMessage and publishes it to javax.jms.TopicPublisher, which then sends the message to the JMS topic.The code below creates a new user tbrown in the system, updates his profile, and then deletes the user from the system: // Get instance of user service as an interface IUserService userService = UserServiceFactory.getInstance().getService(); // Create user with given profile userService.createUser("tbrown", "Timothy", "Brown", "tbrown@somewhere.com"); // Update this user's profile userService.updateUser("tbrown", "Timothy", "Brown", "tbrown@nowhere.com"); // Delete user from system userService.deleteUser("tbrown"); IUserService updates the database and notifies JMSClientManager, which then uses the publisher to publish the user’s profile to the various subscribers. As you can see, the underlying mechanism for updating all applications in the system is completely transparent to the developer—the developer’s task reduces to just one line of code each for user creation, user update, and user deletion.BenefitsThe framework described above provides the following benefits:It offers a robust system for user profile maintenance across heterogeneous applications. The framework ensures that user profiles always remain synchronized among these applications—regular data synchronization is unnecessary.Implementation cost is low; you don’t need to purchase a third-party product for maintaining synchronized lists of user information. A customized framework can be developed in-house with few resources.Only the master database requires backup. This database is considered authoritative.Using JMS at the center of the architecture provides these additional benefits:A standardized API for all applications and services within the framework.Guaranteed message delivery. With unreliable protocols, acknowledgement of data receipt must be built in at the application layer.The publish-subscribe messaging model allows one-to-many broadcast of information.New applications may be dynamically added to the system simply by creating a subscriber for the application and subscribing this subscriber to the JMS topic.The JMS vendor handles the communication infrastructure’s complexity, allowing developers to focus on the system’s higher-level architecture.DrawbacksOur framework does not support the ability to publish user profiles from individual applications. User profiles must be modified only through the Web interface, not by individual applications. Any updates made to a user profile directly in an application are likely to be lost once an updated profile for that user is published to the topic. Also, user groups and access control lists still need to be maintained elsewhere, for which more sophisticated tools are available.Possible enhancementsThe framework is elementary, but completely usable. You can apply some enhancements and make the system more sophisticated:Not all subscribers may need to receive all messages. To filter messages by content, JMS provides a properties-based message selection mechanism called message selectors. Message selectors cause the JMS provider to evaluate message headers and properties prior to sending messages to the subscriber applications. Use message selectors in the framework if you need to selectively publish messages to subscribers.On a client failure, or when a new client is added, a custom program can publish all existing user profiles to the JMS topic, which the newly registered subscribers can then receive.In case of a suspected out-of-sync situation, an on-demand sync feature can be provided through the Web interface.You can author custom JavaServer Pages (JSP) tags to handle user profile updates, making programming easier.JMS and XML: The perfect pairThis article presented a real-life, enterprise JMS example that integrates business applications in a simple, flexible, and guaranteed fashion. JMS links enterprise systems together through reliable messages, even over unreliable networks, and promotes decoupling and scalability of the system at the same time. XML’s use is particularly important here, as it provides a standard data format for information exchange between heterogeneous systems. Although JMS was not designed specifically for carrying XML payloads, in practice, it provides an excellent means for transporting XML. Together, JMS and XML offer a viable solution for many enterprise integration problems.Amit Goel is a senior developer at eSilicon Corp. He has been developing object-oriented applications for several years. He holds a bachelor’s degree in electronics from Indian Institute of Technology Delhi and a master’s degree in computer science from Virginia Tech. You can learn more about him at http://www.amitgoel.com. David Marshall is the platform architect for eSilicon Corp. He has more than 22 years of experience developing distributed tools and enterprise applications like ERP, using relational database systems, multiple operating systems, and distributed client/server, Internet, and Java architectures. David holds a master’s degree in computer science from Clemson University and coauthored US Patent number 5,758,351, a system and method for the creation and use of surrogate information system objects. Web DevelopmentJavaSoftware DevelopmentProgramming Languages