Binding2 runtime - Codecs 77/58977/1
authorJakub Toth <jakub.toth@pantheon.tech>
Thu, 8 Jun 2017 23:07:04 +0000 (01:07 +0200)
committerMartin Ciglan <martin.ciglan@pantheon.tech>
Wed, 14 Jun 2017 20:13:41 +0000 (20:13 +0000)
  * new codecs and contexts
  * BindingContextCodec
  * BindingNormalizdeNodeCodecRegistry

Change-Id: Ieab1cac667f755962b818c452171da9dc74ab979
Signed-off-by: Jakub Toth <jakub.toth@pantheon.tech>
(cherry picked from commit a9deaba3e6463f7056ed327dbc75bd6f727f6cb0)

13 files changed:
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/api/serializer/BindingNormalizedNodeSerializer.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/InstanceIdentifierCodec.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/UnionTypeCodec.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/AugmentationNodeContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ContainerNodeCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/KeyedListNodeCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ListNodeCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/BindingCodecContext.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/DataContainerCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/DataContainerCodecPrototype.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/value/ReflectionBasedCodec.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/value/ValueTypeCodec.java

index 254279ab4bf7fce2b3abbf4c0e342f0b7477fdb1..521af6232159f6e64a9612d9248bc314f5acecf4 100644 (file)
@@ -128,5 +128,5 @@ public interface BindingNormalizedNodeSerializer {
      * @return NormalizedNode representation of operation data
      */
     @Nonnull
-    ContainerNode toNormalizedNodeRpcData(@Nonnull Instantiable<?> data);
+    ContainerNode toNormalizedNodeOperationData(@Nonnull Instantiable<?> data);
 }
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java
new file mode 100644 (file)
index 0000000..c2694d2
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.io.IOException;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.BindingTreeCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.factory.BindingNormalizedNodeWriterFactory;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.factory.BindingTreeCodecFactory;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.serializer.BindingNormalizedNodeSerializer;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.api.TreeNodeSerializerGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.NotificationCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.BindingCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.runtime.context.BindingRuntimeContext;
+import org.opendaylight.mdsal.binding.javav2.runtime.context.ModuleInfoBackedContext;
+import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Notification;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializer;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerImplementation;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerRegistry;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Serializing and deserializing Binding and DOM data
+ */
+@Beta
+public class BindingNormalizedNodeCodecRegistry implements TreeNodeSerializerRegistry, BindingTreeCodecFactory,
+        BindingNormalizedNodeWriterFactory, BindingNormalizedNodeSerializer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BindingNormalizedNodeCodecRegistry.class);
+
+    private final TreeNodeSerializerGenerator generator;
+    private final LoadingCache<Class<? extends TreeNode>, TreeNodeSerializer> serializers;
+    private volatile BindingCodecContext codecContext;
+
+    /**
+     * Prepare generator for generating serializers and create loader for serializers.
+     *
+     * @param generator
+     *            - serializer generator
+     */
+    public BindingNormalizedNodeCodecRegistry(final TreeNodeSerializerGenerator generator) {
+        this.generator = Preconditions.checkNotNull(generator);
+        this.serializers = CacheBuilder.newBuilder().weakKeys().build(new GeneratorLoader());
+    }
+
+    @Override
+    public TreeNodeSerializer getSerializer(final Class<? extends TreeNode> type) {
+        return serializers.getUnchecked(type);
+    }
+
+    /**
+     * Get binding tree codec context.
+     *
+     * @return codec context
+     */
+    public BindingTreeCodec getCodecContext() {
+        return codecContext;
+    }
+
+    /**
+     * Create codec context based on runtime context and notify generator that runtime context has been
+     * updated.
+     *
+     * @param context
+     *            - runtime context
+     */
+    public void onBindingRuntimeContextUpdated(final BindingRuntimeContext context) {
+        codecContext = create(context);
+        generator.onBindingRuntimeContextUpdated(context);
+    }
+
+    @Nullable
+    @Override
+    public YangInstanceIdentifier toYangInstanceIdentifier(@Nonnull final InstanceIdentifier<?> binding) {
+        return codecContext.getInstanceIdentifierCodec().serialize(binding);
+    }
+
+    @Nullable
+    @Override
+    public InstanceIdentifier<?> fromYangInstanceIdentifier(@Nonnull final YangInstanceIdentifier dom) {
+        return codecContext.getInstanceIdentifierCodec().deserialize(dom);
+    }
+
+    @Nullable
+    @Override
+    public <T extends TreeNode> Entry<YangInstanceIdentifier, NormalizedNode<?, ?>>
+            toNormalizedNode(final InstanceIdentifier<T> path, final T data) {
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        // We create DOM stream writer which produces normalized nodes
+        final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+        // We create Binding Stream Writer which translates from Binding to Normalized Nodes
+        final Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx =
+                codecContext.newWriter(path, domWriter);
+
+        // We get serializer which reads binding data and uses Binding To Normalized Node writer to write
+        // result
+        try {
+            getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
+        } catch (final IOException e) {
+            LOG.error("Unexpected failure while serializing path {} data {}", path, data, e);
+            throw new IllegalStateException("Failed to create normalized node", e);
+        }
+        return new SimpleEntry<>(writeCtx.getKey(), result.getResult());
+    }
+
+    @Nonnull
+    @SuppressWarnings("rawtypes")
+    @Override
+    public ContainerNode toNormalizedNodeNotification(@Nonnull final Notification data) {
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        // We create DOM stream writer which produces normalized nodes
+        final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        @SuppressWarnings("unchecked")
+        final Class<? extends TreeNode> type = (Class) data.getClass();
+        @SuppressWarnings("unchecked")
+        final BindingStreamEventWriter writer = newNotificationWriter((Class) type, domWriter);
+        try {
+            getSerializer(type).serialize((TreeNode) data, writer);
+        } catch (final IOException e) {
+            LOG.error("Unexpected failure while serializing data {}", data, e);
+            throw new IllegalStateException("Failed to create normalized node", e);
+        }
+        return (ContainerNode) result.getResult();
+
+    }
+
+    @Nonnull
+    @SuppressWarnings("unchecked")
+    @Override
+    public ContainerNode toNormalizedNodeOperationData(@Nonnull final Instantiable<?> data) {
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        // We create DOM stream writer which produces normalized nodes
+        final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        @SuppressWarnings("rawtypes")
+        final Class<? extends TreeNode> type = (Class) data.implementedInterface();
+        final Class<? extends Instantiable<?>> instData = (Class<? extends Instantiable<?>>) data.getClass();
+        final BindingStreamEventWriter writer = newOperationWriter(instData, domWriter);
+        try {
+            getSerializer(type).serialize((TreeNode) data, writer);
+        } catch (final IOException e) {
+            LOG.error("Unexpected failure while serializing data {}", data, e);
+            throw new IllegalStateException("Failed to create normalized node", e);
+        }
+        return (ContainerNode) result.getResult();
+    }
+
+    private static boolean isBindingRepresentable(final NormalizedNode<?, ?> data) {
+        if (data instanceof ChoiceNode) {
+            return false;
+        }
+        if (data instanceof LeafNode<?>) {
+            return false;
+        }
+        if (data instanceof LeafSetNode) {
+            return false;
+        }
+        if (data instanceof LeafSetEntryNode<?>) {
+            return false;
+        }
+        if (data instanceof MapNode) {
+            return false;
+        }
+        if (data instanceof UnkeyedListNode) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Nullable
+    @Override
+    public Entry<InstanceIdentifier<?>, TreeNode> fromNormalizedNode(@Nonnull final YangInstanceIdentifier path,
+            final NormalizedNode<?, ?> data) {
+        if (!isBindingRepresentable(data)) {
+            return null;
+        }
+
+        final List<TreeArgument<?>> builder = new ArrayList<>();
+        final NodeCodecContext<?> codec = codecContext.getCodecContextNode(path, builder);
+        if (codec == null) {
+            if (data != null) {
+                LOG.warn("Path {} does not have a binding equivalent, should have been caught earlier ({})", path,
+                        data.getClass());
+            }
+            return null;
+        }
+
+        final TreeNode lazyObj = codec.deserialize(data);
+        final InstanceIdentifier<?> bindingPath = InstanceIdentifier.create(builder);
+        return new SimpleEntry<>(bindingPath, lazyObj);
+    }
+
+    @Nullable
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public Notification fromNormalizedNodeNotification(@Nonnull final SchemaPath path,
+            @Nonnull final ContainerNode data) {
+        final NotificationCodecContext<?> codec = codecContext.getNotificationContext(path);
+        return codec.deserialize(data);
+    }
+
+    @Nullable
+    @Override
+    public TreeNode fromNormalizedNodeOperationData(@Nonnull final SchemaPath path, @Nonnull final ContainerNode data) {
+        final OperationInputCodec<?> codec = codecContext.getOperationInputCodec(path);
+        return codec.deserialize(data);
+    }
+
+    @Nonnull
+    @Override
+    public Entry<YangInstanceIdentifier, BindingStreamEventWriter>
+            newWriterAndIdentifier(@Nonnull final InstanceIdentifier<?> path,
+                    @Nonnull final NormalizedNodeStreamWriter domWriter) {
+        return codecContext.newWriter(path, domWriter);
+    }
+
+    @Nonnull
+    @Override
+    public BindingStreamEventWriter newWriter(@Nonnull final InstanceIdentifier<?> path,
+            @Nonnull final NormalizedNodeStreamWriter domWriter) {
+        return codecContext.newWriterWithoutIdentifier(path, domWriter);
+    }
+
+    @Nonnull
+    @Override
+    public BindingStreamEventWriter newNotificationWriter(@Nonnull final Class<? extends Notification<?>> notification,
+            @Nonnull final NormalizedNodeStreamWriter domWriter) {
+        return codecContext.newNotificationWriter(notification, domWriter);
+    }
+
+    @Nonnull
+    @Override
+    public BindingStreamEventWriter newOperationWriter(
+            @Nonnull final Class<? extends Instantiable<?>> operationInputOrOutput,
+            @Nonnull final NormalizedNodeStreamWriter domWriter) {
+        return codecContext.newOperationWriter(operationInputOrOutput, domWriter);
+    }
+
+    /**
+     * Deserialize function based on tree node codec context resolved by binding path.
+     *
+     * @param path
+     *            - binding identifier
+     * @return function deserializer of codec context of binding path
+     */
+    public <T extends TreeNode> Function<Optional<NormalizedNode<?, ?>>, Optional<T>>
+            deserializeFunction(final InstanceIdentifier<T> path) {
+        final TreeNodeCodecContext<?, ?> ctx =
+                (TreeNodeCodecContext<?, ?>) codecContext.getCodecContextNode(path, null);
+        return new DeserializeFunction<>(ctx);
+    }
+
+    @Override
+    public BindingCodecContext create(final BindingRuntimeContext context) {
+        return new BindingCodecContext(context, this);
+    }
+
+    @Override
+    public BindingCodecContext create(final SchemaContext context, final Class<?>... bindingClasses) {
+        final ModuleInfoBackedContext strategy = ModuleInfoBackedContext.create();
+        for (final Class<?> bindingCls : bindingClasses) {
+            try {
+                strategy.registerModuleInfo(BindingReflections.getModuleInfo(bindingCls));
+            } catch (final Exception e) {
+                throw new IllegalStateException(
+                        "Could not create BindingRuntimeContext from class " + bindingCls.getName(), e);
+            }
+        }
+        final BindingRuntimeContext runtimeCtx = BindingRuntimeContext.create(strategy, context);
+        return create(runtimeCtx);
+    }
+
+    private static final class DeserializeFunction<T> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
+        private final TreeNodeCodecContext<?, ?> ctx;
+
+        DeserializeFunction(final TreeNodeCodecContext<?, ?> ctx) {
+            this.ctx = ctx;
+        }
+
+        @Nullable
+        @SuppressWarnings("unchecked")
+        @Override
+        public Optional<T> apply(@Nullable final Optional<NormalizedNode<?, ?>> input) {
+            if (input.isPresent()) {
+                return Optional.of((T) ctx.deserialize(input.get()));
+            }
+            return Optional.absent();
+        }
+    }
+
+    private final class GeneratorLoader extends CacheLoader<Class<? extends TreeNode>, TreeNodeSerializer> {
+        @Override
+        public TreeNodeSerializer load(final Class<? extends TreeNode> key) throws Exception {
+            final TreeNodeSerializerImplementation prototype = generator.getSerializer(key);
+            return new TreeNodeSerializerProxy(prototype);
+        }
+    }
+
+    private final class TreeNodeSerializerProxy
+            implements TreeNodeSerializer, Delegator<TreeNodeSerializerImplementation> {
+        private final TreeNodeSerializerImplementation delegate;
+
+        TreeNodeSerializerProxy(final TreeNodeSerializerImplementation delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public TreeNodeSerializerImplementation getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public void serialize(final TreeNode obj, final BindingStreamEventWriter stream) throws IOException {
+            delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);
+        }
+    }
+
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/InstanceIdentifierCodec.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/InstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..60834d4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ListNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.BindingCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Item;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+/**
+ * Codec for serializer/deserialize DOM and binding identifiers.
+ *
+ */
+@Beta
+public final class InstanceIdentifierCodec implements Codec<YangInstanceIdentifier, InstanceIdentifier<?>> {
+
+    private final BindingCodecContext context;
+
+    /**
+     * Prepare codec context.
+     *
+     * @param context
+     *            - binding codec context
+     */
+    public InstanceIdentifierCodec(final BindingCodecContext context) {
+        this.context = Preconditions.checkNotNull(context);
+    }
+
+    @Override
+    public YangInstanceIdentifier serialize(final InstanceIdentifier<?> input) {
+        final List<PathArgument> domArgs = new ArrayList<>();
+        context.getCodecContextNode(input, domArgs);
+        return YangInstanceIdentifier.create(domArgs);
+    }
+
+    @Override
+    public InstanceIdentifier<?> deserialize(final YangInstanceIdentifier input) {
+        final List<TreeArgument<?>> builder = new ArrayList<>();
+        final NodeCodecContext<?> codec = context.getCodecContextNode(input, builder);
+
+        if (codec == null) {
+            return null;
+        }
+
+        if (codec instanceof ListNodeCodecContext && Iterables.getLast(builder) instanceof Item<?>) {
+            // We ended up in list, but without key, which means it represent list as a whole,
+            // which is not binding representable.
+            return null;
+        }
+
+        return InstanceIdentifier.create(builder);
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/UnionTypeCodec.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/UnionTypeCodec.java
new file mode 100644 (file)
index 0000000..9c09ad0
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
+import java.lang.reflect.Method;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.UnionValueOptionContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.BindingCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.value.ReflectionBasedCodec;
+import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
+import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+
+/**
+ * Codec for serialize/deserialize union type.
+ *
+ */
+@Beta
+public final class UnionTypeCodec extends ReflectionBasedCodec {
+
+    private final ImmutableSet<UnionValueOptionContext> typeCodecs;
+
+    private UnionTypeCodec(final Class<?> unionCls, final Set<UnionValueOptionContext> codecs) {
+        super(unionCls);
+        typeCodecs = ImmutableSet.copyOf(codecs);
+    }
+
+    /**
+     * Loading union type codec for all subtypes of union.
+     *
+     * @param unionCls
+     *            - binding class of union
+     * @param unionType
+     *            - type definition of union
+     * @param bindingCodecContext
+     *            - binding codec context
+     * @return union codec
+     */
+    public static Callable<UnionTypeCodec> loader(final Class<?> unionCls, final UnionTypeDefinition unionType,
+            final BindingCodecContext bindingCodecContext) {
+        return () -> {
+            final Set<UnionValueOptionContext> values = new LinkedHashSet<>();
+            for (final TypeDefinition<?> subtype : unionType.getTypes()) {
+                final Method valueGetter = unionCls.getMethod("get" + JavaIdentifierNormalizer
+                        .normalizeSpecificIdentifier(subtype.getQName().getLocalName(), JavaIdentifier.CLASS));
+                final Class<?> valueType = valueGetter.getReturnType();
+                final Codec<Object, Object> valueCodec = bindingCodecContext.getCodec(valueType, subtype);
+                values.add(new UnionValueOptionContext(unionCls, valueType, valueGetter, valueCodec));
+            }
+            return new UnionTypeCodec(unionCls, values);
+        };
+    }
+
+    @Override
+    public Object deserialize(final Object input) {
+        for (final UnionValueOptionContext member : typeCodecs) {
+            final Object ret = member.deserializeUnion(input);
+            if (ret != null) {
+                return ret;
+            }
+        }
+
+        throw new IllegalArgumentException(
+                String.format("Failed to construct instance of %s for input %s", getTypeClass(), input));
+    }
+
+    @Override
+    public Object serialize(final Object input) {
+        if (input != null) {
+            for (final UnionValueOptionContext valCtx : typeCodecs) {
+                final Object domValue = valCtx.serialize(input);
+                if (domValue != null) {
+                    return domValue;
+                }
+            }
+        }
+        return null;
+    }
+}
index 767cfbc1b612875f53faf20421b751f1b459e738..92936436a0dc30ec1df4da2b8a286907777441b1 100644 (file)
@@ -20,6 +20,9 @@ import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 
 /**
  * Context for prototype of augmentation node.
+ *
+ * @param <D>
+ *            - type of tree node
  */
 @Beta
 public final class AugmentationNodeContext<D extends TreeNode & Augmentation<?>>
index 293fa6db097cd3b74c009841f53569af2d913eec..635f278dce8a3333fb78fc3c05ca7721f126c529 100644 (file)
@@ -34,7 +34,7 @@ public class ContainerNodeCodecContext<D extends TreeNode> extends TreeNodeCodec
      * @param prototype
      *            - codec prototype of container node
      */
-    ContainerNodeCodecContext(final DataContainerCodecPrototype<ContainerSchemaNode> prototype) {
+    public ContainerNodeCodecContext(final DataContainerCodecPrototype<ContainerSchemaNode> prototype) {
         super(prototype);
     }
 
index 2a093a091ce7e1cace009a8a6f772634da802364..3a7a94d6ba5c85134ff0dadf1c8dd93e762937b6 100644 (file)
@@ -42,7 +42,7 @@ public final class KeyedListNodeCodecContext<D extends TreeNode & Identifiable<?
      * @param prototype
      *            - codec prototype of keyed list node
      */
-    KeyedListNodeCodecContext(final DataContainerCodecPrototype<ListSchemaNode> prototype) {
+    public KeyedListNodeCodecContext(final DataContainerCodecPrototype<ListSchemaNode> prototype) {
         super(prototype);
         this.codec = factory().getPathArgumentCodec(getBindingClass(), getSchema());
         try {
index dcb8c94a0a3334eeff77e89778f15ca07d23755b..e98ab2661575366b27484db20b15e867f5777e02 100644 (file)
@@ -28,7 +28,7 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
  *            - type of tree node
  */
 @Beta
-class ListNodeCodecContext<D extends TreeNode> extends TreeNodeCodecContext<D, ListSchemaNode> {
+public class ListNodeCodecContext<D extends TreeNode> extends TreeNodeCodecContext<D, ListSchemaNode> {
 
     /**
      * Prepare context for list node from prototype.
@@ -36,7 +36,7 @@ class ListNodeCodecContext<D extends TreeNode> extends TreeNodeCodecContext<D, L
      * @param prototype
      *            - codec prototype of list node
      */
-    protected ListNodeCodecContext(final DataContainerCodecPrototype<ListSchemaNode> prototype) {
+    public ListNodeCodecContext(final DataContainerCodecPrototype<ListSchemaNode> prototype) {
         super(prototype);
     }
 
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/BindingCodecContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/BindingCodecContext.java
new file mode 100644 (file)
index 0000000..efdfb99
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.BindingTreeCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.BindingTreeNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.IdentifiableItemCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.IdentityCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.InstanceIdentifierCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.OperationInputCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.UnionTypeCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.CaseNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ChoiceNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ListNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.NotificationCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.SchemaRootCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ValueContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext.CodecContextFactory;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.value.ValueTypeCodec;
+import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
+import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
+import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.javav2.runtime.context.BindingRuntimeContext;
+import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
+import org.opendaylight.mdsal.binding.javav2.spec.base.IdentifiableItem;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Notification;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializer;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.Identifier;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+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.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Binding codec context for holding runtime part and codecs.
+ */
+@Beta
+public final class BindingCodecContext implements CodecContextFactory, BindingTreeCodec, Immutable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BindingCodecContext.class);
+
+    private final Codec<YangInstanceIdentifier, InstanceIdentifier<?>> instanceIdentifierCodec;
+    private final Codec<QName, Class<?>> identityCodec;
+    private final BindingNormalizedNodeCodecRegistry registry;
+    private final BindingRuntimeContext context;
+    private final SchemaRootCodecContext<?> root;
+
+    /**
+     * Prepare runtime context and codec registry.
+     *
+     * @param context
+     *            - runtime context
+     * @param registry
+     *            - binding normalized node codec registry
+     */
+    public BindingCodecContext(final BindingRuntimeContext context, final BindingNormalizedNodeCodecRegistry registry) {
+        this.context = Preconditions.checkNotNull(context, "Binding Runtime Context is required.");
+        this.root = SchemaRootCodecContext.create(this);
+        this.identityCodec = new IdentityCodec(context);
+        this.instanceIdentifierCodec = new InstanceIdentifierCodec(this);
+        this.registry = Preconditions.checkNotNull(registry);
+    }
+
+    @Override
+    public BindingRuntimeContext getRuntimeContext() {
+        return context;
+    }
+
+    /**
+     * Get instance identifier codec.
+     *
+     * @return instance identifier codec
+     */
+    public Codec<YangInstanceIdentifier, InstanceIdentifier<?>> getInstanceIdentifierCodec() {
+        return instanceIdentifierCodec;
+    }
+
+    /**
+     * Get identity codec.
+     *
+     * @return identity codec
+     */
+    public Codec<QName, Class<?>> getIdentityCodec() {
+        return identityCodec;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public TreeNodeSerializer getEventStreamSerializer(final Class<?> type) {
+        return registry.getSerializer((Class) type);
+    }
+
+    /**
+     * Prepare specific writer for binding path.
+     *
+     * @param path
+     *            - binding path
+     * @param domWriter
+     *            - DOM writer
+     * @return entry of DOM path and writer
+     */
+    public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriter(final InstanceIdentifier<?> path,
+            final NormalizedNodeStreamWriter domWriter) {
+        final List<YangInstanceIdentifier.PathArgument> yangArgs = new LinkedList<>();
+        final DataContainerCodecContext<?, ?> codecContext = getCodecContextNode(path, yangArgs);
+        return new SimpleEntry<>(YangInstanceIdentifier.create(yangArgs), codecContext.createWriter(domWriter));
+    }
+
+    /**
+     * Prepare specific writer for binding path without DOM identifier.
+     *
+     * @param path
+     *            - binding path
+     * @param domWriter
+     *            - DOM writer
+     * @return stream event writer for binding path
+     */
+    public BindingStreamEventWriter newWriterWithoutIdentifier(final InstanceIdentifier<?> path,
+            final NormalizedNodeStreamWriter domWriter) {
+        return getCodecContextNode(path, null).createWriter(domWriter);
+    }
+
+    /**
+     * Prepare specific writer for operations.
+     *
+     * @param operationInputOrOutput
+     *            - binding data
+     * @param domWriter
+     *            - DOM writer
+     * @return stream event writer for operation
+     */
+    public BindingStreamEventWriter newOperationWriter(final Class<? extends Instantiable<?>> operationInputOrOutput,
+            final NormalizedNodeStreamWriter domWriter) {
+        return root.getOperation(operationInputOrOutput).createWriter(domWriter);
+    }
+
+    @SuppressWarnings("rawtypes")
+    public BindingStreamEventWriter newNotificationWriter(final Class<? extends Notification> notification,
+            final NormalizedNodeStreamWriter domWriter) {
+        return root.getNotification(notification).createWriter(domWriter);
+    }
+
+    /**
+     * Prepare context from Binding and DOM path.
+     *
+     * @param binding
+     *            - binding path
+     * @param builder
+     *            - DOM path
+     *
+     * @return context for path
+     */
+    public DataContainerCodecContext<?, ?> getCodecContextNode(final InstanceIdentifier<?> binding,
+            final List<YangInstanceIdentifier.PathArgument> builder) {
+        DataContainerCodecContext<?, ?> currentNode = root;
+        for (final TreeArgument<?> bindingArg : binding.getPathArguments()) {
+            currentNode = currentNode.bindingPathArgumentChild(bindingArg, builder);
+            Preconditions.checkArgument(currentNode != null, "Supplied Instance Identifier %s is not valid.", binding);
+        }
+        return currentNode;
+    }
+
+    /**
+     * Multi-purpose utility function. Traverse the codec tree, looking for the appropriate codec for the
+     * specified {@link YangInstanceIdentifier}. As a side-effect, gather all traversed binding
+     * {@link TreeArgument} into the supplied collection.
+     *
+     * @param dom
+     *            {@link YangInstanceIdentifier} which is to be translated
+     * @param bindingArguments
+     *            Collection for traversed path arguments
+     * @return Codec for target node, or @null if the node does not have a binding representation (choice,
+     *         case, leaf).
+     *
+     */
+    @Nullable
+    public NodeCodecContext<?> getCodecContextNode(final @Nonnull YangInstanceIdentifier dom,
+            final @Nullable Collection<TreeArgument<?>> bindingArguments) {
+        NodeCodecContext<?> currentNode = root;
+        ListNodeCodecContext<?> currentList = null;
+
+        for (final YangInstanceIdentifier.PathArgument domArg : dom.getPathArguments()) {
+            Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext<?, ?>,
+                    "Unexpected child of non-container node %s", currentNode);
+            final DataContainerCodecContext<?, ?> previous = (DataContainerCodecContext<?, ?>) currentNode;
+            final NodeCodecContext<?> nextNode = previous.yangPathArgumentChild(domArg);
+
+            /*
+             * List representation in YANG Instance Identifier consists of two arguments: first is list as a
+             * whole, second is list as an item so if it is /list it means list as whole, if it is /list/list
+             * - it is wildcarded and if it is /list/list[key] it is concrete item, all this variations are
+             * expressed in Binding Aware Instance Identifier as Item or IdentifiableItem
+             */
+            if (currentList != null) {
+                Preconditions.checkArgument(currentList == nextNode,
+                        "List should be referenced two times in YANG Instance Identifier %s", dom);
+
+                // We entered list, so now we have all information to emit
+                // list path using second list argument.
+                if (bindingArguments != null) {
+                    bindingArguments.add(currentList.getBindingPathArgument(domArg));
+                }
+                currentList = null;
+                currentNode = nextNode;
+            } else if (nextNode instanceof ListNodeCodecContext) {
+                // We enter list, we do not update current Node yet,
+                // since we need to verify
+                currentList = (ListNodeCodecContext<?>) nextNode;
+            } else if (nextNode instanceof ChoiceNodeCodecContext) {
+                // We do not add path argument for choice, since
+                // it is not supported by binding instance identifier.
+                currentNode = nextNode;
+            } else if (nextNode instanceof DataContainerCodecContext<?, ?>) {
+                if (bindingArguments != null) {
+                    bindingArguments.add(((DataContainerCodecContext<?, ?>) nextNode).getBindingPathArgument(domArg));
+                }
+                currentNode = nextNode;
+            } else if (nextNode instanceof LeafNodeCodecContext) {
+                LOG.debug("Instance identifier referencing a leaf is not representable (%s)", dom);
+                return null;
+            }
+        }
+
+        // Algorithm ended in list as whole representation
+        // we sill need to emit identifier for list
+        if (currentNode instanceof ChoiceNodeCodecContext) {
+            LOG.debug("Instance identifier targeting a choice is not representable (%s)", dom);
+            return null;
+        }
+        if (currentNode instanceof CaseNodeCodecContext) {
+            LOG.debug("Instance identifier targeting a case is not representable (%s)", dom);
+            return null;
+        }
+
+        if (currentList != null) {
+            if (bindingArguments != null) {
+                bindingArguments.add(currentList.getBindingPathArgument(null));
+            }
+            return currentList;
+        }
+        return currentNode;
+    }
+
+    /**
+     * Get notification codec according to notification schema path.
+     *
+     * @param notification
+     *            - schema path of notification
+     * @return notification codec context
+     */
+    public NotificationCodecContext<?> getNotificationContext(final SchemaPath notification) {
+        return root.getNotification(notification);
+    }
+
+    /**
+     * Get operation input codec.
+     *
+     * @param path
+     *            - path of input data of operation
+     * @return operation input codec
+     */
+    public OperationInputCodec<?> getOperationInputCodec(final SchemaPath path) {
+        return root.getOperation(path);
+    }
+
+    @Override
+    public ImmutableMap<String, LeafNodeCodecContext<?>> getLeafNodes(final Class<?> parentClass,
+            final DataNodeContainer childSchema) {
+        final Map<String, DataSchemaNode> getterToLeafSchema = new HashMap<>();
+        for (final DataSchemaNode leaf : childSchema.getChildNodes()) {
+            if (leaf instanceof TypedSchemaNode) {
+                getterToLeafSchema.put(getGetterName(leaf.getQName(), ((TypedSchemaNode) leaf).getType()), leaf);
+            }
+        }
+        return getLeafNodesUsingReflection(parentClass, getterToLeafSchema);
+    }
+
+    private static String getGetterName(final QName qName, final TypeDefinition<?> typeDef) {
+        final String suffix =
+                JavaIdentifierNormalizer.normalizeSpecificIdentifier(qName.getLocalName(), JavaIdentifier.CLASS);
+        if (typeDef instanceof BooleanTypeDefinition || typeDef instanceof EmptyTypeDefinition) {
+            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<>();
+        for (final Method method : parentClass.getMethods()) {
+            if (method.getParameterTypes().length == 0) {
+                final DataSchemaNode schema = getterToLeafSchema.get(method.getName());
+                final Class<?> valueType;
+                if (schema instanceof LeafSchemaNode) {
+                    valueType = method.getReturnType();
+                } else if (schema instanceof LeafListSchemaNode) {
+                    final Type genericType = ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType());
+
+                    if (genericType instanceof Class<?>) {
+                        valueType = (Class<?>) genericType;
+                    } else if (genericType instanceof ParameterizedType) {
+                        valueType = (Class<?>) ((ParameterizedType) genericType).getRawType();
+                    } else {
+                        throw new IllegalStateException("Unexpected return type " + genericType);
+                    }
+                } else {
+                    continue; // We do not have schema for leaf, so we will ignore it (eg. getClass,
+                              // getImplementedInterface).
+                }
+                final Codec<Object, Object> codec = getCodec(valueType, schema);
+                final LeafNodeCodecContext<?> leafNode =
+                        new LeafNodeCodecContext<>(schema, codec, method, context.getSchemaContext());
+                leaves.put(schema.getQName().getLocalName(), leafNode);
+            }
+        }
+        return ImmutableMap.copyOf(leaves);
+    }
+
+    private Codec<Object, Object> getCodec(final Class<?> valueType, final DataSchemaNode schema) {
+        Preconditions.checkArgument(schema instanceof TypedSchemaNode, "Unsupported leaf node type %s", schema);
+
+        return getCodec(valueType, ((TypedSchemaNode) schema).getType());
+    }
+
+    /**
+     * Get specific codec for binding class by type.
+     *
+     * @param valueType
+     *            - binding class
+     * @param instantiatedType
+     *            - type definition
+     * @return specific codec
+     */
+    public Codec<Object, Object> getCodec(final Class<?> valueType, final TypeDefinition<?> instantiatedType) {
+        if (Class.class.equals(valueType)) {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            final Codec<Object, Object> casted = (Codec) identityCodec;
+            return casted;
+        } else if (InstanceIdentifier.class.equals(valueType)) {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            final Codec<Object, Object> casted = (Codec) instanceIdentifierCodec;
+            return casted;
+        } else if (Boolean.class.equals(valueType)) {
+            if (instantiatedType instanceof EmptyTypeDefinition) {
+                return ValueTypeCodec.EMPTY_CODEC;
+            }
+        } else if (BindingReflections.isBindingClass(valueType)) {
+            return getCodecForBindingClass(valueType, instantiatedType);
+        }
+        return ValueTypeCodec.NOOP_CODEC;
+    }
+
+    private Codec<Object, Object> getCodecForBindingClass(final Class<?> valueType, final TypeDefinition<?> typeDef) {
+        if (typeDef instanceof IdentityrefTypeDefinition) {
+            return ValueTypeCodec.encapsulatedValueCodecFor(valueType, identityCodec);
+        } else if (typeDef instanceof InstanceIdentifierTypeDefinition) {
+            return ValueTypeCodec.encapsulatedValueCodecFor(valueType, instanceIdentifierCodec);
+        } else if (typeDef instanceof UnionTypeDefinition) {
+            final Callable<UnionTypeCodec> loader =
+                    UnionTypeCodec.loader(valueType, (UnionTypeDefinition) typeDef, this);
+            try {
+                return loader.call();
+            } catch (final Exception e) {
+                throw new IllegalStateException("Unable to load codec for " + valueType, e);
+            }
+        } else if (typeDef instanceof LeafrefTypeDefinition) {
+            final Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(valueType);
+            final Object schema = typeWithSchema.getValue();
+            Preconditions.checkState(schema instanceof TypeDefinition<?>);
+            return getCodec(valueType, (TypeDefinition<?>) schema);
+        }
+        return ValueTypeCodec.getCodecFor(valueType, typeDef);
+    }
+
+    @Override
+    public Codec<NodeIdentifierWithPredicates, IdentifiableItem<?, ?>> getPathArgumentCodec(final Class<?> listClz,
+            final ListSchemaNode schema) {
+        final Class<? extends Identifier> identifier =
+                ClassLoaderUtils.findFirstGenericArgument(listClz, Identifiable.class);
+        final Map<QName, ValueContext> valueCtx = new HashMap<>();
+        for (final LeafNodeCodecContext<?> leaf : getLeafNodes(identifier, schema).values()) {
+            final QName name = leaf.getDomPathArgument().getNodeType();
+            valueCtx.put(name, new ValueContext(identifier, leaf));
+        }
+        return new IdentifiableItemCodec(schema, identifier, listClz, valueCtx);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Nullable
+    @Override
+    public <T extends TreeNode> BindingTreeNodeCodec<T> getSubtreeCodec(final InstanceIdentifier<T> path) {
+        return (BindingTreeNodeCodec<T>) getCodecContextNode(path, null);
+    }
+
+    @Nullable
+    @Override
+    public BindingTreeNodeCodec<?> getSubtreeCodec(final YangInstanceIdentifier path) {
+        return getCodecContextNode(path, null);
+    }
+
+    @Nullable
+    @Override
+    public BindingTreeNodeCodec<?> getSubtreeCodec(final SchemaPath path) {
+        throw new UnsupportedOperationException("Not implemented yet.");
+    }
+}
index e84a7ccc11cb58ab79ac7b0cd46347c89e1ec8dc..88d0108a8b5beaab4f3d5640f4c5eb48eaa57d4f 100644 (file)
@@ -124,16 +124,16 @@ public abstract class DataContainerCodecContext<D extends TreeNode, T> extends N
      *
      * @param childClass input child class
      * @return Context of child node or null, if supplied class is not subtree child
-     * @throws IllegalArgumentException If supplied child class is not valid in specified context.
+     * @throws IllegalArgumentException
+     *             If supplied child class is not valid in specified context.
      */
     @Nonnull
     @Override
     public abstract <DV extends TreeNode> DataContainerCodecContext<DV,?> streamChild(@Nonnull final Class<DV> childClass) throws IllegalArgumentException;
 
     /**
-     * Returns child context as if it was walked by
-     * {@link BindingStreamEventWriter}. This means that to enter case, one
-     * must issue getChild(ChoiceClass).getChild(CaseClass).
+     * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter
+     * case, one must issue getChild(ChoiceClass).getChild(CaseClass).
      *
      * @param childClass input child class
      * @return Context of child or Optional absent is supplied class is not applicable in context.
@@ -157,7 +157,7 @@ public abstract class DataContainerCodecContext<D extends TreeNode, T> extends N
         return new CachingNormalizedNodeCodec<D>(this, ImmutableSet.copyOf(cacheSpecifier));
     }
 
-    BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
+    public BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
         return BindingToNormalizedStreamWriter.create(this, domWriter);
     }
 
index f36464da8f68f66b674d721386c554795be83d9b..ae0db15143eacb18b779681e0082785ef99af715 100644 (file)
@@ -13,20 +13,29 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.AugmentationNodeContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.CaseNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ChoiceNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ContainerNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.KeyedListNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.ListNodeCodecContext;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext.CodecContextFactory;
 import org.opendaylight.mdsal.binding.javav2.spec.base.Item;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeRoot;
+import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 @Beta
 public final class DataContainerCodecPrototype<T> implements NodeContextSupplier {
@@ -124,8 +133,22 @@ public final class DataContainerCodecPrototype<T> implements NodeContextSupplier
     @GuardedBy("this")
     @SuppressWarnings({"rawtypes", "unchecked"})
     protected DataContainerCodecContext<?, T> createInstance() {
-        //TODO - implement it
-        throw new NotImplementedException();
+        if (schema instanceof ContainerSchemaNode) {
+            return new ContainerNodeCodecContext(this);
+        } else if (schema instanceof ListSchemaNode) {
+            if (Identifiable.class.isAssignableFrom(getBindingClass())) {
+                return new KeyedListNodeCodecContext(this);
+            } else {
+                return new ListNodeCodecContext(this);
+            }
+        } else if (schema instanceof ChoiceSchemaNode) {
+            return new ChoiceNodeCodecContext(this);
+        } else if (schema instanceof AugmentationSchema) {
+            return new AugmentationNodeContext(this);
+        } else if (schema instanceof ChoiceCaseNode) {
+            return new CaseNodeCodecContext(this);
+        }
+        throw new IllegalArgumentException("Unsupported type " + bindingClass + " " + schema);
     }
 
     boolean isChoice() {
index 0c0c471bd6abd8ec43510ca47fe6f3fb8535271c..10da93cdda65f255c194545a17e1a04fad1c76ff 100644 (file)
@@ -12,11 +12,11 @@ import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 
 @Beta
-abstract class ReflectionBasedCodec extends ValueTypeCodec {
+public abstract class ReflectionBasedCodec extends ValueTypeCodec {
 
     private final Class<?> typeClass;
 
-    ReflectionBasedCodec(final Class<?> typeClass) {
+    protected ReflectionBasedCodec(final Class<?> typeClass) {
         this.typeClass = Preconditions.checkNotNull(typeClass);
     }
 
index 89a9304c209c2375669516150063763acc4dbaee..bee0c655190b324288c0c0f3050a31fb80f6db66 100644 (file)
@@ -24,7 +24,7 @@ import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
  * Value codec, which serializes / de-serializes values from DOM simple values.
  */
 @Beta
-abstract class ValueTypeCodec implements Codec<Object, Object> {
+public abstract class ValueTypeCodec implements Codec<Object, Object> {
 
     private static final Cache<Class<?>, SchemaUnawareCodec> staticCodecs = CacheBuilder.newBuilder().weakKeys()
             .build();
@@ -94,7 +94,7 @@ abstract class ValueTypeCodec implements Codec<Object, Object> {
     private static SchemaUnawareCodec getCachedSchemaUnawareCodec(final Class<?> typeClz, final Callable<? extends SchemaUnawareCodec> loader) {
         try {
             return staticCodecs.get(typeClz, loader);
-        } catch (ExecutionException e) {
+        } catch (final ExecutionException e) {
             throw new IllegalStateException(e);
         }
     }
@@ -116,8 +116,8 @@ abstract class ValueTypeCodec implements Codec<Object, Object> {
     }
 
     @SuppressWarnings("rawtypes")
-    static ValueTypeCodec encapsulatedValueCodecFor(final Class<?> typeClz, final Codec delegate) {
-        SchemaUnawareCodec extractor = getCachedSchemaUnawareCodec(typeClz, EncapsulatedValueCodec.loader(typeClz));
+    public static ValueTypeCodec encapsulatedValueCodecFor(final Class<?> typeClz, final Codec delegate) {
+        final SchemaUnawareCodec extractor = getCachedSchemaUnawareCodec(typeClz, EncapsulatedValueCodec.loader(typeClz));
         return new CompositeValueCodec(extractor, delegate);
     }
 }
\ No newline at end of file