Merge "BUG-1485: deprecate length/range methods"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 13 Apr 2015 09:27:14 +0000 (09:27 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 13 Apr 2015 09:27:18 +0000 (09:27 +0000)
20 files changed:
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataNodeContainerSerializerSource.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/gen/impl/DataObjectSerializerSource.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/AbstractBindingNormalizedNodeCacheHolder.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCache.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingToNormalizedStreamWriter.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CachingNormalizedNodeCodec.java [moved from code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CachingNormalizedNodeCodecImpl.java with 62% similarity]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CachingNormalizedNodeSerializer.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataContainerCodecContext.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ForwardingBindingStreamEventWriter.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/LazyDataObject.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NonCachingCodec.java [new file with mode: 0644]
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NormalizedNodeWriterWithAddChild.java [new file with mode: 0644]
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CachingCodecTest.java [new file with mode: 0644]
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/AugmentationHolder.java [new file with mode: 0644]
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/AugmentationFieldGetter.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNormalizedNodeStreamWriter.java

index 76d1cd01c6c79188eba4f470b992d453ec04cac0..4d52dab58deefab413fd78cd50a82ff7f8c2cc53 100644 (file)
@@ -15,6 +15,7 @@ import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature;
 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;
@@ -54,12 +55,20 @@ abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSou
 
     @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);
@@ -79,10 +88,10 @@ abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSou
     }
 
     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);
             }
@@ -114,11 +123,11 @@ abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSou
     }
 
     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);
             }
         }
@@ -141,22 +150,34 @@ abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSou
             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;
@@ -170,7 +191,7 @@ abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSou
             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
index ec276e79daa9fa03afd7dd64fc55e797bc59932b..b77fa9ac5eb7c9aadef97750b975135dfe304afa 100644 (file)
@@ -21,6 +21,7 @@ abstract class DataObjectSerializerSource extends AbstractSource {
 
     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";
@@ -39,7 +40,7 @@ abstract class DataObjectSerializerSource extends AbstractSource {
     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);
         }
     }
@@ -131,11 +132,11 @@ abstract class DataObjectSerializerSource extends AbstractSource {
         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
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/AbstractBindingNormalizedNodeCacheHolder.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/AbstractBindingNormalizedNodeCacheHolder.java
new file mode 100644 (file)
index 0000000..07d7464
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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);
+    }
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCache.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCache.java
new file mode 100644 (file)
index 0000000..141353d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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);
+    }
+}
index 0c59f342bc74e10371494e315432964da30740a3..50af39cfbf886c2241cd1cfcdd67343f388295ef 100644 (file)
@@ -18,6 +18,7 @@ import java.util.AbstractMap.SimpleEntry;
 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;
@@ -71,7 +72,7 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         return serializers.getUnchecked(type);
     }
 
-    public BindingCodecContext getCodecContext() {
+    public BindingCodecTree getCodecContext() {
         return codecContext;
     }
 
@@ -231,23 +232,23 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
     }
 
     @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);
     }
 
index 617b514ccd4c2f1c13bfabd8319a61bc628255f8..ed4bb470024eebbc1344f2d0c10c4eb6d5cdff46 100644 (file)
@@ -39,7 +39,7 @@ class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Deleg
 
     }
 
-    private NodeCodecContext<?> current() {
+    protected final NodeCodecContext<?> current() {
         return schema.peek();
     }
 
@@ -13,25 +13,26 @@ import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeCa
 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
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CachingNormalizedNodeSerializer.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/CachingNormalizedNodeSerializer.java
new file mode 100644 (file)
index 0000000..87c8c44
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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
index 455cf674bbf7494ab335bc1123ad2d99bafddb31..371a181ce4111bc96f195d32fceb0f3a092b9a76 100644 (file)
@@ -135,11 +135,14 @@ abstract class DataContainerCodecContext<D extends DataObject,T> extends NodeCod
 
     @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);
     }
 
@@ -151,7 +154,7 @@ abstract class DataContainerCodecContext<D extends DataObject,T> extends NodeCod
     }
 
     @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);
@@ -160,10 +163,10 @@ abstract class DataContainerCodecContext<D extends DataObject,T> extends NodeCod
     }
 
     @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);
         }
     }
index 074a20a790d602416ade8b4246d52c92a4c7888d..8302aed0e6348d283b45d974bf8c2c105ba77edb 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.binding.data.codec.impl;
 
+import org.opendaylight.yangtools.yang.binding.AugmentationHolder;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
@@ -116,7 +118,7 @@ abstract class DataObjectCodecContext<D extends DataObject,T extends DataNodeCon
         byBindingArgClassBuilder.putAll(byStreamClass);
         this.byBindingArgClass = ImmutableMap.copyOf(byBindingArgClassBuilder);
 
-        final Class<?> proxyClass = Proxy.getProxyClass(getBindingClass().getClassLoader(),  new Class[] { getBindingClass() });
+        final Class<?> proxyClass = Proxy.getProxyClass(getBindingClass().getClassLoader(),  new Class[] { getBindingClass(), AugmentationHolder.class });
         try {
             proxyConstructor = LOOKUP.findConstructor(proxyClass, CONSTRUCTOR_TYPE).asType(DATAOBJECT_TYPE);
         } catch (NoSuchMethodException | IllegalAccessException e) {
@@ -161,7 +163,7 @@ abstract class DataObjectCodecContext<D extends DataObject,T extends DataNodeCon
     @SuppressWarnings("unchecked")
     @Override
     public <DV extends DataObject> Optional<DataContainerCodecContext<DV, ?>> possibleStreamChild(
-            Class<DV> childClass) {
+            final Class<DV> childClass) {
         final DataContainerCodecPrototype<?> childProto = byStreamClass.get(childClass);
         if(childProto != null) {
             return Optional.<DataContainerCodecContext<DV,?>>of((DataContainerCodecContext<DV,?>) childProto.get());
@@ -310,13 +312,13 @@ abstract class DataObjectCodecContext<D extends DataObject,T extends DataNodeCon
     }
 
     @Override
-    public InstanceIdentifier.PathArgument deserializePathArgument(YangInstanceIdentifier.PathArgument arg) {
+    public InstanceIdentifier.PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) {
         Preconditions.checkArgument(getDomPathArgument().equals(arg));
         return bindingArg();
     }
 
     @Override
-    public YangInstanceIdentifier.PathArgument serializePathArgument(InstanceIdentifier.PathArgument arg) {
+    public YangInstanceIdentifier.PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
         Preconditions.checkArgument(bindingArg().equals(arg));
         return getDomPathArgument();
     }
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ForwardingBindingStreamEventWriter.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ForwardingBindingStreamEventWriter.java
new file mode 100644 (file)
index 0000000..d6323df
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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();
+    }
+}
index b92acca00784e382c8db2aba813c8701e800b54d..f1b578b9e873bcc38cf27aab456c945cfcba0dea 100644 (file)
@@ -37,6 +37,7 @@ class LazyDataObject<D extends DataObject> implements InvocationHandler, Augment
     private static final String EQUALS = "equals";
     private static final String GET_AUGMENTATION = "getAugmentation";
     private static final String HASHCODE = "hashCode";
+    private static final String AUGMENTATIONS = "augmentations";
     private static final Object NULL_VALUE = new Object();
 
     private final ConcurrentHashMap<Method, Object> cachedData = new ConcurrentHashMap<>();
@@ -62,6 +63,8 @@ class LazyDataObject<D extends DataObject> implements InvocationHandler, Augment
                 return bindingToString();
             } else if (HASHCODE.equals(name)) {
                 return bindingHashCode();
+            } else if (AUGMENTATIONS.equals(name)) {
+                return getAugmentationsImpl();
             }
             return getBindingData(method);
         } else if (GET_AUGMENTATION.equals(method.getName())) {
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NonCachingCodec.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NonCachingCodec.java
new file mode 100644 (file)
index 0000000..4216f58
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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
+    }
+
+}
diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NormalizedNodeWriterWithAddChild.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/NormalizedNodeWriterWithAddChild.java
new file mode 100644 (file)
index 0000000..57f9bcf
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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);
+    }
+}
index 6dc53e5f8f522614859498069a79dd5dd496f488..32006821d47eeb16310fe3cd18d0f3190abb41a5 100644 (file)
@@ -7,6 +7,10 @@
  */
 package org.opendaylight.yangtools.binding.data.codec.test;
 
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.base.Optional;
+import java.util.Collections;
 import javassist.ClassPool;
 import org.junit.Test;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugment;
@@ -27,10 +31,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-
 
 public class AugmentationSubstitutionTest extends AbstractBindingRuntimeTest {
 
@@ -48,26 +48,39 @@ public class AugmentationSubstitutionTest extends AbstractBindingRuntimeTest {
     @Override
     public void setup() {
         super.setup();
-        JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+        final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
         registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
         registry.onBindingRuntimeContextUpdated(getRuntimeContext());
     }
 
     @Test
     public void augmentationInGroupingSubstituted() {
-        TopLevelList baRpc = new TopLevelListBuilder()
+        final TopLevelList baRpc = new TopLevelListBuilder()
             .setKey(TOP_FOO_KEY)
             .addAugmentation(RpcComplexUsesAugment.class, new RpcComplexUsesAugmentBuilder(createComplexData()).build())
             .build();
-        TopLevelList baTree = new TopLevelListBuilder()
+        final TopLevelList baTree = new TopLevelListBuilder()
             .setKey(TOP_FOO_KEY)
             .addAugmentation(TreeComplexUsesAugment.class, new TreeComplexUsesAugmentBuilder(createComplexData()).build())
             .build();
-        NormalizedNode<?, ?> domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue();
-        NormalizedNode<?, ?> domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue();
+        final NormalizedNode<?, ?> domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue();
+        final NormalizedNode<?, ?> domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue();
         assertEquals(domTreeEntry, domRpcEntry);
     }
 
+    @Test
+    public void copyBuilderWithAugmenationsTest() {
+        final TopLevelList manuallyConstructed = new TopLevelListBuilder()
+            .setKey(TOP_FOO_KEY)
+            .addAugmentation(TreeComplexUsesAugment.class, new TreeComplexUsesAugmentBuilder(createComplexData()).build())
+            .build();
+        final NormalizedNode<?, ?> domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, manuallyConstructed).getValue();
+        final TopLevelList deserialized = registry.deserializeFunction(BA_TOP_LEVEL_LIST).apply(Optional.<NormalizedNode<?, ?>>of(domTreeEntry)).get();
+        assertEquals(manuallyConstructed, deserialized);
+        final TopLevelList copiedFromDeserialized = new TopLevelListBuilder(deserialized).build();
+        assertEquals(manuallyConstructed, copiedFromDeserialized);
+    }
+
     private RpcComplexUsesAugment createComplexData() {
         return new RpcComplexUsesAugmentBuilder()
         .setContainerWithUses(new ContainerWithUsesBuilder()
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CachingCodecTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/CachingCodecTest.java
new file mode 100644 (file)
index 0000000..735679a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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());
+    }
+
+}
index 15e93756576ab94104cd4d33549e8b486937e6f9..710f1022104491baf8853ad89d4a2806be45a2eb 100644 (file)
@@ -32,6 +32,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentable
 import org.opendaylight.yangtools.yang.binding.DataObject
 import org.opendaylight.yangtools.yang.binding.Identifiable
 import org.opendaylight.yangtools.concepts.Builder
+import org.opendaylight.yangtools.yang.binding.AugmentationHolder
 
 /**
  * Template for generating JAVA builder classes.
@@ -556,25 +557,28 @@ class BuilderTemplate extends BaseTemplate {
                 this.«field.fieldName» = base.«field.getterMethodName»();
             «ENDFOR»
             «IF augmentField != null»
-                «IF !impl»if (base instanceof «type.name»«IMPL») {«ENDIF»
-                    «IF !impl»«type.name»«IMPL» _impl = («type.name»«IMPL») base;«ENDIF»
-                    «val prop = if (impl) "base" else "_impl"»
-                    «IF impl»
-                        switch («prop».«augmentField.name».size()) {
-                        case 0:
-                            this.«augmentField.name» = «Collections.importedName».emptyMap();
-                            break;
-                            case 1:
-                                final «Map.importedName».Entry<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e = «prop».«augmentField.name».entrySet().iterator().next();
-                                this.«augmentField.name» = «Collections.importedName».<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue());
-                            break;
-                        default :
-                            this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»);
-                        }
-                    «ELSE»
-                        this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»);
-                    «ENDIF»
-                «IF !impl»}«ENDIF»
+                «IF impl»
+                    switch (base.«augmentField.name».size()) {
+                    case 0:
+                        this.«augmentField.name» = «Collections.importedName».emptyMap();
+                        break;
+                        case 1:
+                            final «Map.importedName».Entry<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e = base.«augmentField.name».entrySet().iterator().next();
+                            this.«augmentField.name» = «Collections.importedName».<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue());
+                        break;
+                    default :
+                        this.«augmentField.name» = new «HashMap.importedName»<>(base.«augmentField.name»);
+                    }
+                «ELSE»
+                    if (base instanceof «type.name»«IMPL») {
+                        «type.name»«IMPL» impl = («type.name»«IMPL») base;
+                        this.«augmentField.name» = new «HashMap.importedName»<>(impl.«augmentField.name»);
+                    } else if (base instanceof «AugmentationHolder.importedName») {
+                        @SuppressWarnings("unchecked")
+                        «AugmentationHolder.importedName»<«type.importedName»> casted =(«AugmentationHolder.importedName»<«type.importedName»>) base;
+                        this.«augmentField.name» = new «HashMap.importedName»<>(casted.augmentations());
+                    }
+                «ENDIF»
             «ENDIF»
         }
     '''
diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/AugmentationHolder.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/AugmentationHolder.java
new file mode 100644 (file)
index 0000000..472c3c2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.yang.binding;
+
+import java.util.Map;
+
+/**
+ *
+ * Augmentable (extensible) object which could carry additional data defined by
+ * third-party extension, without introducing conflict between various
+ * extension.
+ *
+ *
+ * @author Tony Tkacik
+ * @param <T>
+ *            Base class which should is target
+ *            for augmentations.
+ */
+public interface AugmentationHolder<T> {
+
+    /**
+     * Returns map of all augmentations.
+     *
+     * @return map of all augmentations.
+     */
+    Map<Class<? extends Augmentation<T>>,Augmentation<T>> augmentations();
+}
index 8178d8f1e1923580d490028cd6222159b1e69ace..2e8a33a272b7f542ba95a731679833f73914e777 100644 (file)
@@ -1,12 +1,14 @@
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014 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
+ * 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.yang.binding.util;
 
+import org.opendaylight.yangtools.yang.binding.AugmentationHolder;
+
 import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
@@ -30,19 +32,31 @@ abstract class AugmentationFieldGetter {
         }
     };
 
-   /**
-    *
-    * Retrieves augmentations from supplied object
-    *
-    * @param input Input Data object, from which augmentations should be extracted
-    * @return Map of Augmentation class to augmentation
-    */
-   protected abstract Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input);
+    private static final AugmentationFieldGetter AUGMENTATION_HOLDER_GETTER = new AugmentationFieldGetter() {
 
-    private static final LoadingCache<Class<?>, AugmentationFieldGetter> AUGMENTATION_GETTERS =
-            CacheBuilder.newBuilder().weakKeys().softValues().build(new AugmentationGetterLoader());
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        protected Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input) {
+            return (Map) ((AugmentationHolder<?>) input).augmentations();
+        }
+    };
+
+    /**
+     *
+     * Retrieves augmentations from supplied object
+     *
+     * @param input Input Data object, from which augmentations should be extracted
+     * @return Map of Augmentation class to augmentation
+     */
+    protected abstract Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input);
+
+    private static final LoadingCache<Class<?>, AugmentationFieldGetter> AUGMENTATION_GETTERS = CacheBuilder
+            .newBuilder().weakKeys().softValues().build(new AugmentationGetterLoader());
 
     public static AugmentationFieldGetter getGetter(final Class<? extends Object> clz) {
+        if(AugmentationHolder.class.isAssignableFrom(clz)) {
+            return AUGMENTATION_HOLDER_GETTER;
+        }
         return AUGMENTATION_GETTERS.getUnchecked(clz);
     }
 
@@ -81,5 +95,4 @@ abstract class AugmentationFieldGetter {
         }
     }
 
-
 }
index 35ddb97e714c34b29351ec604b7bc8a50adf593c..c0f800f07f2031b1116d36e9d149d5bc8fcaa632 100644 (file)
@@ -60,10 +60,14 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
     private final Deque<NormalizedNodeContainerBuilder> builders = new ArrayDeque<>();
 
     @SuppressWarnings("rawtypes")
-    private ImmutableNormalizedNodeStreamWriter( final NormalizedNodeContainerBuilder topLevelBuilder) {
+    protected ImmutableNormalizedNodeStreamWriter(final NormalizedNodeContainerBuilder topLevelBuilder) {
         builders.push(topLevelBuilder);
     }
 
+    protected ImmutableNormalizedNodeStreamWriter(final NormalizedNodeResult result) {
+        this(new NormalizedNodeResultBuilder(result));
+    }
+
     /**
      * Creates a {@link NormalizedNodeStreamWriter} which creates instances of supplied
      * {@link NormalizedNode}s and writes them to supplied builder as child nodes.
@@ -99,7 +103,7 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
      * @return {@link NormalizedNodeStreamWriter} which will write item to supplied result holder.
      */
     public static final NormalizedNodeStreamWriter from(final NormalizedNodeResult result) {
-        return new ImmutableNormalizedNodeStreamWriter(new NormalizedNodeResultBuilder(result));
+        return new ImmutableNormalizedNodeStreamWriter(result);
     }
 
 
@@ -114,7 +118,7 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
     }
 
     @SuppressWarnings("unchecked")
-    private void writeChild(final NormalizedNode<?, ?> child) {
+    protected void writeChild(final NormalizedNode<?, ?> child) {
         getCurrent().addChild(child);
     }
 
@@ -123,9 +127,9 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
     public void endNode() {
         final NormalizedNodeContainerBuilder finishedBuilder = builders.poll();
         Preconditions.checkState(finishedBuilder != null, "Node which should be closed does not exists.");
-        NormalizedNodeContainerBuilder current = getCurrent();
+        final NormalizedNodeContainerBuilder current = getCurrent();
         Preconditions.checkState(current != null, "Reached top level node, which could not be closed in this writer.");
-        NormalizedNode<PathArgument, ?> product = finishedBuilder.build();
+        final NormalizedNode<PathArgument, ?> product = finishedBuilder.build();
         current.addChild(product);
     }
 
@@ -138,7 +142,7 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
     @Override
     public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
         checkDataNodeContainer();
-        ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = UNKNOWN_SIZE == childSizeHint ?
+        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = UNKNOWN_SIZE == childSizeHint ?
                 ImmutableLeafSetNodeBuilder.create() : ImmutableLeafSetNodeBuilder.create(childSizeHint);
         builder.withNodeIdentifier(name);
         enter(builder);
@@ -148,7 +152,7 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
     public void leafSetEntryNode(final Object value) {
         Preconditions.checkArgument(getCurrent() instanceof ImmutableLeafSetNodeBuilder<?>);
         @SuppressWarnings("unchecked")
-        ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = ((ImmutableLeafSetNodeBuilder<Object>) getCurrent());
+        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = ((ImmutableLeafSetNodeBuilder<Object>) getCurrent());
         builder.withChildValue(value);
     }
 
@@ -231,6 +235,7 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
 
     private void checkDataNodeContainer() {
         @SuppressWarnings("rawtypes")
+        final
         NormalizedNodeContainerBuilder current = getCurrent();
         if (!(current instanceof NormalizedNodeResultBuilder)) {
             Preconditions.checkArgument(current instanceof DataContainerNodeBuilder<?, ?>, "Invalid nesting of data.");