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 List<GeneratedType> augmentationToGenTypes(final Module module) {
295 final List<GeneratedType> augmentGenTypes = new ArrayList<GeneratedType>();
297 //TODO: add implementation
299 return augmentGenTypes;
302 private GeneratedType containerToGenType(ContainerSchemaNode container) {
303 if (container == null) {
306 final Set<DataSchemaNode> schemaNodes = container.getChildNodes();
307 final GeneratedTypeBuilder typeBuilder = addRawInterfaceDefinition(container);
309 resolveTypesFromDataSchemaNode(typeBuilder, schemaNodes);
310 return typeBuilder.toInstance();
313 private GeneratedTypeBuilder resolveTypesFromDataSchemaNode(
314 final GeneratedTypeBuilder typeBuilder,
315 final Set<DataSchemaNode> schemaNodes) {
317 if ((schemaNodes != null) && (typeBuilder != null)) {
318 for (final DataSchemaNode node : schemaNodes) {
319 if (node instanceof LeafSchemaNode) {
320 resolveLeafSchemaNodeAsMethod(typeBuilder,
321 (LeafSchemaNode) node);
322 } else if (node instanceof LeafListSchemaNode) {
323 resolveLeafListSchemaNode(typeBuilder,
324 (LeafListSchemaNode) node);
326 } else if (node instanceof ContainerSchemaNode) {
327 resolveContainerSchemaNode(typeBuilder,
328 (ContainerSchemaNode) node);
329 } else if (node instanceof ListSchemaNode) {
330 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
337 private boolean resolveLeafSchemaNodeAsMethod(
338 final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
339 if ((leaf != null) && (typeBuilder != null)) {
340 final String leafName = leaf.getQName().getLocalName();
341 String leafDesc = leaf.getDescription();
342 if (leafDesc == null) {
346 if (leafName != null) {
347 final TypeDefinition<?> typeDef = leaf.getType();
350 if (!(typeDef instanceof EnumTypeDefinition)
351 && !isDerivedFromEnumerationType(typeDef)) {
353 .javaTypeForSchemaDefinitionType(typeDef);
355 if (isImported(leaf.getPath(), typeDef.getPath())) {
356 // TODO: resolving of imported enums as references to
357 // GeneratedTypeData interface
359 final EnumTypeDefinition enumTypeDef = enumTypeDefFromExtendedType(typeDef);
360 final EnumBuilder enumBuilder = resolveEnumFromTypeDefinition(
361 enumTypeDef, leafName, typeBuilder);
363 if (enumBuilder != null) {
364 type = new ReferencedTypeImpl(
365 enumBuilder.getPackageName(),
366 enumBuilder.getName());
371 constructGetter(typeBuilder, leafName, leafDesc, type);
372 if (!leaf.isConfiguration()) {
373 constructSetter(typeBuilder, leafName, leafDesc, type);
381 private boolean isImported(final SchemaPath leafPath,
382 final SchemaPath typeDefPath) {
383 if ((leafPath != null) && (leafPath.getPath() != null)
384 && (typeDefPath != null) && (typeDefPath.getPath() != null)) {
386 final QName leafPathQName = leafPath.getPath().get(0);
387 final QName typePathQName = typeDefPath.getPath().get(0);
389 if ((leafPathQName != null)
390 && (leafPathQName.getNamespace() != null)
391 && (typePathQName != null)
392 && (typePathQName.getNamespace() != null)) {
394 return !leafPathQName.getNamespace().equals(
395 typePathQName.getNamespace());
401 private boolean resolveLeafSchemaNodeAsProperty(
402 final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
403 boolean isReadOnly) {
404 if ((leaf != null) && (toBuilder != null)) {
405 final String leafName = leaf.getQName().getLocalName();
406 String leafDesc = leaf.getDescription();
407 if (leafDesc == null) {
411 if (leafName != null) {
412 final TypeDefinition<?> typeDef = leaf.getType();
414 // TODO: properly resolve enum types
415 final Type javaType = typeProvider
416 .javaTypeForSchemaDefinitionType(typeDef);
418 final GeneratedPropertyBuilder propBuilder = toBuilder
419 .addProperty(BindingGeneratorUtil
420 .parseToClassName(leafName));
422 propBuilder.setReadOnly(isReadOnly);
423 propBuilder.addReturnType(javaType);
424 propBuilder.addComment(leafDesc);
426 toBuilder.addEqualsIdentity(propBuilder);
427 toBuilder.addHashIdentity(propBuilder);
428 toBuilder.addToStringProperty(propBuilder);
436 private boolean resolveLeafListSchemaNode(
437 final GeneratedTypeBuilder typeBuilder,
438 final LeafListSchemaNode node) {
439 if ((node != null) && (typeBuilder != null)) {
440 final String nodeName = node.getQName().getLocalName();
441 String nodeDesc = node.getDescription();
442 if (nodeDesc == null) {
446 if (nodeName != null) {
447 final TypeDefinition<?> type = node.getType();
448 final Type listType = Types.listTypeFor(typeProvider
449 .javaTypeForSchemaDefinitionType(type));
451 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
452 if (!node.isConfiguration()) {
453 constructSetter(typeBuilder, nodeName, nodeDesc, listType);
461 private boolean resolveContainerSchemaNode(
462 final GeneratedTypeBuilder typeBuilder,
463 final ContainerSchemaNode node) {
464 if ((node != null) && (typeBuilder != null)) {
465 final String nodeName = node.getQName().getLocalName();
467 if (nodeName != null) {
468 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
469 constructGetter(typeBuilder, nodeName, "", rawGenType);
477 private boolean resolveListSchemaNode(
478 final GeneratedTypeBuilder typeBuilder, final ListSchemaNode node) {
479 if ((node != null) && (typeBuilder != null)) {
480 final String nodeName = node.getQName().getLocalName();
482 if (nodeName != null) {
483 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
484 constructGetter(typeBuilder, nodeName, "",
485 Types.listTypeFor(rawGenType));
486 if (!node.isConfiguration()) {
487 constructSetter(typeBuilder, nodeName, "",
488 Types.listTypeFor(rawGenType));
496 private GeneratedTypeBuilder addRawInterfaceDefinition(
497 final DataSchemaNode schemaNode) {
498 if (schemaNode == null) {
502 final String packageName = BindingGeneratorUtil
503 .packageNameForGeneratedType(basePackageName,
504 schemaNode.getPath());
505 final String schemaNodeName = schemaNode.getQName().getLocalName();
507 if ((packageName != null) && (schemaNode != null)
508 && (schemaNodeName != null)) {
509 final String genTypeName = BindingGeneratorUtil
510 .parseToClassName(schemaNodeName);
511 final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(
512 packageName, genTypeName);
514 if (!genTypeBuilders.containsKey(packageName)) {
515 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
516 builders.put(genTypeName, newType);
517 genTypeBuilders.put(packageName, builders);
519 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders
521 if (!builders.containsKey(genTypeName)) {
522 builders.put(genTypeName, newType);
530 private String getterMethodName(final String methodName) {
531 final StringBuilder method = new StringBuilder();
532 method.append("get");
533 method.append(BindingGeneratorUtil.parseToClassName(methodName));
534 return method.toString();
537 private String setterMethodName(final String methodName) {
538 final StringBuilder method = new StringBuilder();
539 method.append("set");
540 method.append(BindingGeneratorUtil.parseToClassName(methodName));
541 return method.toString();
544 private MethodSignatureBuilder constructGetter(
545 final GeneratedTypeBuilder interfaceBuilder,
546 final String schemaNodeName, final String comment,
547 final Type returnType) {
548 final MethodSignatureBuilder getMethod = interfaceBuilder
549 .addMethod(getterMethodName(schemaNodeName));
551 getMethod.addComment(comment);
552 getMethod.addReturnType(returnType);
557 private MethodSignatureBuilder constructSetter(
558 final GeneratedTypeBuilder interfaceBuilder,
559 final String schemaNodeName, final String comment,
560 final Type parameterType) {
561 final MethodSignatureBuilder setMethod = interfaceBuilder
562 .addMethod(setterMethodName(schemaNodeName));
564 setMethod.addComment(comment);
565 setMethod.addParameter(parameterType,
566 BindingGeneratorUtil.parseToValidParamName(schemaNodeName));
567 setMethod.addReturnType(Types.voidType());
572 private String resolveBasePackageName(final URI moduleNamespace,
573 final String yangVersion) {
574 final StringBuilder packageNameBuilder = new StringBuilder();
576 packageNameBuilder.append("org.opendaylight.yang.gen.v");
577 packageNameBuilder.append(yangVersion);
578 packageNameBuilder.append(".rev");
579 packageNameBuilder.append(calendar.get(Calendar.YEAR));
580 packageNameBuilder.append((calendar.get(Calendar.MONTH) + 1));
581 packageNameBuilder.append(calendar.get(Calendar.DAY_OF_MONTH));
582 packageNameBuilder.append(".");
584 String namespace = moduleNamespace.toString();
585 namespace = namespace.replace(":", ".");
586 namespace = namespace.replace("-", ".");
588 packageNameBuilder.append(namespace);
590 return packageNameBuilder.toString();
593 private List<Type> listToGenType(final ListSchemaNode list) {
597 final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(list);
598 final List<String> listKeys = listKeys(list);
599 GeneratedTOBuilder genTOBuilder = null;
600 if (listKeys.size() > 0) {
601 genTOBuilder = resolveListKey(list);
604 final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
605 for (final DataSchemaNode node : schemaNodes) {
607 if (node instanceof LeafSchemaNode) {
608 final LeafSchemaNode leaf = (LeafSchemaNode) node;
609 if (!isPartOfListKey(leaf, listKeys)) {
610 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
612 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
614 } else if (node instanceof LeafListSchemaNode) {
615 resolveLeafListSchemaNode(typeBuilder,
616 (LeafListSchemaNode) node);
617 } else if (node instanceof ContainerSchemaNode) {
618 resolveContainerSchemaNode(typeBuilder,
619 (ContainerSchemaNode) node);
620 } else if (node instanceof ListSchemaNode) {
621 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
625 final List<Type> genTypes = new ArrayList<Type>();
626 if (genTOBuilder != null) {
627 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
628 constructGetter(typeBuilder, genTO.getName(),
629 "Returns Primary Key of Yang List Type", genTO);
632 genTypes.add(typeBuilder.toInstance());
640 private GeneratedTOBuilder resolveListKey(final ListSchemaNode list) {
641 final String packageName = BindingGeneratorUtil
642 .packageNameForGeneratedType(basePackageName, list.getPath());
643 final String listName = list.getQName().getLocalName() + "Key";
645 return BindingGeneratorUtil.schemaNodeToTransferObjectBuilder(
646 packageName, list, listName);
649 private boolean isPartOfListKey(final LeafSchemaNode leaf,
650 final List<String> keys) {
651 if ((leaf != null) && (keys != null) && (leaf.getQName() != null)) {
652 final String leafName = leaf.getQName().getLocalName();
653 if (keys.contains(leafName)) {
660 private List<String> listKeys(final ListSchemaNode list) {
661 final List<String> listKeys = new ArrayList<String>();
663 if (list.getKeyDefinition() != null) {
664 final List<QName> keyDefinitions = list.getKeyDefinition();
666 for (final QName keyDefinition : keyDefinitions) {
667 listKeys.add(keyDefinition.getLocalName());
673 private GeneratedTypeBuilder resolveListTypeBuilder(
674 final ListSchemaNode list) {
675 final String packageName = BindingGeneratorUtil
676 .packageNameForGeneratedType(basePackageName,
678 final String schemaNodeName = list.getQName().getLocalName();
679 final String genTypeName = BindingGeneratorUtil
680 .parseToClassName(schemaNodeName);
682 GeneratedTypeBuilder typeBuilder = null;
683 if (genTypeBuilders.containsKey(packageName)) {
684 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
685 typeBuilder = builders.get(genTypeName);
687 if (null == typeBuilder) {
688 typeBuilder = addRawInterfaceDefinition(list);