Author: iocanel
Date: Wed Jul 13 18:06:51 2011
New Revision: 1146175
URL: http://svn.apache.org/viewvc?rev=1146175&view=rev
Log:
[SM-2109] Added EhCache store. Added StoreListener support to EhCache store.
Added unit test for EhCache store.
Added:
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/CacheManagerFactory.java
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStore.java
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStoreFactory.java
servicemix/utils/trunk/src/test/java/org/apache/servicemix/store/ehcache/
servicemix/utils/trunk/src/test/java/org/apache/servicemix/store/ehcache/EhCacheStoreTest.java
Modified:
servicemix/utils/trunk/pom.xml
Modified: servicemix/utils/trunk/pom.xml
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/pom.xml?rev=1146175&r1=1146174&r2=1146175&view=diff
==============================================================================
--- servicemix/utils/trunk/pom.xml (original)
+++ servicemix/utils/trunk/pom.xml Wed Jul 13 18:06:51 2011
@@ -155,7 +155,11 @@
<artifactId>rjc</artifactId>
<version>0.6.4</version>
</dependency>
-
+ <dependency>
+ <groupId>net.sf.ehcache</groupId>
+ <artifactId>ehcache</artifactId>
+ <version>1.5.0</version>
+ </dependency>
<!-- test dependencies -->
<dependency>
<groupId>junit</groupId>
Added:
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/CacheManagerFactory.java
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/CacheManagerFactory.java?rev=1146175&view=auto
==============================================================================
---
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/CacheManagerFactory.java
(added)
+++
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/CacheManagerFactory.java
Wed Jul 13 18:06:51 2011
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.store.ehcache;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.config.Configuration;
+import net.sf.ehcache.config.DiskStoreConfiguration;
+
+/**
+ * @author: iocanel
+ */
+public class CacheManagerFactory {
+
+ private Boolean diskPersistent = Boolean.TRUE;
+ private Boolean eternal = Boolean.FALSE;
+ private int maxElementsInMemory=10000;
+ private Boolean overflowToDisk= Boolean.TRUE;
+ private long timeToIdleSeconds=300;
+ private long timeToLiveSeconds=300;
+ private String memoryStoreEvictionPolicy="LRU";
+
+ private String diskStorePath=".";
+
+
+ /**
+ * Builds the default {@ling CacheManager} instace
+ * @return
+ */
+ public CacheManager build() {
+ Configuration configuration = new Configuration();
+ CacheConfiguration defaultCacheConfiguration = new
CacheConfiguration();
+ defaultCacheConfiguration.setMaxElementsInMemory(maxElementsInMemory);
+ defaultCacheConfiguration.setEternal(eternal);
+ defaultCacheConfiguration.setTimeToIdleSeconds(timeToIdleSeconds);
+ defaultCacheConfiguration.setTimeToLiveSeconds(timeToLiveSeconds);
+ defaultCacheConfiguration.setOverflowToDisk(overflowToDisk);
+ defaultCacheConfiguration.setDiskPersistent(diskPersistent);
+
defaultCacheConfiguration.setMemoryStoreEvictionPolicy(memoryStoreEvictionPolicy);
+
+ DiskStoreConfiguration diskStoreConfiguration = new
DiskStoreConfiguration();
+ diskStoreConfiguration.setPath(diskStorePath);
+ configuration.addDiskStore(diskStoreConfiguration);
+
+ configuration.addDefaultCache(defaultCacheConfiguration);
+
+
+ CacheManager cacheManager = new CacheManager(configuration);
+ return cacheManager;
+ }
+
+ public String getDiskStorePath() {
+ return diskStorePath;
+ }
+
+ public void setDiskStorePath(String diskStorePath) {
+ this.diskStorePath = diskStorePath;
+ }
+
+ public Boolean getDiskPersistent() {
+ return diskPersistent;
+ }
+
+ public void setDiskPersistent(Boolean diskPersistent) {
+ this.diskPersistent = diskPersistent;
+ }
+
+ public Boolean getEternal() {
+ return eternal;
+ }
+
+ public void setEternal(Boolean eternal) {
+ this.eternal = eternal;
+ }
+
+ public int getMaxElementsInMemory() {
+ return maxElementsInMemory;
+ }
+
+ public void setMaxElementsInMemory(int maxElementsInMemory) {
+ this.maxElementsInMemory = maxElementsInMemory;
+ }
+
+ public Boolean getOverflowToDisk() {
+ return overflowToDisk;
+ }
+
+ public void setOverflowToDisk(Boolean overflowToDisk) {
+ this.overflowToDisk = overflowToDisk;
+ }
+
+ public long getTimeToIdleSeconds() {
+ return timeToIdleSeconds;
+ }
+
+ public void setTimeToIdleSeconds(long timeToIdleSeconds) {
+ this.timeToIdleSeconds = timeToIdleSeconds;
+ }
+
+ public long getTimeToLiveSeconds() {
+ return timeToLiveSeconds;
+ }
+
+ public void setTimeToLiveSeconds(long timeToLiveSeconds) {
+ this.timeToLiveSeconds = timeToLiveSeconds;
+ }
+
+ public String getMemoryStoreEvictionPolicy() {
+ return memoryStoreEvictionPolicy;
+ }
+
+ public void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy)
{
+ this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy;
+ }
+}
Added:
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStore.java
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStore.java?rev=1146175&view=auto
==============================================================================
---
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStore.java
(added)
+++
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStore.java
Wed Jul 13 18:06:51 2011
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.store.ehcache;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheException;
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.event.CacheEventListener;
+import org.apache.servicemix.id.IdGenerator;
+import org.apache.servicemix.store.Store;
+import org.apache.servicemix.store.base.BaseStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * EhCache Store.
+ * <p>Note: The current implementation always "removes" expired items.</p>
+ * @author n.dimos
+ */
+public class EhCacheStore extends BaseStore implements CacheEventListener {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(EhCacheStore.class);
+
+ private String name;
+ private Cache cache;
+ private IdGenerator idGenerator;
+
+ public EhCacheStore(Cache cache, IdGenerator idGenerator, String name) {
+ super();
+ this.cache=cache;
+ this.idGenerator=idGenerator;
+ this.name = name;
+ cache.getCacheEventNotificationService().registerListener(this);
+ }
+
+ /**
+ * <p>
+ * Returns true if feature is provided by the store (clustered), false
else.
+ * </p>
+ *
+ * @param feature the feature.
+ * @return true if the given feature is provided by the store, false else.
+ */
+ public boolean hasFeature(String feature) {
+ if(Store.PERSISTENT.equals(feature)) return
cache.getCacheConfiguration().isDiskPersistent();
+ else return false;
+ }
+
+
+ public synchronized void destroy() throws Exception {
+ cache.flush();
+ }
+
+ /**
+ * <p>
+ * Put an object in the store under the given id. This method must be used
+ * with caution and the behavior is unspecified if an object already exist
+ * for the same id.
+ * </p>
+ *
+ * @param id the id of the object to store
+ * @param data the object to store
+ * @throws IOException if an error occurs
+ */
+ public void store(String id, Object data) throws IOException {
+ LOG.debug("Storing object with id: " + id);
+ try {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(buffer);
+ out.writeObject(data);
+ out.close();
+
+ Element element = new Element(id, buffer.toByteArray());
+ cache.put(element);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+
+ }
+
+ /**
+ * <p>
+ * Put an object into the store and return the unique id that may be used
at
+ * a later time to retrieve the object.
+ * </p>
+ *
+ * @param data the object to store
+ * @return the id of the object stored
+ * @throws IOException if an error occurs
+ */
+ public String store(Object data) throws IOException {
+ String id = idGenerator.generateId();
+ store(id, data);
+ return id;
+ }
+
+ /**
+ * <p>
+ * Loads an object that has been previously stored under the specified key.
+ * The object is removed from the store.
+ * </p>
+ *
+ * @param id the id of the object
+ * @return the object, or <code>null></code> if the object could not be
found
+ * @throws IOException if an error occurs
+ */
+ public Object load(String id) throws IOException {
+ LOG.debug("Loading object with id: " + id);
+ try {
+ Object result = null;
+ Element element = cache.get(id);
+ if (element != null) {
+ byte[] data = (byte[]) (element.getValue());
+ result = readObject(data);
+ cache.remove(id);
+ }
+ return result;
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
+ * <p>
+ * Loads an object that has been previously stored under the specified key.
+ * The object is not removed from the store.
+ * </p>
+ *
+ * @param id the id of the object
+ * @return the object, or <code>null</code> if the object could not be
found
+ * @throws IOException if an error occurs
+ */
+ public Object peek(String id) throws IOException {
+ LOG.debug("Peeking object with id: " + id);
+ try {
+ Object result = null;
+ Element element = cache.get(id);
+ if (element != null) {
+ byte[] data = (byte[]) (element.getValue());
+ result = readObject(data);
+ }
+ return result;
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+ private Object readObject(byte[] data) throws IOException,
ClassNotFoundException {
+ Object result = null;
+ if (data != null) {
+ ObjectInputStream ois = new ObjectInputStream(new
ByteArrayInputStream(data));
+ try {
+ result = ois.readObject();
+ } finally {
+ ois.close();
+ }
+ }
+ return result;
+ }
+
+
+ public void notifyElementPut(Ehcache cache, Element element) throws
CacheException {
+ String id = (String) element.getKey();
+ byte[] data = (byte[]) element.getObjectValue();
+ try {
+ fireAddedEvent(id, readObject(data));
+ } catch (IOException e) {
+ throw new CacheException(e);
+ } catch (ClassNotFoundException e) {
+ throw new CacheException(e);
+ }
+ }
+
+ public void notifyElementUpdated(Ehcache cache, Element element) throws
CacheException {
+ notifyElementPut(cache,element);
+ }
+
+ public void notifyElementExpired(Ehcache cache, Element element) {
+
+ String id = (String) element.getKey();
+ byte[] bytes = (byte[]) element.getObjectValue();
+ Object data = null;
+ try {
+ data = readObject(bytes);
+ fireEvictedEvent(id, readObject(bytes));
+ } catch (IOException e) {
+ LOG.error("Error reading expired element",e);
+ } catch (ClassNotFoundException e) {
+ LOG.error("Error reading expired element",e);
+ }
+ cache.removeQuiet(id);
+ }
+
+ public void notifyElementEvicted(Ehcache cache, Element element) {
+ String id = (String) element.getKey();
+ byte[] data = (byte[]) element.getObjectValue();
+ try {
+ fireEvictedEvent(id, readObject(data));
+ } catch (IOException e) {
+ throw new CacheException(e);
+ } catch (ClassNotFoundException e) {
+ throw new CacheException(e);
+ }
+ }
+
+ public void notifyRemoveAll(Ehcache cache) {
+ }
+
+ public void dispose() {
+
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+
+ public void notifyElementRemoved(Ehcache cache, Element element) throws
CacheException {
+ String id = (String) element.getKey();
+ byte[] data = (byte[]) element.getObjectValue();
+ try {
+ //I am doing this to work around an issue in EhCache quiet removal.
+ //This cause problems since elements are always removed on
expiration.
+ if (data != null) {
+ fireRemovedEvent(id, readObject(data));
+ }
+ } catch (IOException e) {
+ throw new CacheException(e);
+ } catch (ClassNotFoundException e) {
+ throw new CacheException(e);
+ }
+ }
+
+ public Cache getCache() {
+ return cache;
+ }
+
+ public void setCache(Cache cache) {
+ this.cache = cache;
+ }
+
+ public IdGenerator getIdGenerator() {
+ return idGenerator;
+ }
+
+ public void setIdGenerator(IdGenerator idGenerator) {
+ this.idGenerator = idGenerator;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Added:
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStoreFactory.java
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStoreFactory.java?rev=1146175&view=auto
==============================================================================
---
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStoreFactory.java
(added)
+++
servicemix/utils/trunk/src/main/java/org/apache/servicemix/store/ehcache/EhCacheStoreFactory.java
Wed Jul 13 18:06:51 2011
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.store.ehcache;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Status;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.config.Configuration;
+import net.sf.ehcache.config.DiskStoreConfiguration;
+import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.id.IdGenerator;
+import org.apache.servicemix.store.Store;
+import org.apache.servicemix.store.StoreFactory;
+
+/**
+ * @author n.dimos
+ */
+public class EhCacheStoreFactory implements StoreFactory {
+
+ private static final Log LOG =
LogFactory.getLog(EhCacheStoreFactory.class);
+
+ protected IdGenerator idGenerator = new IdGenerator();
+ private Map<String, EhCacheStore> stores = new HashMap<String,
EhCacheStore>();
+
+ private CacheManagerFactory cacheManagerFactory = new
CacheManagerFactory();
+ private CacheManager cacheManager = cacheManagerFactory.build();
+
+ public EhCacheStoreFactory() {
+
+ }
+
+ public synchronized Store open(String name) throws IOException {
+ EhCacheStore store = stores.get(name);
+ if (store == null) {
+ Cache cache = cacheManager.getCache(name);
+ if(cache == null) {
+ cacheManager.addCache(name);
+ cache = cacheManager.getCache(name);
+ }
+ store = new EhCacheStore(cache,idGenerator, name);
+ stores.put(name, store);
+ }
+ return store;
+ }
+
+ public synchronized void close(Store store) throws IOException {
+ EhCacheStore ehCacheStore = (EhCacheStore) store;
+ try {
+ ehCacheStore.destroy();
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ stores.remove(ehCacheStore.getName());
+ }
+
+ public IdGenerator getIdGenerator() {
+ return idGenerator;
+ }
+
+ public void setIdGenerator(IdGenerator idGenerator) {
+ this.idGenerator = idGenerator;
+ }
+
+ public CacheManager getCacheManager() {
+ return cacheManager;
+ }
+
+ public void setCacheManager(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+}
Added:
servicemix/utils/trunk/src/test/java/org/apache/servicemix/store/ehcache/EhCacheStoreTest.java
URL:
http://svn.apache.org/viewvc/servicemix/utils/trunk/src/test/java/org/apache/servicemix/store/ehcache/EhCacheStoreTest.java?rev=1146175&view=auto
==============================================================================
---
servicemix/utils/trunk/src/test/java/org/apache/servicemix/store/ehcache/EhCacheStoreTest.java
(added)
+++
servicemix/utils/trunk/src/test/java/org/apache/servicemix/store/ehcache/EhCacheStoreTest.java
Wed Jul 13 18:06:51 2011
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.store.ehcache;
+
+import junit.framework.TestCase;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import org.apache.servicemix.id.IdGenerator;
+import org.apache.servicemix.store.StoreListener;
+import org.easymock.EasyMock;
+
+import static org.easymock.EasyMock.*;
+
+/**
+ * @author: iocanel
+ */
+public class EhCacheStoreTest extends TestCase {
+
+ private static final String TEST_CACHE_NAME = "TEST_CACHE_NAME";
+ IdGenerator idGenerator = new IdGenerator();
+ CacheManagerFactory cacheManagerFactory;
+ CacheManager cacheManager;
+
+ Cache cache = null;
+
+ private StoreListener listener = createMock(StoreListener.class);
+
+ public EhCacheStoreTest() {
+ cacheManagerFactory = new CacheManagerFactory();
+ cacheManagerFactory.setDiskStorePath("target");
+ cacheManager = cacheManagerFactory.build();
+ cacheManager.addCache(TEST_CACHE_NAME);
+ cache = cacheManager.getCache(TEST_CACHE_NAME);
+ }
+
+ public void testStore() throws Exception {
+ EhCacheStore store = new EhCacheStore(cache,idGenerator,"testStore");
+ String id = "1";
+ String data = "Test data ....";
+ store.store(id,data);
+ assertEquals(data,store.peek(id));
+ assertEquals(data,store.load(id));
+ assertEquals(null,store.load(id));
+ }
+
+ public void testEviction() throws Exception {
+ cacheManagerFactory.setTimeToIdleSeconds(2);
+ cacheManagerFactory.setTimeToLiveSeconds(2);
+ cacheManager = cacheManagerFactory.build();
+ cacheManager.addCache(TEST_CACHE_NAME);
+ cache = cacheManager.getCache(TEST_CACHE_NAME);
+
+ EhCacheStore store = new EhCacheStore(cache,idGenerator,"testStore");
+ String id = "1";
+ String data = "Test data ....";
+ store.store(id,data);
+ assertEquals(data,store.peek(id));
+ Thread.sleep(3000);
+ assertEquals(null,store.peek(id));
+ }
+
+ public void testStoreListeners() throws Exception {
+ cacheManagerFactory.setTimeToIdleSeconds(2);
+ cacheManagerFactory.setTimeToLiveSeconds(2);
+ cacheManager = cacheManagerFactory.build();
+ cacheManager.addCache(TEST_CACHE_NAME);
+ cache = cacheManager.getCache(TEST_CACHE_NAME);
+
+ EhCacheStore store = new EhCacheStore(cache,idGenerator,"testStore");
+ store.addListener(listener);
+ String id = "1";
+ String data = "Test data ....";
+
+ //Record behavior
+ listener.onAdd(id,data);
+ expectLastCall().times(1);
+ listener.onEvict(id, data);
+ expectLastCall().once();
+ replay(listener);
+
+ store.store(id,data);
+ assertEquals(data,store.peek(id));
+ Thread.sleep(3000);
+ assertEquals(null,store.peek(id));
+ verify(listener);
+ }
+}