CRM and CX Blogs by SAP
Stay up-to-date on the latest developments and product news about intelligent customer experience and CRM technologies through blog posts from SAP experts.
cancel
Showing results for 
Search instead for 
Did you mean: 
joris_quenee
Product and Topic Expert
Product and Topic Expert
0 Kudos

Introduction

It is straight forward to create a new cache space with ehCache in Java. However, it is a bit harder to add this cache in HAC / Region cache system.

Region cache advantage is to

  • have monitoring usage fromHAC
  • have capacity to force cache cleaning from HAC

This article is explaining step by step how to create this type of cache.

 

New Region Cache

New Simple Class Cache Region

First step is to create a new simple region cache type that simple takes two arguments: key and value.

 

import de.hybris.platform.regioncache.CacheValueLoadException;
import de.hybris.platform.regioncache.CacheValueLoader;
import de.hybris.platform.regioncache.key.CacheKey;
import de.hybris.platform.regioncache.region.impl.EHCacheRegion;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class SimpleEHCacheRegion extends EHCacheRegion {

// Contructor to setting up cache option
public SimpleEHCacheRegion(final String name, 
final int maxEntries, final String evictionPolicy,
final boolean exclusiveComputation, final boolean statsEnabled, 
final Long ttlSeconds) {
 super(name, maxEntries, evictionPolicy, exclusiveComputation, statsEnabled, ttlSeconds);
}
[...]
}

 

Get and Put must be adapted to include type notion into the key

 

public Object get(final Object key) {
// key computation by including hardcoded type
final SimpleGenericCacheKey genericCacheKey 
= generateGenericCacheKey(key);

return super.get(genericCacheKey);
}

 

Put method is a bit more complex 

 

public void put(final Object key, final Object object) {
// key computation by including hardcoded type
final SimpleGenericCacheKey genericCacheKey = generateGenericCacheKey(key);
// loader to insert value into the cache
final DefaultCacheValueLoaderImpl<Object> loader = new DefaultCacheValueLoaderImpl<Object>();
loader.setValue(object);
// remove previous entry if exists
remove(genericCacheKey);
super.getWithLoader(genericCacheKey, loader);
}

 

HandledTypes method must be override to remove super() logic 

 

@Override
public void setHandledTypes(final String[] handledTypes){
 //
}

 

Key generator based on hardcoded type should look like

 

private SimpleGenericCacheKey generateGenericCacheKey(final Object key) {
if (key instanceof SimpleGenericCacheKey) {
  return (SimpleGenericCacheKey) key;
} else { return new SimpleGenericCacheKey(key, "JavaObject");}
}

 

And inner Cache Value Loader class should look like

 

private class DefaultCacheValueLoaderImpl<V> implements CacheValueLoader<V> {
private V obj;

public DefaultCacheValueLoaderImpl() {
 super();
}

@Override
public V load(final CacheKey arg0) throws CacheValueLoadException {
 return this.obj;
}

@SuppressWarnings("unchecked")
public void setValue(final Object obj) {
 this.obj = (V) obj;
}
}

 

 

New Simple Cache Key Class

Second step is to create a cache key class that will define key struct

 

import de.hybris.platform.regioncache.key.CacheKey;
import de.hybris.platform.regioncache.key.CacheUnitValueType;

public class SimpleGenericCacheKey implements CacheKey {

// key itself
private final Object key;
private String tenant;
private final Object typeCode;

public SimpleGenericCacheKey(final Object key, final String typeCode) {
  this.key = key;
  this.typeCode = typeCode;
  this.tenant = "master";
}
[...]
}

 

Then classic method to compare two instance must be override.

hashCode() example

 

@Override
public int hashCode() {
 return this.key.hashCode();
}

 

equals() example

 

@Override
public boolean equals(final Object o) {
if (o == null){
 return false;
}
else if (o == this) {
 return true;
} else if (this.getClass() != o.getClass()) {
 return false;
}
else {
 final SimpleGenericCacheKey command = (SimpleGenericCacheKey) o;
 return this.key.equals(command.key);
 }
}

 

 

Beans declaration

Last step is to declare the beans associated

 

<!-- abstract instance that can be reused for declaring many different caches -->
<bean abstract="true" class="...SimpleEHCacheRegion" id="simpleCacheRegion">
 <constructor-arg name="evictionPolicy" value="LRU"/>
 <constructor-arg name="statsEnabled" value="true"/>
 <constructor-arg name="exclusiveComputation" value="false"/>
</bean>

<!-- concrete instance example -->
<bean id="customCacheRegion" parent="simpleCacheRegion">
    <constructor-arg name="name" value="customCacheRegion"/>
    <constructor-arg name="maxEntries" value="10000"/>
</bean>

 

New cache bean must be recorded in HAC list

deprecated way

 

<!-- Add the cache region to the list displayed in the hac   -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="targetObject" ref="cacheRegionsList"/>
  <property name="targetMethod" value="add"/>
  <property name="singleton" value="true"/>
  <property name="arguments">
    <ref bean="customCacheRegion" />
  </property>
</bean>

 

new way

 

<bean id="customCacheRegionRegistrar" class="de.hybris.platform.regioncache.region.CacheRegionRegistrar" c:region-ref="customCacheRegion" />

 

Spring xml file must be set in global context (project.properties)

 

# Cache regions need to go to the global context
custom.global-context=custom-cache-spring.xml

 

 

Result in HAC

Then, we should see our new cache region in HAC list from https://localhost:9002/monitoring/cache

Capture d’écran 2024-03-20 à 15.20.03.png

 

Conclusion

Custom EhCache integration into HAC Cache Region is possible and it demands a little development effort where we know how to do it. 

And in case official SAP Commerce document is not rich enough, you should not hesitate to ask SAP Expert Services help to perform some customization you needed.