2 * Copyright (c) 2013 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
8 package org.opendaylight.controller.sal.binding.generator.impl;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Calendar;
14 import java.util.GregorianCalendar;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
21 import org.opendaylight.controller.binding.generator.util.CodeGeneratorHelper;
22 import org.opendaylight.controller.binding.generator.util.Types;
23 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
24 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
25 import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator;
26 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
27 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
28 import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
29 import org.opendaylight.controller.sal.binding.model.api.Type;
30 import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
31 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
32 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
33 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
34 import org.opendaylight.controller.sal.binding.model.api.type.builder.MethodSignatureBuilder;
35 import org.opendaylight.controller.sal.binding.yang.types.TypeProviderImpl;
36 import org.opendaylight.controller.yang.common.QName;
37 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
38 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
39 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
40 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
41 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
42 import org.opendaylight.controller.yang.model.api.Module;
43 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
44 import org.opendaylight.controller.yang.model.api.RpcDefinition;
45 import org.opendaylight.controller.yang.model.api.SchemaContext;
46 import org.opendaylight.controller.yang.model.api.SchemaPath;
47 import org.opendaylight.controller.yang.model.api.TypeDefinition;
48 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
49 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
50 import org.opendaylight.controller.yang.model.util.DataNodeIterator;
51 import org.opendaylight.controller.yang.model.util.ExtendedType;
53 public class BindingGeneratorImpl implements BindingGenerator {
55 private static final String[] SET_VALUES = new String[] { "abstract",
56 "assert", "boolean", "break", "byte", "case", "catch", "char",
57 "class", "const", "continue", "default", "double", "do", "else",
58 "enum", "extends", "false", "final", "finally", "float", "for",
59 "goto", "if", "implements", "import", "instanceof", "int",
60 "interface", "long", "native", "new", "null", "package", "private",
61 "protected", "public", "return", "short", "static", "strictfp",
62 "super", "switch", "synchronized", "this", "throw", "throws",
63 "transient", "true", "try", "void", "volatile", "while" };
65 public static final Set<String> JAVA_RESERVED_WORDS = new HashSet<String>(
66 Arrays.asList(SET_VALUES));
68 private static Calendar calendar = new GregorianCalendar();
69 private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
70 private TypeProvider typeProvider;
71 private String basePackageName;
73 public BindingGeneratorImpl() {
77 private static String validatePackage(final String packageName) {
78 if (packageName != null) {
79 final String[] packNameParts = packageName.split("\\.");
80 if (packNameParts != null) {
81 final StringBuilder builder = new StringBuilder();
82 for (int i = 0; i < packNameParts.length; ++i) {
83 if (JAVA_RESERVED_WORDS.contains(packNameParts[i])) {
84 packNameParts[i] = "_" + packNameParts[i];
89 builder.append(packNameParts[i]);
91 return builder.toString();
98 public List<Type> generateTypes(final SchemaContext context) {
99 final List<Type> genTypes = new ArrayList<Type>();
101 typeProvider = new TypeProviderImpl(context);
102 if (context != null) {
103 final Set<Module> modules = context.getModules();
105 if (modules != null) {
106 for (final Module module : modules) {
107 DataNodeIterator moduleIterator = new DataNodeIterator(module);
109 genTypeBuilders = new HashMap<String, Map<String, GeneratedTypeBuilder>>();
110 final List<ContainerSchemaNode> schemaContainers = moduleIterator.allContainers();
111 final List<ListSchemaNode> schemaLists = moduleIterator.allLists();
113 basePackageName = resolveBasePackageName(
114 module.getNamespace(), module.getYangVersion());
116 if (schemaContainers.size() > 0) {
117 for (final ContainerSchemaNode container : schemaContainers) {
118 genTypes.add(containerToGenType(container));
121 if (schemaLists.size() > 0) {
122 for (final ListSchemaNode list : schemaLists) {
123 genTypes.addAll(listToGenType(list));
127 final GeneratedType genDataType = moduleToDataType(module);
128 final GeneratedType genRpcType = rpcMethodsToGenType(module);
129 final GeneratedType genNotifyType = notifycationsToGenType(module);
131 if (genDataType != null) {
132 genTypes.add(genDataType);
134 if (genRpcType != null) {
135 genTypes.add(genRpcType);
137 if (genNotifyType != null) {
138 genTypes.add(genNotifyType);
146 private GeneratedType moduleToDataType(final Module module) {
147 if (module != null) {
148 final Set<TypeDefinition<?>> typeDefinitions = module
149 .getTypeDefinitions();
150 final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(
153 if (moduleDataTypeBuilder != null) {
154 if (typeDefinitions != null) {
155 for (final TypeDefinition<?> typedef : typeDefinitions) {
156 if (isDerivedFromEnumerationType(typedef)) {
157 final EnumTypeDefinition enumBaseType = enumTypeDefFromExtendedType(typedef);
158 resolveEnumFromTypeDefinition(enumBaseType, typedef
159 .getQName().getLocalName(),
160 moduleDataTypeBuilder);
165 final Set<DataSchemaNode> dataNodes = module.getChildNodes();
166 resolveTypesFromDataSchemaNode(moduleDataTypeBuilder, dataNodes);
167 return moduleDataTypeBuilder.toInstance();
173 private boolean isDerivedFromEnumerationType(
174 final TypeDefinition<?> typeDefinition) {
175 if (typeDefinition != null) {
176 if (typeDefinition.getBaseType() instanceof EnumTypeDefinition) {
178 } else if (typeDefinition.getBaseType() instanceof ExtendedType) {
179 return isDerivedFromEnumerationType(typeDefinition
186 private EnumTypeDefinition enumTypeDefFromExtendedType(
187 final TypeDefinition<?> typeDefinition) {
188 if (typeDefinition != null) {
189 if (typeDefinition.getBaseType() instanceof EnumTypeDefinition) {
190 return (EnumTypeDefinition) typeDefinition.getBaseType();
191 } else if (typeDefinition.getBaseType() instanceof ExtendedType) {
192 return enumTypeDefFromExtendedType(typeDefinition.getBaseType());
198 private EnumBuilder resolveEnumFromTypeDefinition(
199 final EnumTypeDefinition enumTypeDef, final String enumName,
200 final GeneratedTypeBuilder typeBuilder) {
201 if ((enumTypeDef != null) && (typeBuilder != null)
202 && (enumTypeDef.getQName() != null)
203 && (enumTypeDef.getQName().getLocalName() != null)) {
205 final String enumerationName = CodeGeneratorHelper
206 .parseToClassName(enumName);
207 final EnumBuilder enumBuilder = typeBuilder
208 .addEnumeration(enumerationName);
210 if (enumBuilder != null) {
211 final List<EnumPair> enums = enumTypeDef.getValues();
214 for (final EnumPair enumPair : enums) {
215 if (enumPair != null) {
216 final String enumPairName = CodeGeneratorHelper
217 .parseToClassName(enumPair.getName());
218 Integer enumPairValue = enumPair.getValue();
220 if (enumPairValue == null) {
221 enumPairValue = listIndex;
223 enumBuilder.addValue(enumPairName, enumPairValue);
234 private GeneratedTypeBuilder moduleTypeBuilder(final Module module,
235 final String postfix) {
236 if (module != null) {
237 String packageName = resolveBasePackageName(module.getNamespace(),
238 module.getYangVersion());
239 final String moduleName = CodeGeneratorHelper
240 .parseToClassName(module.getName()) + postfix;
242 if (packageName != null) {
243 packageName = validatePackage(packageName);
244 return new GeneratedTypeBuilderImpl(packageName, moduleName);
250 private GeneratedType rpcMethodsToGenType(final Module module) {
251 if (module != null) {
252 final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
254 if ((rpcDefinitions != null) && !rpcDefinitions.isEmpty()) {
255 final GeneratedTypeBuilder rpcTypeBuilder = moduleTypeBuilder(
258 for (final RpcDefinition rpc : rpcDefinitions) {
268 private GeneratedType notifycationsToGenType(final Module module) {
269 if (module != null) {
270 final Set<NotificationDefinition> notifications = module
273 if ((notifications != null) && !notifications.isEmpty()) {
274 final GeneratedTypeBuilder notifyTypeBuilder = moduleTypeBuilder(
275 module, "Notification");
277 for (final NotificationDefinition notification : notifications) {
278 if (notification != null) {
287 private String resolveGeneratedTypePackageName(final SchemaPath schemaPath) {
288 final StringBuilder builder = new StringBuilder();
289 builder.append(basePackageName);
290 if ((schemaPath != null) && (schemaPath.getPath() != null)) {
291 final List<QName> pathToNode = schemaPath.getPath();
292 final int traversalSteps = (pathToNode.size() - 1);
293 for (int i = 0; i < traversalSteps; ++i) {
295 String nodeLocalName = pathToNode.get(i).getLocalName();
297 // TODO: create method
298 nodeLocalName = nodeLocalName.replace(":", ".");
299 nodeLocalName = nodeLocalName.replace("-", ".");
300 builder.append(nodeLocalName);
302 return validatePackage(builder.toString());
307 private GeneratedType containerToGenType(ContainerSchemaNode container) {
308 if (container == null) {
311 final Set<DataSchemaNode> schemaNodes = container.getChildNodes();
312 final GeneratedTypeBuilder typeBuilder = addRawInterfaceDefinition(container);
314 resolveTypesFromDataSchemaNode(typeBuilder, schemaNodes);
315 return typeBuilder.toInstance();
318 private GeneratedTypeBuilder resolveTypesFromDataSchemaNode(
319 final GeneratedTypeBuilder typeBuilder,
320 final Set<DataSchemaNode> schemaNodes) {
322 if ((schemaNodes != null) && (typeBuilder != null)) {
323 for (final DataSchemaNode node : schemaNodes) {
324 if (node instanceof LeafSchemaNode) {
325 resolveLeafSchemaNodeAsMethod(typeBuilder,
326 (LeafSchemaNode) node);
327 } else if (node instanceof LeafListSchemaNode) {
328 resolveLeafListSchemaNode(typeBuilder,
329 (LeafListSchemaNode) node);
331 } else if (node instanceof ContainerSchemaNode) {
332 resolveContainerSchemaNode(typeBuilder,
333 (ContainerSchemaNode) node);
334 } else if (node instanceof ListSchemaNode) {
335 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
342 private boolean resolveLeafSchemaNodeAsMethod(
343 final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
344 if ((leaf != null) && (typeBuilder != null)) {
345 final String leafName = leaf.getQName().getLocalName();
346 String leafDesc = leaf.getDescription();
347 if (leafDesc == null) {
351 if (leafName != null) {
352 final TypeDefinition<?> typeDef = leaf.getType();
355 if (!(typeDef instanceof EnumTypeDefinition)
356 && !isDerivedFromEnumerationType(typeDef)) {
358 .javaTypeForSchemaDefinitionType(typeDef);
360 if (isImported(leaf.getPath(), typeDef.getPath())) {
361 //TODO: resolving of imported enums as references to GeneratedTypeData interface
363 final EnumTypeDefinition enumTypeDef = enumTypeDefFromExtendedType(typeDef);
364 final EnumBuilder enumBuilder = resolveEnumFromTypeDefinition(enumTypeDef, leafName,
367 if (enumBuilder != null) {
368 type = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
373 constructGetter(typeBuilder, leafName, leafDesc, type);
374 if (!leaf.isConfiguration()) {
375 constructSetter(typeBuilder, leafName, leafDesc, type);
383 private boolean isImported(final SchemaPath leafPath,
384 final SchemaPath typeDefPath) {
385 if ((leafPath != null) && (leafPath.getPath() != null)
386 && (typeDefPath != null) && (typeDefPath.getPath() != null)) {
388 final QName leafPathQName = leafPath.getPath().get(0);
389 final QName typePathQName = typeDefPath.getPath().get(0);
391 if ((leafPathQName != null)
392 && (leafPathQName.getNamespace() != null)
393 && (typePathQName != null)
394 && (typePathQName.getNamespace() != null)) {
396 return !leafPathQName.getNamespace().equals(
397 typePathQName.getNamespace());
403 private boolean resolveLeafSchemaNodeAsProperty(
404 final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
405 boolean isReadOnly) {
406 if ((leaf != null) && (toBuilder != null)) {
407 final String leafName = leaf.getQName().getLocalName();
408 String leafDesc = leaf.getDescription();
409 if (leafDesc == null) {
413 if (leafName != null) {
414 final TypeDefinition<?> typeDef = leaf.getType();
416 // TODO: properly resolve enum types
417 final Type javaType = typeProvider
418 .javaTypeForSchemaDefinitionType(typeDef);
420 final GeneratedPropertyBuilder propBuilder = toBuilder
421 .addProperty(CodeGeneratorHelper
422 .parseToClassName(leafName));
424 propBuilder.setReadOnly(isReadOnly);
425 propBuilder.addReturnType(javaType);
426 propBuilder.addComment(leafDesc);
428 toBuilder.addEqualsIdentity(propBuilder);
429 toBuilder.addHashIdentity(propBuilder);
430 toBuilder.addToStringProperty(propBuilder);
438 private boolean resolveLeafListSchemaNode(
439 final GeneratedTypeBuilder typeBuilder,
440 final LeafListSchemaNode node) {
441 if ((node != null) && (typeBuilder != null)) {
442 final String nodeName = node.getQName().getLocalName();
443 String nodeDesc = node.getDescription();
444 if (nodeDesc == null) {
448 if (nodeName != null) {
449 final TypeDefinition<?> type = node.getType();
450 final Type listType = Types.listTypeFor(typeProvider
451 .javaTypeForSchemaDefinitionType(type));
453 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
454 if (!node.isConfiguration()) {
455 constructSetter(typeBuilder, nodeName, nodeDesc, listType);
463 private boolean resolveContainerSchemaNode(
464 final GeneratedTypeBuilder typeBuilder,
465 final ContainerSchemaNode node) {
466 if ((node != null) && (typeBuilder != null)) {
467 final String nodeName = node.getQName().getLocalName();
469 if (nodeName != null) {
470 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
471 constructGetter(typeBuilder, nodeName, "", rawGenType);
479 private boolean resolveListSchemaNode(
480 final GeneratedTypeBuilder typeBuilder, final ListSchemaNode node) {
481 if ((node != null) && (typeBuilder != null)) {
482 final String nodeName = node.getQName().getLocalName();
484 if (nodeName != null) {
485 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
486 constructGetter(typeBuilder, nodeName, "",
487 Types.listTypeFor(rawGenType));
488 if (!node.isConfiguration()) {
489 constructSetter(typeBuilder, nodeName, "",
490 Types.listTypeFor(rawGenType));
498 private GeneratedTypeBuilder addRawInterfaceDefinition(
499 final DataSchemaNode schemaNode) {
500 if (schemaNode == null) {
504 final String packageName = resolveGeneratedTypePackageName(schemaNode
506 final String schemaNodeName = schemaNode.getQName().getLocalName();
508 if ((packageName != null) && (schemaNode != null)
509 && (schemaNodeName != null)) {
510 final String genTypeName = CodeGeneratorHelper
511 .parseToClassName(schemaNodeName);
512 final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(
513 packageName, genTypeName);
515 if (!genTypeBuilders.containsKey(packageName)) {
516 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
517 builders.put(genTypeName, newType);
518 genTypeBuilders.put(packageName, builders);
520 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders
522 if (!builders.containsKey(genTypeName)) {
523 builders.put(genTypeName, newType);
531 private String getterMethodName(final String methodName) {
532 final StringBuilder method = new StringBuilder();
533 method.append("get");
534 method.append(CodeGeneratorHelper.parseToClassName(methodName));
535 return method.toString();
538 private String setterMethodName(final String methodName) {
539 final StringBuilder method = new StringBuilder();
540 method.append("set");
541 method.append(CodeGeneratorHelper.parseToClassName(methodName));
542 return method.toString();
545 private MethodSignatureBuilder constructGetter(
546 final GeneratedTypeBuilder interfaceBuilder,
547 final String schemaNodeName, final String comment,
548 final Type returnType) {
549 final MethodSignatureBuilder getMethod = interfaceBuilder
550 .addMethod(getterMethodName(schemaNodeName));
552 getMethod.addComment(comment);
553 getMethod.addReturnType(returnType);
558 private MethodSignatureBuilder constructSetter(
559 final GeneratedTypeBuilder interfaceBuilder,
560 final String schemaNodeName, final String comment,
561 final Type parameterType) {
562 final MethodSignatureBuilder setMethod = interfaceBuilder
563 .addMethod(setterMethodName(schemaNodeName));
565 setMethod.addComment(comment);
566 setMethod.addParameter(parameterType,
567 CodeGeneratorHelper.parseToParamName(schemaNodeName));
568 setMethod.addReturnType(Types.voidType());
573 private String resolveBasePackageName(final URI moduleNamespace,
574 final String yangVersion) {
575 final StringBuilder packageNameBuilder = new StringBuilder();
577 packageNameBuilder.append("org.opendaylight.yang.gen.v");
578 packageNameBuilder.append(yangVersion);
579 packageNameBuilder.append(".rev");
580 packageNameBuilder.append(calendar.get(Calendar.YEAR));
581 packageNameBuilder.append((calendar.get(Calendar.MONTH) + 1));
582 packageNameBuilder.append(calendar.get(Calendar.DAY_OF_MONTH));
583 packageNameBuilder.append(".");
585 String namespace = moduleNamespace.toString();
586 namespace = namespace.replace(":", ".");
587 namespace = namespace.replace("-", ".");
589 packageNameBuilder.append(namespace);
591 return packageNameBuilder.toString();
594 private List<Type> listToGenType(final ListSchemaNode list) {
598 final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(list);
599 final List<String> listKeys = listKeys(list);
600 GeneratedTOBuilder genTOBuilder = null;
601 if (listKeys.size() > 0) {
602 genTOBuilder = resolveListKey(list);
605 final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
606 for (final DataSchemaNode node : schemaNodes) {
608 if (node instanceof LeafSchemaNode) {
609 final LeafSchemaNode leaf = (LeafSchemaNode) node;
610 if (!isPartOfListKey(leaf, listKeys)) {
611 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
613 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
615 } else if (node instanceof LeafListSchemaNode) {
616 resolveLeafListSchemaNode(typeBuilder,
617 (LeafListSchemaNode) node);
618 } else if (node instanceof ContainerSchemaNode) {
619 resolveContainerSchemaNode(typeBuilder,
620 (ContainerSchemaNode) node);
621 } else if (node instanceof ListSchemaNode) {
622 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
626 final List<Type> genTypes = new ArrayList<Type>();
627 if (genTOBuilder != null) {
628 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
629 constructGetter(typeBuilder, genTO.getName(),
630 "Returns Primary Key of Yang List Type", genTO);
633 genTypes.add(typeBuilder.toInstance());
641 private GeneratedTOBuilder resolveListKey(final ListSchemaNode list) {
642 final String packageName = resolveGeneratedTypePackageName(list
644 final String listName = list.getQName().getLocalName() + "Key";
646 if ((packageName != null) && (list != null) && (listName != null)) {
647 final String genTOName = CodeGeneratorHelper
648 .parseToClassName(listName);
649 final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
650 packageName, genTOName);
657 private boolean isPartOfListKey(final LeafSchemaNode leaf,
658 final List<String> keys) {
659 if ((leaf != null) && (keys != null) && (leaf.getQName() != null)) {
660 final String leafName = leaf.getQName().getLocalName();
661 if (keys.contains(leafName)) {
668 private List<String> listKeys(final ListSchemaNode list) {
669 final List<String> listKeys = new ArrayList<String>();
671 if (list.getKeyDefinition() != null) {
672 final List<QName> keyDefinitions = list.getKeyDefinition();
674 for (final QName keyDefinition : keyDefinitions) {
675 listKeys.add(keyDefinition.getLocalName());
681 private GeneratedTypeBuilder resolveListTypeBuilder(
682 final ListSchemaNode list) {
683 final String packageName = resolveGeneratedTypePackageName(list
685 final String schemaNodeName = list.getQName().getLocalName();
686 final String genTypeName = CodeGeneratorHelper
687 .parseToClassName(schemaNodeName);
689 GeneratedTypeBuilder typeBuilder = null;
690 if (genTypeBuilders.containsKey(packageName)) {
691 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
692 typeBuilder = builders.get(genTypeName);
694 if (null == typeBuilder) {
695 typeBuilder = addRawInterfaceDefinition(list);