From: Tony Tkacik Date: Tue, 20 May 2014 12:59:18 +0000 (+0000) Subject: Merge "Bug 735 - Part 1: Update ietf-restconf and ietf-yangtypes to newer versions" X-Git-Tag: release/helium~540 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=85c0405ed187f2d00d47c12c20f3c5ab8029cd2f;hp=3c686d333f56915c0341d1cf1c31501c77552da4;p=yangtools.git Merge "Bug 735 - Part 1: Update ietf-restconf and ietf-yangtypes to newer versions" --- diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java index fd280427d4..373ea7df71 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java @@ -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; diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend index 0ab2fdbc2d..b4362fbd8c 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend @@ -1631,9 +1631,9 @@ public class BindingGeneratorImpl implements BindingGenerator { } /** - * Creates the name of the getter method from methodName. + * Creates the name of the getter method name from localName. * - * @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 diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingSchemaContextUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingSchemaContextUtils.java index 646f3ea4c3..6645aba574 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingSchemaContextUtils.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingSchemaContextUtils.java @@ -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 findFirstDataNodeContainerInRpc(final SchemaContext ctx, final Class 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 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 potential = findInputOutput(rpc,targetType.getSimpleName()); + if(potential.isPresent()) { + return potential; } } - } catch (Exception e) { - // FIXME: Add logging } return Optional.absent(); } diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java index 362ebe6e88..5440e01511 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java @@ -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); } } diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java index 9fac9571c2..fda3f068ac 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.java @@ -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,Set>> augmentationAdapted = new WeakHashMap<>(); + private final Map, Map, Class>> classToPreviousAugment = Collections .synchronizedMap(new WeakHashMap, Map, Class>>()); @@ -70,6 +73,7 @@ public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { } Map, Class> injectAugment = classToPreviousAugment.get(baType); if (injectAugment != null) { + @SuppressWarnings("unchecked") Class augment = (Class) 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 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 processedPath) { + @SuppressWarnings("rawtypes") final Class cls = codecRegistry.getClassForPath(processedPath); + @SuppressWarnings("unchecked") Item item = new Item<>(cls); return item; } - private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument _deserializePathArgument( + private InstanceIdentifier.PathArgument deserializeNodeIdentifierWithPrecicates( final NodeIdentifierWithPredicates argument, final List processedPath) { + @SuppressWarnings("rawtypes") final Class type = codecRegistry.getClassForPath(processedPath); + @SuppressWarnings({ "unchecked", "rawtypes" }) final IdentifierCodec codec = codecRegistry .> getIdentifierCodecForIdentifiable(type); CompositeNode _compositeNode = this.toCompositeNode(argument); + @SuppressWarnings("unchecked") ValueWithQName 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 pathArgs = input.getPath(); + Iterable pathArgs = input.getPathArguments(); QName previousQName = null; - List components = new ArrayList<>(pathArgs.size()); - List qnamePath = new ArrayList<>(pathArgs.size()); + List components = new ArrayList<>(); + List 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 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 augPath, final QName augQName, final Class type) { + Set> augPotential = augmentationAdapted.get(type); + if(augPotential == null) { + augPotential = new HashSet<>(); + augmentationAdapted.put(type, augPotential); + } + ImmutableList augTargetPath = ImmutableList.copyOf(augPath); + if(augPotential.contains(augPath)) { + return; + } + + for(Class child : BindingReflections.getChildrenClasses(type)) { + Item baArg = new Item<>(child); + PathArgument biArg = serializePathArgumentAndUpdateMapping(augPath, baArg, augQName,type); + } + augPotential.add(augTargetPath); + } + + public Class updateAugmentationInjection(final Class class1, - final ImmutableList list, final Class augmentation) { + final List list, final Class augmentation) { if (classToPreviousAugment.get(class1) == null) { classToPreviousAugment.put(class1, new ConcurrentHashMap, 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 predicates = new HashMap<>(); + @SuppressWarnings("rawtypes") Class type = argument.getType(); + @SuppressWarnings("unchecked") IdentifierCodec 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 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. asList(argument, processedPath).toString()); } } + private PathArgument serializePathArgumentAndUpdateMapping(final List parentPath, final InstanceIdentifier.PathArgument baArg, final QName previousQName, final Class previousAugmentation) { + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument biArg = serializePathArgument(baArg, previousQName); + List qnamePath = new ArrayList<>(parentPath); + qnamePath.add(biArg.getNodeType()); + ImmutableList 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. asList(argument, previousQname).toString()); } } + + } diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java index a6bf376298..e62f28e646 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java @@ -112,7 +112,7 @@ class LazyGeneratedCodecRegistry implements // @SuppressWarnings("rawtypes") private static final ConcurrentMap typeToCaseCodecs = new ConcurrentHashMap<>(); - private static final Map pathToType = new ConcurrentHashMap<>(); + private static final Map pathToType = new ConcurrentHashMap<>(); private static final Map, Type> pathToInstantiatedType = new ConcurrentHashMap<>(); private static final Map typeToQname = new ConcurrentHashMap<>(); private static final BiMap typeToAugment = HashBiMap @@ -151,27 +151,36 @@ class LazyGeneratedCodecRegistry implements // @SuppressWarnings("unchecked") @Override - public > AugmentationCodecWrapper getCodecForAugmentation(final Class object) { + public > AugmentationCodecWrapper getCodecForAugmentation(final Class augClass) { AugmentationCodecWrapper 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, Object>> augmentRawCodec = generator - .augmentationTransformerFor(object); + .augmentationTransformerFor(augClass); BindingCodec, Object> rawCodec = newInstanceOf(augmentRawCodec); - codec = new AugmentationCodecWrapper(rawCodec, null, object); - augmentationCodecs.put(object, codec); + codec = new AugmentationCodecWrapper(rawCodec, augClass); + augmentationCodecs.put(augClass, codec); } - Class> objectSupertype = getAugmentableArgumentFrom(object); - if (objectSupertype != null) { - getAugmentableCodec(objectSupertype).addImplementation(codec); - } else { - LOG.warn("Could not find augmentation target for augmentation {}", object); + + final Class> 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>) cls).getAugmentationQName(); } - private static Class> getAugmentableArgumentFrom( - final Class> augmentation) { - try { - Class> 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 names) { final DataSchemaNode node = getSchemaNode(names); @@ -210,7 +207,8 @@ class LazyGeneratedCodecRegistry implements // @SuppressWarnings("rawtypes") final WeakReference 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 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 contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema, path); + Optional 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 implements ChoiceCodec, Delegator, Object>> { + private static class PublicChoiceCodecImpl implements ChoiceCodec, + Delegator, Object>> { private final BindingCodec, Object> delegate; @@ -882,7 +890,8 @@ class LazyGeneratedCodecRegistry implements // private class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec> { @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 { + class AugmentableDispatchCodec extends LocationAwareDispatchCodec { 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> potentialImpl = getCodecForAugmentation(inputType); addImplementation(potentialImpl); return potentialImpl; - } @Override protected void tryToLoadImplementations() { Type type = referencedType(augmentableType); Collection 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 availableAugmentations = ((AugmentationTarget) ctxNode) .getAvailableAugmentations(); if (!availableAugmentations.isEmpty()) { - updateAugmentationMapping(path,availableAugmentations); + updateAugmentationMapping(augTarget, availableAugmentations); } - } } - private void updateAugmentationMapping(final InstanceIdentifier path, final Set 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: + *
    + *
  1. scan of available (valid) augmentations for + * current location + *
  2. lookup for Java classes derived from this augmentations + *
  3. generation of missing codecs + *
  4. updating Augmentation codecs to work with new location + *
  5. updating Instance Identifier to work with new location + * + */ + private void updateAugmentationMapping(final InstanceIdentifier augTarget, + final Set availableAugmentations) { for (AugmentationSchema aug : availableAugmentations) { Type potentialType = getTypeForAugmentation(aug); if (potentialType != null) { Optional 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 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,QName> validAugmentationTargets; + private final Multimap, QName> validAugmentationTargets; private final Class augmentationType; - public AugmentationCodecWrapper(final BindingCodec, Object> rawCodec, - final InstanceIdentifier targetId, final Class dataType) { + public AugmentationCodecWrapper(final BindingCodec, Object> rawCodec, final Class dataType) { this.delegate = rawCodec; this.augmentationType = dataType; this.augmentationQName = BindingReflections.findQName(rawCodec.getClass()); - this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap.,QName>create()); + this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap + ., 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; diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java index 93c63a2c5b..335ec5967e 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java @@ -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, 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 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 moduleInfos) { + public void addModuleInfos(final Iterable moduleInfos) { for (YangModuleInfo yangModuleInfo : moduleInfos) { registerModuleInfo(yangModuleInfo); } } @Override - public ObjectRegistration registerModuleInfo(YangModuleInfo yangModuleInfo) { + public ObjectRegistration registerModuleInfo(final YangModuleInfo yangModuleInfo) { YangModuleInfoRegistration registration = new YangModuleInfoRegistration(yangModuleInfo, this); resolveModuleInfo(yangModuleInfo); @@ -156,7 +157,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // } @Override - public Optional getSchemaSource(SourceIdentifier sourceIdentifier) { + public Optional 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 getSchemaSource(String moduleName, Optional revision) { + public Optional getSchemaSource(final String moduleName, final Optional 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 } diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java index 1589552893..01ed2f0240 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java @@ -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() { diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.java index e19730b35e..252fca7107 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.java @@ -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); diff --git a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedType.java b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedType.java index eefb847ff6..a2bc6da939 100644 --- a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedType.java +++ b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedType.java @@ -39,13 +39,13 @@ abstract class AbstractGeneratedType extends AbstractBaseType implements Generat private final List 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 List makeUnmodifiable(final List list) { + switch (list.size()) { + case 0: + return Collections.emptyList(); + case 1: + return Collections.singletonList(list.get(0)); + default: + return Collections.unmodifiableList(list); + } } - private List toUnmodifiableEnclosedTypes(final List enclosedGenTypeBuilders, + private static List toUnmodifiableEnclosedTypes(final List enclosedGenTypeBuilders, final List enclosedGenTOBuilders) { - final List enclosedTypesList = new ArrayList<>(); + final ArrayList 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 toUnmodifiableAnnotations(final List annotationBuilders) { - final List annotationList = new ArrayList<>(); + protected static final List toUnmodifiableAnnotations(final List annotationBuilders) { + final List annotationList = new ArrayList<>(annotationBuilders.size()); for (final AnnotationTypeBuilder builder : annotationBuilders) { annotationList.add(builder.toInstance()); } - return Collections.unmodifiableList(annotationList); + return makeUnmodifiable(annotationList); } - protected final List toUnmodifiableMethods(List methodBuilders) { - final List methods = new ArrayList<>(); + protected final List toUnmodifiableMethods(final List methodBuilders) { + final List 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 toUnmodifiableEnumerations(List enumBuilders) { - final List enums = new ArrayList<>(); + protected final List toUnmodifiableEnumerations(final List enumBuilders) { + final List 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 toUnmodifiableProperties(List methodBuilders) { - final List methods = new ArrayList<>(); + protected final List toUnmodifiableProperties(final List methodBuilders) { + final List methods = new ArrayList<>(methodBuilders.size()); for (final GeneratedPropertyBuilder methodBuilder : methodBuilders) { methods.add(methodBuilder.toInstance(this)); } - return Collections.unmodifiableList(methods); + return makeUnmodifiable(methods); } @Override diff --git a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedTypeBuilder.java b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedTypeBuilder.java index b3bb742575..1adbe05d33 100644 --- a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedTypeBuilder.java +++ b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractGeneratedTypeBuilder.java @@ -80,7 +80,7 @@ abstract class AbstractGeneratedTypeBuilder other = (AbstractGeneratedTypeBuilder) obj; + AbstractGeneratedTypeBuilder other = (AbstractGeneratedTypeBuilder) obj; if (getName() == null) { if (other.getName() != null) { return false; diff --git a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractTypeMember.java b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractTypeMember.java index 5172188288..cfadce1a5e 100644 --- a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractTypeMember.java +++ b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/AbstractTypeMember.java @@ -29,11 +29,11 @@ abstract class AbstractTypeMember implements TypeMember { public AbstractTypeMember(final Type definingType, final String name, final List 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.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; } diff --git a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java index a2ecc1018d..b3b1c7ce25 100644 --- a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java +++ b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java @@ -23,16 +23,16 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder equalsProperties = new ArrayList<>(); - private final List hashProperties = new ArrayList<>(); - private final List toStringProperties = new ArrayList<>(); + private final ArrayList equalsProperties = new ArrayList<>(); + private final ArrayList hashProperties = new ArrayList<>(); + private final ArrayList 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 AbstractGeneratedTypeBuildernew 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, «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>(); + private final «Map.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, «augmentField.returnType.importedName»> e = builder.«augmentField.name».entrySet().iterator().next(); + this.«augmentField.name» = «Collections.importedName»., «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue()); + break; + default : + this.«augmentField.name» = new «HashMap.importedName»<>(builder.«augmentField.name»); + } «ENDIF» } ''' diff --git a/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java b/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java index f2402270ef..e898e72479 100644 --- a/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java +++ b/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java @@ -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 withClassLoader(ClassLoader cls, Callable function) throws Exception { + public static V withClassLoader(final ClassLoader cls, final Callable function) throws Exception { return withClassLoaderAndLock(cls, null, function); } - public static V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable function) throws Exception { + public static V withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Callable 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 Callable> findFirstGenericArgumentTask(final Class scannedClass, final Class genericType) { return new Callable>() { @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]; } diff --git a/common/object-cache-api/pom.xml b/common/object-cache-api/pom.xml index 8ef8a14433..beb2d035d2 100644 --- a/common/object-cache-api/pom.xml +++ b/common/object-cache-api/pom.xml @@ -36,6 +36,12 @@ jsr305 provided + + + junit + junit + test + @@ -43,6 +49,15 @@ org.apache.felix maven-bundle-plugin + true + + + + org.opendaylight.yangtools.objcache.impl;resolution:=optional, + * + + + org.apache.maven.plugins diff --git a/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/ObjectCacheFactory.java b/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/ObjectCacheFactory.java index 58ca11c4d2..dd3e53bbd0 100644 --- a/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/ObjectCacheFactory.java +++ b/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/ObjectCacheFactory.java @@ -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)); + } } diff --git a/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/AbstractObjectCache.java b/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/AbstractObjectCache.java index 963030cf8b..aeef1ee5cf 100644 --- a/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/AbstractObjectCache.java +++ b/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/AbstractObjectCache.java @@ -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 { - 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 cache; - - protected AbstractObjectCache(final Cache cache, final FinalizableReferenceQueue queue) { - this.queue = Preconditions.checkNotNull(queue); - this.cache = Preconditions.checkNotNull(cache); - } - - private 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 , 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 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 extends FinalizableSoftReference { + 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, Object> cache; + + protected AbstractObjectCache(final Cache, Object> cache, final FinalizableReferenceQueue queue) { + this.queue = Preconditions.checkNotNull(queue); + this.cache = Preconditions.checkNotNull(cache); + } + + protected SoftKey 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(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 , 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 getReference(final T object) { + LOG.debug("Looking up reference for {}", object); + if (object == null) { + return null; + } + + final SoftKey key = createSoftKey(object); + try { + return (T) cache.get(key, new Callable() { + @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 index 0000000000..0ff3365027 --- /dev/null +++ b/common/object-cache-api/src/main/java/org/opendaylight/yangtools/objcache/spi/NoopObjectCacheBinder.java @@ -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 index 0000000000..73aec29d23 --- /dev/null +++ b/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheFactoryTest.java @@ -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 index 0000000000..37434e5bc2 --- /dev/null +++ b/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/CacheTest.java @@ -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()., 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 index 0000000000..dc16f77e92 --- /dev/null +++ b/common/object-cache-api/src/test/java/org/opendaylight/yangtools/objcache/spi/SoftKeyTest.java @@ -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(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)); + } +} diff --git a/common/object-cache-guava/pom.xml b/common/object-cache-guava/pom.xml index ee65f85496..8a5b7c471a 100644 --- a/common/object-cache-guava/pom.xml +++ b/common/object-cache-guava/pom.xml @@ -27,12 +27,29 @@ com.google.guava guava + + + junit + junit + test + org.apache.felix maven-bundle-plugin + true + + + + org.opendaylight.yangtools.objcache.impl + + + org.opendaylight.yangtools.objcache.guava + + + diff --git a/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCache.java b/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCache.java index 7d90e39ee7..617a2936f4 100644 --- a/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCache.java +++ b/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCache.java @@ -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()., Object>build(), queue); + } + + public GuavaObjectCache(final FinalizableReferenceQueue queue, final CacheBuilderSpec spec) { + super(CacheBuilder.from(spec)., Object>build(), queue); + } } diff --git a/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheFactory.java b/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheFactory.java index 067b626e07..895037625d 100644 --- a/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheFactory.java +++ b/common/object-cache-guava/src/main/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheFactory.java @@ -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 index 0000000000..bc41da9ab3 --- /dev/null +++ b/common/object-cache-guava/src/test/java/org/opendaylight/yangtools/objcache/guava/GuavaObjectCacheTest.java @@ -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)); + } + +} diff --git a/common/object-cache-noop/pom.xml b/common/object-cache-noop/pom.xml index e2c9bce995..ca10b3cbb5 100644 --- a/common/object-cache-noop/pom.xml +++ b/common/object-cache-noop/pom.xml @@ -29,6 +29,17 @@ org.apache.felix maven-bundle-plugin + true + + + + org.opendaylight.yangtools.objcache.impl + + + org.opendaylight.yangtools.objcache.noop + + + diff --git a/common/object-cache-noop/src/main/java/org/opendaylight/yangtools/objcache/impl/StaticObjectCacheBinder.java b/common/object-cache-noop/src/main/java/org/opendaylight/yangtools/objcache/impl/StaticObjectCacheBinder.java index 2af58bf5c3..3ef9fbf941 100644 --- a/common/object-cache-noop/src/main/java/org/opendaylight/yangtools/objcache/impl/StaticObjectCacheBinder.java +++ b/common/object-cache-noop/src/main/java/org/opendaylight/yangtools/objcache/impl/StaticObjectCacheBinder.java @@ -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 e229268818..9ccb93b27e 100644 --- a/pom.xml +++ b/pom.xml @@ -201,6 +201,21 @@ concepts ${project.version} + + ${project.groupId} + object-cache-api + ${project.version} + + + ${project.groupId} + object-cache-guava + ${project.version} + + + ${project.groupId} + object-cache-noop + ${project.version} + diff --git a/restconf/restconf-client-impl/src/main/java/org/opendaylight/yangtools/restconf/client/BindingToRestRpc.java b/restconf/restconf-client-impl/src/main/java/org/opendaylight/yangtools/restconf/client/BindingToRestRpc.java index fe4eb76695..40d29da662 100644 --- a/restconf/restconf-client-impl/src/main/java/org/opendaylight/yangtools/restconf/client/BindingToRestRpc.java +++ b/restconf/restconf-client-impl/src/main/java/org/opendaylight/yangtools/restconf/client/BindingToRestRpc.java @@ -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() { @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 getProxy(Class proxiedInterface, - BindingIndependentMappingService mappingService, - RestconfClientImpl restconfClient, - SchemaContext schemaContext) { + public static T getProxy(final Class proxiedInterface, + final BindingIndependentMappingService mappingService, + final RestconfClientImpl restconfClient, + final SchemaContext schemaContext) { T proxiedType = null; try { proxiedType = (T) Proxy.newProxyInstance diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java index a6c3996c5c..0b057a194b 100644 --- a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java +++ b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java @@ -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, Optional> { - - @Override - public Optional 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> 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> 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() { - + return ClassLoaderUtils.withClassLoader(cls.getClassLoader(), new Callable() { @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 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 loadModuleInfos(final ClassLoader loader) { - Builder moduleInfoSet = ImmutableSet.builder(); - ServiceLoader serviceLoader = ServiceLoader.load(YangModelBindingProvider.class, loader); - for(YangModelBindingProvider bindingProvider : serviceLoader) { + Builder moduleInfoSet = ImmutableSet. builder(); + ServiceLoader 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 moduleInfoSet) { + private static void collectYangModuleInfo(final YangModuleInfo moduleInfo, + final Builder 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 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> getChildrenClasses(final Class type) { + checkArgument(type != null, "Target type must not be null"); + checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer"); + List> ret = new LinkedList<>(); + for (Method method : type.getMethods()) { + Optional> entity = getYangModeledReturnType(method); + if (entity.isPresent()) { + ret.add((Class) entity.get()); + } + } + return ret; + } + + @SuppressWarnings("unchecked") + private static Optional> 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.> of(returnType); + } else if (List.class.isAssignableFrom(returnType)) { + try { + return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(), + new Callable>>() { + @SuppressWarnings("rawtypes") + @Override + public Optional> call() { + Type listResult = ClassLoaderUtils.getFirstGenericParameter(method + .getGenericReturnType()); + if (listResult instanceof Class + && DataContainer.class.isAssignableFrom((Class) listResult)) { + return Optional.> 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, Optional> { + + @Override + public Optional 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 index 0000000000..fab50614f2 --- /dev/null +++ b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java @@ -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 withClassLoader(final ClassLoader cls, final Supplier 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 withClassLoader(final ClassLoader cls, final Callable 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 withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Supplier function) { + checkNotNull(lock, "Lock should not be null"); + + lock.lock(); + try { + return withClassLoader(cls, function); + } finally { + lock.unlock(); + } + } + + public static Object construct(final Constructor constructor, final List 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 Class

    findFirstGenericArgument(final Class scannedClass, final Class genericType) { + return withClassLoader(scannedClass.getClassLoader(), ClassLoaderUtils.findFirstGenericArgumentTask(scannedClass, genericType)); + } + + private static Supplier> findFirstGenericArgumentTask(final Class scannedClass, final Class genericType) { + return new Supplier>() { + @Override + @SuppressWarnings("unchecked") + public Class

    get() { + final ParameterizedType augmentationGeneric = findParameterizedType(scannedClass, genericType); + if (augmentationGeneric != null) { + return (Class

    ) 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; + } +} diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifier.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifier.java index 51eb2a5214..951e27f743 100644 --- a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifier.java +++ b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifier.java @@ -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, 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 { 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, 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 keyValues; public NodeIdentifierWithPredicates(final QName node, final Map keyValues) { - this.nodeType = node; + this.nodeType = Preconditions.checkNotNull(node); this.keyValues = ImmutableMap.copyOf(keyValues); } @@ -271,29 +252,29 @@ public class InstanceIdentifier implements Path, 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, 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, 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, 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 childNames; @@ -419,17 +394,17 @@ public class InstanceIdentifier implements Path, 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; } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java index 14f4950581..0dc0c19e6b 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java @@ -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 null * 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 prefixedPath = (schemaPath.getPath()); - if (prefixedPath != null) { - return findNodeInSchemaContext(context, prefixedPath); + + final List 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 null 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 qnamedPath = xpathToQNamePath(context, module, strXPath); if (qnamedPath != null) { @@ -152,8 +173,8 @@ public class SchemaContextUtil { * given relative Revision Aware XPath, otherwise will return * null. */ - 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 * null */ - 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 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 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 path) { + public static GroupingDefinition findGrouping(final SchemaContext context, final Module module, final List 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 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 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 path) { - if (path.isEmpty()) + private static SchemaNode findNodeInGrouping(final GroupingDefinition grouping, final List 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 path) { - if (path.isEmpty()) + private static SchemaNode findNodeInRpc(final RpcDefinition rpc, final List 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 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 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 path) { - if (path.isEmpty()) + private static SchemaNode findNode(final ChoiceNode parent, final List 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 path) { - if (path.isEmpty()) + private static SchemaNode findNode(final ContainerSchemaNode parent, final List 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 path) { - if (path.isEmpty()) + private static SchemaNode findNode(final ListSchemaNode parent, final List 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 path) { - SchemaNode result = null; - if (path.isEmpty()) { - result = parent; - } else { + private static SchemaNode findNode(final DataSchemaNode parent, final List 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 path) { - if (path.isEmpty()) + public static SchemaNode findNodeInCase(final ChoiceCaseNode parent, final List 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 nextLevel(List path) { + private static List nextLevel(final List 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 tmpPath, DataSchemaNode node, SchemaContext ctx) { + private static DataSchemaNode getTargetNode(final List 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 augments, QName name) { + private static AugmentationSchema findNodeInAugment(final Collection 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 dataTree, SchemaContext ctx) { + private static DataSchemaNode findCorrectTargetFromAugmentGrouping(final DataSchemaNode node, + final AugmentationSchema parentNode, final List 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 xpathToQNamePath(SchemaContext context, Module parentModule, String xpath) { + private static List 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 null */ - 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 resolveRelativeXPath(SchemaContext context, Module module, - RevisionAwareXPath relativeXPath, SchemaNode leafrefParentNode) { + private static List 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");