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.BindingGeneratorUtil;
22 import org.opendaylight.controller.binding.generator.util.Types;
23 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
24 import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator;
25 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
26 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
27 import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
28 import org.opendaylight.controller.sal.binding.model.api.Type;
29 import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
30 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
31 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
32 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
33 import org.opendaylight.controller.sal.binding.model.api.type.builder.MethodSignatureBuilder;
34 import org.opendaylight.controller.sal.binding.yang.types.TypeProviderImpl;
35 import org.opendaylight.controller.yang.common.QName;
36 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
37 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
38 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
39 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
40 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
41 import org.opendaylight.controller.yang.model.api.Module;
42 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
43 import org.opendaylight.controller.yang.model.api.RpcDefinition;
44 import org.opendaylight.controller.yang.model.api.SchemaContext;
45 import org.opendaylight.controller.yang.model.api.SchemaPath;
46 import org.opendaylight.controller.yang.model.api.TypeDefinition;
47 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
48 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
49 import org.opendaylight.controller.yang.model.util.DataNodeIterator;
50 import org.opendaylight.controller.yang.model.util.ExtendedType;
52 public class BindingGeneratorImpl implements BindingGenerator {
54 private static final String[] SET_VALUES = new String[] { "abstract",
55 "assert", "boolean", "break", "byte", "case", "catch", "char",
56 "class", "const", "continue", "default", "double", "do", "else",
57 "enum", "extends", "false", "final", "finally", "float", "for",
58 "goto", "if", "implements", "import", "instanceof", "int",
59 "interface", "long", "native", "new", "null", "package", "private",
60 "protected", "public", "return", "short", "static", "strictfp",
61 "super", "switch", "synchronized", "this", "throw", "throws",
62 "transient", "true", "try", "void", "volatile", "while" };
64 public static final Set<String> JAVA_RESERVED_WORDS = new HashSet<String>(
65 Arrays.asList(SET_VALUES));
67 private static Calendar calendar = new GregorianCalendar();
68 private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
69 private TypeProvider typeProvider;
70 private String basePackageName;
72 public BindingGeneratorImpl() {
76 private static String validatePackage(final String packageName) {
77 if (packageName != null) {
78 final String[] packNameParts = packageName.split("\\.");
79 if (packNameParts != null) {
80 final StringBuilder builder = new StringBuilder();
81 for (int i = 0; i < packNameParts.length; ++i) {
82 if (JAVA_RESERVED_WORDS.contains(packNameParts[i])) {
83 packNameParts[i] = "_" + packNameParts[i];
88 builder.append(packNameParts[i]);
90 return builder.toString();
97 public List<Type> generateTypes(final SchemaContext context) {
98 final List<Type> genTypes = new ArrayList<Type>();
100 if (context != null) {
101 typeProvider = new TypeProviderImpl(context);
102 final Set<Module> modules = context.getModules();
104 if (modules != null) {
105 for (final Module module : modules) {
106 final DataNodeIterator moduleIterator = new DataNodeIterator(
109 genTypeBuilders = new HashMap<String, Map<String, GeneratedTypeBuilder>>();
110 final List<ContainerSchemaNode> schemaContainers = moduleIterator
112 final List<ListSchemaNode> schemaLists = moduleIterator
115 basePackageName = BindingGeneratorUtil
116 .moduleNamespaceToPackageName(
117 module.getNamespace(),
118 module.getYangVersion());
120 if (schemaContainers.size() > 0) {
121 for (final ContainerSchemaNode container : schemaContainers) {
122 genTypes.add(containerToGenType(container));
125 if (schemaLists.size() > 0) {
126 for (final ListSchemaNode list : schemaLists) {
127 genTypes.addAll(listToGenType(list));
131 final GeneratedType genDataType = moduleToDataType(module);
132 final GeneratedType genRpcType = rpcMethodsToGenType(module);
133 final GeneratedType genNotifyType = notifycationsToGenType(module);
135 if (genDataType != null) {
136 genTypes.add(genDataType);
138 if (genRpcType != null) {
139 genTypes.add(genRpcType);
141 if (genNotifyType != null) {
142 genTypes.add(genNotifyType);
146 //FIXME this is quick add of typedefs to generated types from type provider
147 genTypes.addAll(((TypeProviderImpl)typeProvider).getGeneratedTypeDefs());
153 private GeneratedType moduleToDataType(final Module module) {
154 if (module != null) {
155 final Set<TypeDefinition<?>> typeDefinitions = module
156 .getTypeDefinitions();
157 final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(
160 if (moduleDataTypeBuilder != null) {
161 if (typeDefinitions != null) {
162 for (final TypeDefinition<?> typedef : typeDefinitions) {
163 if (isDerivedFromEnumerationType(typedef)) {
164 final EnumTypeDefinition enumBaseType = enumTypeDefFromExtendedType(typedef);
165 resolveEnumFromTypeDefinition(enumBaseType, typedef
166 .getQName().getLocalName(),
167 moduleDataTypeBuilder);
172 final Set<DataSchemaNode> dataNodes = module.getChildNodes();
173 resolveTypesFromDataSchemaNode(moduleDataTypeBuilder, dataNodes);
174 return moduleDataTypeBuilder.toInstance();
180 private boolean isDerivedFromEnumerationType(
181 final TypeDefinition<?> typeDefinition) {
182 if (typeDefinition != null) {
183 if (typeDefinition.getBaseType() instanceof EnumTypeDefinition) {
185 } else if (typeDefinition.getBaseType() instanceof ExtendedType) {
186 return isDerivedFromEnumerationType(typeDefinition
193 private EnumTypeDefinition enumTypeDefFromExtendedType(
194 final TypeDefinition<?> typeDefinition) {
195 if (typeDefinition != null) {
196 if (typeDefinition.getBaseType() instanceof EnumTypeDefinition) {
197 return (EnumTypeDefinition) typeDefinition.getBaseType();
198 } else if (typeDefinition.getBaseType() instanceof ExtendedType) {
199 return enumTypeDefFromExtendedType(typeDefinition.getBaseType());
205 private EnumBuilder resolveEnumFromTypeDefinition(
206 final EnumTypeDefinition enumTypeDef, final String enumName,
207 final GeneratedTypeBuilder typeBuilder) {
208 if ((enumTypeDef != null) && (typeBuilder != null)
209 && (enumTypeDef.getQName() != null)
210 && (enumTypeDef.getQName().getLocalName() != null)) {
212 final String enumerationName = BindingGeneratorUtil
213 .parseToClassName(enumName);
214 final EnumBuilder enumBuilder = typeBuilder
215 .addEnumeration(enumerationName);
217 if (enumBuilder != null) {
218 final List<EnumPair> enums = enumTypeDef.getValues();
221 for (final EnumPair enumPair : enums) {
222 if (enumPair != null) {
223 final String enumPairName = BindingGeneratorUtil
224 .parseToClassName(enumPair.getName());
225 Integer enumPairValue = enumPair.getValue();
227 if (enumPairValue == null) {
228 enumPairValue = listIndex;
230 enumBuilder.addValue(enumPairName, enumPairValue);
241 private GeneratedTypeBuilder moduleTypeBuilder(final Module module,
242 final String postfix) {
243 if (module != null) {
244 String packageName = resolveBasePackageName(module.getNamespace(),
245 module.getYangVersion());
246 final String moduleName = BindingGeneratorUtil
247 .parseToClassName(module.getName()) + postfix;
249 if (packageName != null) {
250 packageName = validatePackage(packageName);
251 return new GeneratedTypeBuilderImpl(packageName, moduleName);
257 private GeneratedType rpcMethodsToGenType(final Module module) {
258 if (module != null) {
259 final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
260 //TODO: add implementation
261 if ((rpcDefinitions != null) && !rpcDefinitions.isEmpty()) {
262 final GeneratedTypeBuilder rpcTypeBuilder = moduleTypeBuilder(
265 for (final RpcDefinition rpc : rpcDefinitions) {
275 private GeneratedType notifycationsToGenType(final Module module) {
276 if (module != null) {
277 final Set<NotificationDefinition> notifications = module
279 //TODO: add implementation
280 if ((notifications != null) && !notifications.isEmpty()) {
281 final GeneratedTypeBuilder notifyTypeBuilder = moduleTypeBuilder(
282 module, "Notification");
284 for (final NotificationDefinition notification : notifications) {
285 if (notification != null) {
294 // private String resolveGeneratedTypePackageName(final SchemaPath
296 // final StringBuilder builder = new StringBuilder();
297 // builder.append(basePackageName);
298 // if ((schemaPath != null) && (schemaPath.getPath() != null)) {
299 // final List<QName> pathToNode = schemaPath.getPath();
300 // final int traversalSteps = (pathToNode.size() - 1);
301 // for (int i = 0; i < traversalSteps; ++i) {
302 // builder.append(".");
303 // String nodeLocalName = pathToNode.get(i).getLocalName();
305 // // TODO: refactor with use of BindingGeneratorUtil class
306 // nodeLocalName = nodeLocalName.replace(":", ".");
307 // nodeLocalName = nodeLocalName.replace("-", ".");
308 // builder.append(nodeLocalName);
310 // return validatePackage(builder.toString());
315 private GeneratedType containerToGenType(ContainerSchemaNode container) {
316 if (container == null) {
319 final Set<DataSchemaNode> schemaNodes = container.getChildNodes();
320 final GeneratedTypeBuilder typeBuilder = addRawInterfaceDefinition(container);
322 resolveTypesFromDataSchemaNode(typeBuilder, schemaNodes);
323 return typeBuilder.toInstance();
326 private GeneratedTypeBuilder resolveTypesFromDataSchemaNode(
327 final GeneratedTypeBuilder typeBuilder,
328 final Set<DataSchemaNode> schemaNodes) {
330 if ((schemaNodes != null) && (typeBuilder != null)) {
331 for (final DataSchemaNode node : schemaNodes) {
332 if (node instanceof LeafSchemaNode) {
333 resolveLeafSchemaNodeAsMethod(typeBuilder,
334 (LeafSchemaNode) node);
335 } else if (node instanceof LeafListSchemaNode) {
336 resolveLeafListSchemaNode(typeBuilder,
337 (LeafListSchemaNode) node);
339 } else if (node instanceof ContainerSchemaNode) {
340 resolveContainerSchemaNode(typeBuilder,
341 (ContainerSchemaNode) node);
342 } else if (node instanceof ListSchemaNode) {
343 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
350 private boolean resolveLeafSchemaNodeAsMethod(
351 final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
352 if ((leaf != null) && (typeBuilder != null)) {
353 final String leafName = leaf.getQName().getLocalName();
354 String leafDesc = leaf.getDescription();
355 if (leafDesc == null) {
359 if (leafName != null) {
360 final TypeDefinition<?> typeDef = leaf.getType();
363 if (!(typeDef instanceof EnumTypeDefinition)
364 && !isDerivedFromEnumerationType(typeDef)) {
366 .javaTypeForSchemaDefinitionType(typeDef);
368 if (isImported(leaf.getPath(), typeDef.getPath())) {
369 // TODO: resolving of imported enums as references to
370 // GeneratedTypeData interface
372 final EnumTypeDefinition enumTypeDef = enumTypeDefFromExtendedType(typeDef);
373 final EnumBuilder enumBuilder = resolveEnumFromTypeDefinition(
374 enumTypeDef, leafName, typeBuilder);
376 if (enumBuilder != null) {
377 type = new ReferencedTypeImpl(
378 enumBuilder.getPackageName(),
379 enumBuilder.getName());
384 constructGetter(typeBuilder, leafName, leafDesc, type);
385 if (!leaf.isConfiguration()) {
386 constructSetter(typeBuilder, leafName, leafDesc, type);
394 private boolean isImported(final SchemaPath leafPath,
395 final SchemaPath typeDefPath) {
396 if ((leafPath != null) && (leafPath.getPath() != null)
397 && (typeDefPath != null) && (typeDefPath.getPath() != null)) {
399 final QName leafPathQName = leafPath.getPath().get(0);
400 final QName typePathQName = typeDefPath.getPath().get(0);
402 if ((leafPathQName != null)
403 && (leafPathQName.getNamespace() != null)
404 && (typePathQName != null)
405 && (typePathQName.getNamespace() != null)) {
407 return !leafPathQName.getNamespace().equals(
408 typePathQName.getNamespace());
414 private boolean resolveLeafSchemaNodeAsProperty(
415 final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
416 boolean isReadOnly) {
417 if ((leaf != null) && (toBuilder != null)) {
418 final String leafName = leaf.getQName().getLocalName();
419 String leafDesc = leaf.getDescription();
420 if (leafDesc == null) {
424 if (leafName != null) {
425 final TypeDefinition<?> typeDef = leaf.getType();
427 // TODO: properly resolve enum types
428 final Type javaType = typeProvider
429 .javaTypeForSchemaDefinitionType(typeDef);
431 final GeneratedPropertyBuilder propBuilder = toBuilder
432 .addProperty(BindingGeneratorUtil
433 .parseToClassName(leafName));
435 propBuilder.setReadOnly(isReadOnly);
436 propBuilder.addReturnType(javaType);
437 propBuilder.addComment(leafDesc);
439 toBuilder.addEqualsIdentity(propBuilder);
440 toBuilder.addHashIdentity(propBuilder);
441 toBuilder.addToStringProperty(propBuilder);
449 private boolean resolveLeafListSchemaNode(
450 final GeneratedTypeBuilder typeBuilder,
451 final LeafListSchemaNode node) {
452 if ((node != null) && (typeBuilder != null)) {
453 final String nodeName = node.getQName().getLocalName();
454 String nodeDesc = node.getDescription();
455 if (nodeDesc == null) {
459 if (nodeName != null) {
460 final TypeDefinition<?> type = node.getType();
461 final Type listType = Types.listTypeFor(typeProvider
462 .javaTypeForSchemaDefinitionType(type));
464 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
465 if (!node.isConfiguration()) {
466 constructSetter(typeBuilder, nodeName, nodeDesc, listType);
474 private boolean resolveContainerSchemaNode(
475 final GeneratedTypeBuilder typeBuilder,
476 final ContainerSchemaNode node) {
477 if ((node != null) && (typeBuilder != null)) {
478 final String nodeName = node.getQName().getLocalName();
480 if (nodeName != null) {
481 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
482 constructGetter(typeBuilder, nodeName, "", rawGenType);
490 private boolean resolveListSchemaNode(
491 final GeneratedTypeBuilder typeBuilder, final ListSchemaNode node) {
492 if ((node != null) && (typeBuilder != null)) {
493 final String nodeName = node.getQName().getLocalName();
495 if (nodeName != null) {
496 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
497 constructGetter(typeBuilder, nodeName, "",
498 Types.listTypeFor(rawGenType));
499 if (!node.isConfiguration()) {
500 constructSetter(typeBuilder, nodeName, "",
501 Types.listTypeFor(rawGenType));
509 private GeneratedTypeBuilder addRawInterfaceDefinition(
510 final DataSchemaNode schemaNode) {
511 if (schemaNode == null) {
515 final String packageName = BindingGeneratorUtil
516 .packageNameForGeneratedType(basePackageName,
517 schemaNode.getPath());
518 final String schemaNodeName = schemaNode.getQName().getLocalName();
520 if ((packageName != null) && (schemaNode != null)
521 && (schemaNodeName != null)) {
522 final String genTypeName = BindingGeneratorUtil
523 .parseToClassName(schemaNodeName);
524 final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(
525 packageName, genTypeName);
527 if (!genTypeBuilders.containsKey(packageName)) {
528 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
529 builders.put(genTypeName, newType);
530 genTypeBuilders.put(packageName, builders);
532 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders
534 if (!builders.containsKey(genTypeName)) {
535 builders.put(genTypeName, newType);
543 private String getterMethodName(final String methodName) {
544 final StringBuilder method = new StringBuilder();
545 method.append("get");
546 method.append(BindingGeneratorUtil.parseToClassName(methodName));
547 return method.toString();
550 private String setterMethodName(final String methodName) {
551 final StringBuilder method = new StringBuilder();
552 method.append("set");
553 method.append(BindingGeneratorUtil.parseToClassName(methodName));
554 return method.toString();
557 private MethodSignatureBuilder constructGetter(
558 final GeneratedTypeBuilder interfaceBuilder,
559 final String schemaNodeName, final String comment,
560 final Type returnType) {
561 final MethodSignatureBuilder getMethod = interfaceBuilder
562 .addMethod(getterMethodName(schemaNodeName));
564 getMethod.addComment(comment);
565 getMethod.addReturnType(returnType);
570 private MethodSignatureBuilder constructSetter(
571 final GeneratedTypeBuilder interfaceBuilder,
572 final String schemaNodeName, final String comment,
573 final Type parameterType) {
574 final MethodSignatureBuilder setMethod = interfaceBuilder
575 .addMethod(setterMethodName(schemaNodeName));
577 setMethod.addComment(comment);
578 setMethod.addParameter(parameterType,
579 BindingGeneratorUtil.parseToValidParamName(schemaNodeName));
580 setMethod.addReturnType(Types.voidType());
585 private String resolveBasePackageName(final URI moduleNamespace,
586 final String yangVersion) {
587 final StringBuilder packageNameBuilder = new StringBuilder();
589 packageNameBuilder.append("org.opendaylight.yang.gen.v");
590 packageNameBuilder.append(yangVersion);
591 packageNameBuilder.append(".rev");
592 packageNameBuilder.append(calendar.get(Calendar.YEAR));
593 packageNameBuilder.append((calendar.get(Calendar.MONTH) + 1));
594 packageNameBuilder.append(calendar.get(Calendar.DAY_OF_MONTH));
595 packageNameBuilder.append(".");
597 String namespace = moduleNamespace.toString();
598 namespace = namespace.replace(":", ".");
599 namespace = namespace.replace("-", ".");
601 packageNameBuilder.append(namespace);
603 return packageNameBuilder.toString();
606 private List<Type> listToGenType(final ListSchemaNode list) {
610 final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(list);
611 final List<String> listKeys = listKeys(list);
612 GeneratedTOBuilder genTOBuilder = null;
613 if (listKeys.size() > 0) {
614 genTOBuilder = resolveListKey(list);
617 final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
618 for (final DataSchemaNode node : schemaNodes) {
620 if (node instanceof LeafSchemaNode) {
621 final LeafSchemaNode leaf = (LeafSchemaNode) node;
622 if (!isPartOfListKey(leaf, listKeys)) {
623 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
625 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
627 } else if (node instanceof LeafListSchemaNode) {
628 resolveLeafListSchemaNode(typeBuilder,
629 (LeafListSchemaNode) node);
630 } else if (node instanceof ContainerSchemaNode) {
631 resolveContainerSchemaNode(typeBuilder,
632 (ContainerSchemaNode) node);
633 } else if (node instanceof ListSchemaNode) {
634 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
638 final List<Type> genTypes = new ArrayList<Type>();
639 if (genTOBuilder != null) {
640 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
641 constructGetter(typeBuilder, genTO.getName(),
642 "Returns Primary Key of Yang List Type", genTO);
645 genTypes.add(typeBuilder.toInstance());
653 private GeneratedTOBuilder resolveListKey(final ListSchemaNode list) {
654 final String packageName = BindingGeneratorUtil
655 .packageNameForGeneratedType(basePackageName, list.getPath());
656 final String listName = list.getQName().getLocalName() + "Key";
658 return BindingGeneratorUtil.schemaNodeToTransferObjectBuilder(
659 packageName, list, listName);
662 private boolean isPartOfListKey(final LeafSchemaNode leaf,
663 final List<String> keys) {
664 if ((leaf != null) && (keys != null) && (leaf.getQName() != null)) {
665 final String leafName = leaf.getQName().getLocalName();
666 if (keys.contains(leafName)) {
673 private List<String> listKeys(final ListSchemaNode list) {
674 final List<String> listKeys = new ArrayList<String>();
676 if (list.getKeyDefinition() != null) {
677 final List<QName> keyDefinitions = list.getKeyDefinition();
679 for (final QName keyDefinition : keyDefinitions) {
680 listKeys.add(keyDefinition.getLocalName());
686 private GeneratedTypeBuilder resolveListTypeBuilder(
687 final ListSchemaNode list) {
688 final String packageName = BindingGeneratorUtil
689 .packageNameForGeneratedType(basePackageName,
691 final String schemaNodeName = list.getQName().getLocalName();
692 final String genTypeName = BindingGeneratorUtil
693 .parseToClassName(schemaNodeName);
695 GeneratedTypeBuilder typeBuilder = null;
696 if (genTypeBuilders.containsKey(packageName)) {
697 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
698 typeBuilder = builders.get(genTypeName);
700 if (null == typeBuilder) {
701 typeBuilder = addRawInterfaceDefinition(list);