Binding2 runtime - Codecs impl - cache
[mdsal.git] / binding2 / mdsal-binding2-dom-codec / src / main / java / org / opendaylight / mdsal / binding / javav2 / dom / codec / impl / serializer / CachingNormalizedNodeSerializer.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Throwables;
12 import java.io.IOException;
13 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.AbstractBindingNormalizedNodeCacheHolder;
14 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.BindingNormalizedNodeCache;
15 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
16 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
17 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingSerializer;
18 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
19 import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializer;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
22
23 /**
24  * Serializer of Binding objects to Normalized Node which uses
25  * {@link BindingNormalizedNodeCache} to cache already serialized values.
26  *
27  * This serializer implements {@link BindingStreamEventWriter} along with
28  * {@link BindingSerializer}.
29  *
30  * {@link BindingSerializer} interface is used by generated implementations of
31  * {@link TreeNodeSerializer} to provide Binding object for inspection and to
32  * prevent streaming of already serialized object.
33  */
34 @Beta
35 public final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEventWriter
36         implements BindingSerializer<Object, TreeNode> {
37
38     private final NormalizedNodeResult domResult;
39     private final NormalizedNodeWithAddChildWriter domWriter;
40     private final BindingToNormalizedStreamWriter delegate;
41     private final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
42
43     private CachingNormalizedNodeSerializer(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
44             final DataContainerCodecContext<?, ?> subtreeRoot) {
45         this.cacheHolder = cacheHolder;
46         this.domResult = new NormalizedNodeResult();
47         this.domWriter = new NormalizedNodeWithAddChildWriter(domResult);
48         this.delegate = BindingToNormalizedStreamWriter.create(subtreeRoot, domWriter);
49     }
50
51     @Override
52     protected BindingStreamEventWriter delegate() {
53         return delegate;
54     }
55
56     private NormalizedNode<?, ?> build() {
57         return domResult.getResult();
58     }
59
60     /**
61      * Serializes input if it is cached, returns null otherwise.
62      *
63      * If input is cached it uses
64      * {@link NormalizedNodeWithAddChildWriter#addChild(NormalizedNode)} to
65      * provide already serialized value to underlying NormalizedNodeWriter in
66      * order to reuse value instead of creating new one using Normalized Node
67      * stream APIs.
68      *
69      * Note that this optional is serialization of child node invoked from
70      * {@link TreeNodeSerializer}, which may opt-out from streaming of data when
71      * non-null result is returned.
72      */
73     @Override
74     public NormalizedNode<?, ?> serialize(final TreeNode input) {
75         final BindingNormalizedNodeCache cachingSerializer = getCacheSerializer(input.getClass());
76         if (cachingSerializer != null) {
77             final NormalizedNode<?, ?> domData = cachingSerializer.get(input);
78             domWriter.addChild(domData);
79             return domData;
80         }
81         return null;
82     }
83
84     @SuppressWarnings({ "rawtypes", "unchecked" })
85     private BindingNormalizedNodeCache getCacheSerializer(final Class type) {
86         if (cacheHolder.isCached(type)) {
87             final DataContainerCodecContext<?, ?> currentCtx = (DataContainerCodecContext<?, ?>) delegate.current();
88             if (type.equals(currentCtx.getBindingClass())) {
89                 return cacheHolder.getCachingSerializer(currentCtx);
90             }
91             return cacheHolder.getCachingSerializer(currentCtx.streamChild(type));
92         }
93         return null;
94     }
95
96     /**
97      * Serializes supplied data using stream writer with child cache enabled or
98      * using cache directly if cache is avalaible also for supplied Codec node.
99      *
100      * @param cacheHolder
101      *            - Binding to Normalized Node Cache holder
102      * @param subtreeRoot
103      *            - codec Node for provided data object
104      * @param data
105      *            - data to be serialized
106      * @return Normalized Node representation of data
107      */
108     public static NormalizedNode<?, ?> serialize(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
109             final DataContainerCodecContext<?, ?> subtreeRoot, final TreeNode data) {
110         final BindingNormalizedNodeCache cache = cacheHolder.getCachingSerializer(subtreeRoot);
111         if (cache != null) {
112             return cache.get(data);
113         }
114         return serializeUsingStreamWriter(cacheHolder, subtreeRoot, data);
115     }
116
117     /**
118      * Serializes supplied data using stream writer with child cache enabled.
119      *
120      * @param cacheHolder
121      *            - binding to Normalized Node Cache holder
122      * @param subtreeRoot
123      *            - codec Node for provided data object
124      * @param data
125      *            - data to be serialized
126      * @return Normalized Node representation of data
127      */
128     public static NormalizedNode<?, ?> serializeUsingStreamWriter(
129             final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
130             final DataContainerCodecContext<?, ?> subtreeRoot, final TreeNode data) {
131         final CachingNormalizedNodeSerializer writer = new CachingNormalizedNodeSerializer(cacheHolder, subtreeRoot);
132         try {
133             subtreeRoot.eventStreamSerializer().serialize(data, writer);
134             return writer.build();
135         } catch (final IOException e) {
136             throw Throwables.propagate(e);
137         }
138     }
139 }