Added generation of Transfer Objects from Type Definitions.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / binding-generator-impl / src / main / java / org / opendaylight / controller / sal / binding / yang / types / TypeProviderImpl.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.yang.types;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15
16 import org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil;
17 import org.opendaylight.controller.binding.generator.util.Types;
18 import org.opendaylight.controller.binding.generator.util.generated.type.builder.EnumerationBuilderImpl;
19 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
20 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
21 import org.opendaylight.controller.sal.binding.model.api.Enumeration;
22 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
23 import org.opendaylight.controller.sal.binding.model.api.Type;
24 import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
25 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
26 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
27 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
28 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
29 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
30 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
31 import org.opendaylight.controller.yang.model.api.Module;
32 import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
33 import org.opendaylight.controller.yang.model.api.SchemaContext;
34 import org.opendaylight.controller.yang.model.api.TypeDefinition;
35 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
36 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
37 import org.opendaylight.controller.yang.model.api.type.IdentityrefTypeDefinition;
38 import org.opendaylight.controller.yang.model.api.type.LeafrefTypeDefinition;
39 import org.opendaylight.controller.yang.model.api.type.UnionTypeDefinition;
40 import org.opendaylight.controller.yang.model.util.ExtendedType;
41 import org.opendaylight.controller.yang.model.util.SchemaContextUtil;
42
43 public class TypeProviderImpl implements TypeProvider {
44
45     private final SchemaContext schemaContext;
46     private final SchemaContextUtil schemaContextUtil;
47     private Map<String, Map<String, GeneratedTransferObject>> generatedTypeDefinitions;
48     private final List<GeneratedTransferObject> generatedTypeDefs = new ArrayList<GeneratedTransferObject>();
49
50     public TypeProviderImpl(final SchemaContext schemaContext) {
51         if (schemaContext == null) {
52             throw new IllegalArgumentException("Schema Context cannot be null!");
53         }
54
55         this.schemaContext = schemaContext;
56         schemaContextUtil = new SchemaContextUtil(schemaContext);
57         this.generatedTypeDefinitions = new HashMap<String, Map<String, GeneratedTransferObject>>();
58
59         resolveTypeDefsFromContext();
60
61         final Set<String> moduleNames = generatedTypeDefinitions.keySet();
62
63         for (final String moduleName : moduleNames) {
64             generatedTypeDefs.addAll(generatedTypeDefinitions.get(moduleName)
65                     .values());
66         }
67     }
68
69     public List<GeneratedTransferObject> getGeneratedTypeDefs() {
70         return generatedTypeDefs;
71     }
72
73     /*
74      * (non-Javadoc)
75      * 
76      * @see org.opendaylight.controller.yang.model.type.provider.TypeProvider#
77      * javaTypeForYangType(java.lang.String)
78      */
79     @Override
80     public Type javaTypeForYangType(String type) {
81         Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
82                 .javaTypeForYangType(type);
83         return t;
84     }
85
86     @Override
87     public Type javaTypeForSchemaDefinitionType(
88             final TypeDefinition<?> typeDefinition) {
89         Type returnType = null;
90         if (typeDefinition != null) {
91             final String typedefName = typeDefinition.getQName().getLocalName();
92             if (typeDefinition instanceof ExtendedType) {
93                 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
94
95                 if (baseTypeDef instanceof LeafrefTypeDefinition) {
96                     final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) baseTypeDef;
97                     returnType = provideTypeForLeafref(leafref);
98                 } else if (baseTypeDef instanceof IdentityrefTypeDefinition) {
99
100                 } else if (baseTypeDef instanceof EnumTypeDefinition) {
101                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
102                     returnType = resolveEnumFromTypeDefinition(enumTypeDef,
103                             typedefName);
104                 } else {
105                     final Module module = schemaContextUtil
106                             .resolveModuleFromSchemaPath(typeDefinition
107                                     .getPath());
108
109                     if (module != null) {
110                         final Map<String, GeneratedTransferObject> genTOs = generatedTypeDefinitions
111                                 .get(module.getName());
112                         if (genTOs != null) {
113                             returnType = genTOs.get(typedefName);
114                         }
115                     }
116                 }
117             } else {
118                 if (typeDefinition instanceof LeafrefTypeDefinition) {
119                     final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
120                     returnType = provideTypeForLeafref(leafref);
121                 } else if (typeDefinition instanceof EnumTypeDefinition) {
122                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDefinition;
123                     returnType = resolveEnumFromTypeDefinition(enumTypeDef,
124                             typedefName);
125                 } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
126
127                 } else {
128                     returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
129                             .javaTypeForSchemaDefinitionType(typeDefinition);
130                 }
131             }
132
133             // if (typeDefinition instanceof Leafref) {
134             // final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition)
135             // typeDefinition;
136             // returnType = provideTypeForLeafref(leafref);
137             // } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
138             //
139             // } else if (typeDefinition instanceof ExtendedType) {
140             // final TypeDefinition<?> baseType = typeDefinition.getBaseType();
141             // return javaTypeForSchemaDefinitionType(baseType);
142             // } else {
143             // returnType = baseTypeForExtendedType(typeDefinition);
144             // }
145         }
146         return returnType;
147     }
148
149     private TypeDefinition<?> baseTypeDefForExtendedType(
150             final TypeDefinition<?> extendTypeDef) {
151         if (extendTypeDef != null) {
152             final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
153             if (baseTypeDef instanceof ExtendedType) {
154                 baseTypeDefForExtendedType(baseTypeDef);
155             } else {
156                 return baseTypeDef;
157             }
158         }
159         return null;
160     }
161
162     public Type baseTypeForExtendedType(final TypeDefinition<?> typeDefinition) {
163         Type returnType = null;
164         if (typeDefinition != null) {
165             final TypeDefinition<?> baseTypeDefinition = baseTypeDefForExtendedType(typeDefinition);
166
167             if (baseTypeDefinition instanceof EnumTypeDefinition) {
168                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDefinition;
169                 final String enumName = enumTypeDef.getQName().getLocalName();
170                 return resolveEnumFromTypeDefinition(enumTypeDef, enumName);
171             } else {
172                 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
173                         .javaTypeForSchemaDefinitionType(typeDefinition);
174             }
175
176             // if (typeDefinition instanceof ExtendedType) {
177             // final TypeDefinition<?> extType = typeDefinition.getBaseType();
178             // return baseTypeForExtendedType(extType);
179             // } else if (typeDefinition instanceof EnumerationType) {
180             // final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition)
181             // typeDefinition;
182             // final String enumName = enumTypeDef.getQName().getLocalName();
183             // return resolveEnumFromTypeDefinition(enumTypeDef, enumName);
184             // } else {
185             // returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
186             // .javaTypeForSchemaDefinitionType(typeDefinition);
187             // }
188         }
189         return returnType;
190     }
191
192     public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType) {
193         Type returnType = null;
194         if ((leafrefType != null) && (leafrefType.getPathStatement() != null)
195                 && (leafrefType.getPath() != null)) {
196
197             final RevisionAwareXPath xpath = leafrefType.getPathStatement();
198             final String strXPath = xpath.toString();
199
200             if (strXPath != null) {
201                 if (strXPath.matches(".*//[.* | .*//].*")) {
202                     returnType = Types.typeForClass(Object.class);
203                 } else {
204                     final Module module = schemaContextUtil
205                             .resolveModuleFromSchemaPath(leafrefType.getPath());
206                     if (module != null) {
207                         final DataSchemaNode dataNode;
208                         if (xpath.isAbsolute()) {
209                             dataNode = schemaContextUtil.findDataSchemaNode(
210                                     module, xpath);
211                         } else {
212                             dataNode = schemaContextUtil
213                                     .findDataSchemaNodeForRelativeXPath(module,
214                                             leafrefType, xpath);
215                         }
216                         returnType = resolveTypeFromDataSchemaNode(dataNode);
217                     }
218                 }
219             }
220         }
221         return returnType;
222     }
223
224     private EnumBuilder resolveEnumFromTypeDefinition(
225             final EnumTypeDefinition enumTypeDef, final String enumName,
226             final GeneratedTypeBuilder typeBuilder) {
227         if ((enumTypeDef != null) && (typeBuilder != null)
228                 && (enumTypeDef.getQName() != null)
229                 && (enumTypeDef.getQName().getLocalName() != null)) {
230
231             final String enumerationName = BindingGeneratorUtil
232                     .parseToClassName(enumName);
233             final EnumBuilder enumBuilder = typeBuilder
234                     .addEnumeration(enumerationName);
235
236             if (enumBuilder != null) {
237                 final List<EnumPair> enums = enumTypeDef.getValues();
238                 if (enums != null) {
239                     int listIndex = 0;
240                     for (final EnumPair enumPair : enums) {
241                         if (enumPair != null) {
242                             final String enumPairName = BindingGeneratorUtil
243                                     .parseToClassName(enumPair.getName());
244                             Integer enumPairValue = enumPair.getValue();
245
246                             if (enumPairValue == null) {
247                                 enumPairValue = listIndex;
248                             }
249                             enumBuilder.addValue(enumPairName, enumPairValue);
250                             listIndex++;
251                         }
252                     }
253                 }
254                 return enumBuilder;
255             }
256         }
257         return null;
258     }
259
260     private Enumeration resolveEnumFromTypeDefinition(
261             final EnumTypeDefinition enumTypeDef, final String enumName) {
262         if ((enumTypeDef != null) && (enumTypeDef.getQName() != null)
263                 && (enumTypeDef.getQName().getLocalName() != null)) {
264
265             final String enumerationName = BindingGeneratorUtil
266                     .parseToClassName(enumName);
267
268             Module module = schemaContextUtil
269                     .resolveModuleFromSchemaPath(enumTypeDef.getPath());
270             final String basePackageName = BindingGeneratorUtil
271                     .moduleNamespaceToPackageName(module.getNamespace(),
272                             module.getYangVersion());
273             final String packageName = BindingGeneratorUtil
274                     .packageNameForGeneratedType(basePackageName,
275                             enumTypeDef.getPath());
276
277             final EnumBuilder enumBuilder = new EnumerationBuilderImpl(
278                     packageName, enumerationName);
279
280             if (enumBuilder != null) {
281                 final List<EnumPair> enums = enumTypeDef.getValues();
282                 if (enums != null) {
283                     int listIndex = 0;
284                     for (final EnumPair enumPair : enums) {
285                         if (enumPair != null) {
286                             final String enumPairName = BindingGeneratorUtil
287                                     .parseToClassName(enumPair.getName());
288                             Integer enumPairValue = enumPair.getValue();
289
290                             if (enumPairValue == null) {
291                                 enumPairValue = listIndex;
292                             }
293                             enumBuilder.addValue(enumPairName, enumPairValue);
294                             listIndex++;
295                         }
296                     }
297                 }
298                 return enumBuilder.toInstance(null);
299             }
300         }
301         return null;
302     }
303
304     private Type resolveTypeFromDataSchemaNode(final DataSchemaNode dataNode) {
305         Type returnType = null;
306         if (dataNode != null) {
307             if (dataNode instanceof LeafSchemaNode) {
308                 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
309                 returnType = javaTypeForSchemaDefinitionType(leaf.getType());
310             } else if (dataNode instanceof LeafListSchemaNode) {
311                 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
312                 returnType = javaTypeForSchemaDefinitionType(leafList.getType());
313             }
314         }
315         return returnType;
316     }
317
318     private void resolveTypeDefsFromContext() {
319         final Set<Module> modules = schemaContext.getModules();
320         if (modules != null) {
321             for (final Module module : modules) {
322                 if (module != null) {
323                     final String basePackageName = BindingGeneratorUtil
324                             .moduleNamespaceToPackageName(
325                                     module.getNamespace(),
326                                     module.getYangVersion());
327
328                     final Set<TypeDefinition<?>> typeDefinitions = module
329                             .getTypeDefinitions();
330
331                     if ((typeDefinitions != null) && (basePackageName != null)) {
332                         for (final TypeDefinition<?> typedef : typeDefinitions) {
333                             addGeneratedTypeDefinition(basePackageName,
334                                     module.getName(), typedef);
335                         }
336                         // for (final TypeDefinition<?> typedef :
337                         // typeDefinitions) {
338                         // addUnionGeneratedTypeDefinition(basePackageName,
339                         // module.getName(), typedef);
340                         // }
341                     }
342                 }
343             }
344         }
345     }
346
347     private void addGeneratedTypeDefinition(final String basePackageName,
348             final String moduleName, final TypeDefinition<?> typedef) {
349         if ((basePackageName != null) && (moduleName != null)
350                 && (typedef != null) && (typedef.getQName() != null)) {
351             final GeneratedTOBuilder genTO = typedefToTransferObject(
352                     basePackageName, typedef);
353
354             final String propertyName = BindingGeneratorUtil
355                     .parseToValidParamName(typedef.getQName().getLocalName());
356
357             final TypeDefinition<?> baseTypeDefinition = baseTypeDefForExtendedType(typedef);
358             if (!(baseTypeDefinition instanceof LeafrefTypeDefinition)
359                     && !(baseTypeDefinition instanceof IdentityrefTypeDefinition)) {
360                 Type returnType = null;
361                 if (baseTypeDefinition instanceof EnumTypeDefinition) {
362                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDefinition;
363                     final String enumName = typedef.getQName().getLocalName();
364                     returnType = resolveEnumFromTypeDefinition(enumTypeDef,
365                             enumName);
366                 } else {
367                     returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
368                             .javaTypeForSchemaDefinitionType(baseTypeDefinition);
369                 }
370
371                 if (returnType != null) {
372                     final GeneratedPropertyBuilder genPropBuilder = genTO
373                             .addProperty(propertyName);
374                             
375                     genPropBuilder.addReturnType(returnType);
376                     genTO.addEqualsIdentity(genPropBuilder);
377                     genTO.addHashIdentity(genPropBuilder);
378                     genTO.addToStringProperty(genPropBuilder);
379                     
380                     Map<String, GeneratedTransferObject> genTOsMap = generatedTypeDefinitions
381                             .get(moduleName);
382                     if (genTOsMap == null) {
383                         genTOsMap = new HashMap<String, GeneratedTransferObject>();
384                         generatedTypeDefinitions.put(moduleName, genTOsMap);
385                     }
386                     genTOsMap.put(typedef.getQName().getLocalName(),
387                             genTO.toInstance());
388                 }
389             }
390         }
391     }
392
393     private void addUnionGeneratedTypeDefinition(final String basePackageName,
394             final String moduleName, final TypeDefinition<?> typedef) {
395         if ((basePackageName != null) && (moduleName != null)
396                 && (typedef != null) && (typedef.getQName() != null)) {
397             final TypeDefinition<?> baseTypeDefinition = baseTypeDefForExtendedType(typedef);
398
399             if ((baseTypeDefinition != null)
400                     && (baseTypeDefinition instanceof UnionTypeDefinition)) {
401                 final UnionTypeDefinition unionTypeDef = (UnionTypeDefinition) baseTypeDefinition;
402
403                 final List<TypeDefinition<?>> unionTypes = unionTypeDef
404                         .getTypes();
405                 final Map<String, GeneratedTransferObject> genTOsMap = generatedTypeDefinitions
406                         .get(moduleName);
407                 final GeneratedTOBuilder unionGenTransObject = typedefToTransferObject(
408                         basePackageName, typedef);
409                 if ((unionTypes != null) && (genTOsMap != null)
410                         && (unionGenTransObject != null)) {
411                     for (final TypeDefinition<?> unionType : unionTypes) {
412                         final String typeName = unionType.getQName()
413                                 .getLocalName();
414                         final GeneratedTransferObject genTransferObject = genTOsMap
415                                 .get(typeName);
416
417                         if (genTransferObject != null) {
418                             unionGenTransObject
419                                     .addProperty(
420                                             BindingGeneratorUtil
421                                                     .parseToValidParamName(genTransferObject
422                                                             .getName()))
423                                     .addReturnType(genTransferObject);
424                         }
425                     }
426                     genTOsMap.put(unionTypeDef.getQName().getLocalName(),
427                             unionGenTransObject.toInstance());
428                 }
429             }
430         }
431     }
432
433     private GeneratedTOBuilder typedefToTransferObject(
434             final String basePackageName, final TypeDefinition<?> typedef) {
435
436         final String packageName = BindingGeneratorUtil
437                 .packageNameForGeneratedType(basePackageName, typedef.getPath());
438         final String typeDefTOName = typedef.getQName().getLocalName();
439
440         if ((packageName != null) && (typedef != null)
441                 && (typeDefTOName != null)) {
442             final String genTOName = BindingGeneratorUtil
443                     .parseToClassName(typeDefTOName);
444             final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
445                     packageName, genTOName);
446
447             return newType;
448         }
449         return null;
450     }
451 }