# Spring cache fixes

Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/1a2d2ca1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/1a2d2ca1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/1a2d2ca1

Branch: refs/heads/ignite-66
Commit: 1a2d2ca1e5b008b5dbab1e73513ac61bd9bbcdd9
Parents: b7db215
Author: Valentin Kulichenko <vkuliche...@gridgain.com>
Authored: Tue Jan 20 23:24:59 2015 -0800
Committer: Valentin Kulichenko <vkuliche...@gridgain.com>
Committed: Tue Jan 20 23:24:59 2015 -0800

----------------------------------------------------------------------
 .../grid/cache/spring/GridSpringCache.java      | 185 +++++++++++
 .../cache/spring/GridSpringCacheManager.java    | 190 ++---------
 .../spring/GridSpringDynamicCacheManager.java   | 316 +++++++++++++++++++
 .../spring/GridSpringCacheManagerSelfTest.java  |   2 +-
 .../GridSpringDynamicCacheManagerSelfTest.java  | 218 +++++++++++++
 .../GridSpringDynamicCacheTestService.java      |  62 ++++
 .../cache/spring/spring-dynamic-caching.xml     |  43 +++
 .../testsuites/bamboo/GridSpringTestSuite.java  |   1 +
 8 files changed, 846 insertions(+), 171 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCache.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCache.java
 
b/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCache.java
new file mode 100644
index 0000000..74baf53
--- /dev/null
+++ 
b/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCache.java
@@ -0,0 +1,185 @@
+/*
+ * 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.gridgain.grid.cache.spring;
+
+import org.apache.ignite.*;
+import org.apache.ignite.lang.*;
+import org.gridgain.grid.cache.*;
+import org.gridgain.grid.util.typedef.*;
+import org.springframework.cache.*;
+import org.springframework.cache.support.*;
+
+import java.io.*;
+
+/**
+ * Spring cache implementation.
+ */
+class GridSpringCache implements Cache, Serializable {
+    /** */
+    private String name;
+
+    /** */
+    private Ignite ignite;
+
+    /** */
+    private GridCacheProjection<Object, Object> cache;
+
+    /** */
+    private IgniteClosure<Object, Object> keyFactory;
+
+    /**
+     * @param name Cache name.
+     * @param ignite Ignite instance.
+     * @param cache Cache.
+     * @param keyFactory Key factory.
+     */
+    GridSpringCache(String name, Ignite ignite, GridCacheProjection<?, ?> 
cache,
+        IgniteClosure<Object, Object> keyFactory) {
+        assert cache != null;
+
+        this.name = name;
+        this.ignite = ignite;
+        this.cache = (GridCacheProjection<Object, Object>)cache;
+        this.keyFactory = keyFactory != null ? keyFactory : F.identity();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getName() {
+        return name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object getNativeCache() {
+        return cache;
+    }
+
+    /** {@inheritDoc} */
+    @Override public ValueWrapper get(Object key) {
+        try {
+            Object val = cache.get(keyFactory.apply(key));
+
+            return val != null ? new SimpleValueWrapper(val) : null;
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to get value from cache 
[cacheName=" + cache.name() +
+                ", key=" + key + ']', e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T get(Object key, Class<T> type) {
+        try {
+            Object val = cache.get(keyFactory.apply(key));
+
+            if (val != null && type != null && !type.isInstance(val))
+                throw new IllegalStateException("Cached value is not of 
required type [cacheName=" + cache.name() +
+                    ", key=" + key + ", val=" + val + ", requiredType=" + type 
+ ']');
+
+            return (T)val;
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to get value from cache 
[cacheName=" + cache.name() +
+                ", key=" + key + ']', e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void put(Object key, Object val) {
+        try {
+            cache.putx(keyFactory.apply(key), val);
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to put value to cache 
[cacheName=" + cache.name() +
+                ", key=" + key + ", val=" + val + ']', e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public ValueWrapper putIfAbsent(Object key, Object val) {
+        try {
+            Object old = cache.putIfAbsent(keyFactory.apply(key), val);
+
+            return old != null ? new SimpleValueWrapper(old) : null;
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to put value to cache 
[cacheName=" + cache.name() +
+                ", key=" + key + ", val=" + val + ']', e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void evict(Object key) {
+        try {
+            cache.removex(keyFactory.apply(key));
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to remove value from cache 
[cacheName=" + cache.name() +
+                ", key=" + key + ']', e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void clear() {
+        try {
+            ignite.compute(cache.gridProjection()).broadcast(new 
ClearClosure(cache));
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to clear cache [cacheName=" + 
cache.name() + ']', e);
+        }
+    }
+
+    /**
+     * Closure that removes all entries from cache.
+     */
+    private static class ClearClosure extends CAX implements Externalizable {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** Cache projection. */
+        private GridCacheProjection<Object, Object> cache;
+
+        /**
+         * For {@link Externalizable}.
+         */
+        public ClearClosure() {
+            // No-op.
+        }
+
+        /**
+         * @param cache Cache projection.
+         */
+        private ClearClosure(GridCacheProjection<Object, Object> cache) {
+            this.cache = cache;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void applyx() throws IgniteCheckedException {
+            cache.removeAll();
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeExternal(ObjectOutput out) throws 
IOException {
+            out.writeObject(cache);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+            cache = (GridCacheProjection<Object, Object>)in.readObject();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCacheManager.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCacheManager.java
 
b/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCacheManager.java
index 45c349a..0ab73f9 100644
--- 
a/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCacheManager.java
+++ 
b/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringCacheManager.java
@@ -20,20 +20,16 @@ package org.gridgain.grid.cache.spring;
 import org.apache.ignite.*;
 import org.apache.ignite.configuration.*;
 import org.apache.ignite.lang.*;
-import org.apache.ignite.resources.*;
 import org.gridgain.grid.cache.*;
 import org.gridgain.grid.util.typedef.*;
-import org.gridgain.grid.util.typedef.internal.*;
 import org.springframework.beans.factory.*;
 import org.springframework.cache.*;
-import org.springframework.cache.support.*;
 
-import java.io.*;
 import java.util.*;
 
 /**
  * Implementation of Spring cache abstraction based on GridGain cache.
- * <h1>Overview</h1>
+ * <h1 class="header">Overview</h1>
  * Spring cache abstraction allows to enable caching for Java methods
  * so that the result of a method execution is stored in some storage. If
  * later the same method is called with the same set of parameters,
@@ -65,7 +61,7 @@ import java.util.*;
  *        xsi:schemaLocation="
  *         http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
  *         http://www.springframework.org/schema/cache 
http://www.springframework.org/schema/cache/spring-cache.xsd"&gt;
- *     &lt;-- Provide configuration file path --&gt;
+ *     &lt;-- Provide configuration file path. --&gt;
  *     &lt;bean id="cacheManager" 
class="org.gridgain.grid.cache.spring.GridSpringCacheManager"&gt;
  *         &lt;property name="configurationPath" 
value="examples/config/spring-cache.xml"/&gt;
  *     &lt;/bean>
@@ -108,7 +104,7 @@ import java.util.*;
  *        xsi:schemaLocation="
  *         http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
  *         http://www.springframework.org/schema/cache 
http://www.springframework.org/schema/cache/spring-cache.xsd"&gt;
- *     &lt;-- Provide configuration file path --&gt;
+ *     &lt;-- Provide Grid name. --&gt;
  *     &lt;bean id="cacheManager" 
class="org.gridgain.grid.cache.spring.GridSpringCacheManager"&gt;
  *         &lt;property name="gridName" value="myGrid"/&gt;
  *     &lt;/bean>
@@ -133,18 +129,18 @@ import java.util.*;
  * GridGain distribution, and all these nodes will participate
  * in caching data.
  */
-public class GridSpringCacheManager implements InitializingBean, CacheManager {
+public class GridSpringCacheManager implements CacheManager, InitializingBean {
     /** Grid configuration file path. */
     private String cfgPath;
 
-    /** Grid configuration. */
+    /** Ignite configuration. */
     private IgniteConfiguration cfg;
 
     /** Grid name. */
     private String gridName;
 
-    /** Grid instance. */
-    private Ignite ignite;
+    /** Ignite instance. */
+    protected Ignite grid;
 
     /**
      * Gets configuration file path.
@@ -203,7 +199,7 @@ public class GridSpringCacheManager implements 
InitializingBean, CacheManager {
     /** {@inheritDoc} */
     @SuppressWarnings("IfMayBeConditional")
     @Override public void afterPropertiesSet() throws Exception {
-        assert ignite == null;
+        assert grid == null;
 
         if (cfgPath != null && cfg != null) {
             throw new IllegalArgumentException("Both 'configurationPath' and 
'configuration' are " +
@@ -213,179 +209,33 @@ public class GridSpringCacheManager implements 
InitializingBean, CacheManager {
         }
 
         if (cfgPath != null)
-            ignite = Ignition.start(cfgPath);
+            grid = Ignition.start(cfgPath);
         else if (cfg != null)
-            ignite = Ignition.start(cfg);
+            grid = Ignition.start(cfg);
         else
-            ignite = Ignition.ignite(gridName);
+            grid = Ignition.ignite(gridName);
     }
 
     /** {@inheritDoc} */
     @Override public Cache getCache(String name) {
-        assert ignite != null;
+        assert grid != null;
 
-        return new SpringCache(ignite.cache(name));
+        try {
+            return new GridSpringCache(name, grid, grid.cache(name), null);
+        }
+        catch (IllegalArgumentException ignored) {
+            return null;
+        }
     }
 
     /** {@inheritDoc} */
     @Override public Collection<String> getCacheNames() {
-        assert ignite != null;
+        assert grid != null;
 
-        return F.viewReadOnly(ignite.caches(), new IgniteClosure<GridCache<?, 
?>, String>() {
+        return F.viewReadOnly(grid.caches(), new IgniteClosure<GridCache<?,?>, 
String>() {
             @Override public String apply(GridCache<?, ?> c) {
                 return c.name();
             }
         });
     }
-
-    /**
-     * Cache implementation.
-     */
-    private static class SpringCache implements Cache {
-        /** */
-        private final GridCache<Object, Object> cache;
-
-        /**
-         * @param cache Cache.
-         */
-        SpringCache(GridCache<Object, Object> cache) {
-            assert cache != null;
-
-            this.cache = cache;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String getName() {
-            return cache.name();
-        }
-
-        /** {@inheritDoc} */
-        @Override public Object getNativeCache() {
-            return cache;
-        }
-
-        /** {@inheritDoc} */
-        @Override public ValueWrapper get(Object key) {
-            try {
-                Object val = cache.get(key);
-
-                return val != null ? new SimpleValueWrapper(val) : null;
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to get value from cache 
[cacheName=" + cache.name() +
-                    ", key=" + key + ']', e);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public <T> T get(Object key, Class<T> type) {
-            try {
-                Object val = cache.get(key);
-
-                if (val != null && type != null && !type.isInstance(val))
-                    throw new IllegalStateException("Cached value is not of 
required type [cacheName=" + cache.name() +
-                        ", key=" + key + ", val=" + val + ", requiredType=" + 
type + ']');
-
-                return (T)val;
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to get value from cache 
[cacheName=" + cache.name() +
-                    ", key=" + key + ']', e);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public void put(Object key, Object val) {
-            try {
-                cache.putx(key, val);
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to put value to cache 
[cacheName=" + cache.name() +
-                    ", key=" + key + ", val=" + val + ']', e);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public ValueWrapper putIfAbsent(Object key, Object val) {
-            try {
-                Object old = cache.putIfAbsent(key, val);
-
-                return old != null ? new SimpleValueWrapper(old) : null;
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to put value to cache 
[cacheName=" + cache.name() +
-                    ", key=" + key + ", val=" + val + ']', e);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public void evict(Object key) {
-            try {
-                cache.removex(key);
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to remove value from cache 
[cacheName=" + cache.name() +
-                    ", key=" + key + ']', e);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public void clear() {
-            try {
-                Ignite ignite = cache.gridProjection().ignite();
-
-                ignite.compute(cache.gridProjection()).broadcast(new 
ClearClosure(cache.name()));
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to clear cache [cacheName=" 
+ cache.name() + ']', e);
-            }
-        }
-    }
-
-    /**
-     * Closure that removes all entries from cache.
-     */
-    private static class ClearClosure extends CAX implements Externalizable {
-        /** */
-        private static final long serialVersionUID = 0L;
-
-        /** Cache name. */
-        private String cacheName;
-
-        /** Injected grid instance. */
-        @IgniteInstanceResource
-        private Ignite ignite;
-
-        /**
-         * For {@link Externalizable}.
-         */
-        public ClearClosure() {
-            // No-op.
-        }
-
-        /**
-         * @param cacheName Cache name.
-         */
-        private ClearClosure(String cacheName) {
-            this.cacheName = cacheName;
-        }
-
-        /** {@inheritDoc} */
-        @Override public void applyx() throws IgniteCheckedException {
-            GridCache<Object, Object> cache = ignite.cache(cacheName);
-
-            if (cache != null)
-                cache.removeAll();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void writeExternal(ObjectOutput out) throws 
IOException {
-            U.writeString(out, cacheName);
-        }
-
-        /** {@inheritDoc} */
-        @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
-            cacheName = U.readString(in);
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManager.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManager.java
 
b/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManager.java
new file mode 100644
index 0000000..1cfed51
--- /dev/null
+++ 
b/modules/spring/src/main/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManager.java
@@ -0,0 +1,316 @@
+/*
+ * 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.gridgain.grid.cache.spring;
+
+import org.apache.ignite.*;
+import org.apache.ignite.lang.*;
+import org.gridgain.grid.cache.*;
+import org.gridgain.grid.kernal.*;
+import org.gridgain.grid.kernal.processors.cache.*;
+import org.gridgain.grid.util.tostring.*;
+import org.gridgain.grid.util.typedef.*;
+import org.gridgain.grid.util.typedef.internal.*;
+import org.springframework.cache.*;
+import org.springframework.cache.annotation.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Extension of {@link GridSpringCacheManager} that adds an option to
+ * emulate dynamic cache creation for you Spring-based applications.
+ * <p>
+ * All the data will be actually cached in one GridGain cache. It's
+ * name should be provided to this cache manager via
+ * {@link #setDataCacheName(String)} configuration property.
+ * <p>
+ * Under the hood, this cache manager will create a cache projection
+ * for each cache name provided in {@link Cacheable}, {@link CachePut},
+ * etc. annotations. Note that you're still able to use caches configured in
+ * GridGain configuration. Cache projection will be created only
+ * cache with provided name doesn't exist.
+ * <h1 class="header">Configuration</h1>
+ * {@link GridSpringDynamicCacheManager} inherits all configuration
+ * properties from {@link GridSpringCacheManager} (see it's JavaDoc
+ * for more information on how to enable GridGain-based caching in
+ * a Spring application).
+ * <p>
+ * Additionally you will need to set a GridGain cache name where the data for
+ * all dynamically created caches will be stored. By default its name
+ * is {@code null}, which refers to default cache. Here is the example
+ * of how to configure a named cache:
+ * <pre name="code" class="xml">
+ * &lt;beans xmlns="http://www.springframework.org/schema/beans";
+ *        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+ *        xmlns:cache="http://www.springframework.org/schema/cache";
+ *        xsi:schemaLocation="
+ *         http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
+ *         http://www.springframework.org/schema/cache 
http://www.springframework.org/schema/cache/spring-cache.xsd"&gt;
+ *     &lt;-- Provide configuration file path --&gt;
+ *     &lt;bean id="cacheManager" 
class="org.gridgain.grid.cache.spring.GridSpringCacheManager"&gt;
+ *         &lt;property name="dataCacheName" value="myDataCache"/&gt;
+ *     &lt;/bean>
+ *
+ *     ...
+ * &lt;/beans&gt;
+ * </pre>
+ *
+ * @see GridSpringCacheManager
+ */
+public class GridSpringDynamicCacheManager extends GridSpringCacheManager {
+    /** Data cache name. */
+    private String dataCacheName;
+
+    /** Meta cache. */
+    private GridCacheProjectionEx<MetaKey, Cache> metaCache;
+
+    /** Data cache. */
+    private GridCache<DataKey, Object> dataCache;
+
+    /**
+     * Sets data cache name.
+     *
+     * @return Data cache name.
+     */
+    public String getDataCacheName() {
+        return dataCacheName;
+    }
+
+    /**
+     * Gets data cache name.
+     *
+     * @param dataCacheName Data cache name.
+     */
+    public void setDataCacheName(String dataCacheName) {
+        this.dataCacheName = dataCacheName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void afterPropertiesSet() throws Exception {
+        super.afterPropertiesSet();
+
+        metaCache = ((GridEx)grid).utilityCache(MetaKey.class, Cache.class);
+        dataCache = grid.cache(dataCacheName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Cache getCache(final String name) {
+        Cache cache = super.getCache(name);
+
+        if (cache != null)
+            return cache;
+
+        try {
+            MetaKey key = new MetaKey(name);
+
+            cache = metaCache.get(key);
+
+            if (cache == null) {
+                cache = new GridSpringCache(name, grid, 
dataCache.projection(new ProjectionFilter(name)),
+                    new IgniteClosure<Object, Object>() {
+                        @Override public Object apply(Object o) {
+                            return new DataKey(name, o);
+                        }
+                    });
+
+                Cache old = metaCache.putIfAbsent(key, cache);
+
+                if (old != null)
+                    cache = old;
+            }
+
+            return cache;
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<String> getCacheNames() {
+        Collection<String> names = F.view(super.getCacheNames(), new 
IgnitePredicate<String>() {
+            @Override public boolean apply(String name) {
+                return !F.eq(name, dataCacheName);
+            }
+        });
+
+        return F.concat(false, names, F.transform(metaCache.entrySetx(),
+            new IgniteClosure<Map.Entry<MetaKey, Cache>, String>() {
+                @Override public String apply(Map.Entry<MetaKey, Cache> e) {
+                    return e.getKey().name;
+                }
+            }));
+    }
+
+    /**
+     * Meta key.
+     */
+    private static class MetaKey extends GridCacheUtilityKey<MetaKey> 
implements Externalizable {
+        /** Cache name. */
+        private String name;
+
+        /**
+         * For {@link Externalizable}.
+         */
+        public MetaKey() {
+            // No-op.
+        }
+
+        /**
+         * @param name Cache name.
+         */
+        private MetaKey(String name) {
+            this.name = name;
+        }
+
+        /** {@inheritDoc} */
+        @Override protected boolean equalsx(MetaKey key) {
+            return name != null ? name.equals(key.name) : key.name == null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return name.hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeExternal(ObjectOutput out) throws 
IOException {
+            U.writeString(out, name);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+            name = U.readString(in);
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(MetaKey.class, this);
+        }
+    }
+
+    /**
+     * Data key.
+     */
+    private static class DataKey implements Externalizable {
+        /** Cache name. */
+        private String name;
+
+        /** Key. */
+        @GridToStringInclude
+        private Object key;
+
+        /**
+         * @param name Cache name.
+         * @param key Key.
+         */
+        private DataKey(String name, Object key) {
+            this.name = name;
+            this.key = key;
+        }
+
+        /**
+         * For {@link Externalizable}.
+         */
+        public DataKey() {
+            // No-op.
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            DataKey key0 = (DataKey)o;
+
+            return name != null ? name.equals(key0.name) : key0.name == null &&
+                key != null ? key.equals(key0.key) : key0.key == null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            int res = name != null ? name.hashCode() : 0;
+
+            res = 31 * res + (key != null ? key.hashCode() : 0);
+
+            return res;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeExternal(ObjectOutput out) throws 
IOException {
+            U.writeString(out, name);
+            out.writeObject(key);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+            name = U.readString(in);
+            key = in.readObject();
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(DataKey.class, this);
+        }
+    }
+
+    /**
+     * Projection filter.
+     */
+    private static class ProjectionFilter implements 
IgniteBiPredicate<DataKey, Object>, Externalizable {
+        /** Cache name. */
+        private String name;
+
+        /**
+         * For {@link Externalizable}.
+         */
+        public ProjectionFilter() {
+            // No-op.
+        }
+
+        /**
+         * @param name Cache name.
+         */
+        private ProjectionFilter(String name) {
+            this.name = name;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean apply(DataKey key, Object val) {
+            return name != null ? name.equals(key.name) : key.name == null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeExternal(ObjectOutput out) throws 
IOException {
+            U.writeString(out, name);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+            name = U.readString(in);
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(ProjectionFilter.class, this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringCacheManagerSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringCacheManagerSelfTest.java
 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringCacheManagerSelfTest.java
index 934447d..c16658c 100644
--- 
a/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringCacheManagerSelfTest.java
+++ 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringCacheManagerSelfTest.java
@@ -18,10 +18,10 @@
 package org.gridgain.grid.cache.spring;
 
 import org.apache.ignite.configuration.*;
-import org.gridgain.grid.cache.*;
 import org.apache.ignite.spi.discovery.tcp.*;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*;
+import org.gridgain.grid.cache.*;
 import org.gridgain.testframework.junits.common.*;
 import org.springframework.beans.factory.*;
 import org.springframework.context.support.*;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManagerSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManagerSelfTest.java
 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManagerSelfTest.java
new file mode 100644
index 0000000..29dfd45
--- /dev/null
+++ 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheManagerSelfTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.gridgain.grid.cache.spring;
+
+import org.apache.ignite.configuration.*;
+import org.apache.ignite.spi.discovery.tcp.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*;
+import org.gridgain.grid.cache.*;
+import org.gridgain.testframework.junits.common.*;
+import org.springframework.beans.factory.*;
+import org.springframework.cache.*;
+import org.springframework.context.support.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * Spring cache test.
+ */
+public class GridSpringDynamicCacheManagerSelfTest extends 
GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new 
TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String DATA_CACHE_NAME = "data";
+
+    /** */
+    private GridSpringDynamicCacheTestService svc;
+
+    /** */
+    private CacheManager mgr;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) 
throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        GridCacheConfiguration cache = new GridCacheConfiguration();
+
+        cache.setName(DATA_CACHE_NAME);
+
+        cfg.setCacheConfiguration(cache);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(disco);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getTestGridName() {
+        return "testGrid";
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrid();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        BeanFactory factory = new ClassPathXmlApplicationContext(
+            "org/gridgain/grid/cache/spring/spring-dynamic-caching.xml");
+
+        svc = 
(GridSpringDynamicCacheTestService)factory.getBean("testService");
+        mgr = (CacheManager)factory.getBean("cacheManager");
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        grid().cache(DATA_CACHE_NAME).removeAll();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testNames() throws Exception {
+        assertEquals("value1", svc.cacheable(1));
+
+        Collection<String> names = mgr.getCacheNames();
+
+        assertEquals(names.toString(), 2, names.size());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCacheAndEvict() throws Exception {
+        GridCache<Object, String> c = grid().cache(DATA_CACHE_NAME);
+
+        assertEquals("value1", svc.cacheable(1));
+
+        assertEquals(2, c.size());
+
+        assertEquals("value1", c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+
+        svc.cacheEvict(1);
+
+        assertEquals(1, c.size());
+
+        assertEquals(null, c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPutAndEvict() throws Exception {
+        GridCache<Object, String> c = grid().cache(DATA_CACHE_NAME);
+
+        assertEquals("value1", svc.cachePut(1));
+
+        assertEquals(2, c.size());
+
+        assertEquals("value1", c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+
+        svc.cacheEvict(1);
+
+        assertEquals(1, c.size());
+
+        assertEquals(null, c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCacheAndEvictAll() throws Exception {
+        GridCache<Object, String> c = grid().cache(DATA_CACHE_NAME);
+
+        assertEquals("value1", svc.cacheable(1));
+        assertEquals("value2", svc.cacheable(2));
+
+        assertEquals(4, c.size());
+
+        assertEquals("value1", c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+        assertEquals("value2", c.get(key("testCache1", 2)));
+        assertEquals("value2", c.get(key("testCache2", 2)));
+
+        svc.cacheEvictAll();
+
+        assertEquals(2, c.size());
+
+        assertEquals(null, c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+        assertEquals(null, c.get(key("testCache1", 2)));
+        assertEquals("value2", c.get(key("testCache2", 2)));
+    }
+
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPutAndEvictAll() throws Exception {
+        GridCache<Object, String> c = grid().cache(DATA_CACHE_NAME);
+
+        assertEquals("value1", svc.cachePut(1));
+        assertEquals("value2", svc.cachePut(2));
+
+        assertEquals(4, c.size());
+
+        assertEquals("value1", c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+        assertEquals("value2", c.get(key("testCache1", 2)));
+        assertEquals("value2", c.get(key("testCache2", 2)));
+
+        svc.cacheEvictAll();
+
+        assertEquals(2, c.size());
+
+        assertEquals(null, c.get(key("testCache1", 1)));
+        assertEquals("value1", c.get(key("testCache2", 1)));
+        assertEquals(null, c.get(key("testCache1", 2)));
+        assertEquals("value2", c.get(key("testCache2", 2)));
+    }
+
+    /**
+     * @param cacheName Cache name.
+     * @param key Key.
+     * @return Data key.
+     * @throws Exception In case of error.
+     */
+    private Object key(String cacheName, int key) throws Exception {
+        Class<?> cls = 
Class.forName(GridSpringDynamicCacheManager.class.getName() + "$DataKey");
+
+        Constructor<?> cons = cls.getDeclaredConstructor(String.class, 
Object.class);
+
+        cons.setAccessible(true);
+
+        return cons.newInstance(cacheName, key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheTestService.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheTestService.java
 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheTestService.java
new file mode 100644
index 0000000..9c4accd
--- /dev/null
+++ 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/GridSpringDynamicCacheTestService.java
@@ -0,0 +1,62 @@
+/*
+ * 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.gridgain.grid.cache.spring;
+
+import org.springframework.cache.annotation.*;
+
+/**
+ * Test service.
+ */
+public class GridSpringDynamicCacheTestService {
+    /**
+     * @param key Key.
+     * @return Value.
+     */
+    @Cacheable({"testCache1", "testCache2"})
+    public String cacheable(Integer key) {
+        assert key != null;
+
+        return "value" + key;
+    }
+
+    /**
+     * @param key Key.
+     * @return Value.
+     */
+    @CachePut({"testCache1", "testCache2"})
+    public String cachePut(Integer key) {
+        assert key != null;
+
+        return "value" + key;
+    }
+
+    /**
+     * @param key Key.
+     */
+    @CacheEvict("testCache1")
+    public void cacheEvict(Integer key) {
+        // No-op.
+    }
+
+    /**
+     */
+    @CacheEvict(value = "testCache1", allEntries = true)
+    public void cacheEvictAll() {
+        // No-op.
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/test/java/org/gridgain/grid/cache/spring/spring-dynamic-caching.xml
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/test/java/org/gridgain/grid/cache/spring/spring-dynamic-caching.xml
 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/spring-dynamic-caching.xml
new file mode 100644
index 0000000..ef2f80b
--- /dev/null
+++ 
b/modules/spring/src/test/java/org/gridgain/grid/cache/spring/spring-dynamic-caching.xml
@@ -0,0 +1,43 @@
+<?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.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:cache="http://www.springframework.org/schema/cache";
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/cache 
http://www.springframework.org/schema/cache/spring-cache.xsd";>
+    <!--
+        Test service with cacheable methods.
+    -->
+    <bean id="testService" 
class="org.gridgain.grid.cache.spring.GridSpringDynamicCacheTestService"/>
+
+    <!--
+        Cache manager.
+    -->
+    <bean id="cacheManager" 
class="org.gridgain.grid.cache.spring.GridSpringDynamicCacheManager">
+        <property name="gridName" value="testGrid"/>
+        <property name="dataCacheName" value="data"/>
+    </bean>
+
+    <!--
+        Enable annotation-driver configuration for caching.
+    -->
+    <cache:annotation-driven/>
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1a2d2ca1/modules/spring/src/test/java/org/gridgain/testsuites/bamboo/GridSpringTestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/test/java/org/gridgain/testsuites/bamboo/GridSpringTestSuite.java
 
b/modules/spring/src/test/java/org/gridgain/testsuites/bamboo/GridSpringTestSuite.java
index 99974e3..c5850a8 100644
--- 
a/modules/spring/src/test/java/org/gridgain/testsuites/bamboo/GridSpringTestSuite.java
+++ 
b/modules/spring/src/test/java/org/gridgain/testsuites/bamboo/GridSpringTestSuite.java
@@ -44,6 +44,7 @@ public class GridSpringTestSuite extends TestSuite {
         suite.addTest(new 
TestSuite(GridP2PContinuousLocalDeploySelfTest.class));
 
         suite.addTest(new TestSuite(GridSpringCacheManagerSelfTest.class));
+        suite.addTest(new 
TestSuite(GridSpringDynamicCacheManagerSelfTest.class));
 
         return suite;
     }

Reply via email to