Initial opendaylight infrastructure commit!!
[controller.git] / opendaylight / sal / yang-prototype / code-generator / binding-generator-impl / src / main / java / org / opendaylight / controller / sal / binding / generator / impl / BindingGeneratorImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.binding.generator.impl;
9
10 import java.net.URI;
11 import java.text.DateFormat;
12 import java.text.SimpleDateFormat;
13 import java.util.ArrayList;
14 import java.util.Calendar;
15 import java.util.GregorianCalendar;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20
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.GeneratedType;
26 import org.opendaylight.controller.sal.binding.model.api.Type;
27 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
28 import org.opendaylight.controller.sal.binding.model.api.type.builder.MethodSignatureBuilder;
29 import org.opendaylight.controller.sal.binding.yang.types.TypeProviderImpl;
30 import org.opendaylight.controller.yang.common.QName;
31 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
32 import org.opendaylight.controller.yang.model.api.DataNodeContainer;
33 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
34 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
35 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
36 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
37 import org.opendaylight.controller.yang.model.api.Module;
38 import org.opendaylight.controller.yang.model.api.SchemaPath;
39 import org.opendaylight.controller.yang.model.api.TypeDefinition;
40
41 public class BindingGeneratorImpl implements BindingGenerator {
42
43     private static DateFormat simpleDateFormat = new SimpleDateFormat(
44             "yyyy-MM-dd");
45     private static Calendar calendar = new GregorianCalendar();
46
47     private final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
48     private final List<ContainerSchemaNode> schemaContainers;
49     private final List<ListSchemaNode> schemaLists;
50
51     private final TypeProvider typeProvider;
52
53     private String basePackageName;
54
55     public BindingGeneratorImpl() {
56         super();
57         genTypeBuilders = new HashMap<String, Map<String, GeneratedTypeBuilder>>();
58         schemaContainers = new ArrayList<ContainerSchemaNode>();
59         schemaLists = new ArrayList<ListSchemaNode>();
60
61         // TODO: reimplement in better way
62         typeProvider = new TypeProviderImpl();
63     }
64
65     @Override
66     public List<GeneratedType> generateTypes(final Module module) {
67         final List<GeneratedType> genTypes = new ArrayList<GeneratedType>();
68
69         basePackageName = resolveBasePackageName(module.getNamespace(),
70                 module.getYangVersion());
71
72         traverseModule(module);
73         if (schemaContainers.size() > 0) {
74             for (final ContainerSchemaNode container : schemaContainers) {
75                 genTypes.add(containerToGenType(container));
76             }
77         }
78
79         if (schemaLists.size() > 0) {
80             for (final ListSchemaNode list : schemaLists) {
81                 genTypes.add(listToGenType(list));
82             }
83         }
84
85         return genTypes;
86     }
87
88     private String resolveGeneratedTypePackageName(final SchemaPath schemaPath) {
89         final StringBuilder builder = new StringBuilder();
90         builder.append(basePackageName);
91         if ((schemaPath != null) && (schemaPath.getPath() != null)) {
92             final List<QName> pathToNode = schemaPath.getPath();
93             for (int i = 0; i < pathToNode.size(); ++i) {
94                 builder.append(".");
95                 String nodeLocalName = pathToNode.get(i).getLocalName();
96
97                 // TODO: create method
98                 nodeLocalName = nodeLocalName.replace(":", ".");
99                 nodeLocalName = nodeLocalName.replace("-", ".");
100                 builder.append(nodeLocalName);
101             }
102             return builder.toString();
103         }
104         return null;
105     }
106
107     private GeneratedType containerToGenType(ContainerSchemaNode container) {
108         if (container == null) {
109             return null;
110         }
111         final Set<DataSchemaNode> schemaNodes = container.getChildNodes();
112         final GeneratedTypeBuilder typeBuilder = addRawInterfaceDefinition(container);
113
114         for (final DataSchemaNode node : schemaNodes) {
115             if (node instanceof LeafSchemaNode) {
116                 resolveLeafSchemaNode(typeBuilder, (LeafSchemaNode) node);
117             } else if (node instanceof LeafListSchemaNode) {
118                 resolveLeafListSchemaNode(typeBuilder,
119                         (LeafListSchemaNode) node);
120
121             } else if (node instanceof ContainerSchemaNode) {
122                 resolveContainerSchemaNode(typeBuilder,
123                         (ContainerSchemaNode) node);
124             } else if (node instanceof ListSchemaNode) {
125                 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
126             }
127         }
128         return typeBuilder.toInstance();
129     }
130
131     private boolean resolveLeafSchemaNode(
132             final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode node) {
133         if ((node != null) && (typeBuilder != null)) {
134             final String nodeName = node.getQName().getLocalName();
135             String nodeDesc = node.getDescription();
136             if (nodeDesc == null) {
137                 nodeDesc = "";
138             }
139
140             if (nodeName != null) {
141                 final TypeDefinition<?> typeDef = node.getType();
142                 final Type javaType = typeProvider
143                         .javaTypeForSchemaDefinitionType(typeDef);
144
145                 constructGetter(typeBuilder, nodeName, nodeDesc, javaType);
146                 if (!node.isConfiguration()) {
147                     constructSetter(typeBuilder, nodeName, nodeDesc, javaType);
148                 }
149                 return true;
150             }
151         }
152         return false;
153     }
154
155     private boolean resolveLeafListSchemaNode(
156             final GeneratedTypeBuilder typeBuilder,
157             final LeafListSchemaNode node) {
158         if ((node != null) && (typeBuilder != null)) {
159             final String nodeName = node.getQName().getLocalName();
160             String nodeDesc = node.getDescription();
161             if (nodeDesc == null) {
162                 nodeDesc = "";
163             }
164
165             if (nodeName != null) {
166                 final TypeDefinition<?> type = node.getType();
167                 final Type listType = Types.listTypeFor(typeProvider
168                         .javaTypeForSchemaDefinitionType(type));
169
170                 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
171                 if (!node.isConfiguration()) {
172                     constructSetter(typeBuilder, nodeName, nodeDesc, listType);
173                 }
174                 return true;
175             }
176         }
177         return false;
178     }
179
180     private boolean resolveContainerSchemaNode(
181             final GeneratedTypeBuilder typeBuilder,
182             final ContainerSchemaNode node) {
183         if ((node != null) && (typeBuilder != null)) {
184             final String nodeName = node.getQName().getLocalName();
185
186             if (nodeName != null) {
187                 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
188                 constructGetter(typeBuilder, nodeName, "", rawGenType);
189
190                 return true;
191             }
192         }
193         return false;
194     }
195
196     private boolean resolveListSchemaNode(
197             final GeneratedTypeBuilder typeBuilder, final ListSchemaNode node) {
198         if ((node != null) && (typeBuilder != null)) {
199             final String nodeName = node.getQName().getLocalName();
200
201             if (nodeName != null) {
202                 final GeneratedTypeBuilder rawGenType = addRawInterfaceDefinition(node);
203                 constructGetter(typeBuilder, nodeName, "",
204                         Types.listTypeFor(rawGenType));
205                 if (!node.isConfiguration()) {
206                     constructSetter(typeBuilder, nodeName, "",
207                             Types.listTypeFor(rawGenType));
208                 }
209                 return true;
210             }
211         }
212         return false;
213     }
214
215     private GeneratedTypeBuilder addRawInterfaceDefinition(
216             final DataSchemaNode schemaNode) {
217         if (schemaNode == null) {
218             return null;
219         }
220
221         final String packageName = resolveGeneratedTypePackageName(schemaNode
222                 .getPath());
223         final String schemaNodeName = schemaNode.getQName().getLocalName();
224
225         if ((packageName != null) && (schemaNode != null)
226                 && (schemaNodeName != null)) {
227             final String genTypeName = CodeGeneratorHelper
228                     .parseToClassName(schemaNodeName);
229             final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(
230                     packageName, genTypeName);
231
232             if (!genTypeBuilders.containsKey(packageName)) {
233                 final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
234                 builders.put(genTypeName, newType);
235                 genTypeBuilders.put(packageName, builders);
236             } else {
237                 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders
238                         .get(packageName);
239                 if (!builders.containsKey(genTypeName)) {
240                     builders.put(genTypeName, newType);
241                 }
242             }
243
244             return newType;
245         }
246         return null;
247     }
248
249     private String getterMethodName(final String methodName) {
250         final StringBuilder method = new StringBuilder();
251         method.append("get");
252         method.append(CodeGeneratorHelper.parseToClassName(methodName));
253         return method.toString();
254     }
255
256     private String setterMethodName(final String methodName) {
257         final StringBuilder method = new StringBuilder();
258         method.append("set");
259         method.append(CodeGeneratorHelper.parseToClassName(methodName));
260         return method.toString();
261     }
262
263     private MethodSignatureBuilder constructGetter(
264             final GeneratedTypeBuilder interfaceBuilder,
265             final String schemaNodeName, final String comment,
266             final Type returnType) {
267         final MethodSignatureBuilder getMethod = interfaceBuilder
268                 .addMethod(getterMethodName(schemaNodeName));
269
270         getMethod.addComment(comment);
271         getMethod.addReturnType(returnType);
272
273         return getMethod;
274     }
275
276     private MethodSignatureBuilder constructSetter(
277             final GeneratedTypeBuilder interfaceBuilder,
278             final String schemaNodeName, final String comment,
279             final Type parameterType) {
280         final MethodSignatureBuilder setMethod = interfaceBuilder
281                 .addMethod(setterMethodName(schemaNodeName));
282
283         setMethod.addComment(comment);
284         setMethod.addParameter(parameterType,
285                 CodeGeneratorHelper.parseToParamName(schemaNodeName));
286         setMethod.addReturnType(Types.voidType());
287
288         return setMethod;
289     }
290
291     private boolean isCompositeKey(final String keyDefinition) {
292         if (keyDefinition.contains(" ")) {
293             return true;
294         }
295         return false;
296     }
297
298     private String resolveBasePackageName(final URI moduleNamespace,
299             final String yangVersion) {
300         final StringBuilder packageNameBuilder = new StringBuilder();
301
302         packageNameBuilder.append("com.cisco.yang.gen.v");
303         packageNameBuilder.append(yangVersion);
304         packageNameBuilder.append(".rev");
305         packageNameBuilder.append(calendar.get(Calendar.YEAR));
306         packageNameBuilder.append((calendar.get(Calendar.MONTH) + 1));
307         packageNameBuilder.append(calendar.get(Calendar.DAY_OF_MONTH));
308         packageNameBuilder.append(".");
309
310         String namespace = moduleNamespace.toString();
311         namespace = namespace.replace(":", ".");
312         namespace = namespace.replace("-", ".");
313
314         packageNameBuilder.append(namespace);
315
316         return packageNameBuilder.toString();
317     }
318
319     private GeneratedType listToGenType(ListSchemaNode list) {
320         if (list == null) {
321             return null;
322         }
323         final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(list);
324
325         final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
326         for (final DataSchemaNode node : schemaNodes) {
327             if (node instanceof LeafSchemaNode) {
328                 resolveLeafSchemaNode(typeBuilder, (LeafSchemaNode) node);
329             } else if (node instanceof LeafListSchemaNode) {
330                 resolveLeafListSchemaNode(typeBuilder,
331                         (LeafListSchemaNode) node);
332             } else if (node instanceof ContainerSchemaNode) {
333                 resolveContainerSchemaNode(typeBuilder,
334                         (ContainerSchemaNode) node);
335             } else if (node instanceof ListSchemaNode) {
336                 resolveListSchemaNode(typeBuilder, (ListSchemaNode) node);
337             }
338         }
339         return typeBuilder.toInstance();
340     }
341
342     private GeneratedTypeBuilder resolveListTypeBuilder(
343             final ListSchemaNode list) {
344         final String packageName = resolveGeneratedTypePackageName(list
345                 .getPath());
346         final String schemaNodeName = list.getQName().getLocalName();
347         final String genTypeName = CodeGeneratorHelper
348                 .parseToClassName(schemaNodeName);
349
350         GeneratedTypeBuilder typeBuilder = null;
351         if (genTypeBuilders.containsKey(packageName)) {
352             final Map<String, GeneratedTypeBuilder> builders = new HashMap<String, GeneratedTypeBuilder>();
353             typeBuilder = builders.get(genTypeName);
354
355             if (null == typeBuilder) {
356                 typeBuilder = addRawInterfaceDefinition(list);
357             }
358         }
359         return typeBuilder;
360     }
361
362     private void traverseModule(final Module module) {
363         final Set<DataSchemaNode> schemaNodes = module.getChildNodes();
364
365         for (DataSchemaNode node : schemaNodes) {
366             if (node instanceof ContainerSchemaNode) {
367                 schemaContainers.add((ContainerSchemaNode) node);
368                 traverse((ContainerSchemaNode) node);
369             }
370         }
371     }
372
373     private void traverse(final DataNodeContainer dataNode) {
374         if (!containChildDataNodeContainer(dataNode)) {
375             return;
376         }
377
378         final Set<DataSchemaNode> childs = dataNode.getChildNodes();
379         if (childs != null) {
380             for (DataSchemaNode childNode : childs) {
381                 if (childNode instanceof ContainerSchemaNode) {
382                     final ContainerSchemaNode container = (ContainerSchemaNode) childNode;
383                     schemaContainers.add(container);
384                     traverse(container);
385                 }
386
387                 if (childNode instanceof ListSchemaNode) {
388                     final ListSchemaNode list = (ListSchemaNode) childNode;
389                     schemaLists.add(list);
390                     traverse(list);
391                 }
392             }
393         }
394     }
395
396     /**
397      * Returns <code>true</code> if and only if the child node contain at least
398      * one child container schema node or child list schema node, otherwise will
399      * always returns <code>false</code>
400      * 
401      * @param container
402      * @return <code>true</code> if and only if the child node contain at least
403      *         one child container schema node or child list schema node,
404      *         otherwise will always returns <code>false</code>
405      */
406     private boolean containChildDataNodeContainer(
407             final DataNodeContainer container) {
408         if (container != null) {
409             final Set<DataSchemaNode> childs = container.getChildNodes();
410             if ((childs != null) && (childs.size() > 0)) {
411                 for (final DataSchemaNode childNode : childs) {
412                     if (childNode instanceof DataNodeContainer) {
413                         return true;
414                     }
415                 }
416             }
417         }
418         return false;
419     }
420 }