Customizing the ruleset cache

You can customize the ruleset cache by writing your own implementation class and then modifying the deployment descriptor of the execution unit (XU) accordingly.

Before you begin

For memory information to be available, you must install the Rule Execution Server memory profiler Java™ Agent.

About this task

The execution unit (XU) uses a cache of ruleset instances to avoid having to parse rulesets for each execution. Rulesets stay in memory if at least one connection exists in the JCA connection pool of the XU that references that ruleset. Even if the JCA connection is not in use, it references the ruleset until the application server deletes it. When no JCA connection references the ruleset any more, the ruleset can be garbage-collected. This default behavior guarantees that unused rulesets are removed from the memory. If a ruleset is rarely used compared to another ruleset, reparsing might occur.

The ruleset.cache.maintenance.period property is set to 300 by default. This value means that the maintenance thread is run every 5 minutes.

You can write your own implementation of the ruleset cache by packaging a different implementation class in the ra.xml XU configuration file.

Procedure

  1. Write a class that implements the IlrRulesetCache interface. Your class can define custom properties.
    package ilog.rules.res.xu.ruleset.cache.sample;
    
    import java.util.*;
    import java.util.logging.*;
    
    import ilog.rules.res.xu.ruleset.*;
    
    public class RulesetCacheImpl implements IlrRulesetCache {
    	public static final int DEFAULT_MAXIMUM_SIZE = 2;
    
    	protected IlrRulesetUsageInformationMonitor monitor;
    	protected Logger logger;
    	protected ArrayList<IlrXURuleset> rulesets = new ArrayList<IlrXURuleset>();
    
    	/** Maximum number of rulesets that can be stored in the cache */
    	protected int maxSize = DEFAULT_MAXIMUM_SIZE;
    
    	public synchronized void addRuleset(IlrXURuleset ruleset) {
    		if (rulesets.size() == maxSize) {
    			logger.info("Max size reached, removing less used ruleset");
    			removeLessUsedRuleset();
    		}
    		rulesets.add(ruleset);
    	}
    
    
    	/**
    	 * Removes the least executed ruleset.
    	 */
    	protected void removeLessUsedRuleset() {
    		long minExecCount = Long.MAX_VALUE;
    		IlrXURuleset minExecRuleset = null;
    
    		for(IlrXURuleset ruleset: rulesets) {
    			IlrRulesetUsageInformation info
    				= monitor.getRulesetUsageInformation(ruleset.getCanonicalRulesetPath());
    			long execCounter = info.getExecutionCount();
    
    			if (execCounter <= minExecCount) {
    				minExecRuleset = ruleset;
    				minExecCount = execCounter;
    			}
    		}
    
    		if (minExecRuleset != null) {
    			logger.info("Remove ruleset: "+minExecRuleset.getCanonicalRulesetPath());
    			rulesets.remove(minExecRuleset);
    		}
    	}
    
    	public synchronized void clear() {
    		rulesets.clear();
    	}
    
    	public synchronized IlrXURuleset getDeprecatedRuleset(String canonicalRulesetPath,
    			ClassLoader xomClassLoader) {
    		return null;
    	}
    
    	public synchronized IlrXURuleset getRuleset(String canonicalRulesetPath,
    			ClassLoader xomClassLoader) {
    		for(IlrXURuleset ruleset: rulesets) {
    			if (ruleset.getCanonicalRulesetPath().equals(canonicalRulesetPath) &&
    					ruleset.getXOMClassLoader() == xomClassLoader) {
    				return ruleset;
    			}
    		}
    
    		return null;
    	}
    
    	public void initialize(Logger logger, Map<String, String> properties,
    			IlrRulesetUsageInformationMonitor monitor)
    			throws IlrRulesetCacheException {
    		this.monitor = monitor;
    		this.logger = logger;
    	}
    
    	public synchronized void rulesetChanged(String canonicalRulesetPath) {
    		Iterator<IlrXURuleset> iterator = rulesets.iterator();
    		while(iterator.hasNext()) {
    			IlrXURuleset ruleset = iterator.next();
    			if (ruleset.getCanonicalRulesetPath().equals(canonicalRulesetPath)) {
    				iterator.remove();
    			}
    		}
    	}
    
    }
     
  2. Add the implementation class to the ra.xml XU deployment descriptor.
    1. Implement the custom ruleset cache.
      <config-property>
         <config-property-name>rulesetCacheProperties</config-property-name>
         <config-property-type>java.lang.String</config-property-type>
         <config-property-value>ruleset.cache.class=mypackage.MyRulesetCache</config-property-value>
      </config-property>
    2. Set a custom cache property.
      <config-property>
         <config-property-name>rulesetCacheProperties</config-property-name>
         <config-property-type>java.lang.String</config-property-type>
         <config-property-value>ruleset.cache.class=mypackage.MyRulesetCache,mycustomprop=mycustomvalue/config-property-value>
      </config-property>
    3. Make sure that the rulesetUsageMonitorEnabled property is set to true, its default value.
      <config-property>
         <config-property-name>rulesetUsageMonitorEnabled</config-property-name>
         <config-property-type>java.lang.Boolean</config-property-type> 
         <config-property-value>true</config-property-value>
      </config-property>
  3. Package the class.

    For a Java SE deployment, you must add the class to the same class path as the XU or its parent. In Java EE, you must package the class in the XU .rar file.