Binding codec v2 - fix anyxml #3 51/62351/19
authorJie Han <han.jie@zte.com.cn>
Mon, 28 Aug 2017 06:59:50 +0000 (14:59 +0800)
committerJie Han <han.jie@zte.com.cn>
Fri, 23 Feb 2018 01:12:52 +0000 (09:12 +0800)
- Add AnyxmlNodeCodecContext

Change-Id: I76d3cec49cbd98747f666719908be304057bf364
Signed-off-by: Jie Han <han.jie@zte.com.cn>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/AnyxmlNodeCodecContext.java [new file with mode: 0755]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/BindingCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/NodeCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/TreeNodeCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/serializer/BindingToNormalizedStreamWriter.java

diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/AnyxmlNodeCodecContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/AnyxmlNodeCodecContext.java
new file mode 100755 (executable)
index 0000000..39c10ef
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018 ZTE, 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.mdsal.binding.javav2.dom.codec.impl.context.base;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableCollection;
+import java.lang.reflect.Method;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.BindingNormalizedNodeCachingCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.BindingTreeNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+@Beta
+public final class AnyxmlNodeCodecContext<D extends TreeNode> extends NodeCodecContext<D>
+        implements NodeContextSupplier {
+
+    private final YangInstanceIdentifier.PathArgument yangIdentifier;
+    private final Codec<Object, Object> valueCodec;
+    private final Method getter;
+    private final DataSchemaNode schema;
+
+    AnyxmlNodeCodecContext(final DataSchemaNode schema, final Codec<Object, Object> codec, final Method getter,
+                           final SchemaContext schemaContext) {
+        this.yangIdentifier = new YangInstanceIdentifier.NodeIdentifier(schema.getQName());
+        this.valueCodec = Preconditions.checkNotNull(codec);
+        this.getter = Preconditions.checkNotNull(getter);
+        this.schema = Preconditions.checkNotNull(schema);
+    }
+
+    @Override
+    public YangInstanceIdentifier.PathArgument getDomPathArgument() {
+        return yangIdentifier;
+    }
+
+    public Codec<Object, Object> getValueCodec() {
+        return valueCodec;
+    }
+
+    @Nonnull
+    @Override
+    public D deserialize(@Nonnull final NormalizedNode<?, ?> normalizedNode) {
+        throw new UnsupportedOperationException("Anyxml can not be deserialized to TreeNode");
+    }
+
+    @Nonnull
+    @Override
+    public NodeCodecContext<?> get() {
+        return this;
+    }
+
+    public Method getGetter() {
+        return getter;
+    }
+
+    @Nonnull
+    @Override
+    public BindingTreeNodeCodec<?> bindingPathArgumentChild(@Nonnull final TreeArgument<?> arg,
+            final List<YangInstanceIdentifier.PathArgument> builder) {
+        throw new IllegalArgumentException("Anyxml does not have children");
+    }
+
+    @Nonnull
+    @Override
+    public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
+            @Nonnull final ImmutableCollection<Class<? extends TreeNode>> cacheSpecifier) {
+        throw new UnsupportedOperationException("Anyxml does not support caching codec.");
+    }
+
+    @Nonnull
+    @Override
+    public Class<D> getBindingClass() {
+        throw new UnsupportedOperationException("Anyxml does not have DataObject representation");
+    }
+
+    @Nonnull
+    @Override
+    public NormalizedNode<?, ?> serialize(@Nonnull final D data) {
+        throw new UnsupportedOperationException("Separate serialization of Anyxml node is not supported.");
+    }
+
+    @Override
+    public void writeAsNormalizedNode(final D data, final NormalizedNodeStreamWriter writer) {
+        throw new UnsupportedOperationException("Separate serialization of Anyxml node is not supported.");
+    }
+
+    @Nonnull
+    @Override
+    public <E extends TreeNode> BindingTreeNodeCodec<E> streamChild(@Nonnull final Class<E> childClass) {
+        throw new IllegalArgumentException("Anyxml does not have children");
+    }
+
+    @Override
+    public <E extends TreeNode> Optional<? extends BindingTreeNodeCodec<E>> possibleStreamChild(
+            @Nonnull final Class<E> childClass) {
+        throw new IllegalArgumentException("Anyxml does not have children");
+    }
+
+    @Nonnull
+    @Override
+    public BindingTreeNodeCodec<?> yangPathArgumentChild(final YangInstanceIdentifier.PathArgument child) {
+        throw new IllegalArgumentException("Anyxml does not have children");
+    }
+
+    @Override
+    protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+        if (normalizedNode instanceof AnyXmlNode) {
+            return valueCodec.deserialize(normalizedNode.getValue());
+        }
+        return null;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public TreeArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) {
+        Preconditions.checkArgument(getDomPathArgument().equals(arg));
+        return null;
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public YangInstanceIdentifier.PathArgument serializePathArgument(final TreeArgument arg) {
+        return getDomPathArgument();
+    }
+
+    @Nonnull
+    @Override
+    public DataSchemaNode getSchema() {
+        return schema;
+    }
+}
index 4588340f0b1aa6cfd71c87dd7d105af13474266c..d62d7ea65d4726b68986831e32bf8dfb959005c7 100644 (file)
@@ -63,6 +63,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
@@ -336,6 +337,18 @@ public final class BindingCodecContext implements CodecContextFactory, BindingTr
         return getLeafNodesUsingReflection(parentClass, getterToLeafSchema);
     }
 
+    @Override
+    public ImmutableMap<String, AnyxmlNodeCodecContext<?>> getAnyxmlNodes(final Class<?> parentClass,
+            final DataNodeContainer childSchema) {
+        final Map<String, DataSchemaNode> getterToAnyxmlSchema = new HashMap<>();
+        for (final DataSchemaNode anyxml : childSchema.getChildNodes()) {
+            if (anyxml instanceof AnyXmlSchemaNode) {
+                getterToAnyxmlSchema.put(getGetterName(anyxml.getQName(), false), anyxml);
+            }
+        }
+        return getAnyxmlNodesUsingReflection(parentClass, getterToAnyxmlSchema);
+    }
+
     private static String getGetterName(final QName qname, final TypeDefinition<?> typeDef) {
         final String suffix =
                 JavaIdentifierNormalizer.normalizeSpecificIdentifier(qname.getLocalName(), JavaIdentifier.CLASS);
@@ -345,6 +358,15 @@ public final class BindingCodecContext implements CodecContextFactory, BindingTr
         return "get" + suffix;
     }
 
+    private static String getGetterName(final QName qname, final boolean booleanOrEmpty) {
+        final String suffix =
+                JavaIdentifierNormalizer.normalizeSpecificIdentifier(qname.getLocalName(), JavaIdentifier.CLASS);
+        if (booleanOrEmpty) {
+            return "is" + suffix;
+        }
+        return "get" + suffix;
+    }
+
     private ImmutableMap<String, LeafNodeCodecContext<?>> getLeafNodesUsingReflection(final Class<?> parentClass,
             final Map<String, DataSchemaNode> getterToLeafSchema) {
         final Map<String, LeafNodeCodecContext<?>> leaves = new HashMap<>();
@@ -377,6 +399,24 @@ public final class BindingCodecContext implements CodecContextFactory, BindingTr
         return ImmutableMap.copyOf(leaves);
     }
 
+    private ImmutableMap<String, AnyxmlNodeCodecContext<?>> getAnyxmlNodesUsingReflection(final Class<?> parentClass,
+            final Map<String, DataSchemaNode> getterToAnyxmlSchema) {
+        final Map<String, AnyxmlNodeCodecContext<?>> anyxmls = new HashMap<>();
+        for (final Method method : parentClass.getMethods()) {
+            if (method.getParameterTypes().length == 0) {
+                final DataSchemaNode schema = getterToAnyxmlSchema.get(method.getName());
+                if (schema instanceof AnyXmlSchemaNode) {
+                    final Class<?> valueType = method.getReturnType();
+                    final Codec<Object, Object> codec = (Codec) getAnyxmlCodec();
+                    final AnyxmlNodeCodecContext<?> anyxmlNodeCtx =
+                            new AnyxmlNodeCodecContext<>(schema, codec, method, context.getSchemaContext());
+                    anyxmls.put(schema.getQName().getLocalName(), anyxmlNodeCtx);
+                }
+            }
+        }
+        return ImmutableMap.copyOf(anyxmls);
+    }
+
     private Codec<Object, Object> getCodec(final Class<?> valueType, final DataSchemaNode schema) {
         Preconditions.checkArgument(schema instanceof TypedDataSchemaNode, "Unsupported leaf node type %s", schema);
 
index a73d225e7c83a1d9d7cfd244d952eab3c7e15b40..532ff750f72ba2c1a8323725f8dbccb6c747c3ec 100644 (file)
@@ -74,6 +74,15 @@ public abstract class NodeCodecContext<D extends TreeNode> implements BindingTre
          */
         ImmutableMap<String, LeafNodeCodecContext<?>> getLeafNodes(Class<?> type, DataNodeContainer schema);
 
+        /**
+         * Returns anyxml nodes for supplied data container and parent class.
+         *
+         * @param type Binding type for which anyxml should be loaded.
+         * @param schema  Instantiated schema of binding type.
+         * @return Map of local name to anyxml node context.
+         */
+        ImmutableMap<String, AnyxmlNodeCodecContext<?>> getAnyxmlNodes(Class<?> type, DataNodeContainer schema);
+
         /**
          * Returns Path argument codec for list item.
          *
@@ -103,4 +112,4 @@ public abstract class NodeCodecContext<D extends TreeNode> implements BindingTre
     }
 
     protected abstract Object deserializeObject(NormalizedNode<?, ?> normalizedNode);
-}
\ No newline at end of file
+}
index 2cd1b3f14e13fdf0229e3755f2fe8aefe386562e..0ad65c648e6a9e9c59b0ebec603e254f3373126e 100644 (file)
@@ -66,6 +66,7 @@ public abstract class TreeNodeCodecContext<D extends TreeNode, T extends DataNod
     private static final Comparator<Method> METHOD_BY_ALPHABET = Comparator.comparing(Method::getName);
 
     private final ImmutableMap<String, LeafNodeCodecContext<?>> leafChild;
+    private final ImmutableMap<String, AnyxmlNodeCodecContext<?>> anyxmlChild;
     private final ImmutableMap<YangInstanceIdentifier.PathArgument, NodeContextSupplier> byYang;
     private final ImmutableSortedMap<Method, NodeContextSupplier> byMethod;
     private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byStreamClass;
@@ -82,6 +83,7 @@ public abstract class TreeNodeCodecContext<D extends TreeNode, T extends DataNod
         super(prototype);
 
         this.leafChild = factory().getLeafNodes(getBindingClass(), getSchema());
+        this.anyxmlChild = factory().getAnyxmlNodes(getBindingClass(), getSchema());
 
         final Map<Class<?>, Method> clsToMethod = BindingReflections.getChildrenClassToMethod(getBindingClass());
 
@@ -96,6 +98,11 @@ public abstract class TreeNodeCodecContext<D extends TreeNode, T extends DataNod
             byYangBuilder.put(leaf.getDomPathArgument(), leaf);
         }
 
+        for (final AnyxmlNodeCodecContext<?> anyxml : anyxmlChild.values()) {
+            byMethodBuilder.put(anyxml.getGetter(), anyxml);
+            byYangBuilder.put(anyxml.getDomPathArgument(), anyxml);
+        }
+
         for (final Entry<Class<?>, Method> childDataObj : clsToMethod.entrySet()) {
             final DataContainerCodecPrototype<?> childProto = loadChildPrototype(childDataObj.getKey());
             byMethodBuilder.put(childDataObj.getValue(), childProto);
@@ -209,6 +216,11 @@ public abstract class TreeNodeCodecContext<D extends TreeNode, T extends DataNod
         return IncorrectNestingException.checkNonNull(value, "Leaf %s is not valid for %s", name, getBindingClass());
     }
 
+    public final AnyxmlNodeCodecContext<?> getAnyxmlChild(final String name) {
+        final AnyxmlNodeCodecContext<?> value = anyxmlChild.get(name);
+        return IncorrectNestingException.checkNonNull(value, "Anyxml %s is not valid for %s", name, getBindingClass());
+    }
+
     private DataContainerCodecPrototype<?> loadChildPrototype(final Class<?> childClass) {
         final DataSchemaNode origDef = factory().getRuntimeContext().getSchemaDefinition(childClass);
         // Direct instantiation or use in same module in which grouping
index 35313cd2d9e31260a68ef0337913815601a58106..28eaba57a918bad385c64fe72ac3d18f70091c4e 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.CaseNodeCodecContext;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.KeyedListNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.AnyxmlNodeCodecContext;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.LeafNodeCodecContext;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext;
@@ -144,6 +145,18 @@ public final class BindingToNormalizedStreamWriter
         return new AbstractMap.SimpleEntry<>(domArg, domValue);
     }
 
+    private Map.Entry<NodeIdentifier, Object> serializeAnyxml(final String localName, final Object value) {
+        Preconditions.checkArgument(current() instanceof TreeNodeCodecContext);
+
+        final TreeNodeCodecContext<?, ?> currentCasted = (TreeNodeCodecContext<?, ?>) current();
+        final AnyxmlNodeCodecContext<?> anyxmlContext = currentCasted.getAnyxmlChild(localName);
+
+        final NodeIdentifier domArg = (NodeIdentifier) anyxmlContext.getDomPathArgument();
+        final Object domValue = anyxmlContext.getValueCodec().serialize(value);
+        emitSchema(anyxmlContext.getSchema());
+        return new AbstractMap.SimpleEntry<>(domArg, domValue);
+    }
+
     @Override
     public void leafNode(final String localName, final Object value) throws IOException {
         final Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
@@ -152,7 +165,7 @@ public final class BindingToNormalizedStreamWriter
 
     @Override
     public void anyxmlNode(final String name, final Object value) throws IOException {
-        final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
+        final Entry<NodeIdentifier, Object> dom = serializeAnyxml(name, value);
         getDelegate().anyxmlNode(dom.getKey(), dom.getValue());
     }