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.Preconditions.checkArgument;
11 import static com.google.common.base.Verify.verify;
13 import com.google.common.annotations.Beta;
14 import com.google.common.collect.ImmutableClassToInstanceMap;
15 import java.io.IOException;
16 import java.lang.reflect.InvocationHandler;
17 import java.lang.reflect.Proxy;
18 import java.util.Collection;
19 import java.util.List;
21 import java.util.Map.Entry;
22 import org.opendaylight.mdsal.binding.dom.codec.util.AugmentationReader;
23 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
24 import org.opendaylight.yangtools.yang.binding.Augmentable;
25 import org.opendaylight.yangtools.yang.binding.Augmentation;
26 import org.opendaylight.yangtools.yang.binding.BindingSerializer;
27 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
28 import org.opendaylight.yangtools.yang.binding.DataContainer;
29 import org.opendaylight.yangtools.yang.binding.DataObject;
30 import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
31 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
32 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
33 import org.opendaylight.yangtools.yang.binding.Identifiable;
34 import org.opendaylight.yangtools.yang.binding.OpaqueObject;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * Base superclass for all concrete streamers, that is objects which are able to turn a concrete DataObject into a
42 * @param <T> DataObject type
45 public abstract class DataObjectStreamer<T extends DataObject> implements DataObjectSerializerImplementation {
46 private static final Logger LOG = LoggerFactory.getLogger(DataObjectStreamer.class);
48 protected DataObjectStreamer() {
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) {
55 verify(value instanceof OpaqueObject, "Unexpected data %s", value);
56 ((AnydataBindingStreamWriter) writer).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 DataObjectSerializerRegistry registry,
68 final BindingStreamEventWriter writer, final Augmentable<?> obj) throws IOException {
69 final Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations;
70 if (registry instanceof AugmentationReader) {
71 augmentations = ((AugmentationReader) registry).getAugmentations(obj);
72 } else if (Proxy.isProxyClass(obj.getClass())) {
73 augmentations = getFromProxy(obj);
75 augmentations = BindingReflections.getAugmentations(obj);
77 for (final Entry<Class<? extends Augmentation<?>>, Augmentation<?>> aug : augmentations.entrySet()) {
78 emitAugmentation(aug.getKey(), aug.getValue(), writer, registry);
82 private static Map<Class<? extends Augmentation<?>>, Augmentation<?>> getFromProxy(final Augmentable<?> obj) {
83 final InvocationHandler proxy = Proxy.getInvocationHandler(obj);
84 if (proxy instanceof AugmentationReader) {
85 return ((AugmentationReader) proxy).getAugmentations(obj);
87 return ImmutableClassToInstanceMap.of();
90 protected static final <C extends DataContainer> void streamChoice(final Class<C> choiceClass,
91 final DataObjectSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
94 final Class<? extends DataContainer> caseClass = value.implementedInterface();
95 writer.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
96 final DataObjectSerializer caseStreamer = registry.getSerializer(caseClass.asSubclass(DataObject.class));
97 if (caseStreamer != null) {
98 if (tryCache(writer, (DataObject) value)) {
99 caseStreamer.serialize((DataObject) value, writer);
102 LOG.warn("No serializer for case {} is available in registry {}", caseClass, registry);
109 protected static final <C extends DataObject> void streamContainer(final DataObjectStreamer<C> childStreamer,
110 final DataObjectSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
112 if (value != null && tryCache(writer, value)) {
113 childStreamer.serialize(registry, value, writer);
117 protected static final void streamLeaf(final BindingStreamEventWriter writer, final String localName,
118 final Object value) throws IOException {
120 writer.leafNode(localName, value);
124 protected static final void streamLeafList(final BindingStreamEventWriter writer, final String localName,
125 final List<?> value) throws IOException {
127 writer.startLeafSet(localName, value.size());
128 commonStreamLeafset(writer, value);
132 protected static final void streamOrderedLeafList(final BindingStreamEventWriter writer,
133 final String localName, final List<?> value) throws IOException {
135 writer.startOrderedLeafSet(localName, value.size());
136 commonStreamLeafset(writer, value);
140 protected static final <E extends DataObject> void streamList(final Class<E> childClass,
141 final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
142 final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
143 final int size = nullSize(value);
145 writer.startUnkeyedList(childClass, size);
146 commonStreamList(registry, writer, childStreamer, value);
150 protected static final <E extends DataObject & Identifiable<?>> void streamMap(final Class<E> childClass,
151 final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
152 final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
153 final int size = nullSize(value);
155 writer.startMapNode(childClass, size);
156 commonStreamList(registry, writer, childStreamer, value);
160 protected static final <E extends DataObject & Identifiable<?>> void streamOrderedMap(final Class<E> childClass,
161 final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
162 final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
163 final int size = nullSize(value);
165 writer.startOrderedMapNode(childClass, size);
166 commonStreamList(registry, writer, childStreamer, value);
170 private static <E extends DataObject> void commonStreamList(final DataObjectSerializerRegistry registry,
171 final BindingStreamEventWriter writer, final DataObjectStreamer<E> childStreamer,
172 final Collection<? extends E> value) throws IOException {
174 for (E entry : value) {
175 if (tryCache(writer, entry)) {
176 childStreamer.serialize(registry, entry, writer);
182 private static void commonStreamLeafset(final BindingStreamEventWriter writer, final List<?> value)
184 for (Object entry : value) {
185 writer.leafSetEntryNode(entry);
190 @SuppressWarnings("rawtypes")
191 private static void emitAugmentation(final Class type, final Augmentation<?> value,
192 final BindingStreamEventWriter writer, final DataObjectSerializerRegistry registry) throws IOException {
194 * Binding Specification allowed to insert augmentation with null for
195 * value, which effectively could be used to remove augmentation
196 * from builder / DTO.
199 checkArgument(value instanceof DataObject);
200 @SuppressWarnings("unchecked")
201 final DataObjectSerializer serializer = registry.getSerializer(type);
202 if (serializer != null) {
203 serializer.serialize((DataObject) value, writer);
205 LOG.warn("DataObjectSerializer is not present for {} in registry {}", type, registry);
210 @SuppressWarnings("unchecked")
211 private static <T extends DataObject> boolean tryCache(final BindingStreamEventWriter writer, final T value) {
212 return writer instanceof BindingSerializer ? ((BindingSerializer<?, T>) writer).serialize(value) == null : true;
215 private static int nullSize(final List<?> list) {
216 return list == null ? 0 : list.size();