Administration guide > Configure the deployment environment > Configuring data grids > Configuring peer-to-peer replication with JMS



JMS event listener

The JMSObjectGridEventListener is designed to support client-side near cache invalidation and a peer-to-peer replication mechanism. It is a Java™ Message Service (JMS) implementation of the ObjectGridEventListener interface.

The client invalidation mechanism can be used in a distributed eXtreme Scale environment to ensure client near cache data to be synchronized with servers or other clients. Without this function, the client near cache could hold stale data. However, even with this JMS-based client invalidation mechanism, you have to take into consideration the timing window for updating a client near cache because of the delay for the run time in publishing updates.

The peer-to-peer replication mechanism can be used in both distributed and local eXtreme Scale environments. It is an ObjectGrid core-to-core replication process and allows data updates to flow among local ObjectGrids and distributed ObjectGrids. For example, with this mechanism you can move data updates from a distributed grid to a local ObjectGrid, or from any grid to another grid in a different system domain.

The JMSObjectGridEventListener requires the user to configure JMS and Java Naming and Directory Interface (JNDI) information in order to obtain required JMS resources. Additionally, replication-related properties must be set correctly. In a JEE environment, the JNDI should be available in both Web and Enterprise JavaBean (EJB) containers. In this case, the JNDI property is optional unless to obtained external JMS resources.

This event listener has properties you can configure with XML or programmatic approaches, which can be used for only client invalidation, only peer-to-peer replication, or both. Most properties are optional for customizing the behavior to achieve the required functionality.

For more information, see JMSObjectGridEventListener API.

For more information see the JMSObjectGridEventListener API.


Extend the JMSObjectGridEventListener plug-in

The JMSObjectGridEventListener plug-in allows peer ObjectGrid instances to receive updates when data in the grid has been changed or evicted. It also allows clients to be notified when entries are updated or evicted from an eXtreme Scale grid. This topic describes how to extend the JMSObjectGridEventListener plug-in to allow applications to be notified when a JMS message is received. This is most useful when using the CLIENT_SERVER_MODEL setting for client invalidation.

When running in the receiver role, the overridden JMSObjectGridEventListener.onMessage method is automatically called by the eXtreme Scale runtime when the JMSObjectGridEventListener instance receives JMS message updates from the grid. These messages wrap a collection of LogSequence. Objects. The LogSequence objects are passed to the onMessage method and the application uses the LogSequence to identify which cache entries have been inserted, deleted, updated or invalidated.

To use the onMessage extension point, applications perform the following steps.

  1. Create a new class, extending the JMSObjectGridEventListener class, overriding the onMessage method.

  2. Configure the extended JMSObjectGridEventListener the same way as the ObjectGridEventListener for ObjectGrid.

The extended JMSObjectGridEventListener class is a child class of the JMSObjectGridEventListener class and can only override two methods: the initialize (optional) and onMessage methods. If a child class of the JMSObjectGridEventListener class needs to use any ObjectGrid artifacts such as ObjectGrid or Session in the onMessage method, it can get these artifacts in the initialize method and cache them as instance variables. Also, in the onMessage method, cached ObjectGrid artifacts can be used to process a passed collection of LogSequences.

The overridden initialize method has to invoke super.initialize method in order to initialize parent JMSObjectGridEventListener appropriately.

The following is a sample for an extended JMSObjectGridEventListener class.

package com.ibm.websphere.samples.objectgrid.jms.price;

import java.util.*;
import com.ibm.websphere.objectgrid.*;
import com.ibm.websphere.objectgrid.plugins.LogElement;
import com.ibm.websphere.objectgrid.plugins.LogSequence;
import com.ibm.websphere.objectgrid.plugins.builtins.JMSObjectGridEventListener;

public class ExtendedJMSObjectGridEventListener extends JMSObjectGridEventListener{
    protected static boolean debug = true;
    
    /**
     * This is the grid associated with this listener.
     */
    ObjectGrid grid;

    /**
     * This is the session associated with this listener.
     */
    Session session;
    
    String objectGridType;
    
    public List receivedLogSequenceList = new ArrayList();

 
    /* (non-Javadoc)
     * @see com.ibm.websphere.objectgrid.plugins.builtins.JMSObjectGridEventListener
                #initialize(com.ibm.websphere.objectgrid.Session)
     */
    public void initialize(Session session) {
        // Note: if need to use any ObjectGrid artifact, this class need to get ObjectGrid
        //     from the passed Session instance and get ObjectMap from session instance
        // for any transactional ObjectGrid map operation.
        
        super.initialize(session);  // must invoke super's initialize method.
        this.session = session; // cache the session instance, in case need to
        //            use it to perform map operation.
        this.grid = session.getObjectGrid(); // get ObjectGrid, in case need
        //            to get ObjectGrid information.
        
        if (grid.getObjectGridType() == ObjectGrid.CLIENT)
            objectGridType = "CLIENT";
        else if (grid.getObjectGridType() == ObjectGrid.SERVER)
            objectGridType = "Server";

        if (debug)
            System.out.println("ExtendedJMSObjectGridEventListener[" +
                    objectGridType + "].initialize() : grid = "    + this.grid);
    }
    
    /* (non-Javadoc)
     * @see com.ibm.websphere.objectgrid.plugins.builtins.JMSObjectGridEventListener
                #onMessage(java.util.Collection)
     */
    protected void onMessage(Collection logSequences) {
        System.out.println("ExtendedJMSObjectGridEventListener[" +
                objectGridType + "].onMessage(): ");
        
        Iterator iter = logSequences.iterator();
        
        while (iter.hasNext()) {
            LogSequence seq = (LogSequence) iter.next();
            
            StringBuffer buffer = new StringBuffer();
            String mapName = seq.getMapName();
            int size = seq.size();
            buffer.append("\nLogSequence[mapName=" + mapName + ", size=" + size + ",
                    objectGridType=" + objectGridType
                    + "]: ");

            Iterator logElementIter = seq.getAllChanges();
            for (int i = seq.size() - 1; i >= 0; --i) {
                LogElement le = (LogElement) logElementIter.next();
                buffer.append(le.getType() + " -> key=" + le.getCacheEntry().getKey() + ", ");
            }
            buffer.append("\n");

            receivedLogSequenceList.add(buffer.toString());

            if (debug) {
                System.out.println("ExtendedJMSObjectGridEventListener["
                        + objectGridType + "].onMessage(): " + buffer.toString());
            }
        }    
    }
    
    public String dumpReceivedLogSequenceList() {
        String result = "";
        int size = receivedLogSequenceList.size();
        result = result + "\nExtendedJMSObjectGridEventListener[" + objectGridType
                + "]: receivedLogSequenceList size = " + size + "\n";
        for (int i = 0; i
< size; i++) {
            result = result + receivedLogSequenceList.get(i) + "\n";
        }
        return result;
    }

    public String toString() {
        return "ExtendedJMSObjectGridEventListener["
                + objectGridType + " - " + this.grid + "]";
    }
}


Configuration

The extended JMSObjectGridEventListener class must be configured the same way for both client invalidation and peer-to-peer replication mechanism. The following is the XML configuration example.

<objectGrid name="PRICEGRID">
            <bean id="ObjectGridEventListener"
                className="com.ibm.websphere.samples.objectgrid.jms.
                        price.ExtendedJMSObjectGridEventListener">
                <property name="invalidationModel" type="java.lang.String"
                    value="CLIENT_SERVER_MODEL" description="" />
                <property name="invalidationStrategy" type="java.lang.String"
                    value="INVALIDATE" description="" />
                <property name="jms_topicConnectionFactoryJndiName" type="java.lang.String"
                    value="jms/TCF" description="" />
                <property name="jms_topicJndiName" type="java.lang.String"
                    value="GRID.PRICEGRID" description="" />
                <property name="jms_topicName" type="java.lang.String"
                    value="GRID.PRICEGRID" description="" />
                <property name="jms_userid" type="java.lang.String" value=""
                    description="" />
                <property name="jms_password" type="java.lang.String" value=""
                    description="" />                    
            </bean>
            <backingMap name="PRICE" pluginCollectionRef="PRICE"></backingMap>
     
</objectGrid>    

The className of ObjectGridEventListener bean is configured with the extended JMSObjectGridEventListener class with the same properties as the generic JMSObjectGridEventListener.


Parent topic:

Configure peer-to-peer replication with JMS