From 291aa50f6da2ab115afb6952faf0c469ab73ae5a Mon Sep 17 00:00:00 2001 From: Jakub Toth Date: Wed, 7 Jun 2017 13:29:57 +0200 Subject: [PATCH] Binding2 runtime - Codecs impl - cache * caching data part Change-Id: If0b595c4c50dd3a0741629432623210c31bce381 Signed-off-by: Jakub Toth --- ...tractBindingNormalizedNodeCacheHolder.java | 62 ++++++++ .../cache/BindingNormalizedNodeCache.java | 57 +++++++ .../cache/CachingNormalizedNodeCodec.java | 53 +++++++ .../codec/impl/codecs/NonCachingCodec.java | 48 ++++++ .../base/DataContainerCodecContext.java | 11 +- .../CachingNormalizedNodeSerializer.java | 139 ++++++++++++++++++ 6 files changed, 366 insertions(+), 4 deletions(-) create mode 100644 binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/AbstractBindingNormalizedNodeCacheHolder.java create mode 100644 binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/BindingNormalizedNodeCache.java create mode 100644 binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/CachingNormalizedNodeCodec.java create mode 100644 binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/codecs/NonCachingCodec.java create mode 100644 binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/serializer/CachingNormalizedNodeSerializer.java 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 index 0000000000..7af8e9cf8f --- /dev/null +++ b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/AbstractBindingNormalizedNodeCacheHolder.java @@ -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> cachedValues; + private final LoadingCache, BindingNormalizedNodeCache> caches = CacheBuilder + .newBuilder().build(new CacheLoader, BindingNormalizedNodeCache>() { + + @Override + public BindingNormalizedNodeCache load(@Nonnull final DataContainerCodecContext key) + throws Exception { + return new BindingNormalizedNodeCache(AbstractBindingNormalizedNodeCacheHolder.this, key); + } + + }); + + protected AbstractBindingNormalizedNodeCacheHolder(@Nonnull final Set> 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 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 index 0000000000..50a6de4bc8 --- /dev/null +++ b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/BindingNormalizedNodeCache.java @@ -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> { + + @SuppressWarnings("rawtypes") + private final DataContainerCodecContext subtreeRoot; + private final AbstractBindingNormalizedNodeCacheHolder cacheHolder; + private final LoadingCache> 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 index 0000000000..a58cff12dc --- /dev/null +++ b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/cache/CachingNormalizedNodeCodec.java @@ -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 + * - type of tree node + */ +@Beta +public class CachingNormalizedNodeCodec extends AbstractBindingNormalizedNodeCacheHolder + implements BindingNormalizedNodeCachingCodec { + + private final DataContainerCodecContext context; + + public CachingNormalizedNodeCodec(final DataContainerCodecContext subtreeRoot, + final Set> 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 index 0000000000..8f7f9cf17d --- /dev/null +++ b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/codecs/NonCachingCodec.java @@ -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 + * - type of tree node + */ +@Beta +public class NonCachingCodec implements BindingNormalizedNodeCachingCodec { + + private final BindingNormalizedNodeCodec delegate; + + public NonCachingCodec(final BindingNormalizedNodeCodec 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() { + } + +} diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/DataContainerCodecContext.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/DataContainerCodecContext.java index 6a707c3a12..2f6448be68 100644 --- a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/DataContainerCodecContext.java +++ b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/context/base/DataContainerCodecContext.java @@ -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 extends NodeCodecContext { @@ -149,9 +151,10 @@ public abstract class DataContainerCodecContext extends N @Override public BindingNormalizedNodeCachingCodec createCachingCodec( @Nonnull final ImmutableCollection> cacheSpecifier) { - - //TODO: implement in cache-related patches to come - throw new NotImplementedException(); + if (cacheSpecifier.isEmpty()) { + return new NonCachingCodec(this); + } + return new CachingNormalizedNodeCodec(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 index 0000000000..0f36bdacd2 --- /dev/null +++ b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/impl/serializer/CachingNormalizedNodeSerializer.java @@ -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 { + + 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 -- 2.36.6