Teach BindingNormalizedNodeCache to cache leaf type objects
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / CachingNormalizedNodeSerializer.java
index 658bc8939c7fab37aa9e64c382d67afe463e0174..4012de25382f54f7a14d364c2fab513f1f9cacad 100644 (file)
@@ -8,11 +8,15 @@
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import java.io.IOException;
+import org.opendaylight.mdsal.binding.dom.codec.impl.LeafNodeCodecContext.OfTypeObject;
 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.TypeObject;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Serializer of Binding objects to Normalized Node which uses {@link DataObjectNormalizedNodeCache} to
@@ -26,8 +30,9 @@ import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
  * {@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> {
+final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEventWriter
+        implements BindingSerializer<Object, DataObject> {
+    private static final Logger LOG = LoggerFactory.getLogger(CachingNormalizedNodeSerializer.class);
 
     private final NormalizedNodeResult domResult;
     private final NormalizedNodeWriterWithAddChild domWriter;
@@ -51,6 +56,34 @@ final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEvent
         return domResult.getResult();
     }
 
+    @Override
+    public void leafNode(final String localName, final Object value) throws IOException {
+        if (value instanceof TypeObject) {
+            // TypeObject is a tagging interface used for generated classes which wrap derived and restricted types.
+            // They are immutable and hence we can safely wrap them in LeafNodes and reuse them, if directed to do so.
+            final TypeObject typed = (TypeObject) value;
+            final Class<? extends TypeObject> type = typed.getClass();
+            if (cacheHolder.isCached(type)) {
+                final ValueNodeCodecContext context = ((DataObjectCodecContext<?, ?>) delegate.current())
+                        .getLeafChild(localName);
+                if (context instanceof OfTypeObject) {
+                    final AbstractBindingNormalizedNodeCache<TypeObject, ?> cache = cacheHolder.getCachingSerializer(
+                        (OfTypeObject<?>)context);
+                    if (cache != null) {
+                        // We have a cache hit and are thus done
+                        domWriter.addChild(cache.get(typed));
+                        return;
+                    }
+
+                    LOG.debug("Unexpected failure to acquire cache for context {}, skipping caching", context);
+                } else {
+                    LOG.debug("Context {} does not match expected TypeObject {}, skipping caching", context, typed);
+                }
+            }
+        }
+        super.leafNode(localName, value);
+    }
+
     /**
      * Serializes input if it is cached, returns null otherwise.
      *
@@ -66,7 +99,8 @@ final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEvent
      */
     @Override
     public NormalizedNode<?, ?> serialize(final DataObject input) {
-        final DataObjectNormalizedNodeCache cachingSerializer = getCacheSerializer(input.implementedInterface());
+        final AbstractBindingNormalizedNodeCache<DataObject, ?> cachingSerializer = getCacheSerializer(
+            input.implementedInterface());
         if (cachingSerializer != null) {
             final NormalizedNode<?, ?> domData = cachingSerializer.get(input);
             domWriter.addChild(domData);
@@ -75,7 +109,8 @@ final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEvent
         return null;
     }
 
-    private DataObjectNormalizedNodeCache getCacheSerializer(final Class<? extends DataObject> type) {
+    private AbstractBindingNormalizedNodeCache<DataObject, ?> getCacheSerializer(
+            final Class<? extends DataObject> type) {
         if (cacheHolder.isCached(type)) {
             final DataContainerCodecContext<?, ?> currentCtx = (DataContainerCodecContext<?, ?>) delegate.current();
             if (type.equals(currentCtx.getBindingClass())) {