2 * Copyright (c) 2014, 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
9 package org.opendaylight.mdsal.binding.dom.codec.gen.impl;
11 import static java.util.Objects.requireNonNull;
13 import java.util.HashMap;
15 import org.opendaylight.mdsal.binding.dom.codec.util.BindingSchemaMapping;
16 import org.opendaylight.mdsal.binding.dom.codec.util.ChoiceDispatchSerializer;
17 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
18 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
19 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
20 import org.opendaylight.mdsal.binding.model.api.Type;
21 import org.opendaylight.yangtools.yang.binding.BindingSerializer;
22 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
25 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
26 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
30 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSource {
39 private static final Logger LOG = LoggerFactory.getLogger(DataNodeContainerSerializerSource.class);
41 protected static final String INPUT = "_input";
42 private static final String CHOICE_PREFIX = "CHOICE_";
44 protected final DataNodeContainer schemaNode;
45 private final GeneratedType dtoType;
47 DataNodeContainerSerializerSource(final AbstractGenerator generator, final GeneratedType type,
48 final DataNodeContainer node) {
50 this.dtoType = requireNonNull(type);
51 this.schemaNode = requireNonNull(node);
55 * Return the character sequence which should be used for start event.
57 * @return Start event character sequence
59 protected abstract CharSequence emitStartEvent();
62 protected CharSequence getSerializerBody() {
63 final StringBuilder sb = new StringBuilder()
65 .append(statement(assign(DataObjectSerializerRegistry.class, REGISTRY, "$1")))
66 .append(statement(assign(dtoType, INPUT, cast(dtoType, "$2"))))
67 .append(statement(assign(BindingStreamEventWriter.class, STREAM,
68 cast(BindingStreamEventWriter.class, "$3"))))
69 .append(statement(assign(BindingSerializer.class, SERIALIZER, null)))
72 .append(" instanceof ")
73 .append(BindingSerializer.class.getName())
75 .append(statement(assign(SERIALIZER, cast(BindingSerializer.class, STREAM))))
77 .append(statement(emitStartEvent()));
82 return sb.append(statement(endNode()))
83 .append(statement("return null"))
88 * Allows for customization of emitting code, which is processed after
89 * normal DataNodeContainer body. Ideal for augmentations or others.
91 protected void emitAfterBody(final StringBuilder sb) {
95 private static Map<String, Type> collectAllProperties(final GeneratedType type, final Map<String, Type> hashMap) {
96 for (final MethodSignature definition : type.getMethodDefinitions()) {
97 hashMap.put(definition.getName(), definition.getReturnType());
99 for (final Type parent : type.getImplements()) {
100 if (parent instanceof GeneratedType) {
101 collectAllProperties((GeneratedType) parent, hashMap);
107 private void emitBody(final StringBuilder sb) {
108 final Map<String, Type> getterToType = collectAllProperties(dtoType, new HashMap<String, Type>());
109 for (final DataSchemaNode schemaChild : schemaNode.getChildNodes()) {
110 if (!schemaChild.isAugmenting()) {
111 final String getter = BindingSchemaMapping.getGetterMethodName(schemaChild);
112 final Type childType = getterToType.get(getter);
113 if (childType == null) {
114 // FIXME AnyXml nodes are ignored, since their type cannot be found in generated bindnig
115 // Bug-706 https://bugs.opendaylight.org/show_bug.cgi?id=706
116 if (schemaChild instanceof AnyXmlSchemaNode) {
117 LOG.warn("Node {} will be ignored. AnyXml is not yet supported from binding aware code."
118 + "Binding Independent code can be used to serialize anyXml nodes.",
119 schemaChild.getPath());
123 throw new IllegalStateException(
124 String.format("Unable to find type for child node %s. Expected child nodes: %s",
125 schemaChild.getPath(), getterToType));
127 emitChild(sb, getter, childType, schemaChild);
132 private void emitChild(final StringBuilder sb, final String getterName, final Type childType,
133 final DataSchemaNode schemaChild) {
134 sb.append(statement(assign(childType, getterName, cast(childType, invoke(INPUT, getterName)))));
136 sb.append("if (").append(getterName).append(" != null) {\n");
137 emitChildInner(sb, getterName, childType, schemaChild);
141 private void emitChildInner(final StringBuilder sb, final String getterName, final Type childType,
142 final DataSchemaNode child) {
143 if (child instanceof LeafSchemaNode) {
144 sb.append(statement(leafNode(child.getQName().getLocalName(), getterName)));
145 } else if (child instanceof AnyXmlSchemaNode) {
146 sb.append(statement(anyxmlNode(child.getQName().getLocalName(), getterName)));
147 } else if (child instanceof LeafListSchemaNode) {
148 final CharSequence startEvent;
149 if (((LeafListSchemaNode) child).isUserOrdered()) {
150 startEvent = startOrderedLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"));
152 startEvent = startLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"));
154 sb.append(statement(startEvent));
155 final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
156 sb.append(forEach(getterName, valueType, statement(leafSetEntryNode(CURRENT))));
157 sb.append(statement(endNode()));
158 } else if (child instanceof ListSchemaNode) {
159 final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
160 final ListSchemaNode casted = (ListSchemaNode) child;
161 emitList(sb, getterName, valueType, casted);
162 } else if (child instanceof ContainerSchemaNode) {
163 sb.append(tryToUseCacheElse(getterName, statement(staticInvokeEmitter(childType, getterName))));
164 } else if (child instanceof ChoiceSchemaNode) {
165 final String propertyName = CHOICE_PREFIX + childType.getName();
166 staticConstant(propertyName, DataObjectSerializerImplementation.class,
167 ChoiceDispatchSerializer.from(loadClass(childType)));
168 sb.append(tryToUseCacheElse(getterName, statement(invoke(propertyName,
169 StreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, cast(DataObject.class, getterName), STREAM))));
173 private static StringBuilder tryToUseCacheElse(final String getterName, final CharSequence statement) {
174 return new StringBuilder()
175 .append("if (").append(SERIALIZER).append(" == null || ")
176 .append(invoke(SERIALIZER, "serialize", getterName)).append(" == null) {\n")
181 private void emitList(final StringBuilder sb, final String getterName, final Type valueType,
182 final ListSchemaNode child) {
183 final CharSequence startEvent;
185 sb.append(statement(assign("int", "_count", invoke(getterName, "size"))));
186 if (child.getKeyDefinition().isEmpty()) {
187 startEvent = startUnkeyedList(classReference(valueType), "_count");
188 } else if (child.isUserOrdered()) {
189 startEvent = startOrderedMapNode(classReference(valueType), "_count");
191 startEvent = startMapNode(classReference(valueType), "_count");
193 sb.append(statement(startEvent));
194 sb.append(forEach(getterName, valueType, tryToUseCacheElse(CURRENT, statement(staticInvokeEmitter(valueType,
196 sb.append(statement(endNode()));