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.sal.binding.generator.api.BindingGenerator;
24 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
25 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
26 import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
27 import org.opendaylight.controller.sal.binding.model.api.Type;
28 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
29 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
30 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
31 import org.opendaylight.controller.sal.binding.model.api.type.builder.MethodSignatureBuilder;
32 import org.opendaylight.controller.sal.binding.yang.types.TypeProviderImpl;
33 import org.opendaylight.controller.yang.common.QName;
34 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
35 import org.opendaylight.controller.yang.model.api.DataNodeContainer;
36 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
37 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
38 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
39 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
40 import org.opendaylight.controller.yang.model.api.Module;
41 import org.opendaylight.controller.yang.model.api.SchemaContext;
42 import org.opendaylight.controller.yang.model.api.SchemaPath;
43 import org.opendaylight.controller.yang.model.api.TypeDefinition;
45 public class BindingGeneratorImpl implements BindingGenerator {
47 private static final String[] SET_VALUES = new String[] { "abstract",
48 "assert", "boolean", "break", "byte", "case", "catch", "char",
49 "class", "const", "continue", "default", "double", "do", "else",
50 "enum", "extends", "false", "final", "finally", "float", "for",
51 "goto", "if", "implements", "import", "instanceof", "int",
52 "interface", "long", "native", "new", "null", "package", "private",
53 "protected", "public", "return", "short", "static", "strictfp",
54 "super", "switch", "synchronized", "this", "throw", "throws",
55 "transient", "true", "try", "void", "volatile", "while" };
57 public static final Set<String> JAVA_RESERVED_WORDS = new HashSet<String>(
58 Arrays.asList(SET_VALUES));
60 private static Calendar calendar = new GregorianCalendar();
61 private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
62 private List<ContainerSchemaNode> schemaContainers;
63 private List<ListSchemaNode> schemaLists;
64 private TypeProvider typeProvider;
65 private String basePackageName;
67 public BindingGeneratorImpl() {
71 private static String validatePackage(final String packageName) {
72 if (packageName != null) {
73 final String[] packNameParts = packageName.split("\\.");
74 if (packNameParts != null) {
75 final StringBuilder builder = new StringBuilder();
76 for (int i = 0; i < packNameParts.length; ++i) {
77 if (JAVA_RESERVED_WORDS.contains(packNameParts[i])) {
78 packNameParts[i] = "_" + packNameParts[i];
83 builder.append(packNameParts[i]);
85 return builder.toString();
92 public List<Type> generateTypes(final SchemaContext context) {
93 final List<Type> genTypes = new ArrayList<Type>();
95 typeProvider = new TypeProviderImpl(context);
96 if (context != null) {
97 final Set<Module> modules = context.getModules();
99 if (modules != null) {
100 for (final Module module : modules) {
101 genTypeBuilders = new HashMap<String, Map<String, GeneratedTypeBuilder>>();
102 schemaContainers = new ArrayList<ContainerSchemaNode>();
103 schemaLists = new ArrayList<ListSchemaNode>();
105 basePackageName = resolveBasePackageName(module.getNamespace(),
106 module.getYangVersion());
108 traverseModule(module);
109 if (schemaContainers.size() > 0) {
110 for (final ContainerSchemaNode container : schemaContainers) {
111 genTypes.add(containerToGenType(container));
115 if (schemaLists.size() > 0) {
116 for (final ListSchemaNode list : schemaLists) {
117 genTypes.addAll(listToGenType(list));
127 private String resolveGeneratedTypePackageName(final SchemaPath schemaPath) {
128 final StringBuilder builder = new StringBuilder();
129 builder.append(basePackageName);
130 if ((schemaPath != null) && (schemaPath.getPath() != null)) {
131 final List<QName> pathToNode = schemaPath.getPath();
132 final int traversalSteps = (pathToNode.size() - 1);
133 for (int i = 0; i < traversalSteps; ++i) {
135 String nodeLocalName = pathToNode.get(i).getLocalName();
137 // TODO: create method
138 nodeLocalName = nodeLocalName.replace(":", ".");
139 nodeLocalName = nodeLocalName.replace("-", ".");
140 builder.append(nodeLocalName);
142 return validatePackage(builder.toString());
147 private GeneratedType containerToGenType(ContainerSchemaNode container) {
148 if (container == null) {
151 final Set<DataSchemaNode> schemaNodes = container.getChildNodes();
152 final GeneratedTypeBuilder typeBuilder = addRawInterfaceDefinition(container);
154 for (final DataSchemaNode node : schemaNodes) {
155 if (node instanceof LeafSchemaNode) {
156 resolveLeafSchemaNodeAsMethod(typeBuilder,
157 (LeafSchemaNode) node);
158 } else if (node instanceof LeafListSchemaNode) {
159 resolveLeafListSchemaNode(typeBuilder,
160 (LeafListSchemaNode) node);
162 } else if (node instanceof ContainerSchemaNode) {
163 resolveContainerSchemaNode(typeBuilder,
164 (ContainerSchemaNode) node);
165 } else if (node instanceof ListSchemaNode) {
166 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
169 return typeBuilder.toInstance();
172 private boolean resolveLeafSchemaNodeAsMethod(
173 final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
174 if ((leaf != null) && (typeBuilder != null)) {
175 final String leafName = leaf.getQName().getLocalName();
176 String leafDesc = leaf.getDescription();
177 if (leafDesc == null) {
181 if (leafName != null) {
182 final TypeDefinition<?> typeDef = leaf.getType();
183 final Type javaType = typeProvider
184 .javaTypeForSchemaDefinitionType(typeDef);
186 constructGetter(typeBuilder, leafName, leafDesc, javaType);
187 if (!leaf.isConfiguration()) {
188 constructSetter(typeBuilder, leafName, leafDesc, javaType);
196 private boolean resolveLeafSchemaNodeAsProperty(
197 final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
198 boolean isReadOnly) {
199 if ((leaf != null) && (toBuilder != null)) {
200 final String leafName = leaf.getQName().getLocalName();
201 String leafDesc = leaf.getDescription();
202 if (leafDesc == null) {
206 if (leafName != null) {
207 final TypeDefinition<?> typeDef = leaf.getType();
209 //TODO: properly resolve enum types
210 final Type javaType = typeProvider
211 .javaTypeForSchemaDefinitionType(typeDef);
213 final GeneratedPropertyBuilder propBuilder = toBuilder
214 .addProperty(CodeGeneratorHelper
215 .parseToClassName(leafName));
217 propBuilder.setReadOnly(isReadOnly);
218 propBuilder.addReturnType(javaType);
219 propBuilder.addComment(leafDesc);
221 toBuilder.addEqualsIdentity(propBuilder);
222 toBuilder.addHashIdentity(propBuilder);
223 toBuilder.addToStringProperty(propBuilder);
231 private boolean resolveLeafListSchemaNode(
232 final GeneratedTypeBuilder typeBuilder,
233 final LeafListSchemaNode node) {
234 if ((node != null) && (typeBuilder != null)) {
235 final String nodeName = node.getQName().getLocalName();
236 String nodeDesc = node.getDescription();
237 if (nodeDesc == null) {
241 if (nodeName != null) {
242 final TypeDefinition<?> type = node.getType();
243 final Type listType = Types.listTypeFor(typeProvider
244 .javaTypeForSchemaDefinitionType(type));
246 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
247 if (!node.isConfiguration()) {
248 constructSetter(typeBuilder, nodeName, nodeDesc, listType);
256 private boolean resolveContainerSchemaNode(
257 final GeneratedTypeBuilder typeBuilder,
258 final ContainerSchemaNode node) {
259 if ((node != null) && (typeBuilder != null)) {
260 final String nodeName = node.getQName().getLocalName();
262 if (nodeName != null) {
263 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
264 constructGetter(typeBuilder, nodeName, "", rawGenType);
272 private boolean resolveListSchemaNode(
273 final GeneratedTypeBuilder typeBuilder, final ListSchemaNode node) {
274 if ((node != null) && (typeBuilder != null)) {
275 final String nodeName = node.getQName().getLocalName();
277 if (nodeName != null) {
278 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
279 constructGetter(typeBuilder, nodeName, "",
280 Types.listTypeFor(rawGenType));
281 if (!node.isConfiguration()) {
282 constructSetter(typeBuilder, nodeName, "",
283 Types.listTypeFor(rawGenType));
291 private GeneratedTypeBuilder addRawInterfaceDefinition(
292 final DataSchemaNode schemaNode) {
293 if (schemaNode == null) {
297 final String packageName = resolveGeneratedTypePackageName(schemaNode
299 final String schemaNodeName = schemaNode.getQName().getLocalName();
301 if ((packageName != null) && (schemaNode != null)
302 && (schemaNodeName != null)) {
303 final String genTypeName = CodeGeneratorHelper
304 .parseToClassName(schemaNodeName);
305 final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(
306 packageName, genTypeName);
308 if (!genTypeBuilders.containsKey(packageName)) {
309 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
310 builders.put(genTypeName, newType);
311 genTypeBuilders.put(packageName, builders);
313 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders
315 if (!builders.containsKey(genTypeName)) {
316 builders.put(genTypeName, newType);
324 private String getterMethodName(final String methodName) {
325 final StringBuilder method = new StringBuilder();
326 method.append("get");
327 method.append(CodeGeneratorHelper.parseToClassName(methodName));
328 return method.toString();
331 private String setterMethodName(final String methodName) {
332 final StringBuilder method = new StringBuilder();
333 method.append("set");
334 method.append(CodeGeneratorHelper.parseToClassName(methodName));
335 return method.toString();
338 private MethodSignatureBuilder constructGetter(
339 final GeneratedTypeBuilder interfaceBuilder,
340 final String schemaNodeName, final String comment,
341 final Type returnType) {
342 final MethodSignatureBuilder getMethod = interfaceBuilder
343 .addMethod(getterMethodName(schemaNodeName));
345 getMethod.addComment(comment);
346 getMethod.addReturnType(returnType);
351 private MethodSignatureBuilder constructSetter(
352 final GeneratedTypeBuilder interfaceBuilder,
353 final String schemaNodeName, final String comment,
354 final Type parameterType) {
355 final MethodSignatureBuilder setMethod = interfaceBuilder
356 .addMethod(setterMethodName(schemaNodeName));
358 setMethod.addComment(comment);
359 setMethod.addParameter(parameterType,
360 CodeGeneratorHelper.parseToParamName(schemaNodeName));
361 setMethod.addReturnType(Types.voidType());
366 private String resolveBasePackageName(final URI moduleNamespace,
367 final String yangVersion) {
368 final StringBuilder packageNameBuilder = new StringBuilder();
370 packageNameBuilder.append("org.opendaylight.yang.gen.v");
371 packageNameBuilder.append(yangVersion);
372 packageNameBuilder.append(".rev");
373 packageNameBuilder.append(calendar.get(Calendar.YEAR));
374 packageNameBuilder.append((calendar.get(Calendar.MONTH) + 1));
375 packageNameBuilder.append(calendar.get(Calendar.DAY_OF_MONTH));
376 packageNameBuilder.append(".");
378 String namespace = moduleNamespace.toString();
379 namespace = namespace.replace(":", ".");
380 namespace = namespace.replace("-", ".");
382 packageNameBuilder.append(namespace);
384 return packageNameBuilder.toString();
387 private List<Type> listToGenType(final ListSchemaNode list) {
391 final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(list);
392 final List<String> listKeys = listKeys(list);
393 GeneratedTOBuilder genTOBuilder = null;
394 if (listKeys.size() > 0) {
395 genTOBuilder = resolveListKey(list);
398 final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
399 for (final DataSchemaNode node : schemaNodes) {
401 if (node instanceof LeafSchemaNode) {
402 final LeafSchemaNode leaf = (LeafSchemaNode) node;
403 if (!isPartOfListKey(leaf, listKeys)) {
404 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
406 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
408 } else if (node instanceof LeafListSchemaNode) {
409 resolveLeafListSchemaNode(typeBuilder,
410 (LeafListSchemaNode) node);
411 } else if (node instanceof ContainerSchemaNode) {
412 resolveContainerSchemaNode(typeBuilder,
413 (ContainerSchemaNode) node);
414 } else if (node instanceof ListSchemaNode) {
415 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
419 final List<Type> genTypes = new ArrayList<Type>();
420 if (genTOBuilder != null) {
421 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
422 constructGetter(typeBuilder, genTO.getName(), "Returns Primary Key of Yang List Type", genTO);
425 genTypes.add(typeBuilder.toInstance());
433 private GeneratedTOBuilder resolveListKey(final ListSchemaNode list) {
434 final String packageName = resolveGeneratedTypePackageName(list
436 final String listName = list.getQName().getLocalName() + "Key";
438 if ((packageName != null) && (list != null) && (listName != null)) {
439 final String genTOName = CodeGeneratorHelper
440 .parseToClassName(listName);
441 final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
442 packageName, genTOName);
449 private boolean isPartOfListKey(final LeafSchemaNode leaf,
450 final List<String> keys) {
451 if ((leaf != null) && (keys != null) && (leaf.getQName() != null)) {
452 final String leafName = leaf.getQName().getLocalName();
453 if (keys.contains(leafName)) {
460 private List<String> listKeys(final ListSchemaNode list) {
461 final List<String> listKeys = new ArrayList<String>();
463 if (list.getKeyDefinition() != null) {
464 final List<QName> keyDefinitions = list.getKeyDefinition();
466 for (final QName keyDefinition : keyDefinitions) {
467 listKeys.add(keyDefinition.getLocalName());
473 private GeneratedTypeBuilder resolveListTypeBuilder(
474 final ListSchemaNode list) {
475 final String packageName = resolveGeneratedTypePackageName(list
477 final String schemaNodeName = list.getQName().getLocalName();
478 final String genTypeName = CodeGeneratorHelper
479 .parseToClassName(schemaNodeName);
481 GeneratedTypeBuilder typeBuilder = null;
482 if (genTypeBuilders.containsKey(packageName)) {
483 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
484 typeBuilder = builders.get(genTypeName);
486 if (null == typeBuilder) {
487 typeBuilder = addRawInterfaceDefinition(list);
493 private void traverseModule(final Module module) {
494 final Set<DataSchemaNode> schemaNodes = module.getChildNodes();
496 for (DataSchemaNode node : schemaNodes) {
497 if (node instanceof ContainerSchemaNode) {
498 schemaContainers.add((ContainerSchemaNode) node);
499 traverse((ContainerSchemaNode) node);
504 private void traverse(final DataNodeContainer dataNode) {
505 if (!containChildDataNodeContainer(dataNode)) {
509 final Set<DataSchemaNode> childs = dataNode.getChildNodes();
510 if (childs != null) {
511 for (DataSchemaNode childNode : childs) {
512 if (childNode instanceof ContainerSchemaNode) {
513 final ContainerSchemaNode container = (ContainerSchemaNode) childNode;
514 schemaContainers.add(container);
518 if (childNode instanceof ListSchemaNode) {
519 final ListSchemaNode list = (ListSchemaNode) childNode;
520 schemaLists.add(list);
528 * Returns <code>true</code> if and only if the child node contain at least
529 * one child container schema node or child list schema node, otherwise will
530 * always returns <code>false</code>
533 * @return <code>true</code> if and only if the child node contain at least
534 * one child container schema node or child list schema node,
535 * otherwise will always returns <code>false</code>
537 private boolean containChildDataNodeContainer(
538 final DataNodeContainer container) {
539 if (container != null) {
540 final Set<DataSchemaNode> childs = container.getChildNodes();
541 if ((childs != null) && (childs.size() > 0)) {
542 for (final DataSchemaNode childNode : childs) {
543 if (childNode instanceof DataNodeContainer) {