Skip to content

SPR-10588 Add Infinispan Cache Implementation #292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ configure(allprojects) { project ->
"http://aopalliance.sourceforge.net/doc/",
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"http://ehcache.org/apidocs/",
"http://docs.jboss.org/infinispan/5.2/apidocs/",
"http://quartz-scheduler.org/api/2.1.7/",
"http://jackson.codehaus.org/1.9.12/javadoc/",
"http://fasterxml.github.com/jackson-core/javadoc/2.2.0/",
Expand Down Expand Up @@ -395,6 +396,10 @@ project("spring-jdbc") {
project("spring-context-support") {
description = "Spring Context Support"

repositories {
maven { url "https://repository.jboss.org/nexus/content/repositories/releases/" } // infinispan
}

dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
Expand All @@ -404,6 +409,7 @@ project("spring-context-support") {
optional("javax.mail:mail:1.4.7")
optional("javax.cache:cache-api:0.6")
optional("net.sf.ehcache:ehcache-core:2.6.5")
optional("org.infinispan:infinispan-core:5.2.6.Final")
optional("org.quartz-scheduler:quartz:1.8.6") {
exclude group: "org.slf4j", module: "slf4j-log4j12"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed 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.springframework.cache.infinispan;

import org.infinispan.lifecycle.ComponentStatus;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.Assert;

/**
* {@link org.springframework.cache.Cache} implementation on top of an
* {@link org.infinispan.Cache} instance.
*
* @author Philippe Marschall
* @since 4.0
*/
public class InfinispanCache implements Cache {

private static final Object NULL_HOLDER = NullHolder.INSTANE;

@SuppressWarnings("rawtypes")
private final org.infinispan.Cache cache;

private final boolean allowNullValues;


/**
* Create an {@link org.springframework.cache.infinispan.InfinispanCache} instance.
* @param infinispanCache backing Infinispan Cache instance
*/
public InfinispanCache(org.infinispan.Cache infinispanCache) {
this(infinispanCache, true);
}

/**
* Create an {@link org.springframework.cache.infinispan.InfinispanCache} instance.
* @param infinispanCache backing Infinispan Cache instance
* @param allowNullValues whether to accept and convert null values for this cache
*/
public InfinispanCache(org.infinispan.Cache infinispanCache, boolean allowNullValues) {
Assert.notNull(infinispanCache, "Cache must not be null");
ComponentStatus status = infinispanCache.getStatus();
Assert.isTrue(status == ComponentStatus.RUNNING,
"A 'running' cache is required - current cache is " + status);
this.cache = infinispanCache;
this.allowNullValues = allowNullValues;
}

@Override
public String getName() {
return this.cache.getName();
}

@Override
public org.infinispan.Cache getNativeCache() {
return this.cache;
}

@Override
public ValueWrapper get(Object key) {
Object value = this.cache.get(key);
return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
}

@Override
@SuppressWarnings("unchecked")
public void put(Object key, Object value) {
this.cache.put(key, toStoreValue(value));
}

@Override
public void evict(Object key) {
this.cache.remove(key);
}

@Override
public void clear() {
this.cache.clear();
}



/**
* Convert the given value from the internal store to a user value
* returned from the get method (adapting {@code null}).
* @param storeValue the store value
* @return the value to return to the user
*/
protected Object fromStoreValue(Object storeValue) {
if (this.allowNullValues && storeValue == NULL_HOLDER) {
return null;
}
return storeValue;
}

/**
* Convert the given user value, as passed into the put method,
* to a value in the internal store (adapting {@code null}).
* @param userValue the given user value
* @return the value to store
*/
protected Object toStoreValue(Object userValue) {
if (this.allowNullValues && userValue == null) {
return NULL_HOLDER;
}
return userValue;
}


@SuppressWarnings("serial")
static enum NullHolder {
INSTANE;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed 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.springframework.cache.infinispan;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.manager.EmbeddedCacheManager;
import org.springframework.cache.Cache;
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager;
import org.springframework.util.Assert;

/**
* {@link org.springframework.cache.CacheManager} implementation
* backed by a Infinispan {@link EmbeddedCacheManager}.
*
* @author Philippe Marschall
* @since 4.0
*/
public class InfinispanCacheManager extends AbstractTransactionSupportingCacheManager {

private EmbeddedCacheManager cacheManager;

private boolean allowNullValues = true;


/**
* Create a new InfinispanCacheManager, setting the target Infinispan CacheManager
* through the {@link #setCacheManager} bean property.
*/
public InfinispanCacheManager() {
}

/**
* Create a new InfinispanCacheManager for the given backing Infinispan.
* @param cacheManager the backing Infinispan {@link EmbeddedCacheManager}
*/
public InfinispanCacheManager(EmbeddedCacheManager cacheManager) {
this.cacheManager = cacheManager;
}


/**
* Set the backing Infinispan {@link EmbeddedCacheManager}.
*/
public void setCacheManager(EmbeddedCacheManager cacheManager) {
this.cacheManager = cacheManager;
}

/**
* Return the backing Infinispan {@link EmbeddedCacheManager}.
*/
public EmbeddedCacheManager getCacheManager() {
return this.cacheManager;
}

/**
* Specify whether to accept and convert null values for all caches
* in this cache manager.
* <p>Default is "true", despite Infinispan itself not supporting null values.
* An internal holder object will be used to store user-level null values.
*/
public void setAllowNullValues(boolean allowNullValues) {
this.allowNullValues = allowNullValues;
}

/**
* Return whether this cache manager accepts and converts null values
* for all of its caches.
*/
public boolean isAllowNullValues() {
return this.allowNullValues;
}


@Override
protected Collection<Cache> loadCaches() {
Assert.notNull(this.cacheManager, "A backing CacheManager is required");
ComponentStatus status = this.cacheManager.getStatus();
Assert.isTrue(ComponentStatus.RUNNING == status,
"A 'running' Infinispan CacheManager is required - current cache is " + status);

Set<String> cacheNames = this.cacheManager.getCacheNames();
Collection<Cache> caches = new LinkedHashSet<Cache>(cacheNames.size());

for (String cacheName : cacheNames) {
org.infinispan.Cache infinispanCache = this.cacheManager.getCache(cacheName, true);
caches.add(new InfinispanCache(infinispanCache, this.allowNullValues));
}
return caches;
}

@Override
public Cache getCache(String name) {
Cache cache = super.getCache(name);
if (cache == null) {
// check the Infinispan cache again
// (in case the cache was added at runtime)
org.infinispan.Cache infinispanCache = this.cacheManager.getCache(name, false);
if (infinispanCache != null) {
cache = new InfinispanCache(infinispanCache, this.allowNullValues);
addCache(cache);
}
}
return cache;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed 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.springframework.cache.infinispan;

import java.io.IOException;
import java.io.InputStream;

import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;

/**
* {@link FactoryBean} for a Infinispan {@link EmbeddedCacheManager}.
*
* <p>This class is intended to be used in conjunction with Spring XML configuration and
* Infinispan XML configuration. While it does work with Spring Java configuration in
* such cases you're likely better off instantiating the cache manager yourself and using
* <a
* href="https://docs.jboss.org/author/display/ISPN/Configuring+cache+programmatically">
* Infinispan fluent configuration</a>.
*
* @author Philippe Marschall
* @since 4.0
*/
public class InfinispanCacheManagerFactoryBean
implements FactoryBean<EmbeddedCacheManager>, InitializingBean, DisposableBean {

private Resource configLocation;

private EmbeddedCacheManager cacheManager;


/**
* Set the location of the Infinispan config file. A typical value is "/WEB-INF/infinispan.xml".
* @see org.infinispan.manager.DefaultCacheManager#DefaultCacheManager(java.io.InputStream)
*/
public void setConfigLocation(Resource configLocation) {
this.configLocation = configLocation;
}

@Override
public void afterPropertiesSet() throws IOException {
if (this.configLocation != null) {
InputStream configurationStream = this.configLocation.getInputStream();
try {
this.cacheManager = new DefaultCacheManager(configurationStream, true);
} finally {
configurationStream.close();
}
} else {
this.cacheManager = new DefaultCacheManager(true);
}
}


@Override
public EmbeddedCacheManager getObject() {
return this.cacheManager;
}

@Override
public Class<? extends EmbeddedCacheManager> getObjectType() {
return this.cacheManager != null ? this.cacheManager.getClass() : EmbeddedCacheManager.class;
}

@Override
public boolean isSingleton() {
return true;
}


@Override
public void destroy() {
this.cacheManager.stop();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Support classes for the open source cache
* <a href="http://www.jboss.org/infinispan/">Infinispan</a>,
* allowing to set up an Infinispan CacheManager and Caches
* as beans in a Spring context.
*/
package org.springframework.cache.infinispan;
Loading