I want to distribute my EhCache via a JMS Topic. This is documented here on EhCache's site
I'm using:
ehcache-1.6.0-beta3
ehcache-jmsreplication-0.3
spring-2.5
spring-modules-0.9
My Spring config looks like this:
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
</bean>
<bean id="cacheProvider"
class="org.springmodules.cache.provider.ehcache.EhCacheFacade">
<property name="cacheManager" ref="cacheManager" />
</bean>
<ehcache:proxy id="pocDaoCache" refId="pocDao">
<ehcache:caching methodName="fetch" cacheName="pocCache" />
</ehcache:proxy>
And, pre-JMS config, my ehcache.xml looks like this:
<diskStore path="c:/projects/cache/demo" />
<defaultCache maxElementsInMemory="50" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" />
<cache name="pocCache"
maxElementsInMemory="10000"
maxElementsOnDisk="1000"
eternal="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
/ >
And this works fine. So I add my Topic information:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheManagerPeerProviderFactory"
properties="initialContextFactoryName=JmsInitialContextFactory,
userName=myuser,password=mypass,
providerURL=tcp://jmsdev1-jndi,tcp://jmsdev2-jndi
topicConnectionFactoryBindingName=TCF-00,
topicBindingName=MyTopiceName"
propertySeparator=","
/>
And I get a NullPointer when I get an application context. Here is the stack trace:
org.springframework.beans.factory.BeanCreationException:
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'cacheManager' defined in class path resource [cache-context.xml]:
Invocation of init method failed; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.initializeBean(AbstractAutowireCapableBeanFactory.java:1336)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.doCreateBean(AbstractAutowireCapableBeanFactory.java:471)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getOb
ject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistr
y.getSingleton(DefaultSingletonBeanRegistry.java:217)
[snip]
Any ideas from anyone?
The real problem is that Ehcache's documentation isn't right -- not even close -- to how it is really implemented. Through logging and looking through the code in the jmsreplication module, I was able to get it working.
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheManagerPeerProviderFactory"
properties="initialContextFactoryName=com.InitialContextFactory;
userName=uname;password=passwd;
replicationTopicConnectionFactoryBindingName=TCF;
replicationTopicBindingName=CACHE;
providerURL=tcp://server1:7222,tcp://server2:7222;
getQueueConnectionFactoryBindingName=QCF;
getQueueBindingName=CACHE_LOAD
"
propertySeparator=";"
/>
Another thing that tripped me up was simple, once I realized it -- you have to implement your own key generator to ensure that Ehcache saves the objects with the same keys on each JVM. That makes perfect sense, when you think about it.
Yes, you have to put in the loader queue information into the cacheManagerPeerProviderFactory. That is because, if you start up a process after one has been running, the new process can pre-load the cache from the existing process.
You configure the loader requester (cacheLoaderFactory) with the exact same settings:
<cacheLoaderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheLoaderFactory"
properties="initialContextFactoryName=com.InitialContextFactory;
userName=uname;password=passwd;
replicationTopicConnectionFactoryBindingName=TCF;
replicationTopicBindingName=CACHE;
providerURL=tcp://server1:7222,tcp://server2:7222;
getQueueConnectionFactoryBindingName=QCF;
getQueueBindingName=CACHE_LOAD
"
propertySeparator=";"
/>
Regarding the key generation issue, it's actually a known problem - MOD-255. We are going to be patching that into the Spring Modules Fork shortly.
Related
i am using single weblogic which host two web application. I am using spring container and below is my Ehcache configuration
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" scope="singleton">
<property name="configLocation" value="classpath:ehcache.xml" />
<property name="shared" value="true" />
</bean>
As i mentioned shared attribute as true, i was expecting there will be single cache manager and single cache .But i can see two customerCache
elements in memory separate for each application. How can i make it truly singleton per jvm with spring across application ?
for example
<cache name="customerCache" maxElementsInMemory="1000" eternal="false" overflowToDisk="false" memoryStoreEvictionPolicy="LRU" />
In order to achieve this, you will have to share a common Ehcache CacheManager between your two applications.
For Ehcache, this means having the CacheManager loaded by the same class loader in both applications.
Ways to achieve this are:
Find a way to share a Spring context between your two applications (see this question) or
Move Ehcache library to a shared lib system which will give you the shared cache loader, and then make sure its initialisation is properly handled by either webapps (but not both)
I am facing the ehcache replication issue while deploying the application into WebLogic 10.3.6.
Application is not starting and throwing the below exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ehCacheManager' defined in class path resource [xxxxx.xml]: Invocation of init method failed; nested exception is net.sf.ehcache.CacheException: Problem starting listener for RMICachePeer //xxxx:xxxx/myCache. Initial cause was RemoteException occurred in server thread; nested exception is:
java.rmi.AccessException: Registry.Registry.rebind disallowed; origin /x.x.x.x is non-local host
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
...
Caused by: net.sf.ehcache.CacheException: Problem starting listener for RMICachePeer //xxxx:xxxx/myCache. Initial cause was RemoteException occurred in server thread; nested exception is:
java.rmi.AccessException: Registry.Registry.rebind disallowed; origin /x.x.x.x is non-local host
at net.sf.ehcache.distribution.RMICacheManagerPeerListener.notifyCacheAdded(RMICacheManagerPeerListener.java:538)
at net.sf.ehcache.event.CacheManagerEventListenerRegistry.notifyCacheAdded(CacheManagerEventListenerRegistry.java:159)
at net.sf.ehcache.CacheManager.addCacheNoCheck(CacheManager.java:1118)
at net.sf.ehcache.CacheManager.addConfiguredCaches(CacheManager.java:670)
at net.sf.ehcache.CacheManager.init(CacheManager.java:372)
at net.sf.ehcache.CacheManager.<init>(CacheManager.java:294)
at org.springframework.cache.ehcache.EhCacheManagerFactoryBean.afterPropertiesSet(EhCacheManagerFactoryBean.java:104)
...
EhCache configuration is as follows:
<diskStore path="java.io.tmpdir/myCache" />
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,rmiUrls=//x.x.x.x:xxxx/myCache" />
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=x.x.x.x,port=xxxx,socketTimeoutMillis=300000" />
<cache
name="myCache"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="1000"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts=true,replicateUpdates=true,replicateRemovals=true,replicateUpdatesViaCopy=true,replicateAsynchronously=true" />
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</cache>
Appreciate any help.
I am able to make it working by changing my cache discovery strategy to automatic and multicast.
See the working configuration below:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4447, timeToLive=32" />
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="port=xxxx,socketTimeoutMillis=300000" />
<cache
name="myCache"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="1000"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
I am having xml. (Ehcache.xml)
I want to inject into it property from property file(on the classpath).
However since this xml is not a Spring managed bean I am not able to do so.
Any recommendations how to overcome this?
the xml:
...
properties="peerDiscovery=manual,rmiUrls=//**${other.node.hostname}**:41001/org.jasig.cas.ticket.ServiceTicket|//**${other.node.hostname}**:41001/org.jasig.cas.ticket.TicketGrantingTicket"
propertySeparator="," />
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="port=41001,socketTimeoutMillis=5000" />
</ehcache>
I want to inject ${other.node.hostname} from another properties file.
but I get this on runtime:
Caused by: java.net.URISyntaxException: Illegal character in authority at index 2: //${other.node.hostname}:41001/org.jasig.cas.ticket.TicketGrantingTicket
thanks,
ray.
in the ehcache.xml it won't work because it's not spring configuration. But if you define the equivalent configuration in spring instead of the ehcache file it should work:
<context:property-placeholder location="classpath:config.properties"/>
<bean id="myCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager"/>
<property name="maxElementsInMemory" value="${cache.maxMemoryElements}"/>
</bean>
the best is to use the ehcache.xml file the least possible and configure everything in spring, as most of the options in the file have a spring equivalent.
I have a simple one class test to load ehache 2.8.1
Everything is fine however if setting either diskPersistent="true" or overflowToDisk="true" then the VM never terminates.
I have tried setting the shutdown hook but this isn't fired as the thread used by Ehcache isn't a daemon so the vm never gets that far.
<ehcache
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="/temp"/>
<defaultCache
maxElementsInMemory="100"
eternal="false"
overflowToDisk="false"
/>
<cache
name="resolveIpAddresses"
maxElementsInMemory="100000"
diskPersistent="true"
overflowToDisk="true"
eternal="false"
timeToLiveSeconds="3600"
/>
</ehcache>
The ehcache is being managed by a spring 3.1.8 container with the beans
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="/ehcache.xml" p:shared="true"/>
Changing the disk settings to false works fine but obviously not great. How do I tell ehcache that the disk threads are daemon?
If you are using a servlet container, you can use the servlet ShutdownListener, otherwise it's possible to shutdown the disk threads by calling CacheManager.getInstance().shutdown() explicitly in the code.
The Ehcache documentation says that the JVM shutdown hook will:
shutdown the DiskStore. If the DiskStore is persistent, it will write the entries and index > to disk.
The shutdown hook can be explicitly called with a call to System.exit(), in addition to being called when the last non-daemon thread shutdown.
I'm trying to move the creation of Cache that uses RMI from ehcache.xml file to a Spring xml.
It wasn't a problem to just create a EhCacheFactoryBean but how does RMICacheReplicatorFactory definition suppose to/can be implemented?
Here is how it looks in ehcache.xml file.
Many thanks,
Idan
<cache name="MyCache1"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="20"
timeToLiveSeconds="3000"
timeToIdleSeconds="3000"
memoryStoreEvictionPolicy="LFU">
<!-- RMI replication listener -->
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicatePutsViaCopy=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true" />
<!-- RMI Cache bootstrap -->
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"
propertySeparator="," />
</cache>
When using Spring 3 there is a cacheEventListeners property of type Set<CacheEventListener> for the EhCacheFactoryBean (see https://jira.springsource.org/browse/SPR-6234). When using 2.5 you could extend EhCacheFactoryBean yourself like shown here.