*/
package org.opendaylight.yangtools.binding.data.codec.impl;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
import java.util.List;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeCachingCodec;
import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-
-abstract class DataContainerCodecContext<T> extends NodeCodecContext {
-
- protected final T schema;
- protected final QNameModule namespace;
- protected final CodecContextFactory factory;
- protected final Class<?> bindingClass;
- protected final InstanceIdentifier.Item<?> bindingArg;
-
- protected final LoadingCache<Class<?>, DataContainerCodecContext<?>> containerChild;
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- protected DataContainerCodecContext(final Class<?> cls, final QNameModule namespace, final T nodeSchema,
- final CodecContextFactory factory) {
- super();
- this.schema = nodeSchema;
- this.factory = factory;
- this.namespace = namespace;
- this.bindingClass = cls;
- this.bindingArg = new InstanceIdentifier.Item(bindingClass);
-
- this.containerChild = CacheBuilder.newBuilder().build(new CacheLoader<Class<?>, DataContainerCodecContext<?>>() {
- @Override
- public DataContainerCodecContext<?> load(final Class<?> key) throws Exception {
- return loadChild(key);
- }
- });
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+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;
+
+abstract class DataContainerCodecContext<D extends DataObject,T> extends NodeCodecContext<D> {
+
+ private final DataContainerCodecPrototype<T> prototype;
+ private volatile DataObjectSerializer eventStreamSerializer;
+
+ protected DataContainerCodecContext(final DataContainerCodecPrototype<T> prototype) {
+ this.prototype = prototype;
}
- static DataContainerCodecContext<?> from(final Class<?> cls, final DataSchemaNode schema,
- final CodecContextFactory loader) {
- if (schema instanceof ContainerSchemaNode) {
- return new ContainerNodeCodecContext(cls, (ContainerSchemaNode) schema, loader);
- } else if (schema instanceof ListSchemaNode) {
- return new ListNodeCodecContext(cls, (ListSchemaNode) schema, loader);
- } else if (schema instanceof ChoiceNode) {
- return new ChoiceNodeCodecContext(cls, (ChoiceNode) schema, loader);
- }
- throw new IllegalArgumentException("Not supported type " + cls + " " + schema);
+ protected final T schema() {
+ return prototype.getSchema();
+ }
+
+ protected final QNameModule namespace() {
+ return prototype.getNamespace();
+ }
+
+ protected final CodecContextFactory factory() {
+ return prototype.getFactory();
}
- protected T getSchema() {
- return schema;
+ @Override
+ protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
+ return prototype.getYangArg();
}
/**
* @return Context of child
* @throws IllegalArgumentException If supplied argument does not represent valid child.
*/
- protected abstract NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg);
+ @Override
+ public abstract NodeCodecContext<?> yangPathArgumentChild(final YangInstanceIdentifier.PathArgument arg);
/**
* Returns nested node context using supplied Binding Instance Identifier
* and adds YANG instance identifiers to supplied list.
*
* @param arg Binding Instance Identifier Argument
- * @return Context of child
+ * @return Context of child or null if supplied {@code arg} does not represent valid child.
* @throws IllegalArgumentException If supplied argument does not represent valid child.
*/
- protected DataContainerCodecContext<?> getIdentifierChild(final InstanceIdentifier.PathArgument arg,
+ @Override
+ public @Nullable DataContainerCodecContext<?,?> bindingPathArgumentChild(final InstanceIdentifier.PathArgument arg,
final List<YangInstanceIdentifier.PathArgument> builder) {
- final DataContainerCodecContext<?> child = getStreamChild(arg.getType());
- if (builder != null) {
- child.addYangPathArgument(arg,builder);
+ final DataContainerCodecContext<?,?> child = streamChild(arg.getType());
+ if(child != null) {
+ if (builder != null) {
+ child.addYangPathArgument(arg,builder);
+ }
+ return child;
}
- return child;
+ throw new IllegalArgumentException("SUpplied argument is not valid child");
}
/**
- *
* Returns deserialized Binding Path Argument from YANG instance identifier.
*
* @param domArg
* @return
*/
- protected PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
- return bindingArg;
+ protected PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
+ return bindingArg();
+ }
+
+ protected final PathArgument bindingArg() {
+ return prototype.getBindingArg();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final Class<D> getBindingClass() {
+ return Class.class.cast(prototype.getBindingClass());
}
/**
* must issue getChild(ChoiceClass).getChild(CaseClass).
*
* @param childClass
- * @return Context of child
+ * @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.
*/
- protected DataContainerCodecContext<?> getStreamChild(final Class<?> childClass) {
- return containerChild.getUnchecked(childClass);
- }
+ @Override
+ public abstract @Nullable <DV extends DataObject> DataContainerCodecContext<DV,?> streamChild(final Class<DV> childClass) throws IllegalArgumentException;
/**
- * Loads children identified by supplied class. If children is not
- * valid, throws {@link 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).
*
* @param childClass
- * @return Context of child
+ * @return Context of child or Optional absent is supplied class is not applicable in context.
*/
- protected abstract DataContainerCodecContext<?> loadChild(final Class<?> childClass);
+ @Override
+ public abstract <DV extends DataObject> Optional<DataContainerCodecContext<DV,?>> possibleStreamChild(final Class<DV> childClass);
@Override
public String toString() {
- return getClass().getSimpleName() + " [" + bindingClass + "]";
+ return getClass().getSimpleName() + " [" + prototype.getBindingClass() + "]";
+ }
+
+ @Override
+ public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
+ final ImmutableCollection<Class<? extends DataObject>> cacheSpecifier) {
+ if(cacheSpecifier.isEmpty()) {
+ return new NonCachingCodec<>(this);
+ }
+ return new CachingNormalizedNodeCodec<D>(this,ImmutableSet.copyOf(cacheSpecifier));
+ }
+
+ BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
+ return new BindingToNormalizedStreamWriter(this, domWriter);
+ }
+
+ DataObjectSerializer eventStreamSerializer() {
+ if(eventStreamSerializer == null) {
+ eventStreamSerializer = factory().getEventStreamSerializer(getBindingClass());
+ }
+ return eventStreamSerializer;
+ }
+
+ @Override
+ public NormalizedNode<?, ?> serialize(final D data) {
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ // We create DOM stream writer which produces normalized nodes
+ final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+ writeAsNormalizedNode(data, domWriter);
+ return result.getResult();
+ }
+
+ @Override
+ public void writeAsNormalizedNode(final D data, final NormalizedNodeStreamWriter writer) {
+ try {
+ eventStreamSerializer().serialize(data, createWriter(writer));
+ } catch (final IOException e) {
+ throw new IllegalStateException("Failed to serialize Binding DTO",e);
+ }
}
}
\ No newline at end of file