2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
8 package org.opendaylight.controller.sal.binding.generator.impl;
\r
10 import java.net.URI;
\r
11 import java.util.ArrayList;
\r
12 import java.util.Calendar;
\r
13 import java.util.GregorianCalendar;
\r
14 import java.util.HashMap;
\r
15 import java.util.List;
\r
16 import java.util.Map;
\r
17 import java.util.Set;
\r
19 import org.opendaylight.controller.binding.generator.util.CodeGeneratorHelper;
\r
20 import org.opendaylight.controller.binding.generator.util.Types;
\r
21 import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator;
\r
22 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
\r
23 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
\r
24 import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
\r
25 import org.opendaylight.controller.sal.binding.model.api.Type;
\r
26 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
\r
27 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
\r
28 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
\r
29 import org.opendaylight.controller.sal.binding.model.api.type.builder.MethodSignatureBuilder;
\r
30 import org.opendaylight.controller.sal.binding.yang.types.TypeProviderImpl;
\r
31 import org.opendaylight.controller.yang.common.QName;
\r
32 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
\r
33 import org.opendaylight.controller.yang.model.api.DataNodeContainer;
\r
34 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
\r
35 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
\r
36 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
\r
37 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
\r
38 import org.opendaylight.controller.yang.model.api.Module;
\r
39 import org.opendaylight.controller.yang.model.api.SchemaContext;
\r
40 import org.opendaylight.controller.yang.model.api.SchemaPath;
\r
41 import org.opendaylight.controller.yang.model.api.TypeDefinition;
\r
43 public class BindingGeneratorImpl implements BindingGenerator {
\r
45 private static Calendar calendar = new GregorianCalendar();
\r
46 private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
\r
47 private List<ContainerSchemaNode> schemaContainers;
\r
48 private List<ListSchemaNode> schemaLists;
\r
49 private TypeProvider typeProvider;
\r
50 private String basePackageName;
\r
52 public BindingGeneratorImpl() {
\r
57 public List<Type> generateTypes(final SchemaContext context) {
\r
58 final List<Type> genTypes = new ArrayList<Type>();
\r
60 typeProvider = new TypeProviderImpl(context);
\r
61 if (context != null) {
\r
62 final Set<Module> modules = context.getModules();
\r
64 if (modules != null) {
\r
65 for (final Module module : modules) {
\r
66 genTypeBuilders = new HashMap<String, Map<String, GeneratedTypeBuilder>>();
\r
67 schemaContainers = new ArrayList<ContainerSchemaNode>();
\r
68 schemaLists = new ArrayList<ListSchemaNode>();
\r
70 basePackageName = resolveBasePackageName(module.getNamespace(),
\r
71 module.getYangVersion());
\r
73 traverseModule(module);
\r
74 if (schemaContainers.size() > 0) {
\r
75 for (final ContainerSchemaNode container : schemaContainers) {
\r
76 genTypes.add(containerToGenType(container));
\r
80 if (schemaLists.size() > 0) {
\r
81 for (final ListSchemaNode list : schemaLists) {
\r
82 genTypes.addAll(listToGenType(list));
\r
92 private String resolveGeneratedTypePackageName(final SchemaPath schemaPath) {
\r
93 final StringBuilder builder = new StringBuilder();
\r
94 builder.append(basePackageName);
\r
95 if ((schemaPath != null) && (schemaPath.getPath() != null)) {
\r
96 final List<QName> pathToNode = schemaPath.getPath();
\r
97 final int traversalSteps = (pathToNode.size() - 1);
\r
98 for (int i = 0; i < traversalSteps; ++i) {
\r
99 builder.append(".");
\r
100 String nodeLocalName = pathToNode.get(i).getLocalName();
\r
102 // TODO: create method
\r
103 nodeLocalName = nodeLocalName.replace(":", ".");
\r
104 nodeLocalName = nodeLocalName.replace("-", ".");
\r
105 builder.append(nodeLocalName);
\r
107 return builder.toString();
\r
112 private GeneratedType containerToGenType(ContainerSchemaNode container) {
\r
113 if (container == null) {
\r
116 final Set<DataSchemaNode> schemaNodes = container.getChildNodes();
\r
117 final GeneratedTypeBuilder typeBuilder = addRawInterfaceDefinition(container);
\r
119 for (final DataSchemaNode node : schemaNodes) {
\r
120 if (node instanceof LeafSchemaNode) {
\r
121 resolveLeafSchemaNodeAsMethod(typeBuilder,
\r
122 (LeafSchemaNode) node);
\r
123 } else if (node instanceof LeafListSchemaNode) {
\r
124 resolveLeafListSchemaNode(typeBuilder,
\r
125 (LeafListSchemaNode) node);
\r
127 } else if (node instanceof ContainerSchemaNode) {
\r
128 resolveContainerSchemaNode(typeBuilder,
\r
129 (ContainerSchemaNode) node);
\r
130 } else if (node instanceof ListSchemaNode) {
\r
131 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
\r
134 return typeBuilder.toInstance();
\r
137 private boolean resolveLeafSchemaNodeAsMethod(
\r
138 final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
\r
139 if ((leaf != null) && (typeBuilder != null)) {
\r
140 final String leafName = leaf.getQName().getLocalName();
\r
141 String leafDesc = leaf.getDescription();
\r
142 if (leafDesc == null) {
\r
146 if (leafName != null) {
\r
147 final TypeDefinition<?> typeDef = leaf.getType();
\r
148 final Type javaType = typeProvider
\r
149 .javaTypeForSchemaDefinitionType(typeDef);
\r
151 constructGetter(typeBuilder, leafName, leafDesc, javaType);
\r
152 if (!leaf.isConfiguration()) {
\r
153 constructSetter(typeBuilder, leafName, leafDesc, javaType);
\r
161 private boolean resolveLeafSchemaNodeAsProperty(
\r
162 final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
\r
163 boolean isReadOnly) {
\r
164 if ((leaf != null) && (toBuilder != null)) {
\r
165 final String leafName = leaf.getQName().getLocalName();
\r
166 String leafDesc = leaf.getDescription();
\r
167 if (leafDesc == null) {
\r
171 if (leafName != null) {
\r
172 final TypeDefinition<?> typeDef = leaf.getType();
\r
174 //TODO: properly resolve enum types
\r
175 final Type javaType = typeProvider
\r
176 .javaTypeForSchemaDefinitionType(typeDef);
\r
178 final GeneratedPropertyBuilder propBuilder = toBuilder
\r
179 .addProperty(CodeGeneratorHelper
\r
180 .parseToClassName(leafName));
\r
182 propBuilder.setReadOnly(isReadOnly);
\r
183 propBuilder.addReturnType(javaType);
\r
184 propBuilder.addComment(leafDesc);
\r
186 toBuilder.addEqualsIdentity(propBuilder);
\r
187 toBuilder.addHashIdentity(propBuilder);
\r
188 toBuilder.addToStringProperty(propBuilder);
\r
196 private boolean resolveLeafListSchemaNode(
\r
197 final GeneratedTypeBuilder typeBuilder,
\r
198 final LeafListSchemaNode node) {
\r
199 if ((node != null) && (typeBuilder != null)) {
\r
200 final String nodeName = node.getQName().getLocalName();
\r
201 String nodeDesc = node.getDescription();
\r
202 if (nodeDesc == null) {
\r
206 if (nodeName != null) {
\r
207 final TypeDefinition<?> type = node.getType();
\r
208 final Type listType = Types.listTypeFor(typeProvider
\r
209 .javaTypeForSchemaDefinitionType(type));
\r
211 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
\r
212 if (!node.isConfiguration()) {
\r
213 constructSetter(typeBuilder, nodeName, nodeDesc, listType);
\r
221 private boolean resolveContainerSchemaNode(
\r
222 final GeneratedTypeBuilder typeBuilder,
\r
223 final ContainerSchemaNode node) {
\r
224 if ((node != null) && (typeBuilder != null)) {
\r
225 final String nodeName = node.getQName().getLocalName();
\r
227 if (nodeName != null) {
\r
228 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
\r
229 constructGetter(typeBuilder, nodeName, "", rawGenType);
\r
237 private boolean resolveListSchemaNode(
\r
238 final GeneratedTypeBuilder typeBuilder, final ListSchemaNode node) {
\r
239 if ((node != null) && (typeBuilder != null)) {
\r
240 final String nodeName = node.getQName().getLocalName();
\r
242 if (nodeName != null) {
\r
243 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
\r
244 constructGetter(typeBuilder, nodeName, "",
\r
245 Types.listTypeFor(rawGenType));
\r
246 if (!node.isConfiguration()) {
\r
247 constructSetter(typeBuilder, nodeName, "",
\r
248 Types.listTypeFor(rawGenType));
\r
256 private GeneratedTypeBuilder addRawInterfaceDefinition(
\r
257 final DataSchemaNode schemaNode) {
\r
258 if (schemaNode == null) {
\r
262 final String packageName = resolveGeneratedTypePackageName(schemaNode
\r
264 final String schemaNodeName = schemaNode.getQName().getLocalName();
\r
266 if ((packageName != null) && (schemaNode != null)
\r
267 && (schemaNodeName != null)) {
\r
268 final String genTypeName = CodeGeneratorHelper
\r
269 .parseToClassName(schemaNodeName);
\r
270 final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(
\r
271 packageName, genTypeName);
\r
273 if (!genTypeBuilders.containsKey(packageName)) {
\r
274 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
\r
275 builders.put(genTypeName, newType);
\r
276 genTypeBuilders.put(packageName, builders);
\r
278 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders
\r
280 if (!builders.containsKey(genTypeName)) {
\r
281 builders.put(genTypeName, newType);
\r
289 private String getterMethodName(final String methodName) {
\r
290 final StringBuilder method = new StringBuilder();
\r
291 method.append("get");
\r
292 method.append(CodeGeneratorHelper.parseToClassName(methodName));
\r
293 return method.toString();
\r
296 private String setterMethodName(final String methodName) {
\r
297 final StringBuilder method = new StringBuilder();
\r
298 method.append("set");
\r
299 method.append(CodeGeneratorHelper.parseToClassName(methodName));
\r
300 return method.toString();
\r
303 private MethodSignatureBuilder constructGetter(
\r
304 final GeneratedTypeBuilder interfaceBuilder,
\r
305 final String schemaNodeName, final String comment,
\r
306 final Type returnType) {
\r
307 final MethodSignatureBuilder getMethod = interfaceBuilder
\r
308 .addMethod(getterMethodName(schemaNodeName));
\r
310 getMethod.addComment(comment);
\r
311 getMethod.addReturnType(returnType);
\r
316 private MethodSignatureBuilder constructSetter(
\r
317 final GeneratedTypeBuilder interfaceBuilder,
\r
318 final String schemaNodeName, final String comment,
\r
319 final Type parameterType) {
\r
320 final MethodSignatureBuilder setMethod = interfaceBuilder
\r
321 .addMethod(setterMethodName(schemaNodeName));
\r
323 setMethod.addComment(comment);
\r
324 setMethod.addParameter(parameterType,
\r
325 CodeGeneratorHelper.parseToParamName(schemaNodeName));
\r
326 setMethod.addReturnType(Types.voidType());
\r
331 private String resolveBasePackageName(final URI moduleNamespace,
\r
332 final String yangVersion) {
\r
333 final StringBuilder packageNameBuilder = new StringBuilder();
\r
335 packageNameBuilder.append("org.opendaylight.yang.gen.v");
\r
336 packageNameBuilder.append(yangVersion);
\r
337 packageNameBuilder.append(".rev");
\r
338 packageNameBuilder.append(calendar.get(Calendar.YEAR));
\r
339 packageNameBuilder.append((calendar.get(Calendar.MONTH) + 1));
\r
340 packageNameBuilder.append(calendar.get(Calendar.DAY_OF_MONTH));
\r
341 packageNameBuilder.append(".");
\r
343 String namespace = moduleNamespace.toString();
\r
344 namespace = namespace.replace(":", ".");
\r
345 namespace = namespace.replace("-", ".");
\r
347 packageNameBuilder.append(namespace);
\r
349 return packageNameBuilder.toString();
\r
352 private List<Type> listToGenType(final ListSchemaNode list) {
\r
353 if (list == null) {
\r
356 final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(list);
\r
357 final List<String> listKeys = listKeys(list);
\r
358 GeneratedTOBuilder genTOBuilder = null;
\r
359 if (listKeys.size() > 0) {
\r
360 genTOBuilder = resolveListKey(list);
\r
363 final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
\r
364 for (final DataSchemaNode node : schemaNodes) {
\r
366 if (node instanceof LeafSchemaNode) {
\r
367 final LeafSchemaNode leaf = (LeafSchemaNode) node;
\r
368 if (!isPartOfListKey(leaf, listKeys)) {
\r
369 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
\r
371 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
\r
373 } else if (node instanceof LeafListSchemaNode) {
\r
374 resolveLeafListSchemaNode(typeBuilder,
\r
375 (LeafListSchemaNode) node);
\r
376 } else if (node instanceof ContainerSchemaNode) {
\r
377 resolveContainerSchemaNode(typeBuilder,
\r
378 (ContainerSchemaNode) node);
\r
379 } else if (node instanceof ListSchemaNode) {
\r
380 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
\r
384 final List<Type> genTypes = new ArrayList<Type>();
\r
385 if (genTOBuilder != null) {
\r
386 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
\r
387 constructGetter(typeBuilder, genTO.getName(), "Returns Primary Key of Yang List Type", genTO);
\r
388 genTypes.add(genTO);
\r
390 genTypes.add(typeBuilder.toInstance());
\r
398 private GeneratedTOBuilder resolveListKey(final ListSchemaNode list) {
\r
399 final String packageName = resolveGeneratedTypePackageName(list
\r
401 final String listName = list.getQName().getLocalName() + "Key";
\r
403 if ((packageName != null) && (list != null) && (listName != null)) {
\r
404 final String genTOName = CodeGeneratorHelper
\r
405 .parseToClassName(listName);
\r
406 final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
\r
407 packageName, genTOName);
\r
414 private boolean isPartOfListKey(final LeafSchemaNode leaf,
\r
415 final List<String> keys) {
\r
416 if ((leaf != null) && (keys != null) && (leaf.getQName() != null)) {
\r
417 final String leafName = leaf.getQName().getLocalName();
\r
418 if (keys.contains(leafName)) {
\r
425 private List<String> listKeys(final ListSchemaNode list) {
\r
426 final List<String> listKeys = new ArrayList<String>();
\r
428 if (list.getKeyDefinition() != null) {
\r
429 final List<QName> keyDefinitions = list.getKeyDefinition();
\r
431 for (final QName keyDefinition : keyDefinitions) {
\r
432 listKeys.add(keyDefinition.getLocalName());
\r
438 private GeneratedTypeBuilder resolveListTypeBuilder(
\r
439 final ListSchemaNode list) {
\r
440 final String packageName = resolveGeneratedTypePackageName(list
\r
442 final String schemaNodeName = list.getQName().getLocalName();
\r
443 final String genTypeName = CodeGeneratorHelper
\r
444 .parseToClassName(schemaNodeName);
\r
446 GeneratedTypeBuilder typeBuilder = null;
\r
447 if (genTypeBuilders.containsKey(packageName)) {
\r
448 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
\r
449 typeBuilder = builders.get(genTypeName);
\r
451 if (null == typeBuilder) {
\r
452 typeBuilder = addRawInterfaceDefinition(list);
\r
455 return typeBuilder;
\r
458 private void traverseModule(final Module module) {
\r
459 final Set<DataSchemaNode> schemaNodes = module.getChildNodes();
\r
461 for (DataSchemaNode node : schemaNodes) {
\r
462 if (node instanceof ContainerSchemaNode) {
\r
463 schemaContainers.add((ContainerSchemaNode) node);
\r
464 traverse((ContainerSchemaNode) node);
\r
469 private void traverse(final DataNodeContainer dataNode) {
\r
470 if (!containChildDataNodeContainer(dataNode)) {
\r
474 final Set<DataSchemaNode> childs = dataNode.getChildNodes();
\r
475 if (childs != null) {
\r
476 for (DataSchemaNode childNode : childs) {
\r
477 if (childNode instanceof ContainerSchemaNode) {
\r
478 final ContainerSchemaNode container = (ContainerSchemaNode) childNode;
\r
479 schemaContainers.add(container);
\r
480 traverse(container);
\r
483 if (childNode instanceof ListSchemaNode) {
\r
484 final ListSchemaNode list = (ListSchemaNode) childNode;
\r
485 schemaLists.add(list);
\r
493 * Returns <code>true</code> if and only if the child node contain at least
\r
494 * one child container schema node or child list schema node, otherwise will
\r
495 * always returns <code>false</code>
\r
498 * @return <code>true</code> if and only if the child node contain at least
\r
499 * one child container schema node or child list schema node,
\r
500 * otherwise will always returns <code>false</code>
\r
502 private boolean containChildDataNodeContainer(
\r
503 final DataNodeContainer container) {
\r
504 if (container != null) {
\r
505 final Set<DataSchemaNode> childs = container.getChildNodes();
\r
506 if ((childs != null) && (childs.size() > 0)) {
\r
507 for (final DataSchemaNode childNode : childs) {
\r
508 if (childNode instanceof DataNodeContainer) {
\r