You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bd...@apache.org on 2016/07/13 20:07:59 UTC
[2/3] shiro git commit: SHIRO-412: I got tired referencing
Hazelcast-based examples I created outside of Shiro,
so I'm bringing it into the project properly. Works great. Hazelcast is
Apache-licensed as well and probably should be our default caching r
SHIRO-412: I got tired referencing Hazelcast-based examples I created outside of Shiro, so I'm bringing it into the project properly. Works great. Hazelcast is Apache-licensed as well and probably should be our default caching recommendation (Ehcache is I think still LGPL and a touchy issue - we can't extend any of its code - just invoke it).
git-svn-id: https://svn.apache.org/repos/asf/shiro/trunk@1433611 13f79535-47bb-0310-9956-ffa450edef68
Project: http://git-wip-us.apache.org/repos/asf/shiro/repo
Commit: http://git-wip-us.apache.org/repos/asf/shiro/commit/0b505c27
Tree: http://git-wip-us.apache.org/repos/asf/shiro/tree/0b505c27
Diff: http://git-wip-us.apache.org/repos/asf/shiro/diff/0b505c27
Branch: refs/heads/1.3.x
Commit: 0b505c272d61372bd2674ee88fd103e62d71714e
Parents: bdc0b7c
Author: Les Hazlewood <lh...@apache.org>
Authored: Tue Jan 15 20:08:12 2013 +0000
Committer: Brian Demers <bd...@apache.org>
Committed: Wed Jul 13 13:23:07 2016 -0400
----------------------------------------------------------------------
.../cache/MemoryConstrainedCacheManager.java | 4 +-
pom.xml | 24 +-
support/ehcache/pom.xml | 2 +-
.../shiro/cache/ehcache/EhCacheManager.java | 8 +-
support/features/pom.xml | 3 +-
.../features/src/main/resources/features.xml | 19 ++
support/hazelcast/pom.xml | 83 +++++++
.../hazelcast/cache/HazelcastCacheManager.java | 245 +++++++++++++++++++
.../cache/HazelcastCacheManagerTest.groovy | 181 ++++++++++++++
.../src/test/resources/log4j.properties | 35 +++
support/pom.xml | 1 +
11 files changed, 597 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java b/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java
index 56cf12c..9b331e4 100644
--- a/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java
+++ b/core/src/main/java/org/apache/shiro/cache/MemoryConstrainedCacheManager.java
@@ -28,8 +28,8 @@ import org.apache.shiro.util.SoftHashMap;
* <p/>
* While the {@code Cache} instances created are thread-safe, they do not offer any enterprise-level features such as
* cache coherency, optimistic locking, failover or other similar features. For more enterprise features, consider
- * using a different {@code CacheManager} implementation backed by an enterprise-grade caching product (EhCache,
- * TerraCotta, Coherence, GigaSpaces, etc, etc).
+ * using a different {@code CacheManager} implementation backed by an enterprise-grade caching product (Hazelcast,
+ * EhCache, TerraCotta, Coherence, GigaSpaces, etc, etc).
*
* @since 1.0
*/
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 05b7836..67b9b9a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -80,7 +80,9 @@
<crowd.version>1.5.2</crowd.version>
<!-- Don't change this version without also changing the shiro-ehcache and shiro-features
modules' OSGi metadata: -->
- <ehcache.version>2.5.0</ehcache.version>
+ <ehcache.version>2.5.3</ehcache.version>
+ <!-- Don't change this version without also changing the shiro-hazelcast and shiro-features OSGi metadata: -->
+ <hazelcast.version>2.4.1</hazelcast.version>
<hsqldb.version>1.8.0.7</hsqldb.version>
<jdk.version>1.6</jdk.version>
<jetty.version>6.1.26</jetty.version>
@@ -96,6 +98,9 @@
<gmaven.version>1.3</gmaven.version>
<groovy.version>1.8.5</groovy.version>
<junit.version>4.8.2</junit.version>
+ <!-- so we can mock static methods in 3rd party libraries that sometimes don't use proper interfaces
+ ahem, hazelcast, ahem... -->
+ <powermock.version>1.5</powermock.version>
</properties>
@@ -494,6 +499,18 @@
<version>${groovy.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-junit4</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-easymock</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<dependencyManagement>
@@ -687,6 +704,11 @@
</exclusions>
</dependency>
<dependency>
+ <groupId>com.hazelcast</groupId>
+ <artifactId>hazelcast</artifactId>
+ <version>2.4.1</version>
+ </dependency>
+ <dependency>
<!-- Used for sample applications only - not required for the framework: -->
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/ehcache/pom.xml
----------------------------------------------------------------------
diff --git a/support/ehcache/pom.xml b/support/ehcache/pom.xml
index 02004d5..3020d9d 100644
--- a/support/ehcache/pom.xml
+++ b/support/ehcache/pom.xml
@@ -67,7 +67,7 @@
<Export-Package>org.apache.shiro.cache.ehcache*;version=${project.version}</Export-Package>
<Import-Package>
org.apache.shiro*;version="${shiro.osgi.importRange}",
- net.sf.ehcache*;version="[2.3, 3)",
+ net.sf.ehcache*;version="[2.5, 3)",
*
</Import-Package>
</instructions>
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java
----------------------------------------------------------------------
diff --git a/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java b/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java
index 3a802f2..ce1a637 100644
--- a/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java
+++ b/support/ehcache/src/main/java/org/apache/shiro/cache/ehcache/EhCacheManager.java
@@ -237,13 +237,15 @@ public class EhCacheManager implements CacheManager, Initializable, Destroyable
try {
net.sf.ehcache.CacheManager cacheMgr = getCacheManager();
cacheMgr.shutdown();
- } catch (Exception e) {
+ } catch (Throwable t) {
if (log.isWarnEnabled()) {
log.warn("Unable to cleanly shutdown implicitly created CacheManager instance. " +
- "Ignoring (shutting down)...");
+ "Ignoring (shutting down)...", t);
}
+ } finally {
+ this.manager = null;
+ this.cacheManagerImplicitlyCreated = false;
}
- cacheManagerImplicitlyCreated = false;
}
}
}
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/features/pom.xml
----------------------------------------------------------------------
diff --git a/support/features/pom.xml b/support/features/pom.xml
index f0a4379..fb28c8a 100644
--- a/support/features/pom.xml
+++ b/support/features/pom.xml
@@ -33,7 +33,8 @@
<properties>
<aspectj.bundle.version>1.6.16_1</aspectj.bundle.version>
- <ehcache.bundle.version>2.5.0_1</ehcache.bundle.version>
+ <ehcache.bundle.version>2.5.3_1</ehcache.bundle.version>
+ <hazelcast.bundle.version>2.4.1_1</hazelcast.bundle.version>
<quartz.bundle.version>1.6.1_1</quartz.bundle.version>
<!-- Not a Shiro dependency - used for quartz bundle resolution only (see features.xml): -->
<commons.collections.version>3.2.1</commons.collections.version>
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/support/features/src/main/resources/features.xml b/support/features/src/main/resources/features.xml
index 72451a2..5f9b3fb 100644
--- a/support/features/src/main/resources/features.xml
+++ b/support/features/src/main/resources/features.xml
@@ -53,6 +53,25 @@
<bundle>mvn:org.apache.shiro/shiro-ehcache/${project.version}</bundle>
</feature>
+ <feature name="shiro-hazelcast" version="${project.version}" resolver="(obr)">
+ <feature version="${project.version}">shiro-core</feature>
+ <!-- Is there a Hazelcast osgi bundle somewhere? The following line just assumes it exists: -->
+ <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.hazelcast/${hazelcast.bundle.version}</bundle>
+ <bundle>mvn:org.apache.shiro/shiro-hazelcast/${project.version}</bundle>
+ </feature>
+
+ <!--
+ TODO enable when openid4j module is done
+ <feature name="shiro-openid4j" version="${project.version}" resolver="(obr)">
+ <feature version="${project.version}">shiro-core</feature>
+ <feature version="${project.version}">shiro-web</feature>
+ <feature version="[3,4)">spring</feature>
+ TODO: is there an openid4j OSGi bundle?
+ <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.openid4j/${openid4j.version}</bundle>
+ <bundle>mvn:org.apache.shiro/shiro-openid4j/${project.version}</bundle>
+ </feature>
+ -->
+
<feature name="shiro-quartz" version="${project.version}" resolver="(obr)">
<feature version="${project.version}">shiro-core</feature>
<bundle dependency='true'>mvn:commons-collections/commons-collections/${commons.collections.version}</bundle>
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/hazelcast/pom.xml
----------------------------------------------------------------------
diff --git a/support/hazelcast/pom.xml b/support/hazelcast/pom.xml
new file mode 100644
index 0000000..d5f6194
--- /dev/null
+++ b/support/hazelcast/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-root</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>shiro-hazelcast</artifactId>
+ <name>Apache Shiro :: Support :: Hazelcast</name>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <hazelcast.osgi.importRange>[2.4, 3)</hazelcast.osgi.importRange>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.hazelcast</groupId>
+ <artifactId>hazelcast</artifactId>
+ </dependency>
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>org.apache.shiro.hazelcast</Bundle-SymbolicName>
+ <Export-Package>org.apache.shiro.hazelcast*;version=${project.version}</Export-Package>
+ <Import-Package>
+ org.apache.shiro*;version="${shiro.osgi.importRange}",
+ com.hazelcast*;version="${hazelcast.osgi.importRange}",
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/hazelcast/src/main/java/org/apache/shiro/hazelcast/cache/HazelcastCacheManager.java
----------------------------------------------------------------------
diff --git a/support/hazelcast/src/main/java/org/apache/shiro/hazelcast/cache/HazelcastCacheManager.java b/support/hazelcast/src/main/java/org/apache/shiro/hazelcast/cache/HazelcastCacheManager.java
new file mode 100644
index 0000000..68db4c9
--- /dev/null
+++ b/support/hazelcast/src/main/java/org/apache/shiro/hazelcast/cache/HazelcastCacheManager.java
@@ -0,0 +1,245 @@
+/*
+ * 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.shiro.hazelcast.cache;
+
+import com.hazelcast.config.Config;
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import org.apache.shiro.ShiroException;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.cache.CacheManager;
+import org.apache.shiro.cache.MapCache;
+import org.apache.shiro.util.Destroyable;
+import org.apache.shiro.util.Initializable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+/**
+ * A {@code CacheManager} implementation backed by <a href="http://www.hazelcast.com/">Hazelcast</a>,
+ * "an open source clustering and highly scalable data distribution platform for Java"
+ * <p/>
+ * This implementation interacts with a {@link HazelcastInstance} to
+ * {@link HazelcastInstance#getMap(String) acquire} named {@link java.util.concurrent.ConcurrentMap ConcurrentMap}
+ * instances. Those clustered/distributed Map instances are then wrapped and made available to {@code CacheManager}
+ * callers as {@link MapCache} instances via {@link #getCache(String)}.
+ * <h2>Configuration</h2>
+ * This implementation's backing {@code HazelcastInstance} can be configured in one of three ways:
+ * <ol>
+ * <li>Doing nothing and leveraging default Hazelcast configuration mechanisms</li>
+ * <li>Supplying an already-existing {@code HazelcastInstance}</li>
+ * <li>Supplying a {@link Config} instance and using that to create a new {@code HazelcastInstance}</li>
+ * </ol>
+ * <h3>Default Configuration</h3>
+ * If you simply instantiate a {@code HazelcastCacheManager} and do nothing further, its backing
+ * {@link HazelcastInstance} instance will be created automatically by calling
+ * {@link Hazelcast#newHazelcastInstance(com.hazelcast.config.Config) Hazelcast.newHazelcastInstance(null)}.
+ * <p/>
+ * The null argument instructs Hazelcast to use whatever default configuration mechanism it has at its disposal,
+ * usually a {@code hazelcast.xml} file at the root of the classpath, or if that is not present, the
+ * {@code hazelcast-default.xml} file contained in the Hazelcast {@code .jar} file itself.
+ * <p/>
+ * <h3>An existing {@code HazelcastInstance}</h3>
+ * If you have created a {@code HazelcastInstance} outside of Shiro's knowledge/control, you can simply configure it
+ * to be used by calling {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) setHazelcastInstance}.
+ * <p/>
+ * <h3>A {@link Config} instance</h3>
+ * If you do not want to use the above two options, you can have programmatic control over all of Hazelcast's
+ * configuration by <a href="http://www.hazelcast.com/docs/2.5/manual/multi_html/ch12.html">creating and configuring a
+ * Config instance</a>.
+ * <p/>
+ * Once constructed, you can set it via {@link #setConfig(com.hazelcast.config.Config) setConfig(config)}. This config
+ * instance will be used to acquire a new Hazelcast instance by calling
+ * {@link Hazelcast#newHazelcastInstance(Config) Hazelcast.newHazelcastInstance(config)}
+ *
+ * @see <a href="http://www.hazelcast.com/docs/2.5/manual/multi_html/ch12.html">Hazelcast Configuration Documentation</a>
+ * @since 1.3
+ */
+public class HazelcastCacheManager implements CacheManager, Initializable, Destroyable {
+
+ public static final Logger log = LoggerFactory.getLogger(HazelcastCacheManager.class);
+
+ private boolean implicitlyCreated = false;
+ private HazelcastInstance hazelcastInstance;
+ private Config config;
+
+ /**
+ * Returns a {@link MapCache} instance representing the named Hazelcast-managed
+ * {@link com.hazelcast.core.IMap IMap}. The Hazelcast Map is obtained by calling
+ * {@link HazelcastInstance#getMap(String) hazelcastInstance.getMap(name)}.
+ *
+ * @param name the name of the cache to acquire.
+ * @param <K> the type of map key
+ * @param <V> the type of map value
+ * @return a {@link MapCache} instance representing the named Hazelcast-managed {@link com.hazelcast.core.IMap IMap}.
+ * @throws CacheException
+ * @see HazelcastInstance#getMap(String)
+ * @see #ensureHazelcastInstance()
+ *
+ */
+ public <K, V> Cache<K, V> getCache(String name) throws CacheException {
+ Map<K, V> map = ensureHazelcastInstance().getMap(name); //returned map is a ConcurrentMap
+ return new MapCache<K, V>(name, map);
+ }
+
+ /**
+ * Ensures that this implementation has a backing {@link HazelcastInstance}, and if not, implicitly creates one
+ * via {@link #createHazelcastInstance()}.
+ *
+ * @return the backing (potentially newly created) {@code HazelcastInstance}.
+ * @see #createHazelcastInstance()
+ * @see HazelcastInstance
+ */
+ protected HazelcastInstance ensureHazelcastInstance() {
+ if (this.hazelcastInstance == null) {
+ this.hazelcastInstance = createHazelcastInstance();
+ this.implicitlyCreated = true;
+ }
+ return this.hazelcastInstance;
+ }
+
+ /**
+ * Initializes this instance by {@link #ensureHazelcastInstance() ensuring} there is a backing
+ * {@link HazelcastInstance}.
+ *
+ * @throws ShiroException
+ * @see #ensureHazelcastInstance()
+ * @see HazelcastInstance
+ */
+ public void init() throws ShiroException {
+ ensureHazelcastInstance();
+ }
+
+ /**
+ * Implicitly creates and returns a new {@link HazelcastInstance} that will be used to back this implementation.
+ * This implementation calls:
+ * <pre>
+ * return Hazelcast.newHazelcastInstance(this.config);
+ * </pre>
+ * using any {@link #setConfig(com.hazelcast.config.Config) configured} {@code Config} object. If no config
+ * object has been specified, {@code this.config} will be {@code null}, thereby using Hazelcast's
+ * <a href="http://www.hazelcast.com/docs/2.5/manual/multi_html/ch12.html">default configuration mechanism</a>.
+ * <p/>
+ * Can be overridden by subclasses for custom creation behavior.
+ *
+ * @return a new {@link HazelcastInstance} that will be used to back this implementation
+ * @see Hazelcast#newHazelcastInstance(com.hazelcast.config.Config)
+ * @see Config
+ */
+ protected HazelcastInstance createHazelcastInstance() {
+ return Hazelcast.newHazelcastInstance(this.config);
+ }
+
+ //needed for unit tests only - not part of Shiro's public API
+
+ /**
+ * NOT PART OF SHIRO'S ACCESSIBLE API. DO NOT DEPEND ON THIS. This method was added for testing purposes only.
+ * <p/>
+ * Returns {@code true} if this {@code HazelcastCacheManager} instance implicitly created the backing
+ * {@code HazelcastInstance}, or {@code false} if one was externally provided via
+ * {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) setHazelcastInstance}.
+ *
+ * @return {@code true} if this {@code HazelcastCacheManager} instance implicitly created the backing
+ * {@code HazelcastInstance}, or {@code false} if one was externally provided via
+ * {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) setHazelcastInstance}.
+ */
+ protected final boolean isImplicitlyCreated() {
+ return this.implicitlyCreated;
+ }
+
+ /**
+ * Destroys any {@link #ensureHazelcastInstance() implicitly created} backing {@code HazelcastInstance}. If the
+ * backing Hazelcast was not implicitly created (i.e. because it was configured externally and supplied via
+ * {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) setHazelcastInstance}), this method does
+ * nothing.
+ *
+ * @throws Exception if there is a problem shutting down
+ */
+ public void destroy() throws Exception {
+ if (this.implicitlyCreated) {
+ try {
+ this.hazelcastInstance.getLifecycleService().shutdown();
+ } catch (Throwable t) {
+ if (log.isWarnEnabled()) {
+ log.warn("Unable to cleanly shutdown implicitly created HazelcastInstance. " +
+ "Ignoring (shutting down)...", t);
+ }
+ } finally {
+ this.hazelcastInstance = null;
+ this.implicitlyCreated = false;
+ }
+ }
+ }
+
+ /**
+ * Returns the {@code HazelcastInstance} from which named {@link java.util.concurrent.ConcurrentMap ConcurrentMap}
+ * instances will be acquired to create {@link MapCache} instances.
+ *
+ * @return the {@code HazelcastInstance} from which named {@link java.util.concurrent.ConcurrentMap ConcurrentMap}
+ * instances will be acquired to create {@link MapCache} instances.
+ */
+ public HazelcastInstance getHazelcastInstance() {
+ return hazelcastInstance;
+ }
+
+ /**
+ * Sets the {@code HazelcastInstance} from which named {@link java.util.concurrent.ConcurrentMap ConcurrentMap}
+ * instances will be acquired to create {@link MapCache} instances.
+ *
+ * @param hazelcastInstance the {@code HazelcastInstance} from which named
+ * {@link java.util.concurrent.ConcurrentMap ConcurrentMap} instances will be acquired to create
+ * {@link MapCache} instances.
+ */
+ public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
+ this.hazelcastInstance = hazelcastInstance;
+ }
+
+ /**
+ * Returns the Hazelcast {@code Config} object to use to create a backing {@code HazelcastInstance} if one is not
+ * {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) supplied}, or {@code null} if the
+ * default <a href="http://www.hazelcast.com/docs/2.5/manual/multi_html/ch12.html">Hazelcast configuration
+ * mechanisms</a> will be used.
+ *
+ * @return the Hazelcast {@code Config} object to use to create a backing {@code HazelcastInstance} if one is not
+ * {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) supplied}, or {@code null} if the
+ * default <a href="http://www.hazelcast.com/docs/2.5/manual/multi_html/ch12.html">Hazelcast configuration
+ * mechanisms</a> will be used.
+ * @see Hazelcast#newHazelcastInstance(com.hazelcast.config.Config)
+ */
+ public Config getConfig() {
+ return config;
+ }
+
+ /**
+ * Sets the Hazelcast {@code Config} object to use to create a backing {@code HazelcastInstance} if one is not
+ * {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) supplied}. {@code null} can be set if the
+ * default <a href="http://www.hazelcast.com/docs/2.5/manual/multi_html/ch12.html">Hazelcast configuration
+ * mechanisms</a> will be used.
+ *
+ * @param config the Hazelcast {@code Config} object to use to create a backing {@code HazelcastInstance} if one is not
+ * {@link #setHazelcastInstance(com.hazelcast.core.HazelcastInstance) supplied}, or {@code null} if the
+ * default <a href="http://www.hazelcast.com/docs/2.5/manual/multi_html/ch12.html">Hazelcast configuration
+ * mechanisms</a> will be used.
+ */
+ public void setConfig(Config config) {
+ this.config = config;
+ }
+}
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/hazelcast/src/test/groovy/org/apache/shiro/hazelcast/cache/HazelcastCacheManagerTest.groovy
----------------------------------------------------------------------
diff --git a/support/hazelcast/src/test/groovy/org/apache/shiro/hazelcast/cache/HazelcastCacheManagerTest.groovy b/support/hazelcast/src/test/groovy/org/apache/shiro/hazelcast/cache/HazelcastCacheManagerTest.groovy
new file mode 100644
index 0000000..d22eacb
--- /dev/null
+++ b/support/hazelcast/src/test/groovy/org/apache/shiro/hazelcast/cache/HazelcastCacheManagerTest.groovy
@@ -0,0 +1,181 @@
+/*
+ * 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.shiro.hazelcast.cache
+
+import com.hazelcast.config.Config
+import com.hazelcast.core.Hazelcast
+import com.hazelcast.core.HazelcastInstance
+import com.hazelcast.core.IMap
+import com.hazelcast.core.LifecycleService
+import org.apache.shiro.cache.MapCache
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.powermock.core.classloader.annotations.PrepareForTest
+import org.powermock.modules.junit4.PowerMockRunner
+
+import static org.easymock.EasyMock.*
+import static org.junit.Assert.*
+import static org.powermock.api.easymock.PowerMock.*
+
+/**
+ * Unit tests for {@link HazelcastCacheManager}. Uses PowerMock to mock Hazelcast's static method calls.
+ *
+ * @since 1.3
+ */
+@RunWith(PowerMockRunner)
+@PrepareForTest(Hazelcast)
+class HazelcastCacheManagerTest {
+
+ @Test
+ void testGetSetHazelcastInstance() {
+ def hc = createStrictMock(HazelcastInstance)
+ def manager = new HazelcastCacheManager();
+ manager.hazelcastInstance = hc
+
+ replay hc
+
+ assertSame hc, manager.hazelcastInstance
+
+ verify hc
+ }
+
+ @Test
+ void testInit() {
+
+ mockStatic(Hazelcast)
+ //create a mock instead of starting a networked node:
+ def hc = createStrictMock(HazelcastInstance)
+
+ expect(Hazelcast.newHazelcastInstance(null)).andReturn(hc)
+
+ replay Hazelcast, hc
+
+ def manager = new HazelcastCacheManager()
+
+ try {
+ manager.init()
+
+ assertNull manager.config
+ assertSame hc, manager.hazelcastInstance
+ assertTrue manager.implicitlyCreated
+ } finally {
+ verify Hazelcast, hc
+ }
+ }
+
+ @Test
+ void testDestroy() {
+
+ mockStatic Hazelcast
+ def hc = createStrictMock(HazelcastInstance)
+ def lcService = createStrictMock(LifecycleService)
+
+ expect(Hazelcast.newHazelcastInstance(null)).andReturn(hc)
+ expect(hc.getLifecycleService()).andReturn(lcService)
+ lcService.shutdown()
+
+ replay Hazelcast, hc, lcService
+
+ def manager = new HazelcastCacheManager()
+ manager.init() //force implicit creation
+
+ manager.destroy()
+
+ assertNull manager.hazelcastInstance
+ assertFalse manager.implicitlyCreated
+
+ verify Hazelcast, hc, lcService
+ }
+
+ @Test
+ void testDestroyWithThrowable() {
+
+ mockStatic Hazelcast
+ def hc = createStrictMock(HazelcastInstance)
+ def lcService = createStrictMock(LifecycleService)
+
+ expect(Hazelcast.newHazelcastInstance(null)).andReturn(hc)
+ expect(hc.getLifecycleService()).andReturn(lcService)
+ lcService.shutdown()
+ expectLastCall().andThrow(new IllegalStateException())
+
+ replay Hazelcast, hc, lcService
+
+ def manager = new HazelcastCacheManager()
+ manager.init() //force implicit creation
+
+ manager.destroy()
+
+ assertNull manager.hazelcastInstance
+ assertFalse manager.implicitlyCreated
+
+ verify Hazelcast, hc, lcService
+ }
+
+
+ @Test
+ void testGetCache() {
+
+ mockStatic Hazelcast
+ def hc = createStrictMock(HazelcastInstance)
+ def hcMap = createStrictMock(IMap)
+
+ expect(Hazelcast.newHazelcastInstance(null)).andReturn(hc)
+ expect(hc.getMap("foo")).andReturn(hcMap)
+
+ replay Hazelcast, hc, hcMap
+
+ try {
+ def manager = new HazelcastCacheManager()
+ def cache = manager.getCache("foo")
+
+ assertNotNull cache
+ assertTrue cache instanceof MapCache
+ assertNotNull cache.map
+ assertTrue cache.map instanceof IMap
+ } finally {
+ verify Hazelcast, hc, hcMap
+ }
+ }
+
+ @Test
+ void testCustomConfig() {
+
+ mockStatic Hazelcast
+
+ def hc = createStrictMock(HazelcastInstance)
+ def config = createStrictMock(Config)
+
+ expect(Hazelcast.newHazelcastInstance(same(config))).andReturn(hc)
+
+ replay Hazelcast, config
+
+ def manager = new HazelcastCacheManager()
+ manager.config = config
+
+ manager.init()
+
+ assertSame config, manager.config
+ assertSame hc, manager.hazelcastInstance
+
+ verify Hazelcast, config
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/hazelcast/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/support/hazelcast/src/test/resources/log4j.properties b/support/hazelcast/src/test/resources/log4j.properties
new file mode 100644
index 0000000..e629e58
--- /dev/null
+++ b/support/hazelcast/src/test/resources/log4j.properties
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+log4j.rootLogger=TRACE, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
+
+# Pattern to output: date priority [category] - message
+log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
+log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
+
+# General Apache libraries is WARN
+log4j.logger.org.apache=WARN
+
+log4j.logger.com.hazelcast=DEBUG
+
+log4j.logger.org.apache.shiro=INFO
+log4j.logger.org.apache.shiro.util.ThreadContext=WARN
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/shiro/blob/0b505c27/support/pom.xml
----------------------------------------------------------------------
diff --git a/support/pom.xml b/support/pom.xml
index 7fbd4c8..7d0dbff 100644
--- a/support/pom.xml
+++ b/support/pom.xml
@@ -34,6 +34,7 @@
<modules>
<module>aspectj</module>
<module>ehcache</module>
+ <module>hazelcast</module>
<module>quartz</module>
<module>spring</module>
<module>guice</module>