* @return NormalizedNode representation of operation data
*/
@Nonnull
- ContainerNode toNormalizedNodeRpcData(@Nonnull Instantiable<?> data);
+ ContainerNode toNormalizedNodeOperationData(@Nonnull Instantiable<?> data);
}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
/**
* Context for prototype of augmentation node.
+ *
+ * @param <D>
+ * - type of tree node
*/
@Beta
public final class AugmentationNodeContext<D extends TreeNode & Augmentation<?>>
* @param prototype
* - codec prototype of container node
*/
- ContainerNodeCodecContext(final DataContainerCodecPrototype<ContainerSchemaNode> prototype) {
+ public ContainerNodeCodecContext(final DataContainerCodecPrototype<ContainerSchemaNode> prototype) {
super(prototype);
}
* @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 {
* - 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.
* @param prototype
* - codec prototype of list node
*/
- protected ListNodeCodecContext(final DataContainerCodecPrototype<ListSchemaNode> prototype) {
+ public ListNodeCodecContext(final DataContainerCodecPrototype<ListSchemaNode> prototype) {
super(prototype);
}
--- /dev/null
+/*
+ * 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.");
+ }
+}
*
* @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.
return new CachingNormalizedNodeCodec<D>(this, ImmutableSet.copyOf(cacheSpecifier));
}
- BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
+ public BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
return BindingToNormalizedStreamWriter.create(this, domWriter);
}
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 {
@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() {
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);
}
* 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();
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);
}
}
}
@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