BUG-994: improve object cache 30/6930/6
authorRobert Varga <rovarga@cisco.com>
Sun, 18 May 2014 19:50:36 +0000 (21:50 +0200)
committerRobert Varga <rovarga@cisco.com>
Sun, 18 May 2014 22:54:55 +0000 (00:54 +0200)
This fixes the object cache to work in face of missing concrete
implementation. Also fixes up previous mistakes in cache interaction,
adding tests.

Change-Id: Icd041045ab360630788775c2e6a3ed091c527029
Signed-off-by: Robert Varga <rovarga@cisco.com>
14 files changed:
common/object-cache-api/pom.xml
common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/ObjectCacheFactory.java
common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/AbstractObjectCache.java
common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/NoopObjectCacheBinder.java [new file with mode: 0644]
common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheFactoryTest.java [new file with mode: 0644]
common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheTest.java [new file with mode: 0644]
common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/SoftKeyTest.java [new file with mode: 0644]
common/object-cache-guava/pom.xml
common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCache.java
common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheFactory.java
common/object-cache-guava/src/test/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheTest.java [new file with mode: 0644]
common/object-cache-noop/pom.xml
common/object-cache-noop/src/main/java/org/opendaylight/yangtools/objcache/impl/StaticObjectCacheBinder.java
pom.xml

index 8ef8a14433a309bc26a2edb2bfcf7dd8be78bcc1..beb2d035d2009dc61ee3b8532d003fdaa217b693 100644 (file)
             <artifactId>jsr305</artifactId>
             <scope>provided</scope>
         </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            org.opendaylight.yangtools.objcache.impl;resolution:=optional,
+                            *
+                        </Import-Package>
+                    </instructions>
+                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
index 58ca11c4d2335c489cedffd79634d05a14b9aa6d..dd3e53bbd0225119116a4ed0180620d3a2a11352 100644 (file)
@@ -11,6 +11,7 @@ import javax.annotation.Nonnull;
 
 import org.opendaylight.yangtools.objcache.impl.StaticObjectCacheBinder;
 import org.opendaylight.yangtools.objcache.spi.IObjectCacheFactory;
+import org.opendaylight.yangtools.objcache.spi.NoopObjectCacheBinder;
 
 import com.google.common.base.Preconditions;
 
@@ -18,36 +19,42 @@ import com.google.common.base.Preconditions;
  * Point of entry for acquiring an {@link ObjectCache} instance.
  */
 public final class ObjectCacheFactory {
-       private static IObjectCacheFactory FACTORY;
-
-       private static synchronized IObjectCacheFactory initialize() {
-               // Double-check under lock
-               if (FACTORY != null) {
-                       return FACTORY;
-               }
-
-               final IObjectCacheFactory f = StaticObjectCacheBinder.getInstance().getProductCacheFactory();
-               FACTORY = f;
-               return f;
-       }
-
-       public static synchronized void reset() {
-               FACTORY = null;
-       }
-
-       /**
-        * Get an ObjectCache for caching a particular object class. Note
-        * that it may be shared for multiple classes.
-        * 
-        * @param objClass Class of objects which are to be cached
-        * @return Object cache instance.
-        */
-       public static ObjectCache getObjectCache(@Nonnull final Class<?> objClass) {
-               IObjectCacheFactory f = FACTORY;
-               if (f == null) {
-                       f = initialize();
-               }
-
-               return f.getObjectCache(Preconditions.checkNotNull(objClass));
-       }
+    private static IObjectCacheFactory FACTORY;
+
+    private static synchronized IObjectCacheFactory initialize() {
+        // Double-check under lock
+        if (FACTORY != null) {
+            return FACTORY;
+        }
+
+        IObjectCacheFactory f;
+        try {
+            f = StaticObjectCacheBinder.getInstance().getProductCacheFactory();
+            FACTORY = f;
+        } catch (NoClassDefFoundError e) {
+            f = NoopObjectCacheBinder.INSTANCE.getProductCacheFactory();
+        }
+
+        return f;
+    }
+
+    public static synchronized void reset() {
+        FACTORY = null;
+    }
+
+    /**
+     * Get an ObjectCache for caching a particular object class. Note
+     * that it may be shared for multiple classes.
+     *
+     * @param objClass Class of objects which are to be cached
+     * @return Object cache instance.
+     */
+    public static ObjectCache getObjectCache(@Nonnull final Class<?> objClass) {
+        IObjectCacheFactory f = FACTORY;
+        if (f == null) {
+            f = initialize();
+        }
+
+        return f.getObjectCache(Preconditions.checkNotNull(objClass));
+    }
 }
index 963030cf8b10bc3bcb3695b17f15766a00831680..aeef1ee5cfbbcb28e9f27948bf960587fbb67649 100644 (file)
@@ -7,11 +7,15 @@
  */
 package org.opendaylight.yangtools.objcache.spi;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
 import org.opendaylight.yangtools.concepts.ProductAwareBuilder;
 import org.opendaylight.yangtools.objcache.ObjectCache;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.FinalizableReferenceQueue;
 import com.google.common.base.FinalizableSoftReference;
 import com.google.common.base.Preconditions;
@@ -24,133 +28,143 @@ import com.google.common.cache.Cache;
  * a backing {@link Cache} instance and provide the
  */
 public abstract class AbstractObjectCache implements ObjectCache {
-       /**
-        * Key used when looking up a ProductAwareBuilder product. We assume
-        * the builder is not being modified for the duration of the lookup,
-        * anything else is the user's fault.
-        */
-       private static final class BuilderKey {
-               private final ProductAwareBuilder<?> builder;
-
-               private BuilderKey(final ProductAwareBuilder<?> builder) {
-                       this.builder = Preconditions.checkNotNull(builder);
-               }
-
-               @Override
-               public int hashCode() {
-                       return builder.productHashCode();
-               }
-
-               @Override
-               public boolean equals(Object obj) {
-                       /*
-                        * We can tolerate null objects coming our way, but we need
-                        * to be on the lookout for WeakKeys, as we cannot pass them
-                        * directly to productEquals().
-                        */
-                       if (obj != null && obj instanceof SoftKey) {
-                               obj = ((SoftKey)obj).get();
-                       }
-
-                       return builder.productEquals(obj);
-               }
-       }
-
-       /**
-        * Key used in the underlying map. It is essentially a soft reference, with
-        * slightly special properties.
-        * 
-        * It acts as a proxy for the object it refers to and essentially delegates
-        * to it. There are three exceptions here:
-        * 
-        * 1) This key needs to have a cached hash code. The requirement is that the
-        *    key needs to be able to look itself up after the reference to the object
-        *    has been cleared (and thus we can no longer look it up from there). One
-        *    typical container where we are stored are HashMaps -- and they need it
-        *    to be constant.
-        * 2) This key does not tolerate checks to see if its equal to null. While we
-        *    could return false, we want to catch offenders who try to store nulls
-        *    in the cache.
-        * 3) This key inverts the check for equality, e.g. it calls equals() on the
-        *    object which was passed to its equals(). Instead of supplying itself,
-        *    it supplies the referent. If the soft reference is cleared, such check
-        *    will return false, which is fine as it prevents normal lookup from
-        *    seeing the cleared key. Removal is handled by the explicit identity
-        *    check.
-        */
-       private static abstract class SoftKey extends FinalizableSoftReference<Object> {
-               private final int hashCode;
-
-               public SoftKey(final Object referent, final FinalizableReferenceQueue q) {
-                       super(Preconditions.checkNotNull(referent), q);
-                       hashCode = referent.hashCode();
-               }
-
-               @Override
-               public boolean equals(final Object obj) {
-                       Preconditions.checkState(obj != null);
-
-                       // Order is important: we do not want to call equals() on ourselves!
-                       return this == obj || obj.equals(get());
-               }
-
-               @Override
-               public int hashCode() {
-                       return hashCode;
-               }
-       }
-
-       private static final Logger LOG = LoggerFactory.getLogger(AbstractObjectCache.class);
-       private final FinalizableReferenceQueue queue;
-       private final Cache<Object, Object> cache;
-
-       protected AbstractObjectCache(final Cache<Object, Object> cache, final FinalizableReferenceQueue queue) {
-               this.queue = Preconditions.checkNotNull(queue);
-               this.cache = Preconditions.checkNotNull(cache);
-       }
-
-       private <T> T put(final T object) {
-               /*
-                * This may look like a race (having a soft reference and not have
-                * it in the cache). In fact this is protected by the fact we still
-                * have a strong reference on the object in our arguments and that
-                * reference survives past method return since we return it.
-                */
-               final Object key = new SoftKey(object, queue) {
-                       @Override
-                       public void finalizeReferent() {
-                               /*
-                                * NOTE: while it may be tempting to add "object" into this
-                                *       trace message, do not ever do that: it would retain
-                                *       a strong reference, preventing collection.
-                                */
-                               LOG.trace("Invalidating key {} for object {}", this);
-                               cache.invalidate(this);
-                       }
-               };
-               cache.put(key, object);
-               LOG.debug("Cached key {} to object {}", key, object);
-               return object;
-       }
-
-       @Override
-       public final <B extends ProductAwareBuilder<P>, P> P getProduct(final B builder) {
-               LOG.debug("Looking up product for {}", builder);
-
-               @SuppressWarnings("unchecked")
-               final P ret = (P) cache.getIfPresent(new BuilderKey(builder));
-               return ret == null ? put(Preconditions.checkNotNull(builder.toInstance())) : ret;
-       }
-
-       @Override
-       public final <T> T getReference(final T object) {
-               LOG.debug("Looking up reference for {}", object);
-               if (object == null) {
-                       return null;
-               }
-
-               @SuppressWarnings("unchecked")
-               final T ret = (T) cache.getIfPresent(object);
-               return ret == null ? put(object) : ret;
-       }
+    /**
+     * Key used when looking up a ProductAwareBuilder product. We assume
+     * the builder is not being modified for the duration of the lookup,
+     * anything else is the user's fault.
+     */
+    @VisibleForTesting
+    static final class BuilderKey {
+        private final ProductAwareBuilder<?> builder;
+
+        private BuilderKey(final ProductAwareBuilder<?> builder) {
+            this.builder = Preconditions.checkNotNull(builder);
+        }
+
+        @Override
+        public int hashCode() {
+            return builder.productHashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            /*
+             * We can tolerate null objects coming our way, but we need
+             * to be on the lookout for WeakKeys, as we cannot pass them
+             * directly to productEquals().
+             */
+            if (obj != null && obj instanceof SoftKey) {
+                obj = ((SoftKey<?>)obj).get();
+            }
+
+            return builder.productEquals(obj);
+        }
+    }
+
+    /**
+     * Key used in the underlying map. It is essentially a soft reference, with
+     * slightly special properties.
+     *
+     * It acts as a proxy for the object it refers to and essentially delegates
+     * to it. There are three exceptions here:
+     *
+     * 1) This key needs to have a cached hash code. The requirement is that the
+     *    key needs to be able to look itself up after the reference to the object
+     *    has been cleared (and thus we can no longer look it up from there). One
+     *    typical container where we are stored are HashMaps -- and they need it
+     *    to be constant.
+     * 2) This key does not tolerate checks to see if its equal to null. While we
+     *    could return false, we want to catch offenders who try to store nulls
+     *    in the cache.
+     * 3) This key inverts the check for equality, e.g. it calls equals() on the
+     *    object which was passed to its equals(). Instead of supplying itself,
+     *    it supplies the referent. If the soft reference is cleared, such check
+     *    will return false, which is fine as it prevents normal lookup from
+     *    seeing the cleared key. Removal is handled by the explicit identity
+     *    check.
+     */
+    protected abstract static class SoftKey<T> extends FinalizableSoftReference<T> {
+        private final int hashCode;
+
+        public SoftKey(final T referent, final FinalizableReferenceQueue q) {
+            super(Preconditions.checkNotNull(referent), q);
+            hashCode = referent.hashCode();
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            if (obj == null) {
+                return false;
+            }
+
+            // Order is important: we do not want to call equals() on ourselves!
+            return this == obj || obj.equals(get());
+        }
+
+        @Override
+        public int hashCode() {
+            return hashCode;
+        }
+    }
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractObjectCache.class);
+    private final FinalizableReferenceQueue queue;
+    private final Cache<SoftKey<?>, Object> cache;
+
+    protected AbstractObjectCache(final Cache<SoftKey<?>, Object> cache, final FinalizableReferenceQueue queue) {
+        this.queue = Preconditions.checkNotNull(queue);
+        this.cache = Preconditions.checkNotNull(cache);
+    }
+
+    protected <T> SoftKey<T> createSoftKey(final T object) {
+        /*
+         * This may look like a race (having a soft reference and not have
+         * it in the cache). In fact this is protected by the fact we still
+         * have a strong reference on the object in our arguments and that
+         * reference survives past method return since we return it.
+         */
+        return new SoftKey<T>(object, queue) {
+            @Override
+            public void finalizeReferent() {
+                /*
+                 * NOTE: while it may be tempting to add "object" into this
+                 *       trace message, do not ever do that: it would retain
+                 *       a strong reference, preventing collection.
+                 */
+                LOG.trace("Invalidating key {}", this);
+                cache.invalidate(this);
+            }
+        };
+    }
+
+    @Override
+    public final <B extends ProductAwareBuilder<P>, P> P getProduct(final B builder) {
+        throw new UnsupportedOperationException();
+//        LOG.debug("Looking up product for {}", builder);
+//
+//        @SuppressWarnings("unchecked")
+//        final P ret = (P) cache.getIfPresent(new BuilderKey(builder));
+//        return ret == null ? put(Preconditions.checkNotNull(builder.toInstance())) : ret;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <T> T getReference(final T object) {
+        LOG.debug("Looking up reference for {}", object);
+        if (object == null) {
+            return null;
+        }
+
+        final SoftKey<T> key = createSoftKey(object);
+        try {
+            return (T) cache.get(key, new Callable<T>() {
+                @Override
+                public T call() {
+                    return object;
+                }
+            });
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Failed to load value", e);
+        }
+    }
 }
diff --git a/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/NoopObjectCacheBinder.java b/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/NoopObjectCacheBinder.java
new file mode 100644 (file)
index 0000000..0ff3365
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import org.opendaylight.yangtools.objcache.ObjectCache;
+
+public final class NoopObjectCacheBinder extends AbstractObjectCacheBinder {
+    public static final NoopObjectCacheBinder INSTANCE = new NoopObjectCacheBinder();
+
+    private  NoopObjectCacheBinder() {
+        super(new IObjectCacheFactory() {
+            @Override
+            public ObjectCache getObjectCache(final Class<?> objClass) {
+                return NoopObjectCache.getInstance();
+            }
+        });
+    }
+}
diff --git a/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheFactoryTest.java b/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheFactoryTest.java
new file mode 100644 (file)
index 0000000..73aec29
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.objcache.ObjectCache;
+import org.opendaylight.yangtools.objcache.ObjectCacheFactory;
+
+public class CacheFactoryTest {
+
+    @Test
+    public void testInvalidEnvironment() {
+        final ObjectCache oc = ObjectCacheFactory.getObjectCache(String.class);
+
+        assertNotNull(oc);
+        assertEquals(NoopObjectCache.class, oc.getClass());
+    }
+}
diff --git a/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheTest.java b/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheTest.java
new file mode 100644 (file)
index 0000000..37434e5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.objcache.ObjectCache;
+import org.opendaylight.yangtools.objcache.spi.AbstractObjectCache.SoftKey;
+
+import com.google.common.base.FinalizableReferenceQueue;
+import com.google.common.cache.CacheBuilder;
+
+public class CacheTest {
+    private FinalizableReferenceQueue queue;
+    private ObjectCache oc;
+
+    @Before
+    public void setUp() {
+        queue = new FinalizableReferenceQueue();
+        oc = new AbstractObjectCache(CacheBuilder.newBuilder().softValues().<SoftKey<?>, Object>build(), queue) {
+        };
+    }
+
+    @After
+    public void tearDown() {
+        queue.close();
+    }
+
+    @Test
+    public void testMissingKey() {
+        final String key1 = "abcd";
+        final String key2 = "efgh";
+
+        assertSame(key1, oc.getReference(key1));
+        assertSame(key2, oc.getReference(key2));
+    }
+
+    @Test
+    public void testPresentKey() {
+        final String key1 = new String("abcd");
+        final String key2 = new String("abcd");
+
+        assertSame(key1, oc.getReference(key1));
+
+        final String key3 = oc.getReference(key2);
+        assertEquals(key2, key3);
+        assertNotSame(key2, key3);
+        assertSame(key1, key3);
+    }
+}
diff --git a/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/SoftKeyTest.java b/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/SoftKeyTest.java
new file mode 100644 (file)
index 0000000..dc16f77
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.spi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.objcache.spi.AbstractObjectCache.SoftKey;
+
+import com.google.common.base.FinalizableReferenceQueue;
+
+public class SoftKeyTest {
+    private FinalizableReferenceQueue queue;
+
+
+    @Before
+    public void setUp() {
+        queue = new FinalizableReferenceQueue();
+    }
+
+    @After
+    public void tearDown() {
+        queue.close();
+    }
+
+    @Test
+    public void testEquals() {
+        final String str = "foo";
+
+        final SoftKey<?> key = new SoftKey<String>(str, queue) {
+            @Override
+            public void finalizeReferent() {
+
+            }
+        };
+
+        assertSame(str, key.get());
+        assertEquals(str.hashCode(), key.hashCode());
+        assertTrue(key.equals(str));
+        key.clear();
+        assertNull(key.get());
+        assertEquals(str.hashCode(), key.hashCode());
+        assertFalse(key.equals(str));
+    }
+}
index ee65f854960c78227e087e8e46d3eff4e217bfce..8a5b7c471aa3884acb4a3bc53602803997f8cfb4 100644 (file)
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.opendaylight.yangtools.objcache.impl
+                        </Export-Package>
+                        <Private-Package>
+                            org.opendaylight.yangtools.objcache.guava
+                        </Private-Package>
+                    </instructions>
+                </configuration>
             </plugin>
         </plugins>
     </build>
index 7d90e39ee7bc6f8362b0a3849655e85f652b85d0..617a2936f49661c3dde7b75680fba146022d8122 100644 (file)
@@ -14,7 +14,11 @@ import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheBuilderSpec;
 
 final class GuavaObjectCache extends AbstractObjectCache {
-       public GuavaObjectCache(final FinalizableReferenceQueue queue, final CacheBuilderSpec spec) {
-               super(CacheBuilder.from(spec).softValues().build(), queue);
-       }
+    public GuavaObjectCache(final FinalizableReferenceQueue  queue) {
+        super(CacheBuilder.newBuilder().softValues().<SoftKey<?>, Object>build(), queue);
+    }
+
+    public GuavaObjectCache(final FinalizableReferenceQueue  queue, final CacheBuilderSpec spec) {
+        super(CacheBuilder.from(spec).<SoftKey<?>, Object>build(), queue);
+    }
 }
index 067b626e07a39712d0ed003427b185e3c4f87b6d..895037625ddbf04e778f5cf4829da7a1b63de073 100644 (file)
@@ -12,31 +12,27 @@ import org.opendaylight.yangtools.objcache.spi.IObjectCacheFactory;
 
 import com.google.common.base.FinalizableReferenceQueue;
 
-public final class GuavaObjectCacheFactory implements IObjectCacheFactory {
-       private static final GuavaObjectCacheFactory INSTANCE = new GuavaObjectCacheFactory();
-       private final FinalizableReferenceQueue queue = new FinalizableReferenceQueue();
-       private final ObjectCache cache;
+public final class GuavaObjectCacheFactory implements AutoCloseable, IObjectCacheFactory {
+    private static final GuavaObjectCacheFactory INSTANCE = new GuavaObjectCacheFactory();
+    private final FinalizableReferenceQueue  queue = new FinalizableReferenceQueue();
+    private final ObjectCache cache;
 
-       private GuavaObjectCacheFactory() {
-               // FIXME: make this more dynamic
-               this.cache = new GuavaObjectCache(queue, null);
-       }
+    private GuavaObjectCacheFactory() {
+        // FIXME: make this more dynamic using a spec
+        this.cache = new GuavaObjectCache(queue);
+    }
 
-       @Override
-       public void finalize() throws Throwable {
-               try {
-                       queue.close();
-               } finally {
-                       super.finalize();
-               }
-       }
+    @Override
+    public ObjectCache getObjectCache(final Class<?> objClass) {
+        return cache;
+    }
 
-       @Override
-       public ObjectCache getObjectCache(final Class<?> objClass) {
-               return cache;
-       }
+    @Override
+    public void close() {
+       queue.close();
+    }
 
-       public static GuavaObjectCacheFactory getInstance() {
-               return INSTANCE;
-       }
+    public static GuavaObjectCacheFactory getInstance() {
+        return INSTANCE;
+    }
 }
diff --git a/common/object-cache-guava/src/test/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheTest.java b/common/object-cache-guava/src/test/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheTest.java
new file mode 100644 (file)
index 0000000..bc41da9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.objcache.guava;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.objcache.ObjectCache;
+import org.opendaylight.yangtools.objcache.ObjectCacheFactory;
+
+public class GuavaObjectCacheTest {
+       private ObjectCache cache;
+
+       @Before
+       public void setUp() {
+               cache = ObjectCacheFactory.getObjectCache(String.class);
+       }
+
+       @Test
+       public void testCorrectWiring() {
+               assertEquals(GuavaObjectCache.class, cache.getClass());
+       }
+
+       @Test
+       public void testInitialReference() {
+               final String s1 = "abcd";
+               final String s2 = cache.getReference(s1);
+               assertSame(s1, s2);
+       }
+
+       @Test
+       public void testMultipleReferences() {
+               final String s1 = "abcd";
+               final String s2 = new String(s1);
+
+               // Preliminary check
+               assertEquals(s1, s2);
+               assertNotSame(s1, s2);
+
+               assertSame(s1, cache.getReference(s1));
+               assertSame(s1, cache.getReference(s2));
+               assertNotSame(s2, cache.getReference(s2));
+       }
+
+}
index e2c9bce995b928f91cd0e14119fe1c5b33594a2c..ca10b3cbb52f634cc66ff5c279f12866112fdb3b 100644 (file)
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.opendaylight.yangtools.objcache.impl
+                        </Export-Package>
+                        <Private-Package>
+                            org.opendaylight.yangtools.objcache.noop
+                        </Private-Package>
+                    </instructions>
+                </configuration>
             </plugin>
         </plugins>
     </build>
index 2af58bf5c36928c9b86d813f531c16901f2edc40..3ef9fbf941d90f79dc7eef87a2e72c1d907a42dc 100644 (file)
@@ -13,18 +13,18 @@ import org.opendaylight.yangtools.objcache.spi.IObjectCacheFactory;
 import org.opendaylight.yangtools.objcache.spi.NoopObjectCache;
 
 public final class StaticObjectCacheBinder extends AbstractObjectCacheBinder {
-       private static final StaticObjectCacheBinder INSTANCE = new StaticObjectCacheBinder();
+    private static final StaticObjectCacheBinder INSTANCE = new StaticObjectCacheBinder();
 
-       private StaticObjectCacheBinder() {
-               super(new IObjectCacheFactory() {
-                       @Override
-                       public ObjectCache getObjectCache(final Class<?> objClass) {
-                               return NoopObjectCache.getInstance();
-                       }
-               });
-       }
+    private StaticObjectCacheBinder() {
+        super(new IObjectCacheFactory() {
+            @Override
+            public ObjectCache getObjectCache(final Class<?> objClass) {
+                return NoopObjectCache.getInstance();
+            }
+        });
+    }
 
-       public static StaticObjectCacheBinder getInstance() {
-               return INSTANCE;
-       }
+    public static StaticObjectCacheBinder getInstance() {
+        return INSTANCE;
+    }
 }
diff --git a/pom.xml b/pom.xml
index e229268818624987b3e648f535a231bc302d509a..9ccb93b27e8d0e3ff3b3165c4161a3c1d9a36cc4 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                 <artifactId>concepts</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>object-cache-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>object-cache-guava</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>object-cache-noop</artifactId>
+                <version>${project.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>