Binding2 runtime - Codecs impl - cache 06/58406/16
authorJakub Toth <jakub.toth@pantheon.tech>
Wed, 7 Jun 2017 11:29:57 +0000 (13:29 +0200)
committerJakub Toth <jakub.toth@pantheon.tech>
Tue, 13 Jun 2017 07:04:51 +0000 (07:04 +0000)
  * caching data part

Change-Id: If0b595c4c50dd3a0741629432623210c31bce381
Signed-off-by: Jakub Toth <jakub.toth@pantheon.tech>
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/AbstractBindingNormalizedNodeCacheHolder.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/BindingNormalizedNodeCache.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/CachingNormalizedNodeCodec.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/codecs/NonCachingCodec.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/DataContainerCodecContext.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/serializer/CachingNormalizedNodeSerializer.java [new file with mode: 0644]

diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/AbstractBindingNormalizedNodeCacheHolder.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/AbstractBindingNormalizedNodeCacheHolder.java
new file mode 100644 (file)
index 0000000..7af8e9c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache;
+
+import com.google.common.annotations.Beta;
+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 javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+
+/**
+ * Abstract Holder of Binding to Normalized Node caches indexed by
+ * {@link DataContainerCodecContext} to which cache is associated.
+ *
+ */
+@Beta
+public abstract class AbstractBindingNormalizedNodeCacheHolder {
+
+    private final Set<Class<? extends TreeNode>> cachedValues;
+    private final LoadingCache<DataContainerCodecContext<?, ?>, BindingNormalizedNodeCache> caches = CacheBuilder
+            .newBuilder().build(new CacheLoader<DataContainerCodecContext<?, ?>, BindingNormalizedNodeCache>() {
+
+                @Override
+                public BindingNormalizedNodeCache load(@Nonnull final DataContainerCodecContext<?, ?> key)
+                        throws Exception {
+                    return new BindingNormalizedNodeCache(AbstractBindingNormalizedNodeCacheHolder.this, key);
+                }
+
+            });
+
+    protected AbstractBindingNormalizedNodeCacheHolder(@Nonnull final Set<Class<? extends TreeNode>> cacheSpec) {
+        cachedValues = Preconditions.checkNotNull(cacheSpec);
+    }
+
+    public BindingNormalizedNodeCache getCachingSerializer(final DataContainerCodecContext<?, ?> childCtx) {
+        if (isCached(childCtx.getBindingClass())) {
+            return caches.getUnchecked(childCtx);
+        }
+        return null;
+    }
+
+    /**
+     * Check if specific type is cached.
+     *
+     * @param type
+     *            - type for check
+     * @return true if type is cached, false otherwise
+     */
+    public boolean isCached(final Class<? extends TreeNode> type) {
+        return cachedValues.contains(type);
+    }
+}
+
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/BindingNormalizedNodeCache.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/BindingNormalizedNodeCache.java
new file mode 100644 (file)
index 0000000..50a6de4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache;
+
+import com.google.common.annotations.Beta;
+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 javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.CachingNormalizedNodeSerializer;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Cached NormalizedNode representation of TreeNode.
+ */
+@Beta
+public class BindingNormalizedNodeCache extends CacheLoader<TreeNode, NormalizedNode<?, ?>> {
+
+    @SuppressWarnings("rawtypes")
+    private final DataContainerCodecContext subtreeRoot;
+    private final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
+    private final LoadingCache<TreeNode, NormalizedNode<?, ?>> cache =
+            CacheBuilder.newBuilder().weakValues().build(this);
+
+    public BindingNormalizedNodeCache(@Nonnull final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+            @Nonnull final DataContainerCodecContext<?, ?> subtreeRoot) {
+        this.cacheHolder = Preconditions.checkNotNull(cacheHolder, "cacheHolder");
+        this.subtreeRoot = Preconditions.checkNotNull(subtreeRoot, "subtreeRoot");
+    }
+
+    @Override
+    public NormalizedNode<?, ?> load(@Nonnull final TreeNode key) throws Exception {
+        return CachingNormalizedNodeSerializer.serializeUsingStreamWriter(cacheHolder, subtreeRoot, key);
+    }
+
+    /**
+     * Returns cached NormalizedNode representation of TreeNode.
+     *
+     * If representation is not cached, serializes TreeNode and updates cache
+     * with representation.
+     *
+     * @param obj
+     *            - binding object to be deserialized
+     * @return NormalizedNode representation of binding object
+     */
+    public NormalizedNode<?, ?> get(final TreeNode obj) {
+        return cache.getUnchecked(obj);
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/CachingNormalizedNodeCodec.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/CachingNormalizedNodeCodec.java
new file mode 100644 (file)
index 0000000..a58cff1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.codecs.BindingNormalizedNodeCachingCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.CachingNormalizedNodeSerializer;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Caching codec.
+ *
+ * @param <D>
+ *            - type of tree node
+ */
+@Beta
+public class CachingNormalizedNodeCodec<D extends TreeNode> extends AbstractBindingNormalizedNodeCacheHolder
+        implements BindingNormalizedNodeCachingCodec<D> {
+
+    private final DataContainerCodecContext<D, ?> context;
+
+    public CachingNormalizedNodeCodec(final DataContainerCodecContext<D, ?> subtreeRoot,
+            final Set<Class<? extends TreeNode>> cacheSpec) {
+        super(cacheSpec);
+        this.context = Preconditions.checkNotNull(subtreeRoot);
+    }
+
+    @Nonnull
+    @Override
+    public D deserialize(@Nonnull final NormalizedNode<?, ?> data) {
+        return context.deserialize(data);
+    }
+
+    @Nonnull
+    @Override
+    public NormalizedNode<?, ?> serialize(@Nonnull final D data) {
+        return CachingNormalizedNodeSerializer.serialize(this, context, data);
+    }
+
+    @Override
+    public void close() {
+    }
+}
\ No newline at end of file
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/codecs/NonCachingCodec.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/codecs/NonCachingCodec.java
new file mode 100644 (file)
index 0000000..8f7f9cf
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.codecs;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.codecs.BindingNormalizedNodeCachingCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.api.codecs.BindingNormalizedNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Non caching codec.
+ *
+ * @param <D>
+ *            - type of tree node
+ */
+@Beta
+public class NonCachingCodec<D extends TreeNode> implements BindingNormalizedNodeCachingCodec<D> {
+
+    private final BindingNormalizedNodeCodec<D> delegate;
+
+    public NonCachingCodec(final BindingNormalizedNodeCodec<D> delegate) {
+        this.delegate = delegate;
+    }
+
+    @Nonnull
+    @Override
+    public D deserialize(@Nonnull final NormalizedNode<?, ?> data) {
+        return delegate.deserialize(data);
+    }
+
+    @Nonnull
+    @Override
+    public NormalizedNode<?, ?> serialize(@Nonnull final D data) {
+        return delegate.serialize(data);
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
index 6a707c3a12b9bc6f9899844760569c4e0b9f450f..2f6448be689bf0b7fa8dd0654c1b12727c75494e 100644 (file)
@@ -11,12 +11,15 @@ package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
 import java.util.List;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.api.codecs.BindingNormalizedNodeCachingCodec;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.MissingSchemaException;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.CachingNormalizedNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.codecs.NonCachingCodec;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.BindingToNormalizedStreamWriter;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
@@ -30,7 +33,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
-import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 @Beta
 public abstract class DataContainerCodecContext<D extends TreeNode, T> extends NodeCodecContext<D> {
@@ -149,9 +151,10 @@ public abstract class DataContainerCodecContext<D extends TreeNode, T> extends N
     @Override
     public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
             @Nonnull final ImmutableCollection<Class<? extends TreeNode>> cacheSpecifier) {
-
-        //TODO: implement in cache-related patches to come
-        throw new NotImplementedException();
+        if (cacheSpecifier.isEmpty()) {
+            return new NonCachingCodec<D>(this);
+        }
+        return new CachingNormalizedNodeCodec<D>(this, ImmutableSet.copyOf(cacheSpecifier));
     }
 
     BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/serializer/CachingNormalizedNodeSerializer.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/serializer/CachingNormalizedNodeSerializer.java
new file mode 100644 (file)
index 0000000..0f36bda
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Throwables;
+import java.io.IOException;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.AbstractBindingNormalizedNodeCacheHolder;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.BindingNormalizedNodeCache;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingSerializer;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializer;
+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 TreeNodeSerializer} to provide Binding object for inspection and to
+ * prevent streaming of already serialized object.
+ */
+@Beta
+public final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEventWriter
+        implements BindingSerializer<Object, TreeNode> {
+
+    private final NormalizedNodeResult domResult;
+    private final NormalizedNodeWithAddChildWriter domWriter;
+    private final BindingToNormalizedStreamWriter delegate;
+    private final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
+
+    private CachingNormalizedNodeSerializer(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+            final DataContainerCodecContext<?, ?> subtreeRoot) {
+        this.cacheHolder = cacheHolder;
+        this.domResult = new NormalizedNodeResult();
+        this.domWriter = new NormalizedNodeWithAddChildWriter(domResult);
+        this.delegate = BindingToNormalizedStreamWriter.create(subtreeRoot, domWriter);
+    }
+
+    @Override
+    protected BindingStreamEventWriter delegate() {
+        return delegate;
+    }
+
+    private NormalizedNode<?, ?> build() {
+        return domResult.getResult();
+    }
+
+    /**
+     * Serializes input if it is cached, returns null otherwise.
+     *
+     * If input is cached it uses
+     * {@link NormalizedNodeWithAddChildWriter#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 TreeNodeSerializer}, which may opt-out from streaming of data when
+     * non-null result is returned.
+     */
+    @Override
+    public NormalizedNode<?, ?> serialize(final TreeNode input) {
+        final BindingNormalizedNodeCache cachingSerializer = getCacheSerializer(input.getClass());
+        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);
+            }
+            return cacheHolder.getCachingSerializer(currentCtx.streamChild(type));
+        }
+        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
+     */
+    public static NormalizedNode<?, ?> serialize(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+            final DataContainerCodecContext<?, ?> subtreeRoot, final TreeNode 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
+     */
+    public static NormalizedNode<?, ?> serializeUsingStreamWriter(
+            final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
+            final DataContainerCodecContext<?, ?> subtreeRoot, final TreeNode 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