Merge "BUG-987: improve generated type allocation"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 19 May 2014 09:59:40 +0000 (09:59 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 19 May 2014 09:59:40 +0000 (09:59 +0000)
27 files changed:
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingSchemaContextUtils.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.java
common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java
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
restconf/restconf-client-impl/src/main/java/org/opendaylight/yangtools/restconf/client/BindingToRestRpc.java
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java

index fd280427d41b978c847e301da669b29e9010afc7..373ea7df71f52854129213b62b02f1f67101dbb8 100644 (file)
@@ -16,10 +16,10 @@ import javassist.ClassPool;
 
 import org.eclipse.xtext.xbase.lib.Extension;
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
-import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
index 0ab2fdbc2dfd02a525fe9ed74f5a1eba68590a6d..b4362fbd8cb4a1fdc2ab107cb92347a995228cdb 100644 (file)
@@ -1631,9 +1631,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
     }
 
     /**
-     * Creates the name of the getter method from <code>methodName</code>.
+     * Creates the name of the getter method name from <code>localName</code>.
      *
-     * @param methodName
+     * @param localName
      *            string with the name of the getter method
      * @param returnType return type
      * @return string with the name of the getter method for
index 646f3ea4c3db8b134df8cdfaad836a4ccbaebd8c..6645aba5741a64d4deb339ad2f1cd92dcffb15c2 100644 (file)
@@ -41,6 +41,9 @@ public class BindingSchemaContextUtils {
             currentContainer = findNotification(ctx, currentQName);
         } else if (BindingReflections.isRpcType(currentArg.getType())) {
             currentContainer = findFirstDataNodeContainerInRpc(ctx, currentArg.getType());
+            if(currentQName == null && currentContainer.isPresent()) {
+                currentQName = ((DataSchemaNode) currentContainer.get()).getQName();
+            }
         } else {
             currentContainer = findDataNodeContainer(ctx, currentQName);
         }
@@ -112,20 +115,23 @@ public class BindingSchemaContextUtils {
 
     private static Optional<DataNodeContainer> findFirstDataNodeContainerInRpc(final SchemaContext ctx,
             final Class<? extends DataObject> targetType) {
+        final YangModuleInfo moduleInfo;
         try {
-            YangModuleInfo moduleInfo = BindingReflections.getModuleInfo(targetType);
-            for(RpcDefinition rpc : ctx.getOperations()) {
-                String rpcNamespace = rpc.getQName().getNamespace().toString();
-                String rpcRevision = rpc.getQName().getFormattedRevision();
-                if(moduleInfo.getNamespace().equals(rpcNamespace) && moduleInfo.getRevision().equals(rpcRevision)) {
-                    Optional<DataNodeContainer> potential = findInputOutput(rpc,targetType.getSimpleName());
-                    if(potential.isPresent()) {
-                        return potential;
-                    }
+            moduleInfo = BindingReflections.getModuleInfo(targetType);
+        } catch (Exception e) {
+            throw new IllegalArgumentException(
+                    String.format("Failed to load module information for class %s", targetType), e);
+        }
+
+        for(RpcDefinition rpc : ctx.getOperations()) {
+            String rpcNamespace = rpc.getQName().getNamespace().toString();
+            String rpcRevision = rpc.getQName().getFormattedRevision();
+            if(moduleInfo.getNamespace().equals(rpcNamespace) && moduleInfo.getRevision().equals(rpcRevision)) {
+                Optional<DataNodeContainer> potential = findInputOutput(rpc,targetType.getSimpleName());
+                if(potential.isPresent()) {
+                    return potential;
                 }
             }
-        } catch (Exception e) {
-            // FIXME: Add logging
         }
         return Optional.absent();
     }
index 362ebe6e881e9457e0b6425783a6d82c6ee6b2b9..5440e0151141d8e744abdf428b9d2ecb3ec21b1b 100644 (file)
@@ -8,25 +8,26 @@
 package org.opendaylight.yangtools.sal.binding.generator.impl;
 
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
-import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
 
 public abstract class GeneratedClassLoadingStrategy implements ClassLoadingStrategy {
 
     private static final GeneratedClassLoadingStrategy TCCL_STRATEGY = new TCCLClassLoadingStrategy();
 
     private static final GeneratedClassLoadingStrategy ALWAYS_FAIL_STRATEGY = new GeneratedClassLoadingStrategy() {
-
         @Override
-        public Class<?> loadClass(String fullyQualifiedName) throws ClassNotFoundException {
+        public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
             throw new ClassNotFoundException(fullyQualifiedName);
         }
     };
 
-    public Class<?> loadClass(Type type) throws ClassNotFoundException {
+    @Override
+    public Class<?> loadClass(final Type type) throws ClassNotFoundException {
         return loadClass(type.getFullyQualifiedName());
     }
 
+    @Override
     public abstract Class<?> loadClass(String fullyQualifiedName) throws ClassNotFoundException;
 
     public static final GeneratedClassLoadingStrategy getTCCLClassLoadingStrategy() {
@@ -38,9 +39,8 @@ public abstract class GeneratedClassLoadingStrategy implements ClassLoadingStrat
     }
 
     private static final class TCCLClassLoadingStrategy extends GeneratedClassLoadingStrategy {
-
         @Override
-        public Class<?> loadClass(String fullyQualifiedName) throws ClassNotFoundException {
+        public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
             return ClassLoaderUtils.loadClassWithTCCL(fullyQualifiedName);
         }
     }
index a6bf37629818d798ebf459ee1da9282a7b594a3b..a2c1e4ce88f590e87cafe2bfc74448672bfc0a73 100644 (file)
@@ -166,12 +166,21 @@ class LazyGeneratedCodecRegistry implements //
             codec = new AugmentationCodecWrapper<T>(rawCodec, null, object);
             augmentationCodecs.put(object, codec);
         }
-        Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
-        if (objectSupertype != null) {
-            getAugmentableCodec(objectSupertype).addImplementation(codec);
-        } else {
-            LOG.warn("Could not find augmentation target for augmentation {}", object);
+
+        final Class<? extends Augmentable<?>> objectSupertype;
+        try {
+            objectSupertype = BindingReflections.findAugmentationTarget(object);
+        } catch (Exception e) {
+            LOG.warn("Failed to find target for augmentation {}, ignoring it", object, e);
+            return codec;
+        }
+
+        if (objectSupertype == null) {
+            LOG.warn("Augmentation target for {} not found, ignoring it", object);
+            return codec;
         }
+
+        getAugmentableCodec(objectSupertype).addImplementation(codec);
         return codec;
     }
 
@@ -182,18 +191,6 @@ class LazyGeneratedCodecRegistry implements //
         return getCodecForAugmentation((Class<? extends Augmentation<?>>) cls).getAugmentationQName();
     }
 
-    private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
-            final Class<? extends Augmentation<?>> augmentation) {
-        try {
-            Class<? extends Augmentable<?>> ret = BindingReflections.findAugmentationTarget(augmentation);
-            return ret;
-
-        } catch (Exception e) {
-            LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
-            return null;
-        }
-    }
-
     @Override
     public Class<?> getClassForPath(final List<QName> names) {
         final DataSchemaNode node = getSchemaNode(names);
@@ -276,8 +273,9 @@ class LazyGeneratedCodecRegistry implements //
 
     private DataSchemaNode getSchemaNode(final List<QName> path) {
         QName firstNode = path.get(0);
-        DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(),
-                firstNode.getRevision());
+        DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(), firstNode.getRevision());
+        Preconditions.checkArgument(previous != null, "Failed to find module %s for path %s", firstNode, path);
+
         Iterator<QName> iterator = path.iterator();
         while (iterator.hasNext()) {
             QName arg = iterator.next();
@@ -1110,7 +1108,7 @@ class LazyGeneratedCodecRegistry implements //
                         .loadClass(potential);
                 return Optional.of(tryToLoadImplementation(clazz));
             } catch (ClassNotFoundException e) {
-                LOG.warn("Failed to find class for augmentation of {}, reason: {}", potential, e.toString());
+                LOG.warn("Failed to find class for augmentation of {}", potential, e);
             }
             return Optional.absent();
         }
@@ -1120,7 +1118,6 @@ class LazyGeneratedCodecRegistry implements //
             AugmentationCodecWrapper<? extends Augmentation<?>> potentialImpl = getCodecForAugmentation(inputType);
             addImplementation(potentialImpl);
             return potentialImpl;
-
         }
 
         @Override
@@ -1134,10 +1131,9 @@ class LazyGeneratedCodecRegistry implements //
                 try {
                     tryToLoadImplementation(potential);
                 } catch (CodeGenerationException e) {
-                    LOG.warn("Failed to proactively generate augment coded for {}, reason: {}", type, e.toString());
+                    LOG.warn("Failed to proactively generate augment code for {}", type, e);
                 }
             }
-
         }
 
         @Override
@@ -1148,7 +1144,6 @@ class LazyGeneratedCodecRegistry implements //
                 if (!availableAugmentations.isEmpty()) {
                     updateAugmentationMapping(path,availableAugmentations);
                 }
-
             }
         }
 
@@ -1162,7 +1157,7 @@ class LazyGeneratedCodecRegistry implements //
                         potentialImpl.get().addApplicableFor(path,aug);
                     }
                 } else {
-                    LOG.warn("Could not find generated type for augmentation {} with childs {}.",aug,aug.getChildNodes());
+                    LOG.warn("Could not find generated type for augmentation {} with children {}", aug, aug.getChildNodes());
                 }
             }
             availableAugmentations.toString();
index 93c63a2c5bf54cdaeb91a2e9c38ab6d055f9b853..335ec5967e29536f5c8a97d3843146aa59181986 100644 (file)
@@ -7,16 +7,20 @@
  */
 package org.opendaylight.yangtools.sal.binding.generator.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
 import org.opendaylight.yangtools.sal.binding.generator.api.ModuleInfoRegistry;
-import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
@@ -26,18 +30,15 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.ref.WeakReference;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 
 public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
         implements //
         AdvancedSchemaSourceProvider<InputStream>, ModuleInfoRegistry, SchemaContextProvider {
 
-    private ModuleInfoBackedContext(ClassLoadingStrategy loadingStrategy) {
+    private ModuleInfoBackedContext(final ClassLoadingStrategy loadingStrategy) {
         this.backingLoadingStrategy = loadingStrategy;
     }
 
@@ -45,7 +46,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
         return new ModuleInfoBackedContext(getTCCLClassLoadingStrategy());
     }
 
-    public static ModuleInfoBackedContext create(ClassLoadingStrategy loadingStrategy) {
+    public static ModuleInfoBackedContext create(final ClassLoadingStrategy loadingStrategy) {
         return new ModuleInfoBackedContext(loadingStrategy);
     }
 
@@ -57,7 +58,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
     private final ClassLoadingStrategy backingLoadingStrategy;
 
     @Override
-    public Class<?> loadClass(String fullyQualifiedName) throws ClassNotFoundException {
+    public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
         String modulePackageName = BindingReflections.getModelRootPackageName(fullyQualifiedName);
 
         WeakReference<ClassLoader> classLoaderRef = packageNameToClassLoader.get(modulePackageName);
@@ -110,15 +111,15 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
         return sourceStreams.build();
     }
 
-    private boolean resolveModuleInfo(Class<?> cls) {
+    private boolean resolveModuleInfo(final Class<?> cls) {
         try {
             return resolveModuleInfo(BindingReflections.getModuleInfo(cls));
         } catch (Exception e) {
-            throw new IllegalStateException(e);
+            throw new IllegalStateException(String.format("Failed to resolve module information for class %s", cls), e);
         }
     }
 
-    private boolean resolveModuleInfo(YangModuleInfo moduleInfo) {
+    private boolean resolveModuleInfo(final YangModuleInfo moduleInfo) {
 
         SourceIdentifier identifier = sourceIdentifierFrom(moduleInfo);
         YangModuleInfo previous = sourceIdentifierToModuleInfo.putIfAbsent(identifier, moduleInfo);
@@ -136,18 +137,18 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
         return true;
     }
 
-    private SourceIdentifier sourceIdentifierFrom(YangModuleInfo moduleInfo) {
+    private SourceIdentifier sourceIdentifierFrom(final YangModuleInfo moduleInfo) {
         return SourceIdentifier.create(moduleInfo.getName(), Optional.of(moduleInfo.getRevision()));
     }
 
-    public void addModuleInfos(Iterable<? extends YangModuleInfo> moduleInfos) {
+    public void addModuleInfos(final Iterable<? extends YangModuleInfo> moduleInfos) {
         for (YangModuleInfo yangModuleInfo : moduleInfos) {
             registerModuleInfo(yangModuleInfo);
         }
     }
 
     @Override
-    public ObjectRegistration<YangModuleInfo> registerModuleInfo(YangModuleInfo yangModuleInfo) {
+    public ObjectRegistration<YangModuleInfo> registerModuleInfo(final YangModuleInfo yangModuleInfo) {
         YangModuleInfoRegistration registration = new YangModuleInfoRegistration(yangModuleInfo, this);
 
         resolveModuleInfo(yangModuleInfo);
@@ -156,7 +157,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
     }
 
     @Override
-    public Optional<InputStream> getSchemaSource(SourceIdentifier sourceIdentifier) {
+    public Optional<InputStream> getSchemaSource(final SourceIdentifier sourceIdentifier) {
         YangModuleInfo info = sourceIdentifierToModuleInfo.get(sourceIdentifier);
         if (info == null) {
             return Optional.absent();
@@ -169,7 +170,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
     }
 
     @Override
-    public Optional<InputStream> getSchemaSource(String moduleName, Optional<String> revision) {
+    public Optional<InputStream> getSchemaSource(final String moduleName, final Optional<String> revision) {
         return getSchemaSource(SourceIdentifier.create(moduleName, revision));
     }
 
@@ -177,7 +178,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
 
         private final ModuleInfoBackedContext context;
 
-        public YangModuleInfoRegistration(YangModuleInfo instance, ModuleInfoBackedContext context) {
+        public YangModuleInfoRegistration(final YangModuleInfo instance, final ModuleInfoBackedContext context) {
             super(instance);
             this.context = context;
         }
@@ -189,7 +190,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy //
 
     }
 
-    private void remove(YangModuleInfoRegistration registration) {
+    private void remove(final YangModuleInfoRegistration registration) {
         // FIXME implement
     }
 
index 15895528936020a89ac8010a4a3b0840b8386c4e..01ed2f0240030aeaeff055148af8038b9d1124fb 100644 (file)
@@ -19,6 +19,10 @@ import java.util.concurrent.locks.Lock;
 import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
 
+/**
+ * @deprecated Use {@link org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils} instead.
+ */
+@Deprecated
 public final class ClassLoaderUtils {
 
     private ClassLoaderUtils() {
index e19730b35ef80d2255fb6178af19990e1a1c0eb0..252fca7107953dff0ff04cc49882d48e334ee076 100644 (file)
@@ -59,11 +59,11 @@ public final class JavassistUtils {
      * created if this is a new pool. If an instance already exists, is is
      * returned.
      *
-     * @param pool
-     * @return
+     * @param pool Backing class pool
+     * @return shared utility instance for specified pool
      */
     public static synchronized JavassistUtils forClassPool(final ClassPool pool) {
-        JavassistUtils ret = INSTANCES.get(pool);
+        JavassistUtils ret = INSTANCES.get(Preconditions.checkNotNull(pool));
         if (ret == null) {
             ret = new JavassistUtils(pool, null);
             INSTANCES.put(pool, ret);
index f2402270efeaa409102c3ceffa3553f50e5d515e..e898e72479f441b6a1db405e42ac50f7ff1ec96a 100644 (file)
@@ -12,18 +12,21 @@ import java.lang.reflect.Type;
 import java.util.concurrent.Callable;
 import java.util.concurrent.locks.Lock;
 
-
+/**
+ * @deprecated Use {@link org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils} instead.
+ */
+@Deprecated
 public final class ClassLoaderUtils {
 
     private ClassLoaderUtils() {
         throw new UnsupportedOperationException("Utility class");
     }
 
-    public static <V> V withClassLoader(ClassLoader cls, Callable<V> function) throws Exception {
+    public static <V> V withClassLoader(final ClassLoader cls, final Callable<V> function) throws Exception {
         return withClassLoaderAndLock(cls, null, function);
     }
 
-    public static <V> V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable<V> function) throws Exception {
+    public static <V> V withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Callable<V> function) throws Exception {
         if (cls == null) {
             throw new IllegalArgumentException("Classloader should not be null");
         }
@@ -46,7 +49,7 @@ public final class ClassLoaderUtils {
         }
     }
 
-    public static ParameterizedType findParameterizedType(Class<?> subclass, Class<?> genericType) {
+    public static ParameterizedType findParameterizedType(final Class<?> subclass, final Class<?> genericType) {
         if(subclass == null || genericType == null) {
             throw new IllegalArgumentException("Class was not specified.");
         }
@@ -65,7 +68,7 @@ public final class ClassLoaderUtils {
             return null;
         }
     }
-    
+
     private static <S,G,P> Callable<Class<P>> findFirstGenericArgumentTask(final Class<S> scannedClass, final Class<G> genericType) {
         return new Callable<Class<P>>() {
             @Override
@@ -81,7 +84,7 @@ public final class ClassLoaderUtils {
         };
     }
 
-    public static Type getFirstGenericParameter(Type type) {
+    public static Type getFirstGenericParameter(final Type type) {
         if(type instanceof ParameterizedType) {
             return ((ParameterizedType) type).getActualTypeArguments()[0];
         }
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>
 
index fe4eb76695e25b08007f27215ce3cd26bc1d7e7a..40d29da662a56e725d8ad0af79a409ee1a07e6d5 100644 (file)
@@ -48,7 +48,7 @@ public class BindingToRestRpc implements InvocationHandler {
     private final SchemaContext schcemaContext;
     private final Module module;
 
-    public BindingToRestRpc(Class<?> proxiedInterface,BindingIndependentMappingService mappingService,RestconfClientImpl client,SchemaContext schemaContext) throws Exception {
+    public BindingToRestRpc(final Class<?> proxiedInterface,final BindingIndependentMappingService mappingService,final RestconfClientImpl client,final SchemaContext schemaContext) throws Exception {
         this.mappingService = mappingService;
         this.client  = client;
         this.schcemaContext = schemaContext;
@@ -57,7 +57,7 @@ public class BindingToRestRpc implements InvocationHandler {
     }
 
     @Override
-    public Object invoke(Object o,final Method method, Object[] objects) throws Throwable {
+    public Object invoke(final Object o,final Method method, final Object[] objects) throws Exception {
         for (RpcDefinition rpcDef:module.getRpcs()){
             if (method.getName().equals(BindingMapping.getMethodName(rpcDef.getQName()))){
 
@@ -77,7 +77,7 @@ public class BindingToRestRpc implements InvocationHandler {
                 final DataSchemaNode rpcOutputSchema = rpcDef.getOutput();
                 return client.post(ResourceUri.OPERATIONS.getPath() + "/" + moduleName + ":" + rpcMethodName,payloadString,new Function<ClientResponse, Object>() {
                     @Override
-                    public Object apply(ClientResponse clientResponse) {
+                    public Object apply(final ClientResponse clientResponse) {
                         if (clientResponse.getStatus() != 200) {
                             throw new IllegalStateException("Can't get data from restconf. "+clientResponse.getClientResponseStatus());
                         }
@@ -101,10 +101,10 @@ public class BindingToRestRpc implements InvocationHandler {
         throw new IllegalStateException("Unexpected state of proxy method.");
     }
 
-    public static<T> T getProxy(Class<T> proxiedInterface,
-                                BindingIndependentMappingService mappingService,
-                                RestconfClientImpl restconfClient,
-                                SchemaContext schemaContext) {
+    public static<T> T getProxy(final Class<T> proxiedInterface,
+                                final BindingIndependentMappingService mappingService,
+                                final RestconfClientImpl restconfClient,
+                                final SchemaContext schemaContext) {
         T proxiedType = null;
         try {
             proxiedType = (T) Proxy.newProxyInstance
index a6c3996c5cd22558e44f42ea4283c869f84b9ea4..b0671397f3b179afcd5b14f80d60d2e766b72543 100644 (file)
@@ -9,9 +9,9 @@ package org.opendaylight.yangtools.yang.binding.util;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
-import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.withClassLoader;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 import java.util.ServiceLoader;
@@ -21,7 +21,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
@@ -34,7 +33,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.common.QName;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -124,7 +122,6 @@ public class BindingReflections {
                     YangModuleInfo moduleInfo = getModuleInfo(key);
                     return Optional.of(QName.create(moduleInfo.getNamespace(), moduleInfo.getRevision(), moduleInfo.getName()));
                 }
-
             } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
                 // NOOP
             }
@@ -202,10 +199,9 @@ public class BindingReflections {
         checkArgument(cls != null);
         String packageName = getModelRootPackageName(cls.getPackage());
         final String potentialClassName = getModuleInfoClassName(packageName);
-        return withClassLoader(cls.getClassLoader(), new Callable<YangModuleInfo>() {
-
+        return ClassLoaderUtils.withClassLoader(cls.getClassLoader(), new Callable<YangModuleInfo>() {
             @Override
-            public YangModuleInfo call() throws Exception {
+            public YangModuleInfo call() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
                 Class<?> moduleInfoClass = Thread.currentThread().getContextClassLoader().loadClass(potentialClassName);
                 return (YangModuleInfo) moduleInfoClass.getMethod("getInstance").invoke(null);
             }
diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java
new file mode 100644 (file)
index 0000000..e61aa73
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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.yang.binding.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Lock;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+
+public final class ClassLoaderUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(ClassLoaderUtils.class);
+
+    private ClassLoaderUtils() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+
+    public static <V> V withClassLoader(final ClassLoader cls, final Supplier<V> function) {
+        checkNotNull(cls, "Classloader should not be null");
+        checkNotNull(function, "Function should not be null");
+
+        final ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(cls);
+            return function.get();
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldCls);
+        }
+    }
+
+    public static <V> V withClassLoader(final ClassLoader cls, final Callable<V> function) throws Exception {
+        checkNotNull(cls, "Classloader should not be null");
+        checkNotNull(function, "Function should not be null");
+
+        final ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(cls);
+            return function.call();
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldCls);
+        }
+    }
+
+    public static <V> V withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Supplier<V> function) {
+        checkNotNull(lock, "Lock should not be null");
+
+        lock.lock();
+        try {
+            return withClassLoader(cls, function);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public static Object construct(final Constructor<? extends Object> constructor, final List<Object> objects)
+            throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        final Object[] initargs = objects.toArray();
+        return constructor.newInstance(initargs);
+    }
+
+    public static Class<?> loadClass(final ClassLoader cls, final String name) throws ClassNotFoundException {
+        if ("byte[]".equals(name)) {
+            return byte[].class;
+        }
+        if ("char[]".equals(name)) {
+            return char[].class;
+        }
+
+        try {
+            return cls.loadClass(name);
+        } catch (ClassNotFoundException e) {
+            String[] components = name.split("\\.");
+            String potentialOuter;
+            int length = components.length;
+            if (length > 2 && (potentialOuter = components[length - 2]) != null && Character.isUpperCase(potentialOuter.charAt(0))) {
+                    String outerName = Joiner.on(".").join(Arrays.asList(components).subList(0, length - 1));
+                    String innerName = outerName + "$" + components[length-1];
+                    return cls.loadClass(innerName);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    public static Class<?> loadClassWithTCCL(final String name) throws ClassNotFoundException {
+        return loadClass(Thread.currentThread().getContextClassLoader(), name);
+    }
+
+    public static Class<?> tryToLoadClassWithTCCL(final String fullyQualifiedName) {
+        try {
+            return loadClassWithTCCL(fullyQualifiedName);
+        } catch (ClassNotFoundException e) {
+            LOG.debug("Failed to load class {}", fullyQualifiedName, e);
+            return null;
+        }
+    }
+
+    public static <S,G,P> Class<P> findFirstGenericArgument(final Class<S> scannedClass, final Class<G> genericType) {
+        return withClassLoader(scannedClass.getClassLoader(), ClassLoaderUtils.<S,G,P>findFirstGenericArgumentTask(scannedClass, genericType));
+    }
+
+    private static <S,G,P> Supplier<Class<P>> findFirstGenericArgumentTask(final Class<S> scannedClass, final Class<G> genericType) {
+        return new Supplier<Class<P>>() {
+            @Override
+            @SuppressWarnings("unchecked")
+            public Class<P> get() {
+                final ParameterizedType augmentationGeneric = findParameterizedType(scannedClass, genericType);
+                if (augmentationGeneric != null) {
+                    return (Class<P>) augmentationGeneric.getActualTypeArguments()[0];
+                }
+                return null;
+            }
+        };
+    }
+
+    public static ParameterizedType findParameterizedType(final Class<?> subclass, final Class<?> genericType) {
+        Preconditions.checkNotNull(subclass);
+        Preconditions.checkNotNull(genericType);
+
+        for (Type type : subclass.getGenericInterfaces()) {
+            if (type instanceof ParameterizedType && genericType.equals(((ParameterizedType) type).getRawType())) {
+                return (ParameterizedType) type;
+            }
+        }
+
+        LOG.debug("Class {} does not declare interface {}", subclass, genericType);
+        return null;
+    }
+
+    public static Type getFirstGenericParameter(final Type type) {
+        if (type instanceof ParameterizedType) {
+            return ((ParameterizedType) type).getActualTypeArguments()[0];
+        }
+        return null;
+    }
+}
index 14f495058152d09fcac15b1ce5edd490f3003b59..0dc0c19e6b19d2b7e539052d2c15bab45848a6b7 100644 (file)
@@ -15,14 +15,32 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.*;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 
-import java.util.Set;
-
 /**
  * The Schema Context Util contains support methods for searching through Schema
  * Context modules for specified schema nodes via Schema Path or Revision Aware
@@ -30,7 +48,8 @@ import java.util.Set;
  * instantiable.
  *
  */
-public class SchemaContextUtil {
+public final class SchemaContextUtil {
+    private static final Logger LOG = LoggerFactory.getLogger(SchemaContextUtil.class);
 
     private SchemaContextUtil() {
     }
@@ -53,14 +72,18 @@ public class SchemaContextUtil {
      * @return SchemaNode from the end of the Schema Path or <code>null</code>
      *         if the Node is not present.
      */
-    public static SchemaNode findDataSchemaNode(SchemaContext context, SchemaPath schemaPath) {
+    public static SchemaNode findDataSchemaNode(final SchemaContext context, final SchemaPath schemaPath) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
         Preconditions.checkArgument(schemaPath != null, "Schema Path reference cannot be NULL");
-        List<QName> prefixedPath = (schemaPath.getPath());
-        if (prefixedPath != null) {
-            return findNodeInSchemaContext(context, prefixedPath);
+
+        final List<QName> prefixedPath = (schemaPath.getPath());
+        if (prefixedPath == null) {
+            LOG.debug("Schema path {} has null path", schemaPath);
+            return null;
         }
-        return null;
+
+        LOG.trace("Looking for path {} in context {}", schemaPath, context);
+        return findNodeInSchemaContext(context, prefixedPath);
     }
 
     /**
@@ -93,16 +116,14 @@ public class SchemaContextUtil {
      *         Non-conditional Revision Aware XPath, or <code>null</code> if the
      *         DataSchemaNode is not present in Schema Context.
      */
-    public static SchemaNode findDataSchemaNode(SchemaContext context, Module module, RevisionAwareXPath nonCondXPath) {
+    public static SchemaNode findDataSchemaNode(final SchemaContext context, final Module module, final RevisionAwareXPath nonCondXPath) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
         Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
         Preconditions.checkArgument(nonCondXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");
 
         String strXPath = nonCondXPath.toString();
         if (strXPath != null) {
-            if (strXPath.contains("[")) {
-                throw new IllegalArgumentException("Revision Aware XPath cannot contains condition");
-            }
+            Preconditions.checkArgument(strXPath.indexOf('[') == -1, "Revision Aware XPath may not contain a condition");
             if (nonCondXPath.isAbsolute()) {
                 List<QName> qnamedPath = xpathToQNamePath(context, module, strXPath);
                 if (qnamedPath != null) {
@@ -152,8 +173,8 @@ public class SchemaContextUtil {
      *         given relative Revision Aware XPath, otherwise will return
      *         <code>null</code>.
      */
-    public static SchemaNode findDataSchemaNodeForRelativeXPath(SchemaContext context, Module module,
-            SchemaNode actualSchemaNode, RevisionAwareXPath relativeXPath) {
+    public static SchemaNode findDataSchemaNodeForRelativeXPath(final SchemaContext context, final Module module,
+            final SchemaNode actualSchemaNode, final RevisionAwareXPath relativeXPath) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
         Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
         Preconditions.checkArgument(actualSchemaNode != null, "Actual Schema Node reference cannot be NULL");
@@ -190,7 +211,7 @@ public class SchemaContextUtil {
      *         Schema Node is NOT present, the method will returns
      *         <code>null</code>
      */
-    public static Module findParentModule(SchemaContext context, SchemaNode schemaNode) {
+    public static Module findParentModule(final SchemaContext context, final SchemaNode schemaNode) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL!");
         Preconditions.checkArgument(schemaNode != null, "Schema Node cannot be NULL!");
         Preconditions.checkState(schemaNode.getPath() != null, "Schema Path for Schema Node is not "
@@ -206,15 +227,20 @@ public class SchemaContextUtil {
         return context.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision());
     }
 
-    public static SchemaNode findNodeInSchemaContext(SchemaContext context, List<QName> path) {
-        QName current = path.get(0);
-        Module module = context.findModuleByNamespaceAndRevision(current.getNamespace(), current.getRevision());
-        if (module == null)
+    public static SchemaNode findNodeInSchemaContext(final SchemaContext context, final List<QName> path) {
+        final QName current = path.get(0);
+
+        LOG.trace("Looking up module {} in context {}", current, path);
+        final Module module = context.findModuleByNamespaceAndRevision(current.getNamespace(), current.getRevision());
+        if (module == null) {
+            LOG.debug("Module {} not found", current);
             return null;
+        }
+
         return findNodeInModule(module, path);
     }
 
-    public static GroupingDefinition findGrouping(SchemaContext context, Module module, List<QName> path) {
+    public static GroupingDefinition findGrouping(final SchemaContext context, final Module module, final List<QName> path) {
         QName first = path.get(0);
         Module m = context.findModuleByNamespace(first.getNamespace()).iterator().next();
         DataNodeContainer currentParent = m;
@@ -233,124 +259,189 @@ public class SchemaContextUtil {
                 found = true;
                 currentParent = node;
             }
-            if (!found) {
-                throw new IllegalArgumentException("Failed to find referenced grouping: " + path + "("
-                        + qname.getLocalName() + ")");
-            }
+
+            Preconditions.checkArgument(found, "Failed to find referenced grouping: %s(%s)", path, qname.getLocalName());
         }
 
         return (GroupingDefinition) currentParent;
     }
 
-    private static SchemaNode findNodeInModule(Module module, List<QName> path) {
-        QName current = path.get(0);
-        SchemaNode node = module.getDataChildByName(current);
-        if (node != null)
-            return findNode((DataSchemaNode) node, nextLevel(path));
-        node = getRpcByName(module, current);
-        if (node != null)
-            return findNodeInRpc((RpcDefinition) node, nextLevel(path));
-        node = getNotificationByName(module, current);
-        if (node != null)
-            return findNodeInNotification((NotificationDefinition) node, nextLevel(path));
-        node = getGroupingByName(module, current);
-        if (node != null)
-            return findNodeInGrouping((GroupingDefinition) node, nextLevel(path));
-        return node;
+    private static SchemaNode findNodeInModule(final Module module, final List<QName> path) {
+        final QName current = path.get(0);
+
+        LOG.trace("Looking for data container {} in module {}", current, module);
+        SchemaNode parent = module.getDataChildByName(current);
+        if (parent != null) {
+            final SchemaNode ret = findNode((DataSchemaNode) parent, nextLevel(path));
+            if (ret != null) {
+                return ret;
+            }
+        }
+
+        LOG.trace("Looking for RPC {} in module {}", current, module);
+        parent = getRpcByName(module, current);
+        if (parent != null) {
+            final SchemaNode ret = findNodeInRpc((RpcDefinition) parent, nextLevel(path));
+            if (ret != null) {
+                return ret;
+            }
+        }
+
+        LOG.trace("Looking for notification {} in module {}", current, module);
+        parent = getNotificationByName(module, current);
+        if (parent != null) {
+            final SchemaNode ret = findNodeInNotification((NotificationDefinition) parent, nextLevel(path));
+            if (ret != null) {
+                return ret;
+            }
+        }
+
+        LOG.trace("Looking for grouping {} in module {}", current, module);
+        parent = getGroupingByName(module, current);
+        if (parent != null) {
+            final SchemaNode ret = findNodeInGrouping((GroupingDefinition) parent, nextLevel(path));
+            if (ret != null) {
+                return ret;
+            }
+        }
+
+        LOG.debug("No node matching {} found in module {}", path, module);
+        return null;
     }
 
-    private static SchemaNode findNodeInGrouping(GroupingDefinition grouping, List<QName> path) {
-        if (path.isEmpty())
+    private static SchemaNode findNodeInGrouping(final GroupingDefinition grouping, final List<QName> path) {
+        if (path.isEmpty()) {
+            LOG.debug("Found grouping {}", grouping);
             return grouping;
-        QName current = path.get(0);
-        DataSchemaNode node = grouping.getDataChildByName(current);
-        if (node != null)
-            return findNode(node, nextLevel(path));
-        return null;
+        }
+
+        LOG.trace("Looking for path {} in grouping {}", path, grouping);
+        final QName current = path.get(0);
+        final DataSchemaNode node = grouping.getDataChildByName(current);
+        if (node == null) {
+            LOG.debug("No node matching {} found in grouping {}", current, grouping);
+            return null;
+        }
+
+        return findNode(node, nextLevel(path));
     }
 
-    private static SchemaNode findNodeInRpc(RpcDefinition rpc, List<QName> path) {
-        if (path.isEmpty())
+    private static SchemaNode findNodeInRpc(final RpcDefinition rpc, final List<QName> path) {
+        if (path.isEmpty()) {
+            LOG.debug("Found RPC {}", rpc);
             return rpc;
-        QName current = path.get(0);
+        }
+
+        LOG.trace("Looking for path {} in rpc {}", path, rpc);
+        final QName current = path.get(0);
         switch (current.getLocalName()) {
         case "input":
             return findNode(rpc.getInput(), nextLevel(path));
         case "output":
             return findNode(rpc.getOutput(), nextLevel(path));
+        default:
+            LOG.debug("Invalid component {} of path {} in RPC {}", current, path, rpc);
+            return null;
         }
-        return null;
     }
 
-    private static SchemaNode findNodeInNotification(NotificationDefinition rpc, List<QName> path) {
-        if (path.isEmpty())
-            return rpc;
-        QName current = path.get(0);
-        DataSchemaNode node = rpc.getDataChildByName(current);
-        if (node != null)
-            return findNode(node, nextLevel(path));
-        return null;
+    private static SchemaNode findNodeInNotification(final NotificationDefinition ntf, final List<QName> path) {
+        if (path.isEmpty()) {
+            LOG.debug("Found notification {}", ntf);
+            return ntf;
+        }
+
+        LOG.trace("Looking for path {} in notification {}", path, ntf);
+        final QName current = path.get(0);
+        DataSchemaNode node = ntf.getDataChildByName(current);
+        if (node == null) {
+            LOG.debug("No node matching {} found in notification {}", current, ntf);
+            return null;
+        }
+
+        return findNode(node, nextLevel(path));
     }
 
-    private static SchemaNode findNode(ChoiceNode parent, List<QName> path) {
-        if (path.isEmpty())
+    private static SchemaNode findNode(final ChoiceNode parent, final List<QName> path) {
+        if (path.isEmpty()) {
             return parent;
+        }
         QName current = path.get(0);
         ChoiceCaseNode node = parent.getCaseNodeByName(current);
-        if (node != null)
+        if (node != null) {
             return findNodeInCase(node, nextLevel(path));
+        }
         return null;
     }
 
-    private static SchemaNode findNode(ContainerSchemaNode parent, List<QName> path) {
-        if (path.isEmpty())
+    private static SchemaNode findNode(final ContainerSchemaNode parent, final List<QName> path) {
+        if (path.isEmpty()) {
             return parent;
-        QName current = path.get(0);
-        DataSchemaNode node = parent.getDataChildByName(current);
-        if (node != null)
-            return findNode(node, nextLevel(path));
-        return null;
+        }
+
+        final QName current = path.get(0);
+        final DataSchemaNode node = parent.getDataChildByName(current);
+        if (node == null) {
+            LOG.debug("Failed to find {} in parent {}", path, parent);
+            return null;
+        }
+
+        return findNode(node, nextLevel(path));
     }
 
-    private static SchemaNode findNode(ListSchemaNode parent, List<QName> path) {
-        if (path.isEmpty())
+    private static SchemaNode findNode(final ListSchemaNode parent, final List<QName> path) {
+        if (path.isEmpty()) {
             return parent;
+        }
+
         QName current = path.get(0);
         DataSchemaNode node = parent.getDataChildByName(current);
-        if (node != null)
-            return findNode(node, nextLevel(path));
-        return null;
+        if (node == null) {
+            LOG.debug("Failed to find {} in parent {}", path, parent);
+            return null;
+        }
+        return findNode(node, nextLevel(path));
     }
 
-    private static SchemaNode findNode(DataSchemaNode parent, List<QName> path) {
-        SchemaNode result = null;
-        if (path.isEmpty()) {
-            result = parent;
-        } else {
+    private static SchemaNode findNode(final DataSchemaNode parent, final List<QName> path) {
+        final SchemaNode node;
+        if (!path.isEmpty()) {
             if (parent instanceof ContainerSchemaNode) {
-                result = findNode((ContainerSchemaNode) parent, path);
+                node = findNode((ContainerSchemaNode) parent, path);
             } else if (parent instanceof ListSchemaNode) {
-                result = findNode((ListSchemaNode) parent, path);
+                node = findNode((ListSchemaNode) parent, path);
             } else if (parent instanceof ChoiceNode) {
-                result = findNode((ChoiceNode) parent, path);
+                node = findNode((ChoiceNode) parent, path);
             } else {
-                throw new IllegalArgumentException("Path nesting violation");
+                throw new IllegalArgumentException(
+                        String.format("Path nesting violation in parent %s path %s", parent, path));
             }
+        } else {
+            node = parent;
         }
-        return result;
+
+        if (node == null) {
+            LOG.debug("Failed to find {} in parent {}", path, parent);
+            return null;
+        }
+        return node;
     }
 
-    public static SchemaNode findNodeInCase(ChoiceCaseNode parent, List<QName> path) {
-        if (path.isEmpty())
+    public static SchemaNode findNodeInCase(final ChoiceCaseNode parent, final List<QName> path) {
+        if (path.isEmpty()) {
             return parent;
+        }
+
         QName current = path.get(0);
         DataSchemaNode node = parent.getDataChildByName(current);
-        if (node != null)
-            return findNode(node, nextLevel(path));
-        return null;
+        if (node == null) {
+            LOG.debug("Failed to find {} in parent {}", path, parent);
+            return null;
+        }
+        return findNode(node, nextLevel(path));
     }
 
-    public static RpcDefinition getRpcByName(Module module, QName name) {
+    public static RpcDefinition getRpcByName(final Module module, final QName name) {
         for (RpcDefinition rpc : module.getRpcs()) {
             if (rpc.getQName().equals(name)) {
                 return rpc;
@@ -359,11 +450,11 @@ public class SchemaContextUtil {
         return null;
     }
 
-    private static List<QName> nextLevel(List<QName> path) {
+    private static List<QName> nextLevel(final List<QName> path) {
         return path.subList(1, path.size());
     }
 
-    public static NotificationDefinition getNotificationByName(Module module, QName name) {
+    public static NotificationDefinition getNotificationByName(final Module module, final QName name) {
         for (NotificationDefinition notification : module.getNotifications()) {
             if (notification.getQName().equals(name)) {
                 return notification;
@@ -372,7 +463,7 @@ public class SchemaContextUtil {
         return null;
     }
 
-    public static GroupingDefinition getGroupingByName(Module module, QName name) {
+    public static GroupingDefinition getGroupingByName(final Module module, final QName name) {
         for (GroupingDefinition grouping : module.getGroupings()) {
             if (grouping.getQName().equals(name)) {
                 return grouping;
@@ -387,7 +478,7 @@ public class SchemaContextUtil {
      * @param node
      * @return
      */
-    public static DataSchemaNode findOriginal(DataSchemaNode node, SchemaContext ctx) {
+    public static DataSchemaNode findOriginal(final DataSchemaNode node, final SchemaContext ctx) {
         DataSchemaNode result = findCorrectTargetFromGrouping(node, ctx);
         if (result == null) {
             result = findCorrectTargetFromAugment(node, ctx);
@@ -400,7 +491,7 @@ public class SchemaContextUtil {
         return result;
     }
 
-    private static DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node, SchemaContext ctx) {
+    private static DataSchemaNode findCorrectTargetFromGrouping(final DataSchemaNode node, final SchemaContext ctx) {
         if (node.getPath().getPath().size() == 1) {
             // uses is under module statement
             Module m = findParentModule(ctx, node);
@@ -408,7 +499,7 @@ public class SchemaContextUtil {
             for (UsesNode u : m.getUses()) {
                 SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
                 if (!(targetGrouping instanceof GroupingDefinition)) {
-                    throw new IllegalArgumentException("Failed to generate code for augment in " + u);
+                    throw new IllegalArgumentException(String.format("Failed to generate code for augment in %s", u));
                 }
                 GroupingDefinition gr = (GroupingDefinition) targetGrouping;
                 result = gr.getDataChildByName(node.getQName().getLocalName());
@@ -466,7 +557,7 @@ public class SchemaContextUtil {
         }
     }
 
-    private static DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node, SchemaContext ctx) {
+    private static DataSchemaNode findCorrectTargetFromAugment(final DataSchemaNode node, final SchemaContext ctx) {
         if (!node.isAugmenting()) {
             return null;
         }
@@ -523,23 +614,23 @@ public class SchemaContextUtil {
         }
     }
 
-    private static DataSchemaNode getResultFromUses(UsesNode u, String currentName, SchemaContext ctx) {
+    private static DataSchemaNode getResultFromUses(final UsesNode u, final String currentName, final SchemaContext ctx) {
         SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
-        if (!(targetGrouping instanceof GroupingDefinition)) {
-            throw new IllegalArgumentException("Failed to generate code for augment in " + u);
-        }
+
+        Preconditions.checkArgument(targetGrouping instanceof GroupingDefinition,
+                "Failed to generate code for augment in %s", u);
         GroupingDefinition gr = (GroupingDefinition) targetGrouping;
         return gr.getDataChildByName(currentName);
     }
 
-    private static Module getParentModule(SchemaNode node, SchemaContext ctx) {
+    private static Module getParentModule(final SchemaNode node, final SchemaContext ctx) {
         QName qname = node.getPath().getPath().get(0);
         URI namespace = qname.getNamespace();
         Date revision = qname.getRevision();
         return ctx.findModuleByNamespaceAndRevision(namespace, revision);
     }
 
-    private static DataSchemaNode getTargetNode(List<QName> tmpPath, DataSchemaNode node, SchemaContext ctx) {
+    private static DataSchemaNode getTargetNode(final List<QName> tmpPath, final DataSchemaNode node, final SchemaContext ctx) {
         DataSchemaNode result = node;
         if (tmpPath.size() == 1) {
             if (result != null && result.isAddedByUses()) {
@@ -570,7 +661,7 @@ public class SchemaContextUtil {
         }
     }
 
-    private static AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, QName name) {
+    private static AugmentationSchema findNodeInAugment(final Collection<AugmentationSchema> augments, final QName name) {
         for (AugmentationSchema augment : augments) {
             DataSchemaNode node = augment.getDataChildByName(name);
             if (node != null) {
@@ -580,8 +671,8 @@ public class SchemaContextUtil {
         return null;
     }
 
-    private static DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node,
-            AugmentationSchema parentNode, List<SchemaNode> dataTree, SchemaContext ctx) {
+    private static DataSchemaNode findCorrectTargetFromAugmentGrouping(final DataSchemaNode node,
+            final AugmentationSchema parentNode, final List<SchemaNode> dataTree, final SchemaContext ctx) {
 
         DataSchemaNode result = null;
         QName currentName = node.getQName();
@@ -636,7 +727,7 @@ public class SchemaContextUtil {
      *            XPath String
      * @return return a list of QName
      */
-    private static List<QName> xpathToQNamePath(SchemaContext context, Module parentModule, String xpath) {
+    private static List<QName> xpathToQNamePath(final SchemaContext context, final Module parentModule, final String xpath) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
         Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL");
         Preconditions.checkArgument(xpath != null, "XPath string reference cannot be NULL");
@@ -672,7 +763,7 @@ public class SchemaContextUtil {
      *            Prefixed Path Part string
      * @return QName from prefixed Path Part String.
      */
-    private static QName stringPathPartToQName(SchemaContext context, Module parentModule, String prefixedPathPart) {
+    private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule, final String prefixedPathPart) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
         Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL");
         Preconditions.checkArgument(prefixedPathPart != null, "Prefixed Path Part cannot be NULL!");
@@ -680,12 +771,9 @@ public class SchemaContextUtil {
         if (prefixedPathPart.contains(":")) {
             String[] prefixedName = prefixedPathPart.split(":");
             Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]);
-            if (module == null) {
-                throw new IllegalArgumentException("Failed to resolve xpath: no module found for prefix "
-                        + prefixedName[0] + " in module " + parentModule.getName());
-            } else {
-                return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]);
-            }
+            Preconditions.checkArgument(module != null, "Failed to resolve xpath: no module found for prefix %s in module %s",
+                    prefixedName[0], parentModule.getName());
+            return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]);
         } else {
             return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart);
         }
@@ -715,7 +803,7 @@ public class SchemaContextUtil {
      * @return Module for given prefix in specified Schema Context if is
      *         present, otherwise returns <code>null</code>
      */
-    private static Module resolveModuleForPrefix(SchemaContext context, Module module, String prefix) {
+    private static Module resolveModuleForPrefix(final SchemaContext context, final Module module, final String prefix) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
         Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
         Preconditions.checkArgument(prefix != null, "Prefix string cannot be NULL");
@@ -746,8 +834,8 @@ public class SchemaContextUtil {
      *            Schema Path for Leafref
      * @return list of QName
      */
-    private static List<QName> resolveRelativeXPath(SchemaContext context, Module module,
-            RevisionAwareXPath relativeXPath, SchemaNode leafrefParentNode) {
+    private static List<QName> resolveRelativeXPath(final SchemaContext context, final Module module,
+            final RevisionAwareXPath relativeXPath, final SchemaNode leafrefParentNode) {
         Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
         Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
         Preconditions.checkArgument(relativeXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");