2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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 static com.google.common.base.Verify.verify;
12 import com.google.common.annotations.Beta;
13 import java.io.IOException;
14 import java.util.Collection;
15 import java.util.List;
17 import java.util.Map.Entry;
19 import org.opendaylight.mdsal.binding.dom.codec.api.BindingStreamEventWriter;
20 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
21 import org.opendaylight.yangtools.yang.binding.Augmentable;
22 import org.opendaylight.yangtools.yang.binding.Augmentation;
23 import org.opendaylight.yangtools.yang.binding.DataContainer;
24 import org.opendaylight.yangtools.yang.binding.DataObject;
25 import org.opendaylight.yangtools.yang.binding.Identifiable;
26 import org.opendaylight.yangtools.yang.binding.OpaqueObject;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * Base superclass for all concrete streamers, that is objects which are able to turn a concrete DataObject into a
34 * @param <T> DataObject type
37 public abstract class DataObjectStreamer<T extends DataObject> implements DataObjectSerializerImplementation {
38 private static final Logger LOG = LoggerFactory.getLogger(DataObjectStreamer.class);
40 protected DataObjectStreamer() {
44 protected static final void streamAnydata(final BindingStreamEventWriter writer, final String localName,
45 final Object value) throws IOException {
46 if (value != null && writer instanceof AnydataBindingStreamWriter) {
47 verify(value instanceof OpaqueObject, "Unexpected data %s", value);
48 ((AnydataBindingStreamWriter) writer).anydataNode(localName, (OpaqueObject<?>) value);
52 protected static final void streamAnyxml(final BindingStreamEventWriter writer, final String localName,
53 final Object value) throws IOException {
55 writer.anyxmlNode(localName, value);
59 protected static final void streamAugmentations(final DataObjectSerializerRegistry registry,
60 final BindingStreamEventWriter writer, final Augmentable<?> obj) throws IOException {
61 final Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations =
62 BindingReflections.getAugmentations(obj);
63 for (final Entry<Class<? extends Augmentation<?>>, Augmentation<?>> aug : augmentations.entrySet()) {
64 emitAugmentation(aug.getKey(), aug.getValue(), writer, registry);
68 protected static final <C extends DataContainer> void streamChoice(final Class<C> choiceClass,
69 final DataObjectSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
72 final Class<? extends DataContainer> caseClass = value.implementedInterface();
73 writer.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
74 final DataObjectSerializer caseStreamer = registry.getSerializer(caseClass.asSubclass(DataObject.class));
75 if (caseStreamer != null) {
76 if (tryCache(writer, (DataObject) value)) {
77 caseStreamer.serialize((DataObject) value, writer);
80 LOG.warn("No serializer for case {} is available in registry {}", caseClass, registry);
87 protected static final <C extends DataObject> void streamContainer(final DataObjectStreamer<C> childStreamer,
88 final DataObjectSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
90 if (value != null && tryCache(writer, value)) {
91 childStreamer.serialize(registry, value, writer);
95 protected static final void streamLeaf(final BindingStreamEventWriter writer, final String localName,
96 final Object value) throws IOException {
98 writer.leafNode(localName, value);
102 protected static final void streamLeafList(final BindingStreamEventWriter writer, final String localName,
103 final Set<?> value) throws IOException {
105 writer.startLeafSet(localName, value.size());
106 commonStreamLeafset(writer, value);
110 protected static final void streamOrderedLeafList(final BindingStreamEventWriter writer,
111 final String localName, final List<?> value) throws IOException {
113 writer.startOrderedLeafSet(localName, value.size());
114 commonStreamLeafset(writer, value);
118 protected static final <E extends DataObject> void streamList(final Class<E> childClass,
119 final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
120 final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
121 final int size = nullSize(value);
123 writer.startUnkeyedList(childClass, size);
124 commonStreamList(registry, writer, childStreamer, value);
128 protected static final <E extends DataObject & Identifiable<?>> void streamMap(final Class<E> childClass,
129 final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
130 final BindingStreamEventWriter writer, final Map<?, ? extends E> value) throws IOException {
131 final int size = nullSize(value);
133 writer.startMapNode(childClass, size);
134 commonStreamList(registry, writer, childStreamer, value.values());
138 protected static final <E extends DataObject & Identifiable<?>> void streamOrderedMap(final Class<E> childClass,
139 final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
140 final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
141 final int size = nullSize(value);
143 writer.startOrderedMapNode(childClass, size);
144 commonStreamList(registry, writer, childStreamer, value);
148 private static <E extends DataObject> void commonStreamList(final DataObjectSerializerRegistry registry,
149 final BindingStreamEventWriter writer, final DataObjectStreamer<E> childStreamer,
150 final Collection<? extends E> value) throws IOException {
152 for (E entry : value) {
153 if (tryCache(writer, entry)) {
154 childStreamer.serialize(registry, entry, writer);
160 private static void commonStreamLeafset(final BindingStreamEventWriter writer, final Collection<?> value)
162 for (Object entry : value) {
163 writer.leafSetEntryNode(entry);
168 private static void emitAugmentation(final Class<? extends Augmentation<?>> type, final Augmentation<?> value,
169 final BindingStreamEventWriter writer, final DataObjectSerializerRegistry registry) throws IOException {
171 * Binding Specification allowed to insert augmentation with null for value, which effectively could be used to
172 * remove augmentation from builder / DTO.
175 final DataObjectSerializer serializer = registry.getSerializer(type);
176 if (serializer != null) {
177 serializer.serialize(value, writer);
179 LOG.warn("DataObjectSerializer is not present for {} in registry {}", type, registry);
184 @SuppressWarnings("unchecked")
185 private static <T extends DataObject> boolean tryCache(final BindingStreamEventWriter writer, final T value) {
186 // Force serialization if writer is not a BindingSerializer, otherwise defer to it for a decision
187 return !(writer instanceof BindingSerializer) || ((BindingSerializer<?, T>) writer).serialize(value) == null;
190 private static int nullSize(final Collection<?> list) {
191 return list == null ? 0 : list.size();
194 private static int nullSize(final Map<?, ?> map) {
195 return map == null ? 0 : map.size();