Binding2 runtime - Codecs impl - context - part2 57/58957/1
authorJakub Toth <jakub.toth@pantheon.tech>
Thu, 8 Jun 2017 15:31:33 +0000 (17:31 +0200)
committerMartin Ciglan <martin.ciglan@pantheon.tech>
Wed, 14 Jun 2017 14:27:11 +0000 (14:27 +0000)
  * derived parts
  * fixed base parts

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

binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/AugmentationNodeContext.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ChoiceNodeCodecContext.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/NotificationCodecContext.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/UnionValueOptionContext.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ValueContext.java [new file with mode: 0644]
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/context/base/LeafNodeCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/value/EncapsulatedValueCodec.java

diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/AugmentationNodeContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/AugmentationNodeContext.java
new file mode 100644 (file)
index 0000000..767cfbc
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecPrototype;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentation;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+
+/**
+ * Context for prototype of augmentation node.
+ */
+@Beta
+public final class AugmentationNodeContext<D extends TreeNode & Augmentation<?>>
+        extends TreeNodeCodecContext<D, AugmentationSchema> {
+
+    /**
+     * Prepare context for augmentation node from prototype.
+     *
+     * @param prototype
+     *            - codec prototype of augmentation node
+     */
+    public AugmentationNodeContext(final DataContainerCodecPrototype<AugmentationSchema> prototype) {
+        super(prototype);
+    }
+
+    @Nonnull
+    @Override
+    public D deserialize(@Nonnull final NormalizedNode<?, ?> normalizedNode) {
+        Preconditions.checkArgument(normalizedNode instanceof AugmentationNode);
+        return createBindingProxy((AugmentationNode) normalizedNode);
+    }
+
+    @Override
+    protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+        return deserialize(normalizedNode);
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ChoiceNodeCodecContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ChoiceNodeCodecContext.java
new file mode 100644 (file)
index 0000000..ea6cd43
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecPrototype;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
+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.DataSchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Context for prototype of choice node codec.
+ *
+ * @param <D>
+ *            - type of tree node
+ */
+@Beta
+public class ChoiceNodeCodecContext<D extends TreeNode> extends DataContainerCodecContext<D, ChoiceSchemaNode> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ChoiceNodeCodecContext.class);
+
+    private final ImmutableMap<YangInstanceIdentifier.PathArgument, DataContainerCodecPrototype<?>> byYangCaseChild;
+    private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byClass;
+    private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClass;
+
+    /**
+     * Prepare context for choice node from prototype and all case children of choice class.
+     *
+     * @param prototype
+     *            - codec prototype of choice node
+     */
+    public ChoiceNodeCodecContext(final DataContainerCodecPrototype<ChoiceSchemaNode> prototype) {
+        super(prototype);
+        final Map<YangInstanceIdentifier.PathArgument, DataContainerCodecPrototype<?>> byYangCaseChildBuilder =
+                new HashMap<>();
+        final Map<Class<?>, DataContainerCodecPrototype<?>> byClassBuilder = new HashMap<>();
+        final Map<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClassBuilder = new HashMap<>();
+        final Set<Class<?>> potentialSubstitutions = new HashSet<>();
+        // Walks all cases for supplied choice in current runtime context
+        for (final Class<?> caze : factory().getRuntimeContext().getCases(getBindingClass())) {
+            // We try to load case using exact match thus name
+            // and original schema must equals
+            final DataContainerCodecPrototype<ChoiceCaseNode> cazeDef = loadCase(caze);
+            // If we have case definition, this case is instantiated
+            // at current location and thus is valid in context of parent choice
+            if (cazeDef != null) {
+                byClassBuilder.put(cazeDef.getBindingClass(), cazeDef);
+                // Updates collection of case children
+                @SuppressWarnings("unchecked")
+                final Class<? extends Instantiable<?>> cazeCls = (Class<? extends Instantiable<?>>) caze;
+                for (final Class<? extends TreeNode> cazeChild : BindingReflections.getChildrenClasses(cazeCls)) {
+                    byCaseChildClassBuilder.put(cazeChild, cazeDef);
+                }
+                // Updates collection of YANG instance identifier to case
+                for (final DataSchemaNode cazeChild : cazeDef.getSchema().getChildNodes()) {
+                    if (cazeChild.isAugmenting()) {
+                        final AugmentationSchema augment =
+                                SchemaUtils.findCorrespondingAugment(cazeDef.getSchema(), cazeChild);
+                        if (augment != null) {
+                            byYangCaseChildBuilder.put(SchemaUtils.getNodeIdentifierForAugmentation(augment), cazeDef);
+                            continue;
+                        }
+                    }
+                    byYangCaseChildBuilder.put(NodeIdentifier.create(cazeChild.getQName()), cazeDef);
+                }
+            } else {
+                /*
+                 * If case definition is not available, we store it for later check if it could be used as
+                 * substitution of existing one.
+                 */
+                potentialSubstitutions.add(caze);
+            }
+        }
+
+        final Map<Class<?>, DataContainerCodecPrototype<?>> bySubstitutionBuilder = new HashMap<>();
+        /*
+         * Walks all cases which are not directly instantiated and tries to match them to instantiated cases -
+         * represent same data as instantiated case, only case name or schema path is different. This is
+         * required due property of binding specification, that if choice is in grouping schema path location
+         * is lost, and users may use incorrect case class using copy builders.
+         */
+        for (final Class<?> substitution : potentialSubstitutions) {
+            for (final Entry<Class<?>, DataContainerCodecPrototype<?>> real : byClassBuilder.entrySet()) {
+                if (BindingReflections.isSubstitutionFor(substitution, real.getKey())) {
+                    bySubstitutionBuilder.put(substitution, real.getValue());
+                    break;
+                }
+            }
+        }
+        byClassBuilder.putAll(bySubstitutionBuilder);
+        byYangCaseChild = ImmutableMap.copyOf(byYangCaseChildBuilder);
+        byClass = ImmutableMap.copyOf(byClassBuilder);
+        byCaseChildClass = ImmutableMap.copyOf(byCaseChildClassBuilder);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Nonnull
+    @Override
+    public <DV extends TreeNode> DataContainerCodecContext<DV, ?> streamChild(@Nonnull final Class<DV> childClass) {
+        final DataContainerCodecPrototype<?> child = byClass.get(childClass);
+        return (DataContainerCodecContext<DV,
+                ?>) childNonNull(child, childClass, "Supplied class %s is not valid case", childClass).get();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <DV extends TreeNode> Optional<DataContainerCodecContext<DV, ?>>
+            possibleStreamChild(@Nonnull final Class<DV> childClass) {
+        final DataContainerCodecPrototype<?> child = byClass.get(childClass);
+        if (child != null) {
+            return Optional.of((DataContainerCodecContext<DV, ?>) child.get());
+        }
+        return Optional.absent();
+    }
+
+    Iterable<Class<?>> getCaseChildrenClasses() {
+        return byCaseChildClass.keySet();
+    }
+
+    private DataContainerCodecPrototype<ChoiceCaseNode> loadCase(final Class<?> childClass) {
+        final Optional<ChoiceCaseNode> childSchema =
+                factory().getRuntimeContext().getCaseSchemaDefinition(getSchema(), childClass);
+        if (childSchema.isPresent()) {
+            return DataContainerCodecPrototype.from(childClass, childSchema.get(), factory());
+        }
+
+        LOG.debug("Supplied class %s is not valid case in schema %s", childClass, getSchema());
+        return null;
+    }
+
+    @Nonnull
+    @Override
+    public NodeCodecContext<?> yangPathArgumentChild(final YangInstanceIdentifier.PathArgument arg) {
+        final DataContainerCodecPrototype<?> cazeProto;
+        if (arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
+            cazeProto = byYangCaseChild.get(new NodeIdentifier(arg.getNodeType()));
+        } else {
+            cazeProto = byYangCaseChild.get(arg);
+        }
+
+        return childNonNull(cazeProto, arg, "Argument %s is not valid child of %s", arg, getSchema()).get()
+                .yangPathArgumentChild(arg);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Nonnull
+    @Override
+    public D deserialize(@Nonnull final NormalizedNode<?, ?> data) {
+        Preconditions.checkArgument(data instanceof ChoiceNode);
+        final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> casted =
+                (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
+        final NormalizedNode<?, ?> first = Iterables.getFirst(casted.getValue(), null);
+
+        if (first == null) {
+            return null;
+        }
+        final DataContainerCodecPrototype<?> caze = byYangCaseChild.get(first.getIdentifier());
+        return (D) caze.get().deserialize(data);
+    }
+
+    @Override
+    protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+        return deserialize(normalizedNode);
+    }
+
+    @Nonnull
+    @Override
+    public TreeArgument<?> deserializePathArgument(@Nonnull final YangInstanceIdentifier.PathArgument arg) {
+        Preconditions.checkArgument(getDomPathArgument().equals(arg));
+        return null;
+    }
+
+    @Nonnull
+    @Override
+    public YangInstanceIdentifier.PathArgument serializePathArgument(@Nonnull final TreeArgument<?> arg) {
+        return getDomPathArgument();
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/NotificationCodecContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/NotificationCodecContext.java
new file mode 100644 (file)
index 0000000..eb04792
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecPrototype;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Notification;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+
+/**
+ * Context for prototype of notification.
+ *
+ * @param <D>
+ *            - type of tree node
+ */
+@SuppressWarnings("rawtypes")
+@Beta
+public final class NotificationCodecContext<D extends TreeNode & Notification>
+        extends TreeNodeCodecContext<D, NotificationDefinition> {
+
+    /**
+     * Prepare context for notification from prototype.
+     *
+     * @param key
+     *            - binding class
+     * @param schema
+     *            - schema of notification
+     * @param factory
+     *            - codec context factory
+     */
+    public NotificationCodecContext(final Class<?> key, final NotificationDefinition schema,
+            final CodecContextFactory factory) {
+        super(DataContainerCodecPrototype.from(key, schema, factory));
+    }
+
+    @Nonnull
+    @Override
+    public D deserialize(@Nonnull final NormalizedNode<?, ?> data) {
+        Preconditions.checkState(data instanceof ContainerNode);
+        return createBindingProxy((NormalizedNodeContainer<?, ?, ?>) data);
+    }
+
+    @Override
+    protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+        return deserialize(normalizedNode);
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/UnionValueOptionContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/UnionValueOptionContext.java
new file mode 100644 (file)
index 0000000..9daf43e
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.value.EncapsulatedValueCodec;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Context for serializing input value of union type and deserializing objects to binding.
+ *
+ */
+@Beta
+public class UnionValueOptionContext {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UnionValueOptionContext.class);
+
+    private static final MethodType OBJECT_TYPE = MethodType.methodType(Object.class, Object.class);
+
+    private final Class<?> bindingType;
+    private final Codec<Object, Object> codec;
+    private final MethodHandle getter;
+    private final MethodHandle unionCtor;
+
+    /**
+     * Prepare union as binding object and codec for this object, make a direct method handle of getting union
+     * type and constructor of union type for initializing it.
+     *
+     * @param unionType
+     *            - union as binding object
+     * @param valueType
+     *            - returned type of union
+     * @param getter
+     *            - method for getting union type
+     * @param codec
+     *            - codec for serialize/deserialize type of union
+     */
+    public UnionValueOptionContext(final Class<?> unionType, final Class<?> valueType, final Method getter,
+            final Codec<Object, Object> codec) {
+        this.bindingType = Preconditions.checkNotNull(valueType);
+        this.codec = Preconditions.checkNotNull(codec);
+
+        try {
+            this.getter = MethodHandles.publicLookup().unreflect(getter).asType(OBJECT_TYPE);
+        } catch (final IllegalAccessException e) {
+            throw new IllegalStateException("Failed to access method " + getter, e);
+        }
+
+        try {
+            this.unionCtor = MethodHandles.publicLookup()
+                    .findConstructor(unionType, MethodType.methodType(void.class, valueType)).asType(OBJECT_TYPE);
+        } catch (IllegalAccessException | NoSuchMethodException e) {
+            throw new IllegalStateException(
+                    String.format("Failed to access constructor for %s in type %s", valueType, unionType), e);
+        }
+    }
+
+    /**
+     * Serialize input based on prepared codec.
+     *
+     * @param input
+     *            - object to serialize
+     * @return serialized objetc
+     */
+    public Object serialize(final Object input) {
+        final Object baValue = getValueFrom(input);
+        return baValue == null ? null : codec.serialize(baValue);
+    }
+
+    /**
+     * Deserialize input object via prepared codec for invoking new object of union as binding.
+     *
+     * @param input
+     *            - input object for deserializing
+     * @return deserialized union binding type object
+     */
+    public Object deserializeUnion(final Object input) {
+        // Side-step potential exceptions by checking the type if it is available
+        if (codec instanceof EncapsulatedValueCodec && !((EncapsulatedValueCodec) codec).canAcceptObject(input)) {
+            return null;
+        }
+
+        final Object value;
+        try {
+            value = codec.deserialize(input);
+        } catch (final Exception e) {
+            LOG.debug("Codec {} failed to deserialize input {}", codec, input, e);
+            return null;
+        }
+
+        try {
+            return unionCtor.invokeExact(value);
+        } catch (final ClassCastException e) {
+            // This case can happen. e.g. NOOP_CODEC
+            LOG.debug("Failed to instantiate {} for input {} value {}", bindingType, input, value, e);
+            return null;
+        } catch (final Throwable e) {
+            throw new IllegalArgumentException("Failed to construct union for value " + value, e);
+        }
+    }
+
+    private Object getValueFrom(final Object input) {
+        try {
+            return getter.invokeExact(input);
+        } catch (final Throwable e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return bindingType.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof UnionValueOptionContext)) {
+            return false;
+        }
+
+        final UnionValueOptionContext other = (UnionValueOptionContext) obj;
+        return bindingType.equals(other.bindingType);
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ValueContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/ValueContext.java
new file mode 100644 (file)
index 0000000..1698867
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.LeafNodeCodecContext;
+import org.opendaylight.yangtools.concepts.Codec;
+
+/**
+ * Context for serialize/deserialize leaf.
+ */
+@Beta
+public final class ValueContext {
+
+    private static final MethodType OBJECT_METHOD = MethodType.methodType(Object.class, Object.class);
+    private final Codec<Object, Object> codec;
+    private final MethodHandle getter;
+    private final Class<?> identifier;
+    private final String getterName;
+
+    /**
+     * Prepare codec of leaf value and getter of binding leaf object for getting leaf.
+     *
+     * @param identifier
+     *            - binding class
+     * @param leaf
+     *            - leaf codec context
+     */
+    public ValueContext(final Class<?> identifier, final LeafNodeCodecContext<?> leaf) {
+        getterName = leaf.getGetter().getName();
+        try {
+            getter = MethodHandles.publicLookup().unreflect(identifier.getMethod(getterName)).asType(OBJECT_METHOD);
+        } catch (IllegalAccessException | NoSuchMethodException | SecurityException e) {
+            throw new IllegalStateException(String.format("Cannot find method %s in class %s", getterName, identifier), e);
+        }
+        this.identifier = identifier;
+        codec = leaf.getValueCodec();
+    }
+
+    /**
+     * Get object via invoking getter with input and serializes it by prepared codec of leaf.
+     *
+     * @param obj
+     *            - input object
+     * @return serialized invoked object
+     */
+    public Object getAndSerialize(final Object obj) {
+        final Object value;
+        try {
+            value = getter.invokeExact(obj);
+        } catch (final Throwable e) {
+            throw Throwables.propagate(e);
+        }
+
+        Preconditions.checkArgument(value != null,
+                "All keys must be specified for %s. Missing key is %s. Supplied key is %s",
+                identifier, getterName, obj);
+        return codec.serialize(value);
+    }
+
+    /**
+     * Deserialize input object by prepared codec.
+     *
+     * @param obj
+     *            - input object
+     * @return deserialized object
+     */
+    public Object deserialize(final Object obj) {
+        return codec.deserialize(obj);
+    }
+}
index 2a531bbc0c38ac25109e06ac5d10c9dccd7dd86c..f36464da8f68f66b674d721386c554795be83d9b 100644 (file)
@@ -57,12 +57,12 @@ public final class DataContainerCodecPrototype<T> implements NodeContextSupplier
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
+    public static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
             final CodecContextFactory factory) {
         return new DataContainerCodecPrototype(cls, NodeIdentifier.create(schema.getQName()), schema, factory);
     }
 
-    static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
+    public static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
         final SchemaContext schema = factory.getRuntimeContext().getSchemaContext();
         final NodeIdentifier arg = NodeIdentifier.create(schema.getQName());
         return new DataContainerCodecPrototype<>(TreeRoot.class, arg, schema, factory);
@@ -74,12 +74,13 @@ public final class DataContainerCodecPrototype<T> implements NodeContextSupplier
         return new DataContainerCodecPrototype(augClass, arg, schema, factory);
     }
 
-    static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass, final NotificationDefinition schema, final CodecContextFactory factory) {
+    public static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass,
+            final NotificationDefinition schema, final CodecContextFactory factory) {
         final PathArgument arg = NodeIdentifier.create(schema.getQName());
         return new DataContainerCodecPrototype<>(augClass, arg, schema, factory);
     }
 
-    protected T getSchema() {
+    public T getSchema() {
         return schema;
     }
 
@@ -91,7 +92,7 @@ public final class DataContainerCodecPrototype<T> implements NodeContextSupplier
         return factory;
     }
 
-    protected Class<?> getBindingClass() {
+    public Class<?> getBindingClass() {
         return bindingClass;
     }
 
index 9a88075ebff22cd6dd0d38da96d4a341ab9058b6..3645fbcb8886eb2ad71495ed5e30a73ac578a613 100644 (file)
@@ -149,7 +149,7 @@ public final class LeafNodeCodecContext<D extends TreeNode> extends NodeCodecCon
         return this;
     }
 
-    final Method getGetter() {
+    public final Method getGetter() {
         return getter;
     }
 
index 8727eadddc8416d9d5f23e6068e5ca4e33475a73..959fcb5f395b34244f97379930ca861553beb0bc 100644 (file)
@@ -24,7 +24,7 @@ import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.value.ValueTypeCodec
  * types, which are same as in NormalizedNode model.
  */
 @Beta
-final class EncapsulatedValueCodec extends ReflectionBasedCodec implements SchemaUnawareCodec {
+public final class EncapsulatedValueCodec extends ReflectionBasedCodec implements SchemaUnawareCodec {
 
     private static final Lookup LOOKUP = MethodHandles.publicLookup();
     private static final MethodType OBJ_METHOD = MethodType.methodType(Object.class, Object.class);
@@ -59,24 +59,24 @@ final class EncapsulatedValueCodec extends ReflectionBasedCodec implements Schem
      * @param value Value to be checked
      * @return True if the value can be encapsulated
      */
-    boolean canAcceptObject(final Object value) {
+    public boolean canAcceptObject(final Object value) {
         return valueType.isInstance(value);
     }
 
     @Override
-    public Object deserialize(Object input) {
+    public Object deserialize(final Object input) {
         try {
             return constructor.invokeExact(input);
-        } catch (Throwable e) {
+        } catch (final Throwable e) {
             throw Throwables.propagate(e);
         }
     }
 
     @Override
-    public Object serialize(Object input) {
+    public Object serialize(final Object input) {
         try {
             return getter.invokeExact(input);
-        } catch (Throwable e) {
+        } catch (final Throwable e) {
             throw Throwables.propagate(e);
         }
     }