Switch to Objects.requireNonNull
[mdsal.git] / binding2 / mdsal-binding2-runtime / src / main / java / org / opendaylight / mdsal / binding / javav2 / runtime / context / BindingRuntimeContext.java
old mode 100644 (file)
new mode 100755 (executable)
index d4a98d9..8d43e29
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.javav2.runtime.context;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
@@ -26,11 +27,12 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Optional;
 import java.util.Set;
 import javax.annotation.Nullable;
 import org.opendaylight.mdsal.binding.javav2.generator.api.ClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
 import org.opendaylight.mdsal.binding.javav2.generator.impl.BindingGeneratorImpl;
-import org.opendaylight.mdsal.binding.javav2.generator.impl.ModuleContext;
 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
 import org.opendaylight.mdsal.binding.javav2.generator.util.ReferencedTypeImpl;
@@ -41,21 +43,27 @@ import org.opendaylight.mdsal.binding.javav2.model.api.Type;
 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.mdsal.binding.javav2.runtime.context.util.BindingSchemaContextUtils;
 import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Action;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Rpc;
 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentation;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 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.DocumentedNode.WithStatus;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
+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.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
@@ -88,9 +96,10 @@ public class BindingRuntimeContext implements Immutable {
     private static final char DOT = '.';
     private final ClassLoadingStrategy strategy;
     private final SchemaContext schemaContext;
+    private final Multimap<Type, AugmentationSchemaNode> augmentationToSchemas = HashMultimap.create();
+    private final BiMap<SchemaPath,Type> targetToAugmentation = HashBiMap.create();
 
-    private final Map<Type, AugmentationSchema> augmentationToSchema = new HashMap<>();
-    private final BiMap<Type, Object> typeToDefiningSchema = HashBiMap.create();
+    private final BiMap<Type, WithStatus> typeToDefiningSchema = HashBiMap.create();
     private final Multimap<Type, Type> choiceToCases = HashMultimap.create();
     private final Map<QName, Type> identities = new HashMap<>();
 
@@ -116,7 +125,8 @@ public class BindingRuntimeContext implements Immutable {
         final Map<Module, ModuleContext> modules = generator.getModuleContexts(this.schemaContext);
 
         for (final ModuleContext ctx : modules.values()) {
-            this.augmentationToSchema.putAll(ctx.getTypeToAugmentation());
+            this.augmentationToSchemas.putAll(ctx.getTypeToAugmentations());
+            this.targetToAugmentation.putAll(ctx.getTargetToAugmentation());
             this.typeToDefiningSchema.putAll(ctx.getTypeToSchema());
 
             ctx.getTypedefs();
@@ -171,7 +181,7 @@ public class BindingRuntimeContext implements Immutable {
      * augmentations, which may be present in runtime for them, thus returned
      * schema is unsuitable for use for validation of data.
      * <p>
-     * For retrieving {@link AugmentationSchema}, which will contains full model
+     * For retrieving {@link AugmentationSchemaNode}, which will contains full model
      * for child nodes, you should use method
      * {@link #getResolvedAugmentationSchema(DataNodeContainer, Class)} which
      * will return augmentation schema derived from supplied augmentation target
@@ -184,9 +194,19 @@ public class BindingRuntimeContext implements Immutable {
      * @throws IllegalArgumentException
      *             - if supplied class is not an augmentation
      */
-    public @Nullable AugmentationSchema getAugmentationDefinition(final Class<?> augClass) throws IllegalArgumentException {
-        Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass), "Class %s does not represent augmentation", augClass);
-        return this.augmentationToSchema.get(referencedType(augClass));
+    public @Nullable Entry<Type, Collection<AugmentationSchemaNode>>
+    getAugmentationDefinition(final Class<?> augClass) {
+        Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass),
+            "Class %s does not represent augmentation", augClass);
+
+        final Type refType = referencedType(augClass);
+        for (Entry<Type, Collection<AugmentationSchemaNode>> entry : this.augmentationToSchemas.asMap().entrySet()) {
+            if (refType.equals(entry.getKey())) {
+                return entry;
+            }
+        }
+
+        throw new IllegalArgumentException("Supplied class is not an augmentation.");
     }
 
     /**
@@ -209,20 +229,28 @@ public class BindingRuntimeContext implements Immutable {
         return (DataSchemaNode) this.typeToDefiningSchema.get(referencedType(cls));
     }
 
+    public RpcDefinition getRpcDefinition(final Class<? extends Rpc<?, ?>> cls) {
+        return (RpcDefinition) typeToDefiningSchema.get(referencedType(cls));
+    }
+
+    public ActionDefinition getActionDefinition(final Class<? extends Action<?, ?, ?, ?>> cls) {
+        return (ActionDefinition) typeToDefiningSchema.get(referencedType(cls));
+    }
+
     /**
-     * Returns defining {@link AugmentationSchema} of target for supplied class.
+     * Returns defining {@link AugmentationSchemaNode} of target for supplied class.
      *
      * @param target
      *            - {@link DataNodeContainer}
      * @param aug
      *            - supplied class
-     * @return entry of {@link AugmentationSchema} according to its identifier
+     * @return entry of {@link AugmentationSchemaNode} according to its identifier
      *         {@link AugmentationIdentifier}
      */
-    public Entry<AugmentationIdentifier, AugmentationSchema> getResolvedAugmentationSchema(final DataNodeContainer target,
-            final Class<? extends Augmentation<?>> aug) {
-        final AugmentationSchema origSchema = getAugmentationDefinition(aug);
-        Preconditions.checkArgument(origSchema != null, "Augmentation %s is not known in current schema context",aug);
+    public Entry<AugmentationIdentifier, AugmentationSchemaNode> getResolvedAugmentationSchema(
+            final DataNodeContainer target, final Class<? extends Augmentation<?>> aug) {
+        final Collection<AugmentationSchemaNode> origSchemas = getAugmentationDefinition(aug).getValue();
+        Preconditions.checkArgument(origSchemas != null, "Augmentation %s is not known in current schema context",aug);
         /*
          * FIXME: Validate augmentation schema lookup
          *
@@ -237,24 +265,27 @@ public class BindingRuntimeContext implements Immutable {
          */
         final Set<QName> childNames = new HashSet<>();
         final Set<DataSchemaNode> realChilds = new HashSet<>();
-        for (final DataSchemaNode child : origSchema.getChildNodes()) {
-            final DataSchemaNode dataChildQNname = target.getDataChildByName(child.getQName());
-            final String childLocalName = child.getQName().getLocalName();
-            if (dataChildQNname == null) {
-                for (final DataSchemaNode dataSchemaNode : target.getChildNodes()) {
-                    if (childLocalName.equals(dataSchemaNode.getQName().getLocalName())) {
-                        realChilds.add(dataSchemaNode);
-                        childNames.add(dataSchemaNode.getQName());
+        for (final AugmentationSchemaNode origSchema : origSchemas) {
+            for (final DataSchemaNode child : origSchema.getChildNodes()) {
+                final DataSchemaNode dataChildQNname = target.getDataChildByName(child.getQName());
+                final String childLocalName = child.getQName().getLocalName();
+                if (dataChildQNname == null) {
+                    for (final DataSchemaNode dataSchemaNode : target.getChildNodes()) {
+                        if (childLocalName.equals(dataSchemaNode.getQName().getLocalName())) {
+                            realChilds.add(dataSchemaNode);
+                            childNames.add(dataSchemaNode.getQName());
+                        }
                     }
+                } else {
+                    realChilds.add(dataChildQNname);
+                    childNames.add(child.getQName());
                 }
-            } else {
-                realChilds.add(dataChildQNname);
-                childNames.add(child.getQName());
             }
         }
 
         final AugmentationIdentifier identifier = new AugmentationIdentifier(childNames);
-        final AugmentationSchema proxy = new EffectiveAugmentationSchema(origSchema, realChilds);
+        final AugmentationSchemaNode proxy = new EffectiveAugmentationSchema(origSchemas.stream().findFirst().get(),
+            realChilds);
         return new SimpleEntry<>(identifier, proxy);
     }
 
@@ -265,14 +296,14 @@ public class BindingRuntimeContext implements Immutable {
      *            - resolved parent choice schema
      * @param childClass
      *            - class representing case.
-     * @return Optionally a resolved case schema, absent if the choice is not
+     * @return Optionally a resolved case schema,.empty if the choice is not
      *         legal in the given context.
      * @throws IllegalArgumentException
      *             - if supplied class does not represent case
      */
-    public Optional<ChoiceCaseNode> getCaseSchemaDefinition(final ChoiceSchemaNode schema, final Class<?> childClass) throws IllegalArgumentException {
+    public Optional<CaseSchemaNode> getCaseSchemaDefinition(final ChoiceSchemaNode schema, final Class<?> childClass) throws IllegalArgumentException {
         final DataSchemaNode origSchema = getSchemaDefinition(childClass);
-        Preconditions.checkArgument(origSchema instanceof ChoiceCaseNode, "Supplied schema %s is not case.", origSchema);
+        Preconditions.checkArgument(origSchema instanceof CaseSchemaNode, "Supplied schema %s is not case.", origSchema);
 
         /*
          * FIXME: Make sure that if there are multiple augmentations of same
@@ -281,29 +312,30 @@ public class BindingRuntimeContext implements Immutable {
          * unaware that he is using incorrect case which was generated for
          * choice inside grouping.
          */
-        final Optional<ChoiceCaseNode> found = BindingSchemaContextUtils.findInstantiatedCase(schema,
-                (ChoiceCaseNode) origSchema);
+        final Optional<CaseSchemaNode> found = BindingSchemaContextUtils.findInstantiatedCase(schema,
+                (CaseSchemaNode) origSchema);
         return found;
     }
 
     private static Type referencedType(final Class<?> type) {
-        return new ReferencedTypeImpl(type.getPackage().getName(), type.getSimpleName());
+        return new ReferencedTypeImpl(type.getPackage().getName(), type.getSimpleName(), true, null);
     }
 
     static Type referencedType(final String type) {
         final int packageClassSeparator = type.lastIndexOf(DOT);
-        return new ReferencedTypeImpl(type.substring(0, packageClassSeparator), type.substring(packageClassSeparator + 1));
+        return new ReferencedTypeImpl(type.substring(0, packageClassSeparator),
+            type.substring(packageClassSeparator + 1), true, null);
     }
 
     /**
-     * Returns schema ({@link DataSchemaNode}, {@link AugmentationSchema} or {@link TypeDefinition})
+     * Returns schema ({@link DataSchemaNode}, {@link AugmentationSchemaNode} or {@link TypeDefinition})
      * from which supplied class was generated. Returned schema may be augmented with
      * additional information, which was not available at compile type
      * (e.g. third party augmentations).
      *
      * @param type Binding Class for which schema should be retrieved.
      * @return Instance of generated type (definition of Java API), along with
-     *     {@link DataSchemaNode}, {@link AugmentationSchema} or {@link TypeDefinition}
+     *     {@link DataSchemaNode}, {@link AugmentationSchemaNode} or {@link TypeDefinition}
      *     which was used to generate supplied class.
      */
     public Entry<GeneratedType, Object> getTypeWithSchema(final Class<?> type) {
@@ -316,10 +348,10 @@ public class BindingRuntimeContext implements Immutable {
 
     private Entry<GeneratedType, Object> getTypeWithSchema(final Type referencedType) {
         final Object schema = this.typeToDefiningSchema.get(referencedType);
-        Preconditions.checkNotNull(schema, "Failed to find schema for type %s", referencedType);
+        requireNonNull(schema, () -> "Failed to find schema for type " + referencedType);
 
         final Type definedType = this.typeToDefiningSchema.inverse().get(schema);
-        Preconditions.checkNotNull(definedType, "Failed to find defined type for %s schema %s", referencedType, schema);
+        requireNonNull(definedType, () -> "Failed to find defined type for " + referencedType + " schema " + schema);
 
         if (definedType instanceof GeneratedTypeBuilder) {
             return new SimpleEntry<>(((GeneratedTypeBuilder) definedType).toInstance(), schema);
@@ -411,21 +443,34 @@ public class BindingRuntimeContext implements Immutable {
         }
     }
 
+    private static boolean isLocalAugment(final AugmentationTarget container, final AugmentationSchemaNode augment) {
+        Preconditions.checkState(container instanceof SchemaNode);
+        final QName root = ((SchemaNode) container).getPath().getPathFromRoot().iterator().next();
+        // findFirst makes no sense but just pick up one child to judge whether the target node is
+        // in the same module.
+        final Optional<DataSchemaNode> child = augment.getChildNodes().stream().findFirst();
+        if (child.isPresent()) {
+            return root.getModule().equals(child.get().getQName().getModule());
+        }
+        return false;
+    }
+
     public ImmutableMap<AugmentationIdentifier,Type> getAvailableAugmentationTypes(final DataNodeContainer container) {
         final Map<AugmentationIdentifier,Type> identifierToType = new HashMap<>();
         if (container instanceof AugmentationTarget) {
-            final Set<AugmentationSchema> augments = ((AugmentationTarget) container).getAvailableAugmentations();
-            for (final AugmentationSchema augment : augments) {
-                // Augmentation must have child nodes if is to be used with Binding classes
-                AugmentationSchema augOrig = augment;
-                while (augOrig.getOriginalDefinition().isPresent()) {
-                    augOrig = augOrig.getOriginalDefinition().get();
-                }
+            for (final AugmentationSchemaNode augment : ((AugmentationTarget) container).getAvailableAugmentations()) {
+                if (!isLocalAugment((AugmentationTarget) container, augment)) {
+                    // Augmentation must have child nodes if is to be used with Binding classes
+                    AugmentationSchemaNode augOrig = augment;
+                    while (augOrig.getOriginalDefinition().isPresent()) {
+                        augOrig = augOrig.getOriginalDefinition().get();
+                    }
 
-                if (!augment.getChildNodes().isEmpty()) {
-                    final Type augType = this.typeToDefiningSchema.inverse().get(augOrig);
-                    if (augType != null) {
-                        identifierToType.put(getAugmentationIdentifier(augment),augType);
+                    if (!augment.getChildNodes().isEmpty()) {
+                        final Type augType = this.targetToAugmentation.get(augOrig.getTargetPath());
+                        if (augType != null) {
+                            identifierToType.put(getAugmentationIdentifier(augment), augType);
+                        }
                     }
                 }
             }
@@ -434,7 +479,7 @@ public class BindingRuntimeContext implements Immutable {
         return ImmutableMap.copyOf(identifierToType);
     }
 
-    private static AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchema augment) {
+    private static AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchemaNode augment) {
         final Set<QName> childNames = new HashSet<>();
         for (final DataSchemaNode child : augment.getChildNodes()) {
             childNames.add(child.getQName());
@@ -446,7 +491,7 @@ public class BindingRuntimeContext implements Immutable {
         if (type instanceof ReferencedTypeImpl) {
             return type;
         }
-        return new ReferencedTypeImpl(type.getPackageName(), type.getName());
+        return new ReferencedTypeImpl(type.getPackageName(), type.getName(), true, null);
     }
 
     private static Set<Type> collectAllContainerTypes(final GeneratedType type, final Set<Type> collection) {