Binding codec v2 - fix get implemented interface as input of getCacheSerializer
[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.Preconditions;
12 import com.google.common.base.Throwables;
13 import java.io.IOException;
14 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.AbstractBindingNormalizedNodeCacheHolder;
15 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.BindingNormalizedNodeCache;
16 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
17 import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
18 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
19 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingSerializer;
20 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
21 import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializer;
22 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
23 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
24
25 /**
26  * Serializer of Binding objects to Normalized Node which uses
27  * {@link BindingNormalizedNodeCache} to cache already serialized values.
28  *
29  * <p>
30  * This serializer implements {@link BindingStreamEventWriter} along with
31  * {@link BindingSerializer}.
32  *
33  * {@link BindingSerializer} interface is used by generated implementations of
34  * {@link TreeNodeSerializer} to provide Binding object for inspection and to
35  * prevent streaming of already serialized object.
36  */
37 @Beta
38 public final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEventWriter
39         implements BindingSerializer<Object, TreeNode> {
40
41     private final NormalizedNodeResult domResult;
42     private final NormalizedNodeWithAddChildWriter domWriter;
43     private final BindingToNormalizedStreamWriter delegate;
44     private final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
45
46     private CachingNormalizedNodeSerializer(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
47             final DataContainerCodecContext<?, ?> subtreeRoot) {
48         this.cacheHolder = cacheHolder;
49         this.domResult = new NormalizedNodeResult();
50         this.domWriter = new NormalizedNodeWithAddChildWriter(domResult);
51         this.delegate = BindingToNormalizedStreamWriter.create(subtreeRoot, domWriter);
52     }
53
54     @Override
55     protected BindingStreamEventWriter delegate() {
56         return delegate;
57     }
58
59     private NormalizedNode<?, ?> build() {
60         return domResult.getResult();
61     }
62
63     /**
64      * Serializes input if it is cached, returns null otherwise.
65      *
66      * <p>
67      * If input is cached it uses
68      * {@link NormalizedNodeWithAddChildWriter#addChild(NormalizedNode)} to
69      * provide already serialized value to underlying NormalizedNodeWriter in
70      * order to reuse value instead of creating new one using Normalized Node
71      * stream APIs.
72      *
73      * <p>
74      * Note that this optional is serialization of child node invoked from
75      * {@link TreeNodeSerializer}, which may opt-out from streaming of data when
76      * non-null result is returned.
77      */
78     @Override
79     public NormalizedNode<?, ?> serialize(final TreeNode input) {
80         // Binding data input MUST be an instance of Instantiable too.
81         Preconditions.checkArgument(input instanceof Instantiable, "Input %s is not instantiable", input);
82
83         final BindingNormalizedNodeCache cachingSerializer =
84             getCacheSerializer(((Instantiable<?>) input).implementedInterface());
85         if (cachingSerializer != null) {
86             final NormalizedNode<?, ?> domData = cachingSerializer.get(input);
87             domWriter.addChild(domData);
88             return domData;
89         }
90         return null;
91     }
92
93     /**
94      * Serializes supplied data using stream writer with child cache enabled or
95      * using cache directly if cache is avalaible also for supplied Codec node.
96      *
97      * @param cacheHolder
98      *            - Binding to Normalized Node Cache holder
99      * @param subtreeRoot
100      *            - codec Node for provided data object
101      * @param data
102      *            - data to be serialized
103      * @return Normalized Node representation of data
104      */
105     public static NormalizedNode<?, ?> serialize(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
106             final DataContainerCodecContext<?, ?> subtreeRoot, final TreeNode data) {
107         final BindingNormalizedNodeCache cache = cacheHolder.getCachingSerializer(subtreeRoot);
108         if (cache != null) {
109             return cache.get(data);
110         }
111         return serializeUsingStreamWriter(cacheHolder, subtreeRoot, data);
112     }
113
114     @SuppressWarnings({ "rawtypes", "unchecked" })
115     private BindingNormalizedNodeCache getCacheSerializer(final Class type) {
116         if (cacheHolder.isCached(type)) {
117             final DataContainerCodecContext<?, ?> currentCtx = (DataContainerCodecContext<?, ?>) delegate.current();
118             if (type.equals(currentCtx.getBindingClass())) {
119                 return cacheHolder.getCachingSerializer(currentCtx);
120             }
121             return cacheHolder.getCachingSerializer(currentCtx.streamChild(type));
122         }
123         return null;
124     }
125
126     /**
127      * Serializes supplied data using stream writer with child cache enabled.
128      *
129      * @param cacheHolder
130      *            - binding to Normalized Node Cache holder
131      * @param subtreeRoot
132      *            - codec Node for provided data object
133      * @param data
134      *            - data to be serialized
135      * @return Normalized Node representation of data
136      */
137     public static NormalizedNode<?, ?> serializeUsingStreamWriter(
138             final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
139             final DataContainerCodecContext<?, ?> subtreeRoot, final TreeNode data) {
140         final CachingNormalizedNodeSerializer writer = new CachingNormalizedNodeSerializer(cacheHolder, subtreeRoot);
141         try {
142             subtreeRoot.eventStreamSerializer().serialize(data, writer);
143             return writer.build();
144         } catch (final IOException e) {
145             throw Throwables.propagate(e);
146         }
147     }
148 }