import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.BindingSerializer;
import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
@Override
protected CharSequence getSerializerBody() {
- StringBuilder b = new StringBuilder();
+ final StringBuilder b = new StringBuilder();
b.append("{\n");
b.append(statement(assign(DataObjectSerializerRegistry.class.getName(), REGISTRY, "$1")));
b.append(statement(assign(dtoType.getFullyQualifiedName(), INPUT,
cast(dtoType.getFullyQualifiedName(), "$2"))));
b.append(statement(assign(BindingStreamEventWriter.class.getName(), STREAM, cast(BindingStreamEventWriter.class.getName(), "$3"))));
+ b.append(statement(assign(BindingSerializer.class.getName(), SERIALIZER, null)));
+ b.append("if (");
+ b.append(STREAM);
+ b.append(" instanceof ");
+ b.append(BindingSerializer.class.getName());
+ b.append(") {");
+ b.append(statement(assign(SERIALIZER, cast(BindingSerializer.class.getName(), STREAM))));
+ b.append('}');
b.append(statement(emitStartEvent()));
emitBody(b);
}
private static Map<String, Type> collectAllProperties(final GeneratedType type, final Map<String, Type> hashMap) {
- for (MethodSignature definition : type.getMethodDefinitions()) {
+ for (final MethodSignature definition : type.getMethodDefinitions()) {
hashMap.put(definition.getName(), definition.getReturnType());
}
- for (Type parent : type.getImplements()) {
+ for (final Type parent : type.getImplements()) {
if (parent instanceof GeneratedType) {
collectAllProperties((GeneratedType) parent, hashMap);
}
}
private void emitBody(final StringBuilder b) {
- Map<String, Type> getterToType = collectAllProperties(dtoType, new HashMap<String, Type>());
- for (DataSchemaNode schemaChild : schemaNode.getChildNodes()) {
+ final Map<String, Type> getterToType = collectAllProperties(dtoType, new HashMap<String, Type>());
+ for (final DataSchemaNode schemaChild : schemaNode.getChildNodes()) {
if (!schemaChild.isAugmenting()) {
- String getter = getGetterName(schemaChild);
- Type childType = getterToType.get(getter);
+ final String getter = getGetterName(schemaChild);
+ final Type childType = getterToType.get(getter);
emitChild(b, getter, childType, schemaChild);
}
}
b.append(statement(anyxmlNode(child.getQName().getLocalName(), getterName)));
} else if (child instanceof LeafListSchemaNode) {
b.append(statement(startLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"))));
- Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+ final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
b.append(forEach(getterName, valueType, statement(leafSetEntryNode(CURRENT))));
b.append(statement(endNode()));
} else if (child instanceof ListSchemaNode) {
- Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
- ListSchemaNode casted = (ListSchemaNode) child;
+ final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+ final ListSchemaNode casted = (ListSchemaNode) child;
emitList(b, getterName, valueType, casted);
} else if (child instanceof ContainerSchemaNode) {
- b.append(statement(staticInvokeEmitter(childType, getterName)));
+ b.append(tryToUseCacheElse(getterName,statement(staticInvokeEmitter(childType, getterName))));
} else if (child instanceof ChoiceSchemaNode) {
- String propertyName = CHOICE_PREFIX + childType.getName();
+ final String propertyName = CHOICE_PREFIX + childType.getName();
staticConstant(propertyName, DataObjectSerializerImplementation.class, ChoiceDispatchSerializer.from(loadClass(childType)));
- b.append(statement(invoke(propertyName, StreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, cast(DataObject.class.getName(),getterName), STREAM)));
+ b.append(tryToUseCacheElse(getterName,statement(invoke(propertyName, StreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, cast(DataObject.class.getName(),getterName), STREAM))));
}
}
+ private StringBuilder tryToUseCacheElse(final String getterName, final CharSequence statement) {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("if ( ");
+ b.append(SERIALIZER).append("== null || ");
+ b.append(invoke(SERIALIZER, "serialize", getterName)).append("== null");
+ b.append(") {");
+ b.append(statement);
+ b.append("}");
+ return b;
+ }
+
private void emitList(final StringBuilder b, final String getterName, final Type valueType,
final ListSchemaNode child) {
final CharSequence startEvent;
startEvent = startMapNode(classReference(valueType), "_count");
}
b.append(statement(startEvent));
- b.append(forEach(getterName, valueType, statement(staticInvokeEmitter(valueType, CURRENT))));
+ b.append(forEach(getterName, valueType, tryToUseCacheElse(CURRENT,statement(staticInvokeEmitter(valueType, CURRENT)))));
b.append(statement(endNode()));
}
}
\ No newline at end of file
private static final ClassLoadingStrategy STRATEGY = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+ protected static final String SERIALIZER = "_serializer";
protected static final String STREAM = "_stream";
protected static final String ITERATOR = "_iterator";
protected static final String CURRENT = "_current";
protected Class<? extends DataContainer> loadClass(final Type childType) {
try {
return (Class<? extends DataContainer>) STRATEGY.loadClass(childType);
- } catch (ClassNotFoundException e) {
+ } catch (final ClassNotFoundException e) {
throw new IllegalStateException("Could not load referenced class ", e);
}
}
final Class<?> cls;
try {
cls = STRATEGY.loadClass(childType);
- } catch (ClassNotFoundException e) {
+ } catch (final ClassNotFoundException e) {
throw new IllegalStateException("Failed to invoke emitter", e);
}
- String className = this.generator.loadSerializerFor(cls) + ".getInstance()";
+ final String className = this.generator.loadSerializerFor(cls) + ".getInstance()";
return invoke(className, AbstractStreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, name, STREAM);
}
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+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.util.Set;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+/**
+ *
+ * Abstract Holder of Binding to Normalized Node caches indexed by {@link DataContainerCodecContext}
+ * to which cache is associated.
+ *
+ */
+abstract class AbstractBindingNormalizedNodeCacheHolder {
+
+ private final Set<Class<? extends DataObject>> cachedValues;
+ private final LoadingCache<DataContainerCodecContext<?, ?>, BindingNormalizedNodeCache> caches = CacheBuilder
+ .newBuilder().build(new CacheLoader<DataContainerCodecContext<?, ?>, BindingNormalizedNodeCache>() {
+
+ @Override
+ public BindingNormalizedNodeCache load(final DataContainerCodecContext<?, ?> key) throws Exception {
+ return new BindingNormalizedNodeCache(AbstractBindingNormalizedNodeCacheHolder.this, key);
+ }
+
+ });
+
+ protected AbstractBindingNormalizedNodeCacheHolder(final Set<Class<? extends DataObject>> cacheSpec) {
+ cachedValues = Preconditions.checkNotNull(cacheSpec);
+ }
+
+ BindingNormalizedNodeCache getCachingSerializer(final DataContainerCodecContext<?, ?> childCtx) {
+ if (isCached(childCtx.getBindingClass())) {
+ return caches.getUnchecked(childCtx);
+ }
+ return null;
+ }
+
+ boolean isCached(final Class<?> type) {
+ return cachedValues.contains(type);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+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 org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+final class BindingNormalizedNodeCache extends CacheLoader<DataObject, NormalizedNode<?, ?>> {
+
+ private final LoadingCache<DataObject, NormalizedNode<?, ?>> cache = CacheBuilder.newBuilder().weakValues()
+ .build(this);
+ final DataContainerCodecContext<?, ?> subtreeRoot;
+ final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
+
+ public BindingNormalizedNodeCache(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+ final DataContainerCodecContext<?, ?> subtreeRoot) {
+ this.cacheHolder = Preconditions.checkNotNull(cacheHolder, "cacheHolder");
+ this.subtreeRoot = Preconditions.checkNotNull(subtreeRoot, "subtreeRoot");
+ }
+
+ @Override
+ public NormalizedNode<?, ?> load(final DataObject key) throws Exception {
+ return CachingNormalizedNodeSerializer.serializeUsingStreamWriter(cacheHolder, subtreeRoot, key);
+ }
+
+ /**
+ * Returns cached NormalizedNode representation of DataObject.
+ *
+ * If representation is not cached, serializes DataObject and updates cache with representation.
+ *
+ * @param obj Binding object to be deserialized
+ * @return NormalizedNode representation of binding object.
+ */
+ NormalizedNode<?, ?> get(final DataObject obj) {
+ return cache.getUnchecked(obj);
+ }
+}
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTree;
import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeWriterFactory;
return serializers.getUnchecked(type);
}
- public BindingCodecContext getCodecContext() {
+ public BindingCodecTree getCodecContext() {
return codecContext;
}
}
@Override
- public BindingCodecContext create(BindingRuntimeContext context) {
+ public BindingCodecContext create(final BindingRuntimeContext context) {
return new BindingCodecContext(context, this);
}
@Override
- public BindingCodecContext create(SchemaContext context, Class<?>... bindingClasses) {
- ModuleInfoBackedContext strategy = ModuleInfoBackedContext.create();
- for (Class<?> bindingCls : bindingClasses) {
+ 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 (Exception e) {
+ } catch (final Exception e) {
throw new IllegalStateException(
"Could not create BindingRuntimeContext from class " + bindingCls.getName(),
e);
}
}
- BindingRuntimeContext runtimeCtx = BindingRuntimeContext.create(strategy, context);
+ final BindingRuntimeContext runtimeCtx = BindingRuntimeContext.create(strategy, context);
return create(runtimeCtx);
}
}
- private NodeCodecContext<?> current() {
+ protected final NodeCodecContext<?> current() {
return schema.peek();
}
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-class CachingNormalizedNodeCodecImpl<D extends DataObject> implements BindingNormalizedNodeCachingCodec<D>{
+class CachingNormalizedNodeCodec<D extends DataObject> extends AbstractBindingNormalizedNodeCacheHolder implements
+ BindingNormalizedNodeCachingCodec<D> {
- private final Set<Class<? extends DataObject>> cachedValues;
private final DataContainerCodecContext<D, ?> context;
- CachingNormalizedNodeCodecImpl(DataContainerCodecContext<D, ?> subtreeRoot, Set<Class<? extends DataObject>> cacheSpec) {
+
+ CachingNormalizedNodeCodec(final DataContainerCodecContext<D, ?> subtreeRoot,
+ final Set<Class<? extends DataObject>> cacheSpec) {
+ super(cacheSpec);
this.context = Preconditions.checkNotNull(subtreeRoot);
- this.cachedValues = Preconditions.checkNotNull(cacheSpec);
}
@Override
- public D deserialize(NormalizedNode<?, ?> data) {
+ public D deserialize(final NormalizedNode<?, ?> data) {
return context.deserialize(data);
}
@Override
- public NormalizedNode<?, ?> serialize(D data) {
- // FIXME: Add real-class based serialization.
- return context.serialize(data);
+ public NormalizedNode<?, ?> serialize(final D data) {
+ return CachingNormalizedNodeSerializer.serialize(this, context, data);
}
@Override
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import com.google.common.base.Throwables;
+import java.io.IOException;
+import org.opendaylight.yangtools.yang.binding.BindingSerializer;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+
+/**
+ * Serializer of Binding objects to Normalized Node which uses {@link BindingNormalizedNodeCache} to
+ * cache already serialized values.
+ *
+ * This serializer implements {@link BindingStreamEventWriter} along with {@link BindingSerializer}.
+ *
+ * {@link BindingSerializer} interface is used by generated implementations of
+ * {@link org.opendaylight.yangtools.yang.binding.DataObjectSerializer} to provide Binding object
+ * for inspection and to prevent streaming of already serialized object.
+ *
+ */
+final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEventWriter implements
+ BindingSerializer<Object, DataObject> {
+
+ private final NormalizedNodeResult domResult;
+ private final NormalizedNodeWriterWithAddChild domWriter;
+ private final BindingToNormalizedStreamWriter delegate;
+ private final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
+
+ CachingNormalizedNodeSerializer(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+ final DataContainerCodecContext<?, ?> subtreeRoot) {
+ this.cacheHolder = cacheHolder;
+ this.domResult = new NormalizedNodeResult();
+ this.domWriter = new NormalizedNodeWriterWithAddChild(domResult);
+ this.delegate = new BindingToNormalizedStreamWriter(subtreeRoot, domWriter);
+ }
+
+ @Override
+ protected BindingStreamEventWriter delegate() {
+ return delegate;
+ }
+
+ NormalizedNode<?, ?> build() {
+ return domResult.getResult();
+ }
+
+ /**
+ * Serializes input if it is cached, returns null otherwise.
+ *
+ * If input is cached it uses {@link NormalizedNodeWriterWithAddChild#addChild(NormalizedNode)}
+ * to provide already serialized value to underlying NormalizedNodeWriter in order to reuse
+ * value instead of creating new one using Normalized Node stream APIs.
+ *
+ * Note that this optional is serialization of child node invoked from
+ * {@link org.opendaylight.yangtools.yang.binding.DataObjectSerializer}, which may opt-out from
+ * streaming of data when non-null result is returned.
+ */
+ @Override
+ public NormalizedNode<?, ?> serialize(final DataObject input) {
+ final BindingNormalizedNodeCache cachingSerializer = getCacheSerializer(input.getImplementedInterface());
+ if (cachingSerializer != null) {
+ final NormalizedNode<?, ?> domData = cachingSerializer.get(input);
+ domWriter.addChild(domData);
+ return domData;
+ }
+ return null;
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private BindingNormalizedNodeCache getCacheSerializer(final Class type) {
+ if (cacheHolder.isCached(type)) {
+ final DataContainerCodecContext<?, ?> currentCtx = (DataContainerCodecContext<?, ?>) delegate.current();
+ if (type.equals(currentCtx.getBindingClass())) {
+ return cacheHolder.getCachingSerializer(currentCtx);
+ }
+ final DataContainerCodecContext<?, ?> childCtx =
+ (DataContainerCodecContext<?, ?>) currentCtx.streamChild(type);
+ return cacheHolder.getCachingSerializer(childCtx);
+ }
+ return null;
+ }
+
+ /**
+ * Serializes supplied data using stream writer with child cache enabled or using cache directly
+ * if cache is avalaible also for supplied Codec node.
+ *
+ * @param cacheHolder Binding to Normalized Node Cache holder
+ * @param subtreeRoot Codec Node for provided data object
+ * @param data Data to be serialized
+ * @return Normalized Node representation of data.
+ */
+ static NormalizedNode<?, ?> serialize(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+ final DataContainerCodecContext<?, ?> subtreeRoot, final DataObject data) {
+ final BindingNormalizedNodeCache cache = cacheHolder.getCachingSerializer(subtreeRoot);
+ if (cache != null) {
+ return cache.get(data);
+ }
+ return serializeUsingStreamWriter(cacheHolder, subtreeRoot, data);
+ }
+
+ /**
+ * Serializes supplied data using stream writer with child cache enabled.
+ *
+ * @param cacheHolder Binding to Normalized Node Cache holder
+ * @param subtreeRoot Codec Node for provided data object
+ * @param data Data to be serialized
+ * @return Normalized Node representation of data.
+ */
+ static NormalizedNode<?, ?> serializeUsingStreamWriter(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+ final DataContainerCodecContext<?, ?> subtreeRoot, final DataObject data) {
+ final CachingNormalizedNodeSerializer writer = new CachingNormalizedNodeSerializer(cacheHolder, subtreeRoot);
+ try {
+ subtreeRoot.eventStreamSerializer().serialize(data, writer);
+ return writer.build();
+ } catch (final IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+}
\ No newline at end of file
@Override
public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
- ImmutableCollection<Class<? extends DataObject>> cacheSpecifier) {
- return new CachingNormalizedNodeCodecImpl<D>(this,ImmutableSet.copyOf(cacheSpecifier));
+ final ImmutableCollection<Class<? extends DataObject>> cacheSpecifier) {
+ if(cacheSpecifier.isEmpty()) {
+ return new NonCachingCodec<>(this);
+ }
+ return new CachingNormalizedNodeCodec<D>(this,ImmutableSet.copyOf(cacheSpecifier));
}
- BindingStreamEventWriter createWriter(NormalizedNodeStreamWriter domWriter) {
+ BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
return new BindingToNormalizedStreamWriter(this, domWriter);
}
}
@Override
- public NormalizedNode<?, ?> serialize(D data) {
+ 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);
}
@Override
- public void writeAsNormalizedNode(D data, NormalizedNodeStreamWriter writer) {
+ public void writeAsNormalizedNode(final D data, final NormalizedNodeStreamWriter writer) {
try {
eventStreamSerializer().serialize(data, createWriter(writer));
- } catch (IOException e) {
+ } catch (final IOException e) {
throw new IllegalStateException("Failed to serialize Binding DTO",e);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import java.io.IOException;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+//FIXME: Consider moving this to yang.binding.util.* in Be
+abstract class ForwardingBindingStreamEventWriter implements BindingStreamEventWriter {
+
+ protected abstract BindingStreamEventWriter delegate();
+
+ @Override
+ public void leafNode(final String localName, final Object value) throws IOException, IllegalArgumentException {
+ delegate().leafNode(localName, value);
+ }
+
+
+ @Override
+ public void startLeafSet(final String localName, final int childSizeHint) throws IOException, IllegalArgumentException {
+ delegate().startLeafSet(localName, childSizeHint);
+ }
+
+
+ @Override
+ public void leafSetEntryNode(final Object value) throws IOException, IllegalArgumentException {
+ delegate().leafSetEntryNode(value);
+ }
+
+
+ @Override
+ public void startContainerNode(final Class<? extends DataObject> container, final int childSizeHint) throws IOException,
+ IllegalArgumentException {
+ delegate().startContainerNode(container, childSizeHint);
+ }
+
+
+ @Override
+ public void startUnkeyedList(final Class<? extends DataObject> localName, final int childSizeHint) throws IOException,
+ IllegalArgumentException {
+ delegate().startUnkeyedList(localName, childSizeHint);
+ }
+
+
+ @Override
+ public void startUnkeyedListItem(final int childSizeHint) throws IOException, IllegalStateException {
+ delegate().startUnkeyedListItem(childSizeHint);
+ }
+
+
+ @Override
+ public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType, final int childSizeHint)
+ throws IOException, IllegalArgumentException {
+ delegate().startMapNode(mapEntryType, childSizeHint);
+ }
+
+
+ @Override
+ public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType, final int childSizeHint)
+ throws IOException, IllegalArgumentException {
+ delegate().startOrderedMapNode(mapEntryType, childSizeHint);
+ }
+
+
+ @Override
+ public void startMapEntryNode(final Identifier<?> keyValues, final int childSizeHint) throws IOException,
+ IllegalArgumentException {
+ delegate().startMapEntryNode(keyValues, childSizeHint);
+ }
+
+
+ @Override
+ public void startChoiceNode(final Class<? extends DataContainer> choice, final int childSizeHint) throws IOException,
+ IllegalArgumentException {
+ delegate().startChoiceNode(choice, childSizeHint);
+ }
+
+
+ @Override
+ public void startCase(final Class<? extends DataObject> caze, final int childSizeHint) throws IOException,
+ IllegalArgumentException {
+ delegate().startCase(caze, childSizeHint);
+ }
+
+
+ @Override
+ public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType) throws IOException,
+ IllegalArgumentException {
+ delegate().startAugmentationNode(augmentationType);
+ }
+
+
+ @Override
+ public void anyxmlNode(final String name, final Object value) throws IOException, IllegalArgumentException {
+ delegate().anyxmlNode(name, value);
+ }
+
+
+ @Override
+ public void endNode() throws IOException, IllegalStateException {
+ delegate().endNode();
+ }
+
+
+ @Override
+ public void flush() throws IOException {
+ delegate().flush();
+ }
+
+
+ @Override
+ public void close() throws IOException {
+ delegate().close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeCachingCodec;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeCodec;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+class NonCachingCodec<D extends DataObject> implements BindingNormalizedNodeCachingCodec<D> {
+
+ private final BindingNormalizedNodeCodec<D> delegate;
+
+ protected NonCachingCodec(final BindingNormalizedNodeCodec<D> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public D deserialize(final NormalizedNode<?, ?> data) {
+ return delegate.deserialize(data);
+ }
+
+ @Override
+ public NormalizedNode<?, ?> serialize(final D data) {
+ return delegate.serialize(data);
+ }
+
+ @Override
+ public void close() {
+ // NOOP
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.impl;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+
+final class NormalizedNodeWriterWithAddChild extends ImmutableNormalizedNodeStreamWriter {
+
+ NormalizedNodeWriterWithAddChild(final NormalizedNodeResult result) {
+ super(result);
+ }
+
+ void addChild(final NormalizedNode<?, ?> child) {
+ this.writeChild(child);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.binding.data.codec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.List;
+import javassist.ClassPool;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.binding.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeNode;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeCachingCodec;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class CachingCodecTest extends AbstractBindingRuntimeTest {
+
+ private static final NodeIdentifier TOP_LEVEL_LIST_ARG = new NodeIdentifier(TopLevelList.QNAME);
+ private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
+ private static final List<TopLevelList> TWO_LIST = createList(2);
+ private static final List<TopLevelList> THREE_LIST = createList(3);
+
+ private static final Top TOP_TWO_LIST_DATA = new TopBuilder().setTopLevelList(TWO_LIST).build();
+ private static final Top TOP_THREE_LIST_DATA = new TopBuilder().setTopLevelList(THREE_LIST).build();
+
+ private BindingNormalizedNodeCodecRegistry registry;
+ private BindingCodecTreeNode<Top> topNode;
+
+ @Override
+ public void setup() {
+ super.setup();
+ final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+ registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+ registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+ topNode = registry.getCodecContext().getSubtreeCodec(TOP_PATH);
+
+ }
+
+
+ private static List<TopLevelList> createList(final int num) {
+
+ final ImmutableList.Builder<TopLevelList> builder = ImmutableList.builder();
+ for (int i = 0; i < num; i++) {
+ final TopLevelListKey key = new TopLevelListKey("test-" + i);
+ builder.add(new TopLevelListBuilder().setKey(key).build());
+ }
+ return builder.build();
+ }
+
+ @Test
+ public void testListCache() {
+ final BindingNormalizedNodeCachingCodec<Top> cachingCodec = createCachingCodec(TopLevelList.class);
+ final NormalizedNode<?, ?> first = cachingCodec.serialize(TOP_TWO_LIST_DATA);
+ final NormalizedNode<?, ?> second = cachingCodec.serialize(TOP_TWO_LIST_DATA);
+
+ assertNotSame(first, second);
+ assertEquals(first, second);
+ verifyListItemSame(first, second);
+
+ final NormalizedNode<?, ?> third = cachingCodec.serialize(TOP_THREE_LIST_DATA);
+ verifyListItemSame(first, third);
+ verifyListItemSame(second, third);
+ }
+
+
+ @Test
+ public void testTopAndListCache() {
+ final BindingNormalizedNodeCachingCodec<Top> cachingCodec = createCachingCodec(Top.class, TopLevelList.class);
+ final NormalizedNode<?, ?> first = cachingCodec.serialize(TOP_TWO_LIST_DATA);
+ final NormalizedNode<?, ?> second = cachingCodec.serialize(TOP_TWO_LIST_DATA);
+
+ assertEquals(first, second);
+ assertSame(first, second);
+
+ final NormalizedNode<?, ?> third = cachingCodec.serialize(TOP_THREE_LIST_DATA);
+ verifyListItemSame(first, third);
+ }
+
+ @SafeVarargs
+ private final BindingNormalizedNodeCachingCodec<Top> createCachingCodec(
+ final Class<? extends DataObject>... classes) {
+ return topNode.createCachingCodec(ImmutableSet.<Class<? extends DataObject>>copyOf(classes));
+ }
+
+ private static void verifyListItemSame(final NormalizedNode<?, ?> firstTop, final NormalizedNode<?, ?> secondTop) {
+ final Collection<MapEntryNode> initialNodes = getListItems(firstTop).getValue();
+ final MapNode secondMap = getListItems(secondTop);
+
+ for (final MapEntryNode initial : initialNodes) {
+ final MapEntryNode second = secondMap.getChild(initial.getIdentifier()).get();
+ assertEquals(initial, second);
+ assertSame(initial, second);
+ }
+ }
+
+
+ private static MapNode getListItems(final NormalizedNode<?, ?> top) {
+ return ((MapNode) ((DataContainerNode<?>) top).getChild(TOP_LEVEL_LIST_ARG).get());
+ }
+
+}