Jump to: navigation, search

Difference between revisions of "EclipseLink/Development/JMSCacheCoordinationUsingMDB"

m (JMS Cache Coordination Using MDB)
(JMS Cache Coordination Using MDB)
 
Line 1: Line 1:
 
= JMS Cache Coordination Using MDB =  
 
= JMS Cache Coordination Using MDB =  
{{214534|bug}}
+
{{bug|214534}}
 
__TOC__
 
__TOC__
 
Cache Coordination is described in the docs at:
 
Cache Coordination is described in the docs at:

Latest revision as of 17:27, 5 April 2012

JMS Cache Coordination Using MDB

bug 214534

Cache Coordination is described in the docs at: http://wiki.eclipse.org/Introduction_to_Cache_(ELUG)#Cache_Coordination

The goal of this is to allow cache coordination to occur via JMS with a MessageDrivenBean used as a listener, eliminating the need for threads to be used to listen in the current JMSTopicTransportManager used for RCM.

Requirements

  • a JMSTransportManager to publish commands to JMS
    • this will need to obey the shouldPropagateAsynchronously flag on RemoteCommandManager and use the current JMS configuration settings
  • a MDB to listen and process received messages from JMS
    • should require no threads
  • Container testing

Design

JMS Publishing

The publishing behavior will be the same as the current JMS RCM using the JMSTopicTransportManager, in that it will push commands to the JMS queue. Configuration, such as setting the topic, host etc will remain exactly the same. Only differences the new JMSPublishingOnlyTopicTransportManager class will have over the JMSTopicTransportManager are that it will not need to create or remove local (listening) connections. Except for the following methods, all other methods will be common:

public void removeLocalConnection() public void createLocalConnection() public Hashtable getConnectionsToExternalServicesForCommandPropagation()

removeLocalConnection and createLocalConnection will be empty methods getConnectionsToExternalServicesForCommandPropagation need to behave differently, as JMSPublishingOnlyTopicTransportManager will only require the external (publishing) connection – JMSTopicTransportManager creates both the external and internal – which are JMSTopicRemoteConnection objects used to publish and receive messages.

As such, all methods but the above 3 will be moved to JMSPublishingOnlyTopicTransportManager, and JMSTopicTransportManager will be changed to extend JMSPublishingOnlyTopicTransportManager.

The shouldPropagateAsynchronously flag on the RemoteCommandManager will determine if this is done using a new thread or the current thread.


MDB

This feature will require a method to listen to the JMS topic and process messages. EclipseLink will include a MDB reference implementation, ClusterMDB.java, that can be deployed, and will create a JMSTopicRemoteConnection instance in order to delegate message processing to it.

protected JMSTopicRemoteConnection connection;
public void ejbCreate() {
    connection = new JMSTopicRemoteConnection((RemoteCommandManager)getSession().getCommandManager());
}

And the listener method to process the method:

public void onMessage(javax.jms.Message message) {
    connection.onMessage(message);
}
 Inorder to create a  JMSTopicRemoteConnection, the session to be used for cache coordination will need to be obtained:
public final String SESSION_NAME = "session_name_for_mdb";
/**
     * PUBLIC:
     * Return the EclipseLink session that has the session's name configured as an env-entry element in the ejb-jar.xml.
     * User can subclass and overwrite this method to obtain the session differently.
     *
     * @exception org.eclipse.persistence.exceptions.JMSProcessingException if it is unable to lookup the session's name or the session is null
     */
    public AbstractSession getSession() {
        AbstractSession session;
        try {
            Context initCtx = new InitialContext();
            Context myEnv = (Context) initCtx.lookup("java:comp/env");
 
            // Obtain the session name configured by the Deployer.
            String sessionName = (String) myEnv.lookup(SESSION_NAME);
            session = SessionManager.getManager().getSession(sessionName);
        } catch (NamingException e) {
            //RemoteCommandManagerException.errorCreatingJMSConnection(topicName, topicFactory, contextProperties, internalEx)
            throw RemoteCommandManagerException.errorLookupSessionNameInCtx(e);
        }
        if (session == null) {
            throw RemoteCommandManagerException.mdbFoundNoSession();
        }
        return session;
    }


Configuration

Sessions.xml

RCM uses a JMSTopicTransportManagerConfig class for configuration through sessions.xml. A new JMSPublishingTransportManagerConfig is needed to contain all the current configuration in JMSTopicTransportManagerConfig which JMSTopicTransportManagerConfig will then extend. This JMSPublishingTransportManagerConfig will then be used within the SessionsFactory to create JMSPublishingTransportManager instances. From a sessions xml, a JMSPublishingTransportManagerConfig will be created through the <transport xsi:type="jms-publishing-transport"> tag with the same options as the jms-topic-transport does, so there are no xsd changes.

Example

Or, if using sessions.xml:

 
<session xsi:type="server-session">
      <name>rcm_test_session</name>
      <remote-command>
         <channel>new_channel</channel>
         <commands>
            <cache-sync>true</cache-sync>
         </commands>
         <transport xsi:type="jms-publishing-transport">
            <on-connection-error>DiscardConnection</on-connection-error>
            <topic-host-url>t3://jms_topic_host</topic-host-url>
            <topic-connection-factory-name>test-topic-connection-factory-name</topic-connection-factory-name>
            <topic-name>test-topic-name</topic-name>
            <jndi-naming-service>
               <url>new_jndi_url</url>
               <user-name>new_user_name</user-name>
               <password>new_password</password>
               <initial-context-factory-name>weblogic.jndi.WLInitialContextFactory</initial-context-factory-name>
            </jndi-naming-service>
         </transport>
      </remote-command>

Persistence.xml

Same JMS properties are needed for JMS using an MDB, only difference is the protocol should be specified as jms-mdb instead of jms:

<persistence-unit> ..
<properties>
    <property name="eclipselink.cache.coordination.protocol" value="JMS-MDB"/>
    <property name="eclipselink.cache.coordination.jms.host" value="t3://jms_topic_host"/>
    <property name="eclipselink.cache.coordination.jms.topic" value="test-topic-name”/>
    <property name="eclipselink.cache.coordination.jms.factory" value="test-topic-connection-factory-name"/>
    <property name="eclipselink.cache.coordination.jndi.user" value="jndi_user_name"/>
    <property name="eclipselink.cache.coordination.jndi.password" value="jndi-password"/>
</properties

Code Example

From within a customizer or login event:

RemoteCommandManager rcm = new RemoteCommandManager((AbstractSession)session);
JMSTopicTransportManager tm = new JMSPublishingOnlyTopicTransportManager(rcm);
tm.setTopicHostUrl(<rcm.jms.topichost.url>);
tm.setTopicName(<rcm.jms.topicname>);
tm.setTopicConnectionFactoryName(<rcm.jms.topic.connectionfactory.name>);
tm.setUserName(<server.user>);
tm.setEncryptedPassword(<server.encrypted.pwd>);
// or use the unencrypted password
// tm.setPassword(<server.pwd>);     
 
rcm.setTransportManager(tm);
rcm.setShouldPropagateAsynchronously(false);
((AbstractSession)session).setCommandManager(rcm);
((AbstractSession)session).setShouldPropagateChanges(true);
 
rcm.initialize();


Testing

Cache coordination doc

http://wiki.eclipse.org/EclipseLink/Development/Testing/CacheCoordination

describes our current testing on Weblogic. “cachecoordination.protocol” property will need to accept value jms-mdb. This value will be used in the cachecoordination_<server>.xml files to set the configuration required (all required properties will be the same as when using cachecoordination.protocol=jms), and to deploy the ClusterMDB as apart of the testing application.

Open Issues

  • MDB needs to be deployed by the user. Should we provide the MDB in the EclipseLink.jar or just document how it is to be created
  • Example MDB’s getSession requires the session name be defined in the ejb-jar.xml under a “session_name_for_mdb” property.
    • JPA users will need to either
      • define a unique session name in persistence.xml using <property name="eclipselink.session-name" value="MySession"/>
      • deploy their own MDB and use EM injection or Persistence.getEntityManagerFactory and the JPAHelper to get the session.
  • Example MDB will create an external dependencies on javax.ejb.MessageDrivenBean and javax.ejb.MessageDrivenContext
  • Current CacheCoordination server testing is not failing when not set up to coordinate.
    • I believe there is a problem in the scripts and code causing the tests to use the same session to make changes and then to verify that the changes were sent (instead of 2 separate sessions). Working with QA to resolve.