Hero #18
Posted on 28 July, 2017 by Riaan Ingram & Siddharth Dubey

How to Invalidate Result Cache in OSB 11g and OSB 12c using Java Callout

In this blog, we will discuss how to programmatically control the cleaning of the cache in Oracle Service Bus and how to selectively invalidate the Result Cache for specific cache key in OSB using Java Callouts.

Existing Cache Invalidation Mechanisms in OSB

Out of the box Result Cache invalidation can be achieved in an OSB Business Service by configuring the Expiration Time, either accepting the default option (TTL for default is 5 mins), or by explicitly setting the Expiration Time in DD:HH:MM:SS. An alternative is to calculate the cache expiry time via an XQuery expression. These mechanisms do not provide a lot of flexibility in the control of the cache invalidation.

A more ‘on demand’ cache expiration option is not available out of the box in both the 11g and 12c versions of OSB.

Invalidate Result Cache in OSB 11g

Result cache can be invalidated on demand using Java Callouts from an OSB Proxy Service. This Java callout can be wrapped in a Proxy Service. This Proxy Service in turn can be configured to be invoked either from any other transactional Proxy Service (which intends to clean the cache and re-populate the cache with fresh data), or via an explicit action from the user such as the click of a button from UI screen.

The Java code snippet below can be used in an OSB Java Callout to invalidate the cache in OSB 11g for a given cache key (‘cacheKeyToken’):

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
* The Jars used are coherence.jar, osb-coherence-client.jar, weblogic.server.modules.coherence.server_10.3.5.0.jar. 
*These jars are part of OSB 11g classpath hence not required runtime, but will be needed compile time.
*They can be found at
*$MiddleWareHome/oracle_common/modules/oracle.coherence_3.6/coherence.jar
$MDW/modules/features/weblogic.server.modules.coherence.server_10.3.4.0.jar
*$OSB/lib/osb-coherence-client.jar
*/
import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.Filter;
import com.tangosol.util.extractor.KeyExtractor;
import com.tangosol.util.filter.LikeFilter;

public class ResultCacheHelper {
     
    private static String CACHE_NAME = "/osb/service/ResultCache";
    
/**
   *The method for invalidating the OSB result cache, this will delete the cache token
*and the value (data) associated with the token. 
   *@param cacheKeyToken is the cacheToken which is to be deleted from the Result Cache  
   */ 
    public static Boolean clearCache(String cacheKeyToken) throws Exception {
        Boolean cacheKeyInvalidated=false;
        
        try {
            
            System.setProperty("tangosol.coherence.override", "$PathToOSBDomain/config/osb/coherence/osb-coherence-override.xml");
            System.setProperty("tangosol.coherence.cacheconfig","$PathToOSBDomain /config/osb/coherence/osb-coherence-cache-config.xml");
                        System.setProperty("tangosol.coherence.distributed.localstorage","false");
            System.setProperty("tangosol.coherence.cluster","OSB-cluster");
            System.setProperty("tangosol.coherence.localhost","localhost");
            System.setProperty("OSB.coherence.cluster","OSB-cluster");
        
            CacheFactory.ensureCluster();
        
            NamedCache cache = CacheFactory.getCache(CACHE_NAME);
            
            /**The filter extracts all the ResultCacheKeys which has name equals ‘cacheKeyToken’*/
Filter filter = new LikeFilter(new KeyExtractor("toString"),cacheKeyToken, '/', true);
            Set set = cache.entrySet(filter);
        
            Object obj = new Object();
        
            for (Iterator iter = set.iterator(); iter.hasNext(); ){
                Map.Entry entry = (Map.Entry) iter.next();
                obj = ((Object)entry.getKey());
                try {
                    cache.remove(obj);
                } catch (Exception e){
                    //Intentionally consuming exception
                }
                cacheKeyInvalidated=true;
            }
        } catch (Exception e){
            e.printStackTrace();
            throw e;
    }
    return cacheKeyInvalidated;

    }
}

This works for small data sets, but it may encounter problems, such as running out of heap space, if the data set is too large. It also takes as input an exact cache key string.

Invalidate Result Cache in OSB 12c

In OSB 12c different classes can be used to achieve the same selective cache invalidation. The Java code snippet below can be used in an OSB Java Callout to invalidate the cache in OSB 12c for a given cache key (‘cacheKeyToken’):

/**The jars used are oracle.servicebus.resources.service-1.0.jar, oracle.servicebus.configfwk-1.0.jar, oracle.servicebus.common-1.0.jar. These jars are part of OSB 12c classpath hence not required runtime, but will be needed compile time.
*/
import com.bea.wli.sb.service.resultcache.ResultCacheKey;
import com.bea.wli.config.Ref;
import com.bea.wli.sb.service.resultcache.Result;
import com.bea.wli.sb.service.resultcache.ResultCacheException;
import com.bea.wli.sb.service.resultcache.ResultCacheManager;

public class ResultCacheHelper {
    
    /**
     * Method for invalidate single OSB result cache entry.
     * @param serviceType - Type of the server (BusinessService or ProxyService)
     * @param servicePath - Fully qualified path name of the service
     * @param operationName - Operation name of the business service.
     * @param cacheKeyToken - The token configured in Business Service (e.g. - Unique ID)
     * @return true if successfully invalidate the cache entry, otherwise false
     * @throws XPathFunctionException
     */
    public static Boolean clearCache(String serviceType, String servicePath,
 String operationName, String cacheKeyToken) throws Exception 
    {
        Boolean invalidateResult = false;
Ref serviceRef = constructRef(serviceType, servicePath);
        com.bea.wli.sb.service.resultcache.ResultCacheKey key = new com.bea.wli.sb.service.resultcache.ResultCacheKey(serviceRef, operationName, cacheKeyToken);

        
        try {
        com.bea.wli.sb.service.resultcache.Result cachedValue = com.bea.wli.sb.service.resultcache.ResultCacheManager.get().getResultCache().get(key);
            if (cachedValue != null) {
    com.bea.wli.sb.service.resultcache.ResultCacheManager.get().getResultCache().remove(key);
                invalidateResult = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
        return invalidateResult;
    }

    /**
     * Create OSB service reference.
     * @param refType - Type of the reference type
     * @param serviceuri - Service URI
     * @return
     */
    private static Ref constructRef(String refType, String serviceuri) {
        Ref ref = null;
        String[] uriData = serviceuri.split("/");
        ref = new Ref(refType, uriData);
        return ref;
    }
}

In conclusion, to selectively invalidate an OSB (built-in coherence) Result Cache ‘on demand’ is a very useful tool to have, especially when Oracle does not provide an out of the box feature to do it. Now with the ability to clean out cached OSB payloads, as provided, you can improve performance bottlenecks in more places without fear of obsolete data.

Back to blog
Riaan Ingram
Principal Consultant (Architecture & Integration)

Riaan is a Principal SOA Consultant with over 14 years’ IT design and development experience. Riaan has a strong technical background and specialises in developing and integrating enterprise applications. Riaan has in depth knowledge of middleware and cloud technologies and is an expert in the planning, design and implementation of service-oriented architecture (SOA) solutions.

Siddharth Dubey
Solution Designer

Siddharth is a Solution Designer with over 12 years of Java, SOA integration and performance engineering experience. Siddharth specialises in designing enterprise applications, and integrating them leveraging APIs, microservices and middleware technologies.