2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
10 import java.io.IOException;
11 import org.opendaylight.mdsal.binding.dom.codec.api.BindingStreamEventWriter;
12 import org.opendaylight.mdsal.binding.dom.codec.impl.LeafNodeCodecContext.OfTypeObject;
13 import org.opendaylight.yangtools.yang.binding.DataObject;
14 import org.opendaylight.yangtools.yang.binding.TypeObject;
15 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
16 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
21 * Serializer of Binding objects to Normalized Node which uses {@link DataObjectNormalizedNodeCache} to
22 * cache already serialized values.
25 * This serializer implements {@link BindingStreamEventWriter} along with {@link BindingSerializer}.
28 * {@link BindingSerializer} interface is used by generated implementations of {@link DataObjectSerializer} to provide
29 * Binding object for inspection and to prevent streaming of already serialized object.
31 final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEventWriter
32 implements BindingSerializer<Object, DataObject> {
33 private static final Logger LOG = LoggerFactory.getLogger(CachingNormalizedNodeSerializer.class);
35 private final NormalizedNodeResult domResult;
36 private final NormalizedNodeWriterWithAddChild domWriter;
37 private final BindingToNormalizedStreamWriter delegate;
38 private final AbstractBindingNormalizedNodeCacheHolder cacheHolder;
40 CachingNormalizedNodeSerializer(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
41 final DataContainerCodecContext<?, ?> subtreeRoot) {
42 this.cacheHolder = cacheHolder;
43 this.domResult = new NormalizedNodeResult();
44 this.domWriter = new NormalizedNodeWriterWithAddChild(domResult);
45 this.delegate = BindingToNormalizedStreamWriter.create(subtreeRoot, domWriter);
49 protected AnydataBindingStreamWriter delegate() {
53 NormalizedNode build() {
54 return domResult.getResult();
58 public void leafNode(final String localName, final Object value) throws IOException {
59 if (value instanceof TypeObject) {
60 // TypeObject is a tagging interface used for generated classes which wrap derived and restricted types.
61 // They are immutable and hence we can safely wrap them in LeafNodes and reuse them, if directed to do so.
62 final TypeObject typed = (TypeObject) value;
63 final Class<? extends TypeObject> type = typed.getClass();
64 if (cacheHolder.isCached(type)) {
65 final ValueNodeCodecContext context = ((DataObjectCodecContext<?, ?>) delegate.current())
66 .getLeafChild(localName);
67 if (context instanceof OfTypeObject) {
68 final AbstractBindingNormalizedNodeCache<TypeObject, ?> cache = cacheHolder.getCachingSerializer(
69 (OfTypeObject<?>)context);
71 // We have a cache hit and are thus done
72 domWriter.addChild(cache.get(typed));
76 LOG.debug("Unexpected failure to acquire cache for context {}, skipping caching", context);
78 LOG.debug("Context {} does not match expected TypeObject {}, skipping caching", context, typed);
82 super.leafNode(localName, value);
86 * Serializes input if it is cached, returns null otherwise.
89 * If input is cached it uses {@link NormalizedNodeWriterWithAddChild#addChild(NormalizedNode)}
90 * to provide already serialized value to underlying NormalizedNodeWriter in order to reuse
91 * value instead of creating new one using Normalized Node stream APIs.
94 * Note that this optional is serialization of child node invoked from
95 * {@link org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectSerializer}, which may opt-out from
96 * streaming of data when non-null result is returned.
99 public NormalizedNode serialize(final DataObject input) {
100 final AbstractBindingNormalizedNodeCache<DataObject, ?> cachingSerializer = getCacheSerializer(
101 input.implementedInterface());
102 if (cachingSerializer != null) {
103 final NormalizedNode domData = cachingSerializer.get(input);
104 domWriter.addChild(domData);
110 private AbstractBindingNormalizedNodeCache<DataObject, ?> getCacheSerializer(
111 final Class<? extends DataObject> type) {
112 if (cacheHolder.isCached(type)) {
113 final DataContainerCodecContext<?, ?> currentCtx = (DataContainerCodecContext<?, ?>) delegate.current();
114 if (type.equals(currentCtx.getBindingClass())) {
115 return cacheHolder.getCachingSerializer(currentCtx);
117 return cacheHolder.getCachingSerializer(currentCtx.streamChild(type));
123 * Serializes supplied data using stream writer with child cache enabled.
125 * @param cacheHolder Binding to Normalized Node Cache holder
126 * @param subtreeRoot Codec Node for provided data object
127 * @param data Data to be serialized
128 * @return Normalized Node representation of data.
130 static NormalizedNode serializeUsingStreamWriter(final AbstractBindingNormalizedNodeCacheHolder cacheHolder,
131 final DataContainerCodecContext<?, ?> subtreeRoot, final DataObject data) {
132 final CachingNormalizedNodeSerializer writer = new CachingNormalizedNodeSerializer(cacheHolder, subtreeRoot);
134 subtreeRoot.eventStreamSerializer().serialize(data, writer);
135 return writer.build();
136 } catch (final IOException e) {
137 throw new IllegalStateException(e);