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;
18 import org.opendaylight.mdsal.binding.dom.codec.api.BindingStreamEventWriter;
19 import org.opendaylight.yangtools.yang.binding.Augmentable;
20 import org.opendaylight.yangtools.yang.binding.Augmentation;
21 import org.opendaylight.yangtools.yang.binding.DataContainer;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.KeyAware;
24 import org.opendaylight.yangtools.yang.binding.OpaqueObject;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * Base superclass for all concrete streamers, that is objects which are able to turn a concrete DataObject into a
32 * @param <T> DataContainer type
35 public abstract class DataContainerStreamer<T extends DataContainer> {
36 private static final Logger LOG = LoggerFactory.getLogger(DataContainerStreamer.class);
38 protected DataContainerStreamer() {
43 * Writes stream events for supplied data object to provided stream.
46 * DataObjectSerializerRegistry may be used to lookup serializers for other generated classes in order to support
47 * writing their events.
49 protected abstract void serialize(DataContainerSerializerRegistry reg, DataContainer obj,
50 BindingStreamEventWriter stream) throws IOException;
52 protected static final void streamAnydata(final BindingStreamEventWriter writer, final String localName,
53 final Object value) throws IOException {
54 if (value != null && writer instanceof AnydataBindingStreamWriter anydataWriter) {
55 verify(value instanceof OpaqueObject, "Unexpected data %s", value);
56 anydataWriter.anydataNode(localName, (OpaqueObject<?>) value);
60 protected static final void streamAnyxml(final BindingStreamEventWriter writer, final String localName,
61 final Object value) throws IOException {
63 writer.anyxmlNode(localName, value);
67 protected static final void streamAugmentations(final DataContainerSerializerRegistry registry,
68 final BindingStreamEventWriter writer, final Augmentable<?> obj) throws IOException {
69 for (final var aug : obj.augmentations().entrySet()) {
70 emitAugmentation(aug.getKey(), aug.getValue(), writer, registry);
74 protected static final <C extends DataContainer> void streamChoice(final Class<C> choiceClass,
75 final DataContainerSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
78 final Class<? extends DataContainer> caseClass = value.implementedInterface();
79 writer.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
80 final DataContainerSerializer caseStreamer = registry.getSerializer(caseClass.asSubclass(DataObject.class));
81 if (caseStreamer != null) {
82 if (tryCache(writer, (DataObject) value)) {
83 caseStreamer.serialize((DataObject) value, writer);
86 LOG.warn("No serializer for case {} is available in registry {}", caseClass, registry);
93 protected static final <C extends DataObject> void streamContainer(final DataContainerStreamer<C> childStreamer,
94 final DataContainerSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
96 if (value != null && tryCache(writer, value)) {
97 childStreamer.serialize(registry, value, writer);
101 protected static final void streamLeaf(final BindingStreamEventWriter writer, final String localName,
102 final Object value) throws IOException {
104 writer.leafNode(localName, value);
108 protected static final void streamLeafList(final BindingStreamEventWriter writer, final String localName,
109 final Set<?> value) throws IOException {
111 writer.startLeafSet(localName, value.size());
112 commonStreamLeafset(writer, value);
116 protected static final void streamOrderedLeafList(final BindingStreamEventWriter writer,
117 final String localName, final List<?> value) throws IOException {
119 writer.startOrderedLeafSet(localName, value.size());
120 commonStreamLeafset(writer, value);
124 protected static final <E extends DataObject> void streamList(final Class<E> childClass,
125 final DataContainerStreamer<E> childStreamer, final DataContainerSerializerRegistry registry,
126 final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
127 final int size = nullSize(value);
129 writer.startUnkeyedList(childClass, size);
130 commonStreamList(registry, writer, childStreamer, value);
134 protected static final <E extends DataObject & KeyAware<?>> void streamMap(final Class<E> childClass,
135 final DataContainerStreamer<E> childStreamer, final DataContainerSerializerRegistry registry,
136 final BindingStreamEventWriter writer, final Map<?, ? extends E> value) throws IOException {
137 final int size = nullSize(value);
139 writer.startMapNode(childClass, size);
140 commonStreamList(registry, writer, childStreamer, value.values());
144 protected static final <E extends DataObject & KeyAware<?>> void streamOrderedMap(final Class<E> childClass,
145 final DataContainerStreamer<E> childStreamer, final DataContainerSerializerRegistry registry,
146 final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
147 final int size = nullSize(value);
149 writer.startOrderedMapNode(childClass, size);
150 commonStreamList(registry, writer, childStreamer, value);
154 private static <E extends DataObject> void commonStreamList(final DataContainerSerializerRegistry registry,
155 final BindingStreamEventWriter writer, final DataContainerStreamer<E> childStreamer,
156 final Collection<? extends E> value) throws IOException {
158 for (E entry : value) {
159 if (tryCache(writer, entry)) {
160 childStreamer.serialize(registry, entry, writer);
166 private static void commonStreamLeafset(final BindingStreamEventWriter writer, final Collection<?> value)
168 for (Object entry : value) {
169 writer.leafSetEntryNode(entry);
174 private static void emitAugmentation(final Class<? extends Augmentation<?>> type, final Augmentation<?> value,
175 final BindingStreamEventWriter writer, final DataContainerSerializerRegistry registry) throws IOException {
177 * Binding Specification allowed to insert augmentation with null for value, which effectively could be used to
178 * remove augmentation from builder / DTO.
181 final DataContainerSerializer serializer = registry.getSerializer(type);
182 if (serializer != null) {
183 serializer.serialize(value, writer);
185 LOG.warn("DataObjectSerializer is not present for {} in registry {}", type, registry);
190 @SuppressWarnings("unchecked")
191 private static <T extends DataObject> boolean tryCache(final BindingStreamEventWriter writer, final T value) {
192 // Force serialization if writer is not a BindingSerializer, otherwise defer to it for a decision
193 return !(writer instanceof BindingSerializer) || ((BindingSerializer<?, T>) writer).serialize(value) == null;
196 private static int nullSize(final Collection<?> list) {
197 return list == null ? 0 : list.size();
200 private static int nullSize(final Map<?, ?> map) {
201 return map == null ? 0 : map.size();