Contents


Overview

Skill Level: Intermediate

The scope of this article is to implement and deploy a WebSphere application that performs automatically the invalidation for all the WCM cache entries corresponding to the modified content or site-areas, at subscriber side, after a syndication event.

Ingredients

  • Basic WCM development (components, site framework, contents, site-areas, authoring templates, presentation templates)
  • Java and J2EE
  • WCM caching system
  • Websphere Integrated Solutions Console

Step-by-step

  1. 1. Introduction

    The reason of this publication is to explain how to implement and deploy a WebSphere application that performs automatically the invalidation for all the WCM cache entries corresponding to the modified content, at subscriber side, after a syndication event. The application must start automatically every time a syndication event occurs and involves all modified Content and SiteArea WCM objects.

    Optionally, also the parent site-area will be invalidated and in such a case is useful to see changes in content's lists too (WCM menus and navigator components, that usually have as context, the parent site-area).

    This application works correctly only if the advanced WCM cache is configured.

    The application will use:

    • The Java Messaging Service for Web Content Manager item events.
    • The Java API to perform search and invalidation of WCM advanced cache entries.

    Follow some flow-charts describing how the application will be:

    fc1

    General process

     

     

    fc2

    Invalidation sub-process

     

    The application prototype will be tested between a couple of virtual portals, the first one will be our syndicator and the last one will be out subscriber.

    The application will be deployed into the physical portal and the JMS definitions (Topic and Activation Specification) will also be performed on the physical portal.

    You can implement a more sophisticated environment having different physical portals and in a cluster (multi-node) environment.

    Don't hesitate to contact me for any question or for the updated .EAR file with source code and Javadoc of this prototype application at fiori@it.ibm.com

  2. 2. Events management

    Web Content Manager supports for the notification of events such as item state changes, or services starting and stopping.

    These notifications can be delivered as messages to the Java Messaging Service.

    The event classes can be delivered as messages to the Java messaging service:

     

    Event class Events
    Item Created
    Updated
    Moved
    Deleted
    Syndication Starting
    Stopping
    Pre-render Starting
    Stopping

     

    To enable JMS for WCM events:

    • Run the following command from the wp_profile_root/ConfigEngine directory:
      ./ConfigEngine.sh create-wcm-jms-resources -DPortalAdminId=username -DPortalAdminPwd=password -DuseRemoteEndPoints=false/true
    • Restart WebSphere Portal
    • Create a new JMS Topic and a new Activation specification through WebSphere Integrated Solutions Console
  3. 2.1. Events management: Create a new JMS Topic

    Follow some screenshots showing how to create a new JMS Topic:

    1. Navigate to Resources → JMS → Topics and select Node=wpNode,Server=WebSphere_Portal  from Scope combo:

      topic1

    2. Click the New button:

      topic2

    3. Select Default messaging provider then click the OK button:

      topic3

    4. Compile the various sections of the form with the following values and then click the OK button:
      Administration section
      Scope Node=wpNode,Server=WebSphere_Portal
      Provider Default messaging provider
      Name IWKTopics_ItemsTopicsForCacheInvalidation
      JNDI name jms/IWKTopic/ItemsTopicsForCacheInvalidation
      Description WCM Topics used for invalidating cache entries
      Connection section
      Topic name Items
      Bus name IWKBus
      Topic space IWK.Topic.Space
      JMS delivery mode Application
      Time to live  
      Message priority  
      Advanced section
      Read ahead Inherit from connection factory

      topic4

    5. Click the Save link:

      topic5

  4. 2.2. Events management: Create a new Activation specification

    Follow some screenshots showing how to create a new Activation Specification:

    1. Navigate to Resources → JMS → Activation specifications and select Node=wpNode,Server=WebSphere_Portal from Scope combo:

      activation1

    2. Click the New button:

      activation2

    3. Select Default messaging provider and click the OK button:

      activation3

    4. Compile the various sections of the form with the following values and then click the OK button:
      Administration section
      Scope Node=wpNode,Server=WebSphere_Portal
      Provider Default messaging provider
      Name IWKItemsTopicsMonitorActivationForCacheInvalidation
      JNDI name jms/IWKItemsTopicsMonitorActivationForCacheInvalidation
      Description WCM Activation Specification for Topics events for cache entries invalidation
      Destination section
      Destination type Topic
      Destination JNDI name jms/IWKTopics/ItemsTopicsForCacheInvalidation
      Message selector  
      Bus name IWKBus
      Acknowledge mode Auto-acknowledge
      Target  
      Target type Bus member name
      Target significance Preferred
      Target inbound transport chain  
      Provider endpoints [hostname]:10048:BootstrapBasicMessaging,
      [hostname]:10049:BootstrapSecureMessaging
      Destination section
      Maximum batch size 1
      Maximum concurrent 10
      Maximum concurrent MDB invocations per endpoint 10
      Automatically stop endpoints on repeated message failure
      Enable Unchecked
      Sequential failed message threshold 0
      Delay between failing message retries 0 milliseconds
      Subscription durability section
      Subscription durability Durable
      Subscription name ItemsTopicsClientForCacheInvalidation
      Client identifier ItemsTopicsClientForCacheInvalidation
      Durable subscription home WpNode.WebSphere_Portal-IWKBus
      Pass message payload by reference section
      Applications using this Activation Specification to receive messages Unchecked
      Applications resending messages that were originally received using this Activation Specification Unchecked
      Advanced section
      Share durable subscriptions In cluster
      Share data source with CMP Unchecked
      Read ahead Default
      Always activate MDBs in all servers Unchecked
      Retry interval 30 seconds
      Security settings section
      Authentication alias (none)

      activation4

    5. Click the Save link:

      activation5

      activation6

  5. 2.3. Events management: Message Driven Bean

    The Message Driven Bean is a Java class that implements the javax.jms.MessageListener interface. Such an interface have a single method to implement, the public void onMessage(Message msg). The bean will stay in wait and wakeup itself every time a topic arise as Message. Follows a skeleton of this class:

     

    package com.ibm.issc.it.cacheinvalidationaftersyndication;
    
    import javax.ejb.*;
    import javax.jms.*;
    ...
    public class CacheInvalidationAfterSyndicationMDB implements MessageListener
    {
        public void onMessage(Message msg)
        {
            ...
        }
    }
    
  6. 2.4. Events management: message structure

    The message structure, corresponding to the topic, after msg.toString() conversion, is like the following one:

     

    JMSMessage class:         jms_map
    JMSType:                  IWKContentUpdate
    JMSDeliveryMode:          2
    JMSExpiration:            0
    JMSPriority:              4
    JMSMessageID:             ID:97a4eefdabf7d98c93ba1ee4110a134f0000000000000003
    JMSTimestamp:             1475060538917
    JMSCorrelationID:         null
    JMSDestination:           topic://Items?topicSpace=IWK.Topic.Space&busName=IWKBus
    JMSReplyTo:               null
    JMSRedelivered:           false
    DocType:                  com.ibm.workplace.wcm.api.Content
    JMSXDeliveryCount:        1
    AuthoringTemplateName:    TestSyndicationItem
    JMS_IBM_System_MessageID: AAAB5064126EAAB7_80000008
    ItemStatus:               PUBLISHED
    VPId:                     Z18_2G1IHBK0KORBC0ALCSUTF21894
    ItemState:                CHANGED
    LibraryDisplayName:       vp1content
    LibraryName:              vp1content
    SyndicationInProgress:    true
    JMSXUserID: 
    VPName:                   wps.vp.vp2
    JMSXAppID:                Service Integration Bus
    ParentId =                422f79f5-b29a-446e-b736-6be39f4035a3
    LibraryId =               36cd9d12-f16c-4b08-9e78-333a83e22aaf
    LibraryDisplayName =      vp1content
    DocId =                   5424255f-a096-47a2-bd48-0a9558731939
    SyndicationInProgress =   true
    AuthoringTemplateId =     9bc480ea-09fb-480a-a490-21f59d9b074a
    OldDocName =              TestItem7
    LibraryName =             vp1content
    ParentDocType =           com.ibm.workplace.wcm.api.SiteArea
    DocModDate =              1475060504256
    DocType =                 com.ibm.workplace.wcm.api.Content
    AuthoringTemplateName =   TestSyndicationItem
    VPId =                    Z18_2G1IHBK0KORBC0ALCSUTF21894
    ItemStatus =              PUBLISHED
    SourceNodeName =          wpNode
    ItemState =               CHANGED
    intItemState =            1
    ItemLocation =            /vp1content/TestSyndication/TestItem7 bis
    booleanItemRenamed =      true
    VPName =                  wps.vp.vp2
    DocName =                 TestItem7 bis
    
    

     

  7. 2.5. Events management: message parsing

    To get the values for the properties contained in the message we can use the class WCMItemMessage, containing some custom getter methods, that are invoking the following method:

    msg.getStringProperty(String sPropertyName)

    Unfortunately, for some properties, msg.getStringProperty(String sPropertyName) returns an empty String. In such a case, it is necessary to completely code the custom getter methods by parsing the whole message and find the correct value, after converting the message to string through the msg.toString() method.

    Follows a table showing the implemented getter methods and the retrieved properties:

     

    Getter method Completely custom  Used properties
    Properties possible values
    getState() No “ItemState” “CHANGED”, “REMOVED”, “NEW”
    getDocumentType() No “DocType” “com.ibm.workplace.wcm.api.Content”
    “com.ibm.workplace.wcm.api.SiteArea”
    isSyndicationInProgress() Yes “SyndicationInProgress: “ “false”, “true”
    getPath() Yes “ItemLocation = “
    “OldDocName = “
    Library name/sitearea name/item name and the name of the item (before renaming)
    getParentPath() Yes “ItemLocation = “
    “OldDocName = “
    Library name/sitearea name/item name and the name of the item (before renaming)
    isItemRenamed() Yes “booleanItemRenamed = “ “false”, “true”
    getDocumentId() Yes “DocId = “ The WCM document’s ID as String representation

     

    Follows a skeleton of the public void onMessage(Message msg) method:

    public void onMessage(Message msg) 
    {
        ...
        String         sUser, sPassword;
        WCMItemMessage wimsg;
        String         sDocumentType;
        WCMCache       cache;
        String         sState;
        String         sPath, sParentPath;
        Boolean        fIncludeParent;
    	    
        sUser     = ...;
        sPassword = ...;
    	    
        Authenticator.login(sUser, sPassword);
    	    
        ...
    	    
        if (msg != null)
        {   
            wimsg         = new WCMItemMessage(msg);
            sDocumentType = wimsg.getDocumentType();
            sPath         = wimsg.getPath();
            sParentPath   = wimsg.getParentPath();
            sState        = wimsg.getState();
    
            if (sDocumentType.equalsIgnoreCase(Content.class.getCanonicalName()) || sDocumentType.equalsIgnoreCase(SiteArea.class.getCanonicalName()))
            {
        	    if (wimsg.isSyndicationInProgress())
        	    {   
        	        fIncludeParent = bndl.getBoolean("JMS_INCLUDE_PARENT_SITEAREA");
        	          
        	        cache = new WCMCache();
        	            
        	        if (sState.equalsIgnoreCase(WCMItemMessage.ITEMSTATE_CHANGED) || sState.equalsIgnoreCase(WCMItemMessage.ITEMSTATE_REMOVED))
                    {
        	            cache.invalidateEntriesForPath(sPath);
                    }
        	          
        	        if (fIncludeParent)
        	        {
        	            cache.invalidateEntriesForPath(sParentPath);
        	        }   
        	    }
        	}
        }
    }
    

     For further detail see the Javadoc and the full source code, available on request.

  8. 3. Cache entries search invalidation

    There are several advanced WCM cache instances, but only one have entries we can  search for and then invalidate:

     

    Instance name WCM advanced & resources
    JNDI name services/cache/iwk/processing
    Description Only content and site-area entries can be invalidated.
  9. 3.1. Cache entries search invalidation: cache entry key

    It is necessary to search for keys containing the desired path followed by a question mark (to avoid to search for the keys related to all descendants of the item), for example (content and its site-area):

    vp1content/testsyndication/testitem7?
    vp1content/testsyndication?
    

     

    Follows an example of cache entry key:

    [PROCESSED:/myconnect/vp1vp1content/testsyndication/testitem7?1dmy=&WCMUrlPrefix=&current=true
    &urile=wcm%3apath%3a, all_auth_portal_users%all_auth_portal_users_group_id,
    all_users%all_users_group_id,anonymous_user%anonymous_user_id, cn=contentadmins,dc=demos,dc=ibm,
    dc=com%2f5aeacf-1c64-448f-8fbe-a34531bfcc1c, cn=contentauthors,dc=demos,dc=ibm,
    dc=com%58780abf-806b-4259-9888-77f6707a4253, cn=contenteditors,dc=demos,
    dc=ibm,dc=com%8c2122bb-25d5-49c2-adca-254dd0cf0d1a, cn=wpadmins,dc=demos,
    dc=ibm,dc=com%72dac65c-62de-4f99-9903-51957e865ed0]
  10. 3.2. Cache entries search invalidation: cache entries invalidation

    Follows the skeleton for the class/method to searching for a key/invalidating an entry:

    package com.ibm.issc.it.cacheinvalidationaftersyndication.util;
    
    import java.util.*;
    import javax.naming.*;
    import com.ibm.websphere.cache.*;
    ...
    public class WCMCache 
    {
        private static final String WCM_ADVANCED_CACHE_INSTANCE_NAME = "services/cache/iwk/processing";
    
        public void invalidateEntriesForPath(String sPath)
        {
            InitialContext   ctx;
            DistributedMap   dm;
            Iterator         it;
            Set              setKeys;
            Object           oKey;
            String           sSearchString;
    
            ...
    
            sSearchString = sPath.toLowerCase() + "?";
            ctx           = null;
    
            try
            {
                ctx = new InitialContext();
    
                try
                {
                    dm      = (DistributedMap)ctx.lookup(WCM_ADVANCED_CACHE_INSTANCE_NAME);
                    setKeys = (Set)dm.keySet(true);
                    it      = setKeys.iterator();
    
                    while (it.hasNext())
                    {
                        oKey = it.next();
                          
                        if (oKey.toString().toLowerCase().contains(sSearchString))
                        {
                            dm.invalidate(oKey);
                        } 
                    }
                    ...
                }
                ...
            }
        }
    }

     

  11. 4. The Enterprise application

    The application's packages and their modules are the following:

    com.ibm.issc.it.cacheinvalidationaftersyndication package modules
    CacheInvalidationAfterSyndicationMDB.class This is the main class, the EJB/MDB that is triggered everytime a WCM item change even occurs.
    Default.properties This file contains the property/value pairs for the application.

     

    com.ibm.issc.it.cacheinvalidationaftersyndication.util package modules
    Authenticator.class This class is used to authenticate a granted user, in order to permit the WCM cache's entries invalidations.
    Bundle.class This helper class is used to read the properties values from a properties file.
    Logger.class This utility class manages the logging of messages to the SystemOut.log file.
    WCMCache.class This is the class that performs the WCM caches entries searches and invalidations.
    WCMItemMessage.class This class is a parser for the WCM item's messages. It contains methods to extract properties values from the MDB message.

     The application include also the Javadoc.

  12. 4.1. The Enterprise application: configuration

    The configuration for this application is defined in the Defaults.properties file; its default content is the following one:

     1 #==========================================================
     2 # Package com.ibm.issc.it.cacheinvalidationaftersyndication
     3 # File Defaults.properties
     4 #==========================================================
     5
     6 #----------------------------------------------------------
     7 # Logging
     8 #
     9 # Possible values for LOGGING_LEVEL:
    10 # Logging inactive: 0
    11 # Minimum logging:  1
    12 # Full logging:     2
    13 #----------------------------------------------------------
    14 LOGGING_LEVEL=1
    15 LOGGING_APPLICATION_NAME=CacheInvalidationAfterSyndication
    16
    17 #----------------------------------------------------------
    18 # Credentials for invalidating cache
    19 #----------------------------------------------------------
    20 AUTHENTICATION_USERNAME=wpadmin
    21 AUTHENTICATION_PASSWORD=passw0rd
    22
    23 #----------------------------------------------------------
    24 # JMS
    25 #
    26 # Possible values for JMS_INCLUDE_PARENT_SITEAREA:
    27 # Don't include: no, off, untrue, false, 0
    28 # Include: yes, on, true, 1
    29 #----------------------------------------------------------
    30 JMS_INCLUDE_PARENT_SITEAREA=yes
    31
    32 #----------------------------------------------------------
    33 # Application
    34 #----------------------------------------------------------
    35 APPLICATION_VERSION=2.0.2
  13. 4.2. The Enterprise application: deploy

    To deploy the application, on the subscriber side, we will use the WebSphere Integrated Solutions Console

    1. Navigate to Applications → Application types → WebSphere enterprise applications, then click the Install button:

      deploy1

    2. Select Local file system and click the Browse… button:

      deploy2

    3. Locate the CacheInvalidationAfterSyndicationMDBEAR.ear file in local filesystem, then the Open button:

      deploy3

    4. Click the Next button:

      deploy4

    5. Select Fast path and click the Next button:

      deploy5

    6. Click the Next button:

      deploy6

    7. Click the Next button:

      deploy7

    8. Select Activation Specification, type jms/IWKItemsTopicsMonitorActivationForCacheInvalidation in the Target resource JNDI name field and click the Next button:

      deploy8

    9. Click the Next button:

      deploy9

    10. Click the Finish button:

      deploy10

    11. Click the Save link:

      deploy11

      deploy12

  14. 4.3. The Enterprise application: start

    To start the application, navigate to Applications → Application Types → WebSphere enterprisa applications, select the application (CacheInvalidationAfterSyndicationMDBEAR) and click the Start button:

    start

    start2

    start3

  15. 5. Test the application

    For testing the application we can create two virtual portals on a physical one,  Virtual portal 1 and Virtual portal 2, like the following:

    virtualportals

    then we can create in Virtual portal 1 a new Web Content Library, naming it as FromV1. We need now to create some WCM design elements and content to perform the test. For example we can have a site area containing a number of contents and we can use a menu to list them and some authoring tools components to be able to edit contents:

    test0

    Now, we can create a WCM syndicator/subscriber pair on Virtual portal 1 and Virtual portal 2, respectively:

    syndicator

    subscriber

    Let us perform, after syndication, a browser screen refresh on our page on the subscriber side (Virtual portal 2) to generate cache entries for the new contents. The content would be appear in this way:

    test-bis

    Now let's go to the Virtual portal 1 page and let us perform a content's editing:

    test1

    test2

    Finally let's go to the Virtual portal 2 (subscriber) page and let us perform some page refresh until we can see content updates due to terminated syndication and invalidation of the cache entry corresponding to the modified content:

    test3

    test4

    test5

  16. 6. Acknowledgements

    Many thanks to those colleagues who have made a crucial help for the realization of this prototype:

     

    Malarvizhi Malarvizhi Kandasamy
    Advisory L3 Support Engineer Digital Experience and WCM
    developerWorks article: How to read JMS messages from WCM Topics for Syndication and Pre-render events
    David David De Vos
    WCM CF Chief Programmer and WCM Field Architect
    Suggestions on how to invalidate cache entries through Java API
    Domenico Domenico Di Santo
    IBM Cloud Lab Services
    Tips in WAS JMS configuration, MDB coding and deploy

     

Join The Discussion