Merge "Bug 735 - Part 1: Update ietf-restconf and ietf-yangtypes to newer versions"
authorTony Tkacik <ttkacik@cisco.com>
Tue, 20 May 2014 12:59:18 +0000 (12:59 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 20 May 2014 12:59:18 +0000 (12:59 +0000)
34 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/InstanceIdentifierCodecImpl.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
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedType.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedTypeBuilder.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractTypeMember.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend
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-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifier.java
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 9fac9571c23f2124b36a087da7fd312a7517c075..fda3f068ac8faed5c341ae19083d36ef805f006d 100644 (file)
@@ -11,6 +11,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -46,6 +47,8 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
 
     private final CodecRegistry codecRegistry;
 
+    private final Map<Class<?>,Set<List<QName>>> augmentationAdapted = new WeakHashMap<>();
+
     private final Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = Collections
             .synchronizedMap(new WeakHashMap<Class<?>, Map<List<QName>, Class<?>>>());
 
@@ -70,6 +73,7 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
             }
             Map<List<QName>, Class<?>> injectAugment = classToPreviousAugment.get(baType);
             if (injectAugment != null) {
+                @SuppressWarnings("unchecked")
                 Class<? extends DataObject> augment = (Class<? extends DataObject>) injectAugment.get(scannedPath);
                 if (augment != null) {
                     baArgs.add(new Item(augment));
@@ -77,7 +81,7 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
             }
             baArgs.add(baArg);
         }
-        InstanceIdentifier ret = InstanceIdentifier.create(baArgs);
+        InstanceIdentifier<?> ret = InstanceIdentifier.create(baArgs);
         LOG.debug("DOM Instance Identifier {} deserialized to {}", input, ret);
         return ret;
     }
@@ -85,23 +89,28 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     @Override
     public InstanceIdentifier<? extends Object> deserialize(
             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input,
-            InstanceIdentifier<?> bindingIdentifier) {
+            final InstanceIdentifier<?> bindingIdentifier) {
         return deserialize(input);
     }
 
-    private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument _deserializePathArgument(
+    private InstanceIdentifier.PathArgument deserializeNodeIdentifier(
             final NodeIdentifier argument, final List<QName> processedPath) {
+        @SuppressWarnings("rawtypes")
         final Class cls = codecRegistry.getClassForPath(processedPath);
+        @SuppressWarnings("unchecked")
         Item<DataObject> item = new Item<>(cls);
         return item;
     }
 
-    private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument _deserializePathArgument(
+    private InstanceIdentifier.PathArgument deserializeNodeIdentifierWithPrecicates(
             final NodeIdentifierWithPredicates argument, final List<QName> processedPath) {
+        @SuppressWarnings("rawtypes")
         final Class type = codecRegistry.getClassForPath(processedPath);
+        @SuppressWarnings({ "unchecked", "rawtypes" })
         final IdentifierCodec codec = codecRegistry
                 .<Identifiable<? extends Object>> getIdentifierCodecForIdentifiable(type);
         CompositeNode _compositeNode = this.toCompositeNode(argument);
+        @SuppressWarnings("unchecked")
         ValueWithQName<CompositeNode> deserialize = codec.deserialize(_compositeNode);
         Object value = null;
         if (deserialize != null) {
@@ -122,27 +131,21 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     @Override
     public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier serialize(final InstanceIdentifier<?> input) {
         Class<?> previousAugmentation = null;
-        List<InstanceIdentifier.PathArgument> pathArgs = input.getPath();
+        Iterable<InstanceIdentifier.PathArgument> pathArgs = input.getPathArguments();
         QName previousQName = null;
-        List<PathArgument> components = new ArrayList<>(pathArgs.size());
-        List<QName> qnamePath = new ArrayList<>(pathArgs.size());
+        List<PathArgument> components = new ArrayList<>();
+        List<QName> qnamePath = new ArrayList<>();
         for (InstanceIdentifier.PathArgument baArg : pathArgs) {
-
             if (!Augmentation.class.isAssignableFrom(baArg.getType())) {
-                org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument biArg = serializePathArgument(
-                        baArg, previousQName);
-                previousQName = biArg.getNodeType();
+                PathArgument biArg = serializePathArgumentAndUpdateMapping(qnamePath, baArg, previousQName,previousAugmentation);
                 components.add(biArg);
                 qnamePath.add(biArg.getNodeType());
-                ImmutableList<QName> immutableList = ImmutableList.copyOf(qnamePath);
-                codecRegistry.putPathToClass(immutableList, baArg.getType());
-                if (previousAugmentation != null) {
-                    updateAugmentationInjection(baArg.getType(), immutableList, previousAugmentation);
-                }
+                previousQName = biArg.getNodeType();
                 previousAugmentation = null;
             } else {
                 previousQName = codecRegistry.getQNameForAugmentation(baArg.getType());
                 previousAugmentation = baArg.getType();
+                ensureAugmentation(qnamePath,previousQName,baArg.getType());
             }
         }
         org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ret = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
@@ -151,15 +154,34 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
         return ret;
     }
 
+    private synchronized void ensureAugmentation(final List<QName> augPath, final QName augQName, final Class<? extends DataObject> type) {
+        Set<List<QName>> augPotential = augmentationAdapted.get(type);
+        if(augPotential == null) {
+            augPotential = new HashSet<>();
+            augmentationAdapted.put(type, augPotential);
+        }
+        ImmutableList<QName> augTargetPath = ImmutableList.copyOf(augPath);
+        if(augPotential.contains(augPath)) {
+            return;
+        }
+
+        for(Class<? extends DataObject> child : BindingReflections.getChildrenClasses(type)) {
+            Item<? extends DataObject> baArg = new Item<>(child);
+            PathArgument biArg = serializePathArgumentAndUpdateMapping(augPath, baArg, augQName,type);
+        }
+        augPotential.add(augTargetPath);
+    }
+
+
     public Class<? extends Object> updateAugmentationInjection(final Class<? extends DataObject> class1,
-            final ImmutableList<QName> list, final Class<?> augmentation) {
+            final List<QName> list, final Class<?> augmentation) {
         if (classToPreviousAugment.get(class1) == null) {
             classToPreviousAugment.put(class1, new ConcurrentHashMap<List<QName>, Class<?>>());
         }
         return classToPreviousAugment.get(class1).put(list, augmentation);
     }
 
-    private PathArgument _serializePathArgument(final Item<?> argument, final QName previousQname) {
+    private PathArgument serializeItem(final Item<?> argument, final QName previousQname) {
         Class<?> type = argument.getType();
         QName qname = BindingReflections.findQName(type);
         if (previousQname == null || (BindingReflections.isAugmentationChild(argument.getType()))) {
@@ -168,15 +190,19 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
         return new NodeIdentifier(QName.create(previousQname, qname.getLocalName()));
     }
 
-    private PathArgument _serializePathArgument(final IdentifiableItem argument, final QName previousQname) {
+    private PathArgument serializeIdentifiableItem(final IdentifiableItem<?,?> argument, final QName previousQname) {
         Map<QName, Object> predicates = new HashMap<>();
+        @SuppressWarnings("rawtypes")
         Class type = argument.getType();
+        @SuppressWarnings("unchecked")
         IdentifierCodec<? extends Object> keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type);
         QName qname = BindingReflections.findQName(type);
         if (previousQname != null && !(BindingReflections.isAugmentationChild(argument.getType()))) {
             qname = QName.create(previousQname, qname.getLocalName());
         }
+        @SuppressWarnings({ "rawtypes", "unchecked" })
         ValueWithQName combinedInput = new ValueWithQName(previousQname, argument.getKey());
+        @SuppressWarnings("unchecked")
         CompositeNode compositeOutput = keyCodec.serialize(combinedInput);
         for (Node<?> outputValue : compositeOutput.getValue()) {
             predicates.put(outputValue.getNodeType(), outputValue.getValue());
@@ -190,26 +216,40 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(
             final PathArgument argument, final List<QName> processedPath) {
         if (argument instanceof NodeIdentifier) {
-            return _deserializePathArgument((NodeIdentifier) argument, processedPath);
+            return deserializeNodeIdentifier((NodeIdentifier) argument, processedPath);
         } else if (argument instanceof NodeIdentifierWithPredicates) {
-            return _deserializePathArgument((NodeIdentifierWithPredicates) argument, processedPath);
+            return deserializeNodeIdentifierWithPrecicates((NodeIdentifierWithPredicates) argument, processedPath);
         } else {
             throw new IllegalArgumentException("Unhandled parameter types: "
                     + Arrays.<Object> asList(argument, processedPath).toString());
         }
     }
 
+    private PathArgument serializePathArgumentAndUpdateMapping(final List<QName> parentPath, final InstanceIdentifier.PathArgument baArg, final QName previousQName, final Class<?> previousAugmentation) {
+        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument biArg = serializePathArgument(baArg, previousQName);
+        List<QName> qnamePath = new ArrayList<>(parentPath);
+        qnamePath.add(biArg.getNodeType());
+        ImmutableList<QName> currentPath = ImmutableList.copyOf(qnamePath);
+        codecRegistry.putPathToClass(currentPath, baArg.getType());
+        if (previousAugmentation != null) {
+            updateAugmentationInjection(baArg.getType(), currentPath, previousAugmentation);
+        }
+        return biArg;
+    }
+
     private PathArgument serializePathArgument(
-            final org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument argument,
+            final InstanceIdentifier.PathArgument argument,
             final QName previousQname) {
         if (argument instanceof IdentifiableItem) {
-            return _serializePathArgument((IdentifiableItem) argument, previousQname);
+            return serializeIdentifiableItem((IdentifiableItem<?,?>) argument, previousQname);
         } else if (argument instanceof Item) {
-            return _serializePathArgument((Item<?>) argument, previousQname);
+            return serializeItem((Item<?>) argument, previousQname);
         } else {
             throw new IllegalArgumentException("Unhandled parameter types: "
                     + Arrays.<Object> asList(argument, previousQname).toString());
         }
     }
 
+
+
 }
index a6bf37629818d798ebf459ee1da9282a7b594a3b..e62f28e6469f2ad1f9a2af9e319b7ca92650ec4a 100644 (file)
@@ -112,7 +112,7 @@ class LazyGeneratedCodecRegistry implements //
     @SuppressWarnings("rawtypes")
     private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
 
-    private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+    private static final Map<SchemaPath, Type> pathToType = new ConcurrentHashMap<>();
     private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
     private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
     private static final BiMap<Type, AugmentationSchema> typeToAugment = HashBiMap
@@ -151,27 +151,36 @@ class LazyGeneratedCodecRegistry implements //
 
     @SuppressWarnings("unchecked")
     @Override
-    public <T extends Augmentation<?>> AugmentationCodecWrapper<T> getCodecForAugmentation(final Class<T> object) {
+    public <T extends Augmentation<?>> AugmentationCodecWrapper<T> getCodecForAugmentation(final Class<T> augClass) {
         AugmentationCodecWrapper<T> codec = null;
         @SuppressWarnings("rawtypes")
-        AugmentationCodecWrapper potentialCodec = augmentationCodecs.get(object);
+        AugmentationCodecWrapper potentialCodec = augmentationCodecs.get(augClass);
         if (potentialCodec != null) {
             codec = potentialCodec;
         } else {
-            lock.waitForSchema(object);
+            lock.waitForSchema(augClass);
             Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
-                    .augmentationTransformerFor(object);
+                    .augmentationTransformerFor(augClass);
 
             BindingCodec<Map<QName, Object>, Object> rawCodec = newInstanceOf(augmentRawCodec);
-            codec = new AugmentationCodecWrapper<T>(rawCodec, null, object);
-            augmentationCodecs.put(object, codec);
+            codec = new AugmentationCodecWrapper<T>(rawCodec, augClass);
+            augmentationCodecs.put(augClass, 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(augClass);
+        } catch (Exception e) {
+            LOG.warn("Failed to find target for augmentation {}, ignoring it", augClass, e);
+            return codec;
         }
+
+        if (objectSupertype == null) {
+            LOG.warn("Augmentation target for {} not found, ignoring it", augClass);
+            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);
@@ -210,7 +207,8 @@ class LazyGeneratedCodecRegistry implements //
 
         @SuppressWarnings("rawtypes")
         final WeakReference<Class> weakRef = typeToClass.get(type);
-        Preconditions.checkState(weakRef != null, "Could not find loaded class for path: %s and type: %s", path, type.getFullyQualifiedName());
+        Preconditions.checkState(weakRef != null, "Could not find loaded class for path: %s and type: %s", path,
+                type.getFullyQualifiedName());
         return weakRef.get();
     }
 
@@ -278,6 +276,8 @@ class LazyGeneratedCodecRegistry implements //
         QName firstNode = path.get(0);
         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();
@@ -329,7 +329,8 @@ class LazyGeneratedCodecRegistry implements //
             LOG.error("Failed to instantiate codec {}", cls.getSimpleName(), e);
             throw new IllegalStateException(String.format("Failed to instantiate codec %s", cls), e);
         } catch (IllegalAccessException e) {
-            LOG.debug("Run-time consistency issue: constructor for {} is not available. This indicates either a code generation bug or a misconfiguration of JVM.",
+            LOG.debug(
+                    "Run-time consistency issue: constructor for {} is not available. This indicates either a code generation bug or a misconfiguration of JVM.",
                     cls.getSimpleName(), e);
             throw new IllegalStateException(String.format("Cannot access contructor of %s", cls), e);
         }
@@ -430,10 +431,10 @@ class LazyGeneratedCodecRegistry implements //
                     identity.getKey());
         }
 
-        synchronized(augmentableToAugmentations) {
+        synchronized (augmentableToAugmentations) {
             augmentableToAugmentations.putAll(context.getAugmentableToAugmentations());
         }
-        synchronized(choiceToCases)  {
+        synchronized (choiceToCases) {
             choiceToCases.putAll(context.getChoiceToCases());
         }
         captureCases(context.getCases(), schemaContext);
@@ -495,7 +496,7 @@ class LazyGeneratedCodecRegistry implements //
             }
             SchemaPath path = caseNode.getPath();
 
-            GeneratedTypeBuilder type;
+            Type type;
             if (path != null && (type = pathToType.get(path)) != null) {
                 ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
                 @SuppressWarnings("rawtypes")
@@ -532,7 +533,7 @@ class LazyGeneratedCodecRegistry implements //
         }
     }
 
-    public AugmentableDispatchCodec getAugmentableCodec(final Class<?> dataClass) {
+    public synchronized AugmentableDispatchCodec getAugmentableCodec(final Class<?> dataClass) {
         AugmentableDispatchCodec ret = augmentableCodecs.get(dataClass);
         if (ret != null) {
             return ret;
@@ -677,43 +678,49 @@ class LazyGeneratedCodecRegistry implements //
             return implementation;
         }
 
-        protected final void adaptForPath(final InstanceIdentifier<?> path) {
+        protected final synchronized void adaptForPath(final InstanceIdentifier<?> path) {
             if (adaptedForPaths.contains(path)) {
                 return;
             }
             /**
-             * We search in schema context if the use of this location aware codec (augmentable codec, case codec)
-             * makes sense on provided location (path)
+             * We search in schema context if the use of this location aware
+             * codec (augmentable codec, case codec) makes sense on provided
+             * location (path)
              *
              */
-            Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema, path);
+            Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema,
+                    path);
             /**
-             * If context node is present, this codec makes sense on provided location.
+             * If context node is present, this codec makes sense on provided
+             * location.
              *
              */
             if (contextNode.isPresent()) {
                 synchronized (this) {
                     /**
                      *
-                     * We adapt (turn on / off) possible implementations of child codecs (augmentations, cases)
-                     * based on this location.
+                     * We adapt (turn on / off) possible implementations of
+                     * child codecs (augmentations, cases) based on this
+                     * location.
                      *
                      *
                      */
+
                     adaptForPathImpl(path, contextNode.get());
-                    try  {
+                    try {
                         /**
-                         * We trigger serialization of instance identifier, to make sure instance identifier
-                         * codec is aware of combination of this path / augmentation / case
+                         * We trigger serialization of instance identifier, to
+                         * make sure instance identifier codec is aware of
+                         * combination of this path / augmentation / case
                          */
                         instanceIdentifierCodec.serialize(path);
                     } catch (Exception e) {
-                        LOG.warn("Exception during preparation of instance identifier codec for  path {}.",path,e);
+                        LOG.warn("Exception during preparation of instance identifier codec for  path {}.", path, e);
                     }
                     adaptedForPaths.add(path);
                 }
             } else {
-                LOG.debug("Context node (parent node) not found for {}",path);
+                LOG.debug("Context node (parent node) not found for {}", path);
             }
         }
 
@@ -837,7 +844,8 @@ class LazyGeneratedCodecRegistry implements //
         }
     }
 
-    private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
+    private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>,
+            Delegator<BindingCodec<Map<QName, Object>, Object>> {
 
         private final BindingCodec<Map<QName, Object>, Object> delegate;
 
@@ -882,7 +890,8 @@ class LazyGeneratedCodecRegistry implements //
     private class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec<ChoiceCaseCodecImpl<?>> {
 
         @Override
-        public Object deserialize(final Object input, @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) {
+        public Object deserialize(final Object input,
+                @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) {
             // TODO Auto-generated method stub
             return null;
         }
@@ -1038,7 +1047,7 @@ class LazyGeneratedCodecRegistry implements //
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    private class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
+    class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
 
         private final Class augmentableType;
 
@@ -1110,7 +1119,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,59 +1129,93 @@ class LazyGeneratedCodecRegistry implements //
             AugmentationCodecWrapper<? extends Augmentation<?>> potentialImpl = getCodecForAugmentation(inputType);
             addImplementation(potentialImpl);
             return potentialImpl;
-
         }
 
         @Override
         protected void tryToLoadImplementations() {
             Type type = referencedType(augmentableType);
             Collection<Type> potentialAugmentations;
-            synchronized(augmentableToAugmentations) {
+            synchronized (augmentableToAugmentations) {
                 potentialAugmentations = new ArrayList(augmentableToAugmentations.get(type));
             }
             for (Type potential : potentialAugmentations) {
                 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
-        protected void adaptForPathImpl(final InstanceIdentifier<?> path, final DataNodeContainer ctxNode) {
+        protected void adaptForPathImpl(final InstanceIdentifier<?> augTarget, final DataNodeContainer ctxNode) {
             if (ctxNode instanceof AugmentationTarget) {
                 Set<AugmentationSchema> availableAugmentations = ((AugmentationTarget) ctxNode)
                         .getAvailableAugmentations();
                 if (!availableAugmentations.isEmpty()) {
-                    updateAugmentationMapping(path,availableAugmentations);
+                    updateAugmentationMapping(augTarget, availableAugmentations);
                 }
-
             }
         }
 
-        private void updateAugmentationMapping(final InstanceIdentifier<?> path, final Set<AugmentationSchema> availableAugmentations) {
+        /**
+         *
+         * Adapts augmentation codec for specific provider location (target)
+         *
+         * Since augmentation are not forward-referencing and may be discovered
+         * during runtime, we need to adapt {@link AugmentableDispatchCodec},
+         * {@link AugmentationCodecWrapper} and {@link InstanceIdentifierCodec}
+         * for this newly discovered location where augmentation may be used.
+         *
+         * Adaptation consists of:
+         * <ol>
+         * <li> scan of available (valid) augmentations for
+         * current location
+         * <li>lookup for Java classes derived from this augmentations
+         * <li>generation of missing codecs
+         * <li>updating Augmentation codecs to work with new location
+         * <li>updating Instance Identifier to work with new location
+         *
+         */
+        private void updateAugmentationMapping(final InstanceIdentifier<?> augTarget,
+                final Set<AugmentationSchema> availableAugmentations) {
             for (AugmentationSchema aug : availableAugmentations) {
 
                 Type potentialType = getTypeForAugmentation(aug);
                 if (potentialType != null) {
                     Optional<AugmentationCodecWrapper> potentialImpl = tryToLoadImplementation(potentialType);
                     if (potentialImpl.isPresent()) {
-                        potentialImpl.get().addApplicableFor(path,aug);
+                        potentialImpl.get().addApplicableFor(augTarget, aug);
+                        Class augType = potentialImpl.get().getDataType();
+                        InstanceIdentifier augPath = augTarget.augmentation(augType);
+                        try {
+
+                            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = getInstanceIdentifierCodec().serialize(augPath);
+                            if(domPath == null) {
+                                LOG.error("Unable to serialize instance identifier for {}",augPath);
+                            }
+                        } catch (Exception e) {
+                            LOG.error("Unable to serialize instance identifiers for {}",augPath,e);
+                        }
+
                     }
                 } else {
-                    LOG.warn("Could not find generated type for augmentation {} with childs {}.",aug,aug.getChildNodes());
+                    // Omits warning for empty augmentations since they are not represented in data
+                    if(!aug.getChildNodes().isEmpty()) {
+                        LOG.warn("Could not find generated type for augmentation {} with children {}", aug,
+                            aug.getChildNodes());
+                    }
                 }
             }
-            availableAugmentations.toString();
         }
 
+
+
         private Type getTypeForAugmentation(final AugmentationSchema aug) {
             Optional<AugmentationSchema> currentAug = Optional.of(aug);
-            while(currentAug.isPresent()) {
+            while (currentAug.isPresent()) {
                 Type potentialType = typeToAugment.inverse().get(currentAug.get());
-                if(potentialType != null) {
+                if (potentialType != null) {
                     return potentialType;
                 }
                 currentAug = currentAug.get().getOriginalDefinition();
@@ -1217,20 +1260,20 @@ class LazyGeneratedCodecRegistry implements //
 
         private final BindingCodec delegate;
         private final QName augmentationQName;
-        private final Multimap<InstanceIdentifier<?>,QName> validAugmentationTargets;
+        private final Multimap<InstanceIdentifier<?>, QName> validAugmentationTargets;
         private final Class<?> augmentationType;
 
-        public AugmentationCodecWrapper(final BindingCodec<Map<QName, Object>, Object> rawCodec,
-                final InstanceIdentifier<?> targetId, final Class<?> dataType) {
+        public AugmentationCodecWrapper(final BindingCodec<Map<QName, Object>, Object> rawCodec, final Class<?> dataType) {
             this.delegate = rawCodec;
             this.augmentationType = dataType;
             this.augmentationQName = BindingReflections.findQName(rawCodec.getClass());
-            this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap.<InstanceIdentifier<?>,QName>create());
+            this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap
+                    .<InstanceIdentifier<?>, QName> create());
         }
 
         public void addApplicableFor(final InstanceIdentifier<?> path, final AugmentationSchema aug) {
-            for(DataSchemaNode child : aug.getChildNodes()) {
-                validAugmentationTargets.put(path,child.getQName());
+            for (DataSchemaNode child : aug.getChildNodes()) {
+                validAugmentationTargets.put(path, child.getQName());
             }
         }
 
@@ -1326,7 +1369,7 @@ class LazyGeneratedCodecRegistry implements //
         }
 
         @Override
-        public Object deserialize(final Object input,final InstanceIdentifier bindingIdentifier) {
+        public Object deserialize(final Object input, final InstanceIdentifier bindingIdentifier) {
             Type type = qnamesToIdentityMap.get(input);
             if (type == null) {
                 return null;
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 eefb847ff63046cb408857387390daea88c75614..a2bc6da9394ea0b0265313bcd9dcf38a8609f7a4 100644 (file)
@@ -39,13 +39,13 @@ abstract class AbstractGeneratedType extends AbstractBaseType implements Generat
     private final List<GeneratedProperty> properties;
     private final boolean isAbstract;
 
-    public AbstractGeneratedType(AbstractGeneratedTypeBuilder<?> builder) {
+    public AbstractGeneratedType(final AbstractGeneratedTypeBuilder<?> builder) {
         super(builder.getPackageName(), builder.getName());
         this.parent = builder.getParent();
         this.comment = builder.getComment();
         this.annotations = toUnmodifiableAnnotations(builder.getAnnotations());
-        this.implementsTypes = Collections.unmodifiableList(builder.getImplementsTypes());
-        this.constants = Collections.unmodifiableList(builder.getConstants());
+        this.implementsTypes = makeUnmodifiable(builder.getImplementsTypes());
+        this.constants = makeUnmodifiable(builder.getConstants());
         this.enumerations = toUnmodifiableEnumerations(builder.getEnumerations());
         this.methodSignatures = toUnmodifiableMethods(builder.getMethodDefinitions());
         this.enclosedTypes = toUnmodifiableEnclosedTypes(builder.getEnclosedTypes(),
@@ -64,19 +64,29 @@ abstract class AbstractGeneratedType extends AbstractBaseType implements Generat
         this.parent = parent;
         this.comment = comment;
         this.annotations = toUnmodifiableAnnotations(annotationBuilders);
-        this.implementsTypes = Collections.unmodifiableList(implementsTypes);
-        this.constants = Collections.unmodifiableList(constants);
+        this.implementsTypes = makeUnmodifiable(implementsTypes);
+        this.constants = makeUnmodifiable(constants);
         this.enumerations = toUnmodifiableEnumerations(enumBuilders);
         this.methodSignatures = toUnmodifiableMethods(methodBuilders);
         this.enclosedTypes = toUnmodifiableEnclosedTypes(enclosedGenTypeBuilders, enclosedGenTOBuilders);
         this.properties = toUnmodifiableProperties(propertyBuilders);
         this.isAbstract = isAbstract;
+    }
 
+    protected static final <T> List<T> makeUnmodifiable(final List<T> list) {
+        switch (list.size()) {
+        case 0:
+            return Collections.emptyList();
+        case 1:
+            return Collections.singletonList(list.get(0));
+        default:
+            return Collections.unmodifiableList(list);
+        }
     }
 
-    private List<GeneratedType> toUnmodifiableEnclosedTypes(final List<GeneratedTypeBuilder> enclosedGenTypeBuilders,
+    private static List<GeneratedType> toUnmodifiableEnclosedTypes(final List<GeneratedTypeBuilder> enclosedGenTypeBuilders,
             final List<GeneratedTOBuilder> enclosedGenTOBuilders) {
-        final List<GeneratedType> enclosedTypesList = new ArrayList<>();
+        final ArrayList<GeneratedType> enclosedTypesList = new ArrayList<>(enclosedGenTypeBuilders.size() + enclosedGenTOBuilders.size());
         for (final GeneratedTypeBuilder builder : enclosedGenTypeBuilders) {
             if (builder != null) {
                 enclosedTypesList.add(builder.toInstance());
@@ -88,39 +98,40 @@ abstract class AbstractGeneratedType extends AbstractBaseType implements Generat
                 enclosedTypesList.add(builder.toInstance());
             }
         }
-        return enclosedTypesList;
+
+        return makeUnmodifiable(enclosedTypesList);
     }
 
-    protected final List<AnnotationType> toUnmodifiableAnnotations(final List<AnnotationTypeBuilder> annotationBuilders) {
-        final List<AnnotationType> annotationList = new ArrayList<>();
+    protected static final List<AnnotationType> toUnmodifiableAnnotations(final List<AnnotationTypeBuilder> annotationBuilders) {
+        final List<AnnotationType> annotationList = new ArrayList<>(annotationBuilders.size());
         for (final AnnotationTypeBuilder builder : annotationBuilders) {
             annotationList.add(builder.toInstance());
         }
-        return Collections.unmodifiableList(annotationList);
+        return makeUnmodifiable(annotationList);
     }
 
-    protected final List<MethodSignature> toUnmodifiableMethods(List<MethodSignatureBuilder> methodBuilders) {
-        final List<MethodSignature> methods = new ArrayList<>();
+    protected final List<MethodSignature> toUnmodifiableMethods(final List<MethodSignatureBuilder> methodBuilders) {
+        final List<MethodSignature> methods = new ArrayList<>(methodBuilders.size());
         for (final MethodSignatureBuilder methodBuilder : methodBuilders) {
             methods.add(methodBuilder.toInstance(this));
         }
-        return Collections.unmodifiableList(methods);
+        return makeUnmodifiable(methods);
     }
 
-    protected final List<Enumeration> toUnmodifiableEnumerations(List<EnumBuilder> enumBuilders) {
-        final List<Enumeration> enums = new ArrayList<>();
+    protected final List<Enumeration> toUnmodifiableEnumerations(final List<EnumBuilder> enumBuilders) {
+        final List<Enumeration> enums = new ArrayList<>(enumBuilders.size());
         for (final EnumBuilder enumBuilder : enumBuilders) {
             enums.add(enumBuilder.toInstance(this));
         }
-        return Collections.unmodifiableList(enums);
+        return makeUnmodifiable(enums);
     }
 
-    protected final List<GeneratedProperty> toUnmodifiableProperties(List<GeneratedPropertyBuilder> methodBuilders) {
-        final List<GeneratedProperty> methods = new ArrayList<>();
+    protected final List<GeneratedProperty> toUnmodifiableProperties(final List<GeneratedPropertyBuilder> methodBuilders) {
+        final List<GeneratedProperty> methods = new ArrayList<>(methodBuilders.size());
         for (final GeneratedPropertyBuilder methodBuilder : methodBuilders) {
             methods.add(methodBuilder.toInstance(this));
         }
-        return Collections.unmodifiableList(methods);
+        return makeUnmodifiable(methods);
     }
 
     @Override
index b3bb7425754fb996bc774980c25af7fb157f8965..1adbe05d3300cf587c4b8df4712f0f07747a840b 100644 (file)
@@ -80,7 +80,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     protected abstract T thisInstance();
 
     @Override
-    public GeneratedTOBuilder addEnclosingTransferObject(String name) {
+    public GeneratedTOBuilder addEnclosingTransferObject(final String name) {
         if (name == null) {
             throw new IllegalArgumentException("Name for Enclosing Generated Transfer Object cannot be null!");
         }
@@ -99,7 +99,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public T addComment(String comment) {
+    public T addComment(final String comment) {
         this.comment = comment;
         return thisInstance();
     }
@@ -119,13 +119,13 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public T setAbstract(boolean isAbstract) {
+    public T setAbstract(final boolean isAbstract) {
         this.isAbstract = isAbstract;
         return thisInstance();
     }
 
     @Override
-    public T addImplementsType(Type genType) {
+    public T addImplementsType(final Type genType) {
         if (genType == null) {
             throw new IllegalArgumentException("Type cannot be null");
         }
@@ -134,7 +134,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public Constant addConstant(Type type, String name, Object value) {
+    public Constant addConstant(final Type type, final String name, final Object value) {
         if (type == null) {
             throw new IllegalArgumentException("Returning Type for Constant cannot be null!");
         }
@@ -148,7 +148,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public EnumBuilder addEnumeration(String name) {
+    public EnumBuilder addEnumeration(final String name) {
         if (name == null) {
             throw new IllegalArgumentException("Name of enumeration cannot be null!");
         }
@@ -158,7 +158,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public MethodSignatureBuilder addMethod(String name) {
+    public MethodSignatureBuilder addMethod(final String name) {
         if (name == null) {
             throw new IllegalArgumentException("Name of method cannot be null!");
         }
@@ -170,7 +170,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public boolean containsMethod(String name) {
+    public boolean containsMethod(final String name) {
         if (name == null) {
             throw new IllegalArgumentException("Parameter name can't be null");
         }
@@ -183,7 +183,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public GeneratedPropertyBuilder addProperty(String name) {
+    public GeneratedPropertyBuilder addProperty(final String name) {
         final GeneratedPropertyBuilder builder = new GeneratedPropertyBuilderImpl(name);
         builder.setAccessModifier(AccessModifier.PUBLIC);
         properties.add(builder);
@@ -191,7 +191,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public boolean containsProperty(String name) {
+    public boolean containsProperty(final String name) {
         if (name == null) {
             throw new IllegalArgumentException("Parameter name can't be null");
         }
@@ -213,7 +213,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(final Object obj) {
         if (this == obj) {
             return true;
         }
@@ -223,7 +223,7 @@ abstract class AbstractGeneratedTypeBuilder<T extends GeneratedTypeBuilderBase<T
         if (getClass() != obj.getClass()) {
             return false;
         }
-        AbstractGeneratedTypeBuilder<T> other = (AbstractGeneratedTypeBuilder<T>) obj;
+        AbstractGeneratedTypeBuilder<?> other = (AbstractGeneratedTypeBuilder<?>) obj;
         if (getName() == null) {
             if (other.getName() != null) {
                 return false;
index 51721882883201c377ddb8e51c1a2e237aef3928..cfadce1a5e6f36938bbaacc8f06ea5af7759c0de 100644 (file)
@@ -29,11 +29,11 @@ abstract class AbstractTypeMember implements TypeMember {
 
     public AbstractTypeMember(final Type definingType, final String name,  final List<AnnotationType> annotations,
                               final String comment, final AccessModifier accessModifier, final Type returnType,
-                              boolean isFinal, boolean isStatic) {
+                              final boolean isFinal, final boolean isStatic) {
         super();
         this.definingType = definingType;
         this.name = name;
-        this.annotations = Collections.unmodifiableList(annotations);
+        this.annotations = annotations.isEmpty() ? Collections.<AnnotationType>emptyList() : Collections.unmodifiableList(annotations);
         this.comment = comment;
         this.accessModifier = accessModifier;
         this.returnType = returnType;
@@ -92,7 +92,7 @@ abstract class AbstractTypeMember implements TypeMember {
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(final Object obj) {
         if (this == obj) {
             return true;
         }
index a2ecc1018d1d765fba3a1c5a5ae67baf47bf7d2a..b3b1c7ce256ddff61166bc341dbafdfdc1b966ab 100644 (file)
@@ -23,16 +23,16 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
         GeneratedTOBuilder {
 
     private GeneratedTransferObject extendsType;
-    private final List<GeneratedPropertyBuilder> equalsProperties = new ArrayList<>();
-    private final List<GeneratedPropertyBuilder> hashProperties = new ArrayList<>();
-    private final List<GeneratedPropertyBuilder> toStringProperties = new ArrayList<>();
+    private final ArrayList<GeneratedPropertyBuilder> equalsProperties = new ArrayList<>();
+    private final ArrayList<GeneratedPropertyBuilder> hashProperties = new ArrayList<>();
+    private final ArrayList<GeneratedPropertyBuilder> toStringProperties = new ArrayList<>();
     private boolean isTypedef = false;
     private boolean isUnionType = false;
     private boolean isUnionTypeBuilder = false;
     private Restrictions restrictions;
     private GeneratedPropertyBuilder SUID;
 
-    public GeneratedTOBuilderImpl(String packageName, String name) {
+    public GeneratedTOBuilderImpl(final String packageName, final String name) {
         super(packageName, name);
         setAbstract(false);
     }
@@ -61,26 +61,26 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
      * @return <code>new</code> instance of Method Signature Builder.
      */
     @Override
-    public MethodSignatureBuilder addMethod(String name) {
+    public MethodSignatureBuilder addMethod(final String name) {
         final MethodSignatureBuilder builder = super.addMethod(name);
         builder.setAbstract(false);
         return builder;
     }
 
     @Override
-    public GeneratedTOBuilder addEqualsIdentity(GeneratedPropertyBuilder property) {
+    public GeneratedTOBuilder addEqualsIdentity(final GeneratedPropertyBuilder property) {
         equalsProperties.add(property);
         return this;
     }
 
     @Override
-    public GeneratedTOBuilder addHashIdentity(GeneratedPropertyBuilder property) {
+    public GeneratedTOBuilder addHashIdentity(final GeneratedPropertyBuilder property) {
         hashProperties.add(property);
         return this;
     }
 
     @Override
-    public GeneratedTOBuilder addToStringProperty(GeneratedPropertyBuilder property) {
+    public GeneratedTOBuilder addToStringProperty(final GeneratedPropertyBuilder property) {
         toStringProperties.add(property);
         return this;
     }
@@ -91,17 +91,18 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
     }
 
     @Override
-    public void setRestrictions(Restrictions restrictions) {
+    public void setRestrictions(final Restrictions restrictions) {
         this.restrictions = restrictions;
     }
 
     @Override
-    public void setSUID(GeneratedPropertyBuilder suid) {
+    public void setSUID(final GeneratedPropertyBuilder suid) {
         this.SUID = suid;
     }
 
     @Override
     public GeneratedTransferObject toInstance() {
+        // FIXME: can we compact the arrays now? It needs to be thread-safe, though
         return new GeneratedTransferObjectImpl(this);
     }
 
@@ -133,17 +134,17 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
     }
 
     @Override
-    public void setTypedef(boolean isTypedef) {
+    public void setTypedef(final boolean isTypedef) {
         this.isTypedef = isTypedef;
     }
 
     @Override
-    public void setIsUnion(boolean isUnion) {
+    public void setIsUnion(final boolean isUnion) {
         this.isUnionType = isUnion;
     }
 
     @Override
-    public void setIsUnionBuilder(boolean isUnionTypeBuilder) {
+    public void setIsUnionBuilder(final boolean isUnionTypeBuilder) {
         this.isUnionTypeBuilder = isUnionTypeBuilder;
     }
 
@@ -160,7 +161,7 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
         private final Restrictions restrictions;
         private final GeneratedProperty SUID;
 
-        public GeneratedTransferObjectImpl(GeneratedTOBuilderImpl builder) {
+        public GeneratedTransferObjectImpl(final GeneratedTOBuilderImpl builder) {
             super(builder);
             this.extendsType = builder.extendsType;
             this.equalsProperties = toUnmodifiableProperties(builder.equalsProperties);
@@ -260,7 +261,7 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
             return builder.toString();
         }
 
-        public String serializeTypedef(Type type) {
+        public String serializeTypedef(final Type type) {
             if (type instanceof ParameterizedType) {
                 ParameterizedType parameterizedType = (ParameterizedType) type;
                 StringBuffer sb = new StringBuffer();
index db0a31b8bdf8845c55bdb2d4b8cc7a8804d78315..7d954465df34d83b3234563e28d66c7065d81462 100644 (file)
@@ -207,6 +207,8 @@ class BuilderTemplate extends BaseTemplate {
 
             Â«generateFields(false)»
 
+            Â«generateAugmentField(true)»
+
             Â«generateConstructorsFromIfcs(type)»
 
             Â«generateMethodFieldsFrom(type)»
@@ -225,6 +227,8 @@ class BuilderTemplate extends BaseTemplate {
 
                 Â«generateFields(true)»
 
+                Â«generateAugmentField(false)»
+
                 Â«generateConstructor»
 
                 Â«generateGetters(true)»
@@ -256,7 +260,7 @@ class BuilderTemplate extends BaseTemplate {
     /**
      * Generate constructor with argument of given type.
      */
-    def private generateConstructorFromIfc(Type impl) '''
+    def private Object generateConstructorFromIfc(Type impl) '''
         Â«IF (impl instanceof GeneratedType)»
             Â«val implType = impl as GeneratedType»
 
@@ -271,7 +275,7 @@ class BuilderTemplate extends BaseTemplate {
         Â«ENDIF»
     '''
 
-    def private printConstructorPropertySetter(Type implementedIfc) '''
+    def private Object printConstructorPropertySetter(Type implementedIfc) '''
         Â«IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
             Â«val ifc = implementedIfc as GeneratedType»
             Â«FOR getter : ifc.methodDefinitions»
@@ -398,8 +402,11 @@ class BuilderTemplate extends BaseTemplate {
                 private«IF _final» final«ENDIF» Â«f.returnType.importedName» Â«f.fieldName»;
             Â«ENDFOR»
         Â«ENDIF»
+    '''
+
+    def private generateAugmentField(boolean init) '''
         Â«IF augmentField != null»
-            private Â«Map.importedName»<Class<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»> Â«augmentField.name» = new Â«HashMap.importedName»<>();
+            private final Â«Map.importedName»<Class<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»> Â«augmentField.name»«IF init» = new Â«HashMap.importedName»<>()«ENDIF»;
         Â«ENDIF»
     '''
 
@@ -467,7 +474,17 @@ class BuilderTemplate extends BaseTemplate {
                 this.«field.fieldName» = builder.«field.getterMethodName»();
             Â«ENDFOR»
             Â«IF augmentField != null»
-                this.«augmentField.name».putAll(builder.«augmentField.name»);
+               switch (builder.«augmentField.name».size()) {
+                case 0:
+                    this.«augmentField.name» = Â«Collections.importedName».emptyMap();
+                    break;
+                case 1:
+                    final Â«Map.importedName».Entry<Class<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»> e = builder.«augmentField.name».entrySet().iterator().next();
+                    this.«augmentField.name» = Â«Collections.importedName».<Class<? extends Â«augmentField.returnType.importedName»>, Â«augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue());
+                    break;
+                default :
+                    this.«augmentField.name» = new Â«HashMap.importedName»<>(builder.«augmentField.name»);
+                }
             Â«ENDIF»
         }
     '''
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..0b057a194bc86b1d79a8218b67e820eb88dee819 100644 (file)
@@ -9,11 +9,13 @@ 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.LinkedList;
+import java.util.List;
 import java.util.ServiceLoader;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Future;
@@ -21,7 +23,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 +35,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;
 
@@ -57,7 +57,17 @@ public class BindingReflections {
             .expireAfterAccess(EXPIRATION_TIME, TimeUnit.SECONDS) //
             .build(new ClassToQNameLoader());
 
+
+    private BindingReflections() {
+        throw new UnsupportedOperationException("Utility class.");
+    }
+
     /**
+     *
+     * Find augmentation target class from concrete Augmentation class
+     *
+     * This method uses first generic argument of
+     * implemented {@link Augmentation} interface.
      *
      * @param augmentation
      *            {@link Augmentation} subclass for which we want to determine
@@ -71,6 +81,10 @@ public class BindingReflections {
     }
 
     /**
+     * Find data hierarchy parent from concrete Data class
+     *
+     * This method uses first generic argument of
+     * implemented {@link ChildOf} interface.
      *
      * @param augmentation
      *            {@link Augmentation} subclass for which we want to determine
@@ -83,16 +97,20 @@ public class BindingReflections {
     }
 
     /**
+     * Find data hierarchy parent from concrete Data class
      *
-     * @param augmentation
+     * This method is shorthand which gets DataObject class by invoking
+     * {@link DataObject#getImplementedInterface()} and uses {@link #findHierarchicalParent(Class)}.
+     *
+     * @param childClass
      *            {@link Augmentation} subclass for which we want to determine
      *            augmentation target.
      * @return Augmentation target - class which augmentation provides
      *         additional extensions.
      */
-    public static Class<?> findHierarchicalParent(final DataObject childClass) {
-        if (childClass instanceof ChildOf) {
-            return ClassLoaderUtils.findFirstGenericArgument(childClass.getImplementedInterface(), ChildOf.class);
+    public static Class<?> findHierarchicalParent(final DataObject child) {
+        if (child instanceof ChildOf) {
+            return ClassLoaderUtils.findFirstGenericArgument(child.getImplementedInterface(), ChildOf.class);
         }
         return null;
     }
@@ -101,43 +119,39 @@ public class BindingReflections {
      * Returns a QName associated to supplied type
      *
      * @param dataType
-     * @return QName associated to supplied dataType. If dataType is Augmentation
-     *    method does not return canonical QName, but QName with correct namespace
-     *    revision, but virtual local name, since augmentations do not have name.
+     * @return QName associated to supplied dataType. If dataType is
+     *         Augmentation method does not return canonical QName, but QName
+     *         with correct namespace revision, but virtual local name, since
+     *         augmentations do not have name.
+     *
+     *         May return null if QName is not present.
      */
     public static final QName findQName(final Class<?> dataType) {
         return classToQName.getUnchecked(dataType).orNull();
     }
 
-    private static class ClassToQNameLoader extends CacheLoader<Class<?>, Optional<QName>> {
-
-        @Override
-        public Optional<QName> load(final Class<?> key) throws Exception {
-            try {
-                Field field = key.getField(BindingMapping.QNAME_STATIC_FIELD_NAME);
-                Object obj = field.get(null);
-                if (obj instanceof QName) {
-                    return Optional.of((QName) obj);
-                }
-            } catch (NoSuchFieldException e) {
-                if(Augmentation.class.isAssignableFrom(key)) {
-                    YangModuleInfo moduleInfo = getModuleInfo(key);
-                    return Optional.of(QName.create(moduleInfo.getNamespace(), moduleInfo.getRevision(), moduleInfo.getName()));
-                }
-
-            } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
-                // NOOP
-            }
-            return Optional.absent();
-        }
-    }
-
+    /**
+     * Checks if method is RPC invocation
+     *
+     *
+     *
+     * @param possibleMethod Method to check
+     * @return true if method is RPC invocation, false otherwise.
+     */
     public static boolean isRpcMethod(final Method possibleMethod) {
         return possibleMethod != null && RpcService.class.isAssignableFrom(possibleMethod.getDeclaringClass())
                 && Future.class.isAssignableFrom(possibleMethod.getReturnType())
                 && possibleMethod.getParameterTypes().length <= 1;
     }
 
+    /**
+     *
+     * Extracts Output class for RPC method
+     *
+     * @param targetMethod method to scan
+     * @return Optional.absent() if result type could not be get,
+     *         or return type is Void.
+     */
     @SuppressWarnings("rawtypes")
     public static Optional<Class<?>> resolveRpcOutputClass(final Method targetMethod) {
         checkState(isRpcMethod(targetMethod), "Supplied method is not Rpc invocation method");
@@ -150,6 +164,13 @@ public class BindingReflections {
         return Optional.absent();
     }
 
+    /**
+     *
+     * Extracts input class for RPC method
+     *
+     * @param targetMethod method to scan
+     * @return Optional.absent() if rpc has no input, Rpc input type otherwise.
+     */
     @SuppressWarnings("unchecked")
     public static Optional<Class<? extends DataContainer>> resolveRpcInputClass(final Method targetMethod) {
         @SuppressWarnings("rawtypes")
@@ -167,6 +188,14 @@ public class BindingReflections {
         return findQName(context);
     }
 
+    /**
+     *
+     * Checks if class is child of augmentation.
+     *
+     *
+     * @param clazz
+     * @return
+     */
     public static boolean isAugmentationChild(final Class<?> clazz) {
         // FIXME: Current resolver could be still confused when
         // child node was added by grouping
@@ -185,27 +214,48 @@ public class BindingReflections {
         return !clazzModelPackage.equals(parentModelPackage);
     }
 
+    /**
+     * Returns root package name for suplied package.
+     *
+     * @param pkg Package for which find model root package.
+     * @return Package of model root.
+     */
     public static String getModelRootPackageName(final Package pkg) {
         return getModelRootPackageName(pkg.getName());
     }
 
+    /**
+     * Returns root package name for suplied package name.
+     *
+     * @param pkg Package for which find model root package.
+     * @return Package of model root.
+     */
     public static String getModelRootPackageName(final String name) {
         checkArgument(name != null, "Package name should not be null.");
         checkArgument(name.startsWith(BindingMapping.PACKAGE_PREFIX), "Package name not starting with %s, is: %s",
                 BindingMapping.PACKAGE_PREFIX, name);
         Matcher match = ROOT_PACKAGE_PATTERN.matcher(name);
-        checkArgument(match.find(),"Package name '%s' does not match required pattern '%s'",name,ROOT_PACKAGE_PATTERN_STRING);
+        checkArgument(match.find(), "Package name '%s' does not match required pattern '%s'", name,
+                ROOT_PACKAGE_PATTERN_STRING);
         return match.group(0);
     }
 
+    /**
+     *
+     * Returns instance of {@link YangModuleInfo} of declaring model for specific class.
+     *
+     * @param cls
+     * @return Instance of {@link YangModuleInfo} associated with model, from which this class was derived.
+     * @throws Exception
+     */
     public static YangModuleInfo getModuleInfo(final Class<?> cls) throws Exception {
         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);
             }
@@ -216,6 +266,13 @@ public class BindingReflections {
         return packageName + "." + BindingMapping.MODULE_INFO_CLASS_NAME;
     }
 
+    /**
+     *
+     * Check if supplied class is derived from YANG model.
+     *
+     * @param cls Class to check
+     * @return true if class is derived from YANG model.
+     */
     public static boolean isBindingClass(final Class<?> cls) {
         if (DataContainer.class.isAssignableFrom(cls) || Augmentation.class.isAssignableFrom(cls)) {
             return true;
@@ -223,6 +280,13 @@ public class BindingReflections {
         return (cls.getName().startsWith(BindingMapping.PACKAGE_PREFIX));
     }
 
+    /**
+     *
+     * Checks if supplied method is callback for notifications.
+     *
+     * @param method
+     * @return true if method is notification callback.
+     */
     public static boolean isNotificationCallback(final Method method) {
         checkArgument(method != null);
         if (method.getName().startsWith("on") && method.getParameterTypes().length == 1) {
@@ -235,38 +299,171 @@ public class BindingReflections {
         return false;
     }
 
+    /**
+     *
+     * Checks is supplied class is Notification.
+     *
+     * @param potentialNotification
+     * @return
+     */
     public static boolean isNotification(final Class<?> potentialNotification) {
-        checkArgument(potentialNotification != null);
+        checkArgument(potentialNotification != null,"potentialNotification must not be null.");
         return Notification.class.isAssignableFrom(potentialNotification);
     }
 
+    /**
+     *
+     * Loads {@link YangModuleInfo} infos available on current classloader.
+     *
+     * This method is shorthand for {@link #loadModuleInfos(ClassLoader)} with
+     * {@link Thread#getContextClassLoader()} for current thread.
+     *
+     * @return Set of {@link YangModuleInfo} available for current classloader.
+     */
     public static ImmutableSet<YangModuleInfo> loadModuleInfos() {
         return loadModuleInfos(Thread.currentThread().getContextClassLoader());
     }
 
+    /**
+    *
+    * Loads {@link YangModuleInfo} infos available on supplied classloader.
+    *
+    * {@link YangModuleInfo} are discovered using {@link ServiceLoader}
+    * for {@link YangModelBindingProvider}. {@link YangModelBindingProvider}
+    * are simple classes which holds only pointers to actual instance
+    * {@link YangModuleInfo}.
+    *
+    * When {@link YangModuleInfo} is available, all dependencies are recursivelly collected
+    * into returning set by collecting results of {@link YangModuleInfo#getImportedModules()}.
+    *
+    *
+    * @param loader Classloader for which {@link YangModuleInfo} should be retrieved.
+    * @return Set of {@link YangModuleInfo} available for supplied classloader.
+    */
     public static ImmutableSet<YangModuleInfo> loadModuleInfos(final ClassLoader loader) {
-        Builder<YangModuleInfo> moduleInfoSet = ImmutableSet.<YangModuleInfo>builder();
-        ServiceLoader<YangModelBindingProvider> serviceLoader = ServiceLoader.load(YangModelBindingProvider.class, loader);
-        for(YangModelBindingProvider bindingProvider : serviceLoader) {
+        Builder<YangModuleInfo> moduleInfoSet = ImmutableSet.<YangModuleInfo> builder();
+        ServiceLoader<YangModelBindingProvider> serviceLoader = ServiceLoader.load(YangModelBindingProvider.class,
+                loader);
+        for (YangModelBindingProvider bindingProvider : serviceLoader) {
             YangModuleInfo moduleInfo = bindingProvider.getModuleInfo();
-            checkState(moduleInfo != null, "Module Info for %s is not available.",bindingProvider.getClass());
-            collectYangModuleInfo(bindingProvider.getModuleInfo(),moduleInfoSet);
+            checkState(moduleInfo != null, "Module Info for %s is not available.", bindingProvider.getClass());
+            collectYangModuleInfo(bindingProvider.getModuleInfo(), moduleInfoSet);
         }
-        return  moduleInfoSet.build();
+        return moduleInfoSet.build();
     }
 
-    private static void collectYangModuleInfo(final YangModuleInfo moduleInfo, final Builder<YangModuleInfo> moduleInfoSet) {
+    private static void collectYangModuleInfo(final YangModuleInfo moduleInfo,
+            final Builder<YangModuleInfo> moduleInfoSet) {
         moduleInfoSet.add(moduleInfo);
-        for(YangModuleInfo dependency : moduleInfo.getImportedModules()) {
+        for (YangModuleInfo dependency : moduleInfo.getImportedModules()) {
             collectYangModuleInfo(dependency, moduleInfoSet);
         }
     }
 
+    /**
+     *
+     * Checks if supplied class represents RPC Input / RPC Output.
+     *
+     * @param targetType Class to be checked
+     * @return true if class represents RPC Input or RPC Output class.
+     */
     public static boolean isRpcType(final Class<? extends DataObject> targetType) {
-        return  DataContainer.class.isAssignableFrom(targetType) //
+        return DataContainer.class.isAssignableFrom(targetType) //
                 && !ChildOf.class.isAssignableFrom(targetType) //
                 && !Notification.class.isAssignableFrom(targetType) //
                 && (targetType.getName().endsWith("Input") || targetType.getName().endsWith("Output"));
     }
 
+    /**
+     *
+     * Scans supplied class and returns an iterable of all data children classes.
+     *
+     * @param type YANG Modeled Entity derived from DataContainer
+     * @return Iterable of all data children, which have YANG modeled entity
+     */
+    @SuppressWarnings("unchecked")
+    public static Iterable<Class<? extends DataObject>> getChildrenClasses(final Class<? extends DataContainer> type) {
+        checkArgument(type != null, "Target type must not be null");
+        checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer");
+        List<Class<? extends DataObject>> ret = new LinkedList<>();
+        for (Method method : type.getMethods()) {
+            Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method);
+            if (entity.isPresent()) {
+                ret.add((Class<? extends DataObject>) entity.get());
+            }
+        }
+        return ret;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method) {
+        if (method.getName().equals("getClass") || !method.getName().startsWith("get")
+                || method.getParameterTypes().length > 0) {
+            return Optional.absent();
+        }
+
+        @SuppressWarnings("rawtypes")
+        Class returnType = method.getReturnType();
+        if (DataContainer.class.isAssignableFrom(returnType)) {
+            return Optional.<Class<? extends DataContainer>> of(returnType);
+        } else if (List.class.isAssignableFrom(returnType)) {
+            try {
+                return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
+                        new Callable<Optional<Class<? extends DataContainer>>>() {
+                            @SuppressWarnings("rawtypes")
+                            @Override
+                            public Optional<Class<? extends DataContainer>> call() {
+                                Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
+                                        .getGenericReturnType());
+                                if (listResult instanceof Class
+                                        && DataContainer.class.isAssignableFrom((Class) listResult)) {
+                                    return Optional.<Class<? extends DataContainer>> of((Class) listResult);
+                                }
+                                return Optional.absent();
+                            }
+
+                        });
+            } catch (Exception e) {
+                /*
+                 *
+                 * It is safe to log this this exception on debug, since
+                 * this method should not fail. Only failures are possible if
+                 * the runtime / backing.
+                 *
+                 */
+                LOG.debug("Unable to find YANG modeled return type for {}", method, e);
+            }
+        }
+        return Optional.absent();
+    }
+
+    private static class ClassToQNameLoader extends CacheLoader<Class<?>, Optional<QName>> {
+
+        @Override
+        public Optional<QName> load(final Class<?> key) throws Exception {
+            try {
+                Field field = key.getField(BindingMapping.QNAME_STATIC_FIELD_NAME);
+                Object obj = field.get(null);
+                if (obj instanceof QName) {
+                    return Optional.of((QName) obj);
+                }
+            } catch (NoSuchFieldException e) {
+                if (Augmentation.class.isAssignableFrom(key)) {
+                    YangModuleInfo moduleInfo = getModuleInfo(key);
+                    return Optional.of(QName.create(moduleInfo.getNamespace(), moduleInfo.getRevision(),
+                            moduleInfo.getName()));
+                }
+            } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
+                /*
+                 *
+                 * It is safe to log this this exception on debug, since
+                 * this method should not fail. Only failures are possible if
+                 * the runtime / backing.
+                 *
+                 */
+                LOG.debug("Unexpected exception during extracting QName for {}",key,e);
+            }
+            return Optional.absent();
+        }
+    }
 }
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..fab5061
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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");
+    }
+
+    /**
+     *
+     * Runs {@link Supplier} with provided {@link ClassLoader}.
+     *
+     * Invokes supplies function and makes sure that original {@link ClassLoader}
+     * is context {@link ClassLoader} after execution.
+     *
+     * @param cls {@link ClassLoader} to be used.
+     * @param function Function to be executed.
+     * @return Result of supplier invocation.
+     *
+     */
+    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);
+        }
+    }
+
+    /**
+    *
+    * Runs {@link Callable} with provided {@link ClassLoader}.
+    *
+    * Invokes supplies function and makes sure that original {@link ClassLoader}
+    * is context {@link ClassLoader} after execution.
+    *
+    * @param cls {@link ClassLoader} to be used.
+    * @param function Function to be executed.
+    * @return Result of callable invocation.
+    *
+    */
+    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);
+        }
+    }
+
+   /**
+    *
+    * Runs {@link Callable} with provided {@link ClassLoader} and Lock.
+    *
+    * Invokes supplies function after acquiring lock
+    * and makes sure that original {@link ClassLoader}
+    * is context {@link ClassLoader} and lock is unlocked
+    * after execution.
+    *
+    * @param cls {@link ClassLoader} to be used.
+    * @param function Function to be executed.
+    * @return Result of Callable invocation.
+    *
+    */
+    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);
+    }
+
+    /**
+     *
+     * Loads class using this supplied classloader.
+     *
+     *
+     * @param cls
+     * @param name String name of class.
+     * @return
+     * @throws ClassNotFoundException
+     */
+    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 51eb2a5214cf66d1561f5d48662273db43a74252..951e27f743dfb7d16883b6255da1f7116e6b7c59 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -167,20 +168,14 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
 
     /**
      * Simple path argument identifying a {@link ContainerNode} or {@link LeafNode} leaf
-     * overal data tree.
-     *
+     * overall data tree.
      */
-    public static final class NodeIdentifier implements PathArgument {
-
-        /**
-         *
-         */
+    public static final class NodeIdentifier implements PathArgument, Comparable<NodeIdentifier> {
         private static final long serialVersionUID = -2255888212390871347L;
-
         private final QName nodeType;
 
         public NodeIdentifier(final QName node) {
-            this.nodeType = node;
+            this.nodeType = Preconditions.checkNotNull(node);
         }
 
         @Override
@@ -190,58 +185,44 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
 
         @Override
         public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((nodeType == null) ? 0 : nodeType.hashCode());
-            return result;
+            return 31 + nodeType.hashCode();
         }
 
         @Override
         public boolean equals(final Object obj) {
             if (this == obj) {
-                               return true;
-                       }
-            if (obj == null) {
-                               return false;
-                       }
-            if (getClass() != obj.getClass()) {
-                               return false;
-                       }
-            NodeIdentifier other = (NodeIdentifier) obj;
-            if (nodeType == null) {
-                if (other.nodeType != null) {
-                                       return false;
-                               }
-            } else if (!nodeType.equals(other.nodeType)) {
-                               return false;
-                       }
-            return true;
+                return true;
+            }
+            if (!(obj instanceof NodeIdentifier)) {
+                return false;
+            }
+            final NodeIdentifier other = (NodeIdentifier) obj;
+            return nodeType.equals(other.nodeType);
         }
 
         @Override
         public String toString() {
             return nodeType.toString();
         }
+
+        @Override
+        public int compareTo(final NodeIdentifier o) {
+            return nodeType.compareTo(o.nodeType);
+        }
     }
 
     /**
-     *
      * Composite path argument identifying a {@link MapEntryNode} leaf
-     * overal data tree.
-     *
+     * overall data tree.
      */
     public static final class NodeIdentifierWithPredicates implements PathArgument {
-
-        /**
-         *
-         */
         private static final long serialVersionUID = -4787195606494761540L;
 
         private final QName nodeType;
         private final Map<QName, Object> keyValues;
 
         public NodeIdentifierWithPredicates(final QName node, final Map<QName, Object> keyValues) {
-            this.nodeType = node;
+            this.nodeType = Preconditions.checkNotNull(node);
             this.keyValues = ImmutableMap.copyOf(keyValues);
         }
 
@@ -271,29 +252,29 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
         @Override
         public boolean equals(final Object obj) {
             if (this == obj) {
-                               return true;
-                       }
+                return true;
+            }
             if (obj == null) {
-                               return false;
-                       }
+                return false;
+            }
             if (getClass() != obj.getClass()) {
-                               return false;
-                       }
+                return false;
+            }
             NodeIdentifierWithPredicates other = (NodeIdentifierWithPredicates) obj;
             if (keyValues == null) {
                 if (other.keyValues != null) {
-                                       return false;
-                               }
+                    return false;
+                }
             } else if (!keyValues.equals(other.keyValues)) {
-                               return false;
-                       }
+                return false;
+            }
             if (nodeType == null) {
                 if (other.nodeType != null) {
-                                       return false;
-                               }
+                    return false;
+                }
             } else if (!nodeType.equals(other.nodeType)) {
-                               return false;
-                       }
+                return false;
+            }
             return true;
         }
 
@@ -305,24 +286,16 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
 
     /**
      * Simple path argument identifying a {@link LeafSetEntryNode} leaf
-     * overal data tree.
-     *
+     * overall data tree.
      */
     public static final class NodeWithValue implements PathArgument {
-
-       /**
-        *
-        * Composite path argument identifying a {@link AugmentationNode} leaf
-        * overal data tree.
-        *
-        */
         private static final long serialVersionUID = -3637456085341738431L;
 
         private final QName nodeType;
         private final Object value;
 
         public NodeWithValue(final QName node, final Object value) {
-            this.nodeType = node;
+            this.nodeType = Preconditions.checkNotNull(node);
             this.value = value;
         }
 
@@ -347,29 +320,29 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
         @Override
         public boolean equals(final Object obj) {
             if (this == obj) {
-                               return true;
-                       }
+                return true;
+            }
             if (obj == null) {
-                               return false;
-                       }
+                return false;
+            }
             if (getClass() != obj.getClass()) {
-                               return false;
-                       }
+                return false;
+            }
             NodeWithValue other = (NodeWithValue) obj;
             if (value == null) {
                 if (other.value != null) {
-                                       return false;
-                               }
+                    return false;
+                }
             } else if (!value.equals(other.value)) {
-                               return false;
-                       }
+                return false;
+            }
             if (nodeType == null) {
                 if (other.nodeType != null) {
-                                       return false;
-                               }
+                    return false;
+                }
             } else if (!nodeType.equals(other.nodeType)) {
-                               return false;
-                       }
+                return false;
+            }
             return true;
         }
 
@@ -380,9 +353,11 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
 
     }
 
-
+    /**
+     * Composite path argument identifying a {@link AugmentationNode} leaf
+     * overall data tree.
+     */
     public static final class AugmentationIdentifier implements PathArgument {
-
         private static final long serialVersionUID = -8122335594681936939L;
         private final ImmutableSet<QName> childNames;
 
@@ -419,17 +394,17 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
         @Override
         public boolean equals(final Object o) {
             if (this == o) {
-                               return true;
-                       }
+                return true;
+            }
             if (!(o instanceof AugmentationIdentifier)) {
-                               return false;
-                       }
+                return false;
+            }
 
             AugmentationIdentifier that = (AugmentationIdentifier) o;
 
             if (!childNames.equals(that.childNames)) {
-                               return false;
-                       }
+                return false;
+            }
 
             return true;
         }
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");