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 com.google.common.base.Preconditions;
12 import java.util.HashMap;
14 import org.opendaylight.mdsal.binding.dom.codec.util.ChoiceDispatchSerializer;
15 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
16 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
17 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
18 import org.opendaylight.mdsal.binding.model.api.Type;
19 import org.opendaylight.yangtools.yang.binding.BindingMapping;
20 import org.opendaylight.yangtools.yang.binding.BindingSerializer;
21 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
24 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
25 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
29 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
34 import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSource {
42 private static final Logger LOG = LoggerFactory.getLogger(DataNodeContainerSerializerSource.class);
44 protected static final String INPUT = "_input";
45 private static final String CHOICE_PREFIX = "CHOICE_";
47 protected final DataNodeContainer schemaNode;
48 private final GeneratedType dtoType;
50 DataNodeContainerSerializerSource(final AbstractGenerator generator, final GeneratedType type,
51 final DataNodeContainer node) {
53 this.dtoType = Preconditions.checkNotNull(type);
54 this.schemaNode = Preconditions.checkNotNull(node);
58 * Return the character sequence which should be used for start event.
60 * @return Start event character sequence
62 protected abstract CharSequence emitStartEvent();
65 protected CharSequence getSerializerBody() {
66 final StringBuilder sb = new StringBuilder();
68 sb.append(statement(assign(DataObjectSerializerRegistry.class.getName(), REGISTRY, "$1")));
69 sb.append(statement(assign(dtoType.getFullyQualifiedName(), INPUT,
70 cast(dtoType.getFullyQualifiedName(), "$2"))));
71 sb.append(statement(assign(BindingStreamEventWriter.class.getName(), STREAM,
72 cast(BindingStreamEventWriter.class.getName(), "$3"))));
73 sb.append(statement(assign(BindingSerializer.class.getName(), SERIALIZER, null)));
76 sb.append(" instanceof ");
77 sb.append(BindingSerializer.class.getName());
79 sb.append(statement(assign(SERIALIZER, cast(BindingSerializer.class.getName(), STREAM))));
81 sb.append(statement(emitStartEvent()));
85 sb.append(statement(endNode()));
86 sb.append(statement("return null"));
92 * Allows for customization of emitting code, which is processed after
93 * normal DataNodeContainer body. Ideal for augmentations or others.
95 protected void emitAfterBody(final StringBuilder sb) {
99 private static Map<String, Type> collectAllProperties(final GeneratedType type, final Map<String, Type> hashMap) {
100 for (final MethodSignature definition : type.getMethodDefinitions()) {
101 hashMap.put(definition.getName(), definition.getReturnType());
103 for (final Type parent : type.getImplements()) {
104 if (parent instanceof GeneratedType) {
105 collectAllProperties((GeneratedType) parent, hashMap);
111 private static String getGetterName(final DataSchemaNode node) {
112 final TypeDefinition<?> type;
113 if (node instanceof TypedSchemaNode) {
114 type = ((TypedSchemaNode) node).getType();
120 if (type instanceof BooleanTypeDefinition || type instanceof EmptyTypeDefinition) {
125 return prefix + BindingMapping.getGetterSuffix(node.getQName());
128 private void emitBody(final StringBuilder sb) {
129 final Map<String, Type> getterToType = collectAllProperties(dtoType, new HashMap<String, Type>());
130 for (final DataSchemaNode schemaChild : schemaNode.getChildNodes()) {
131 if (!schemaChild.isAugmenting()) {
132 final String getter = getGetterName(schemaChild);
133 final Type childType = getterToType.get(getter);
134 if (childType == null) {
135 // FIXME AnyXml nodes are ignored, since their type cannot be found in generated bindnig
136 // Bug-706 https://bugs.opendaylight.org/show_bug.cgi?id=706
137 if (schemaChild instanceof AnyXmlSchemaNode) {
138 LOG.warn("Node {} will be ignored. AnyXml is not yet supported from binding aware code."
139 + "Binding Independent code can be used to serialize anyXml nodes.",
140 schemaChild.getPath());
144 throw new IllegalStateException(
145 String.format("Unable to find type for child node %s. Expected child nodes: %s",
146 schemaChild.getPath(), getterToType));
148 emitChild(sb, getter, childType, schemaChild);
153 private void emitChild(final StringBuilder sb, final String getterName, final Type childType,
154 final DataSchemaNode schemaChild) {
155 sb.append(statement(assign(childType, getterName, cast(childType, invoke(INPUT, getterName)))));
157 sb.append("if (").append(getterName).append(" != null) {\n");
158 emitChildInner(sb, getterName, childType, schemaChild);
162 private void emitChildInner(final StringBuilder sb, final String getterName, final Type childType,
163 final DataSchemaNode child) {
164 if (child instanceof LeafSchemaNode) {
165 sb.append(statement(leafNode(child.getQName().getLocalName(), getterName)));
166 } else if (child instanceof AnyXmlSchemaNode) {
167 sb.append(statement(anyxmlNode(child.getQName().getLocalName(), getterName)));
168 } else if (child instanceof LeafListSchemaNode) {
169 final CharSequence startEvent;
170 if (((LeafListSchemaNode) child).isUserOrdered()) {
171 startEvent = startOrderedLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"));
173 startEvent = startLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"));
175 sb.append(statement(startEvent));
176 final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
177 sb.append(forEach(getterName, valueType, statement(leafSetEntryNode(CURRENT))));
178 sb.append(statement(endNode()));
179 } else if (child instanceof ListSchemaNode) {
180 final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
181 final ListSchemaNode casted = (ListSchemaNode) child;
182 emitList(sb, getterName, valueType, casted);
183 } else if (child instanceof ContainerSchemaNode) {
184 sb.append(tryToUseCacheElse(getterName,statement(staticInvokeEmitter(childType, getterName))));
185 } else if (child instanceof ChoiceSchemaNode) {
186 final String propertyName = CHOICE_PREFIX + childType.getName();
187 staticConstant(propertyName, DataObjectSerializerImplementation.class,
188 ChoiceDispatchSerializer.from(loadClass(childType)));
189 sb.append(tryToUseCacheElse(getterName,statement(invoke(propertyName,
190 StreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, cast(DataObject.class.getName(), getterName),
195 private static StringBuilder tryToUseCacheElse(final String getterName, final CharSequence statement) {
196 final StringBuilder b = new StringBuilder();
198 b.append(SERIALIZER).append("== null || ");
199 b.append(invoke(SERIALIZER, "serialize", getterName)).append("== null");
206 private void emitList(final StringBuilder sb, final String getterName, final Type valueType,
207 final ListSchemaNode child) {
208 final CharSequence startEvent;
210 sb.append(statement(assign("int", "_count", invoke(getterName, "size"))));
211 if (child.getKeyDefinition().isEmpty()) {
212 startEvent = startUnkeyedList(classReference(valueType), "_count");
213 } else if (child.isUserOrdered()) {
214 startEvent = startOrderedMapNode(classReference(valueType), "_count");
216 startEvent = startMapNode(classReference(valueType), "_count");
218 sb.append(statement(startEvent));
219 sb.append(forEach(getterName, valueType, tryToUseCacheElse(CURRENT, statement(staticInvokeEmitter(valueType,
221 sb.append(statement(endNode()));