c57bb756c56edd4dab273aeeeea00589cf758d8f
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / CachingNormalizedNodeSerializer.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.dom.codec.impl;
9
10 import java.io.IOException;
11 import org.opendaylight.yangtools.yang.binding.BindingSerializer;
12 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
13 import org.opendaylight.yangtools.yang.binding.DataObject;
14 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
15 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
16
17 /**
18  * Serializer of Binding objects to Normalized Node which uses {@link BindingNormalizedNodeCache} to
19  * cache already serialized values.
20  *
21  * This serializer implements {@link BindingStreamEventWriter} along with {@link BindingSerializer}.
22  *
23  * {@link BindingSerializer} interface is used by generated implementations of
24  * {@link org.opendaylight.yangtools.yang.binding.DataObjectSerializer} to provide Binding object
25  * for inspection and to prevent streaming of already serialized object.
26  *
27  */
28 final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEventWriter implements
29         BindingSerializer<Object, DataObject> {
30
31     private final NormalizedNodeResult domResult;
32     private final NormalizedNodeWriterWithAddChild domWriter;
33     private final BindingToNormalizedStreamWriter delegate;
34     private final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
35
36     CachingNormalizedNodeSerializer(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
37             final DataContainerCodecContext<?, ?> subtreeRoot) {
38         this.cacheHolder = cacheHolder;
39         this.domResult = new NormalizedNodeResult();
40         this.domWriter = new NormalizedNodeWriterWithAddChild(domResult);
41         this.delegate = BindingToNormalizedStreamWriter.create(subtreeRoot, domWriter);
42     }
43
44     @Override
45     protected BindingStreamEventWriter delegate() {
46         return delegate;
47     }
48
49     NormalizedNode<?, ?> build() {
50         return domResult.getResult();
51     }
52
53     /**
54      * Serializes input if it is cached, returns null otherwise.
55      *
56      * If input is cached it uses {@link NormalizedNodeWriterWithAddChild#addChild(NormalizedNode)}
57      * to provide already serialized value to underlying NormalizedNodeWriter in order to reuse
58      * value instead of creating new one using Normalized Node stream APIs.
59      *
60      * Note that this optional is serialization of child node invoked from
61      * {@link org.opendaylight.yangtools.yang.binding.DataObjectSerializer}, which may opt-out from
62      * streaming of data when non-null result is returned.
63      */
64     @Override
65     public NormalizedNode<?, ?> serialize(final DataObject input) {
66         final BindingNormalizedNodeCache cachingSerializer = getCacheSerializer(input.getImplementedInterface());
67         if (cachingSerializer != null) {
68             final NormalizedNode<?, ?> domData = cachingSerializer.get(input);
69             domWriter.addChild(domData);
70             return domData;
71         }
72         return null;
73     }
74
75     @SuppressWarnings({"rawtypes", "unchecked"})
76     private BindingNormalizedNodeCache getCacheSerializer(final Class type) {
77         if (cacheHolder.isCached(type)) {
78             final DataContainerCodecContext<?, ?> currentCtx = (DataContainerCodecContext<?, ?>) delegate.current();
79             if (type.equals(currentCtx.getBindingClass())) {
80                 return cacheHolder.getCachingSerializer(currentCtx);
81             }
82             return cacheHolder.getCachingSerializer(currentCtx.streamChild(type));
83         }
84         return null;
85     }
86
87     /**
88      * Serializes supplied data using stream writer with child cache enabled or using cache directly
89      * if cache is avalaible also for supplied Codec node.
90      *
91      * @param cacheHolder Binding to Normalized Node Cache holder
92      * @param subtreeRoot Codec Node for provided data object
93      * @param data Data to be serialized
94      * @return Normalized Node representation of data.
95      */
96     static NormalizedNode<?, ?> serialize(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
97             final DataContainerCodecContext<?, ?> subtreeRoot, final DataObject data) {
98         final BindingNormalizedNodeCache cache = cacheHolder.getCachingSerializer(subtreeRoot);
99         if (cache != null) {
100             return cache.get(data);
101         }
102         return serializeUsingStreamWriter(cacheHolder, subtreeRoot, data);
103     }
104
105     /**
106      * Serializes supplied data using stream writer with child cache enabled.
107      *
108      * @param cacheHolder Binding to Normalized Node Cache holder
109      * @param subtreeRoot Codec Node for provided data object
110      * @param data Data to be serialized
111      * @return Normalized Node representation of data.
112      */
113     static NormalizedNode<?, ?> serializeUsingStreamWriter(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
114             final DataContainerCodecContext<?, ?> subtreeRoot, final DataObject data) {
115         final CachingNormalizedNodeSerializer writer = new CachingNormalizedNodeSerializer(cacheHolder, subtreeRoot);
116         try {
117             subtreeRoot.eventStreamSerializer().serialize(data, writer);
118             return writer.build();
119         } catch (final IOException e) {
120             throw new RuntimeException(e);
121         }
122     }
123 }