Bug 6859 - Binding generator v1 refactoring
[controller.git] / opendaylight / config / yang-jmx-generator / src / main / java / org / opendaylight / controller / config / yangjmxgenerator / attribute / JavaAttribute.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.config.yangjmxgenerator.attribute;
9
10 import com.google.common.base.Preconditions;
11 import java.util.Arrays;
12 import java.util.List;
13 import javax.management.openmbean.ArrayType;
14 import javax.management.openmbean.CompositeType;
15 import javax.management.openmbean.OpenDataException;
16 import javax.management.openmbean.OpenType;
17 import javax.management.openmbean.SimpleType;
18 import org.opendaylight.controller.config.api.IdentityAttributeRef;
19 import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
20 import org.opendaylight.mdsal.binding.model.api.Type;
21 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.util.type.CompatUtils;
28
29 public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
30
31     public static final String DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION = "valueOfArtificialUnionProperty";
32
33     private final Type type;
34     private final String nullableDescription, nullableDefault, nullableDefaultWrappedForCode;
35     private final TypeProviderWrapper typeProviderWrapper;
36     private final TypeDefinition<?> typeDefinition;
37
38     public JavaAttribute(final LeafSchemaNode leaf,
39             final TypeProviderWrapper typeProviderWrapper) {
40         super(leaf);
41         this.type = typeProviderWrapper.getType(leaf);
42
43         this.typeDefinition = CompatUtils.compatLeafType(leaf);
44         this.typeProviderWrapper = typeProviderWrapper;
45         this.nullableDefault = leaf.getDefault();
46         this.nullableDefaultWrappedForCode = leaf.getDefault() == null ? null : typeProviderWrapper.getDefault(leaf);
47         this.nullableDescription = leaf.getDescription();
48     }
49
50     public JavaAttribute(final LeafListSchemaNode leaf,
51             final TypeProviderWrapper typeProviderWrapper) {
52         super(leaf);
53         this.type = typeProviderWrapper.getType(leaf);
54         this.typeDefinition = leaf.getType();
55         this.typeProviderWrapper = typeProviderWrapper;
56         this.nullableDefault = this.nullableDefaultWrappedForCode = null;
57         this.nullableDescription = leaf.getDescription();
58     }
59
60     public boolean isUnion() {
61         final TypeDefinition<?> base = getBaseType(this.typeProviderWrapper, this.typeDefinition);
62         return base instanceof UnionTypeDefinition;
63     }
64
65     public boolean isEnum() {
66         final TypeDefinition<?> base = getBaseType(this.typeProviderWrapper, this.typeDefinition);
67         return base instanceof EnumTypeDefinition;
68     }
69
70     public TypeDefinition<?> getTypeDefinition() {
71         return this.typeDefinition;
72     }
73
74     /**
75      * Returns the most base type
76      */
77     private TypeDefinition<?> getBaseType(final TypeProviderWrapper typeProviderWrapper, TypeDefinition<?> baseType) {
78         while(baseType.getBaseType()!=null) {
79             baseType = baseType.getBaseType();
80         }
81         return baseType;
82     }
83
84     public String getNullableDefaultWrappedForCode() {
85         return this.nullableDefaultWrappedForCode;
86     }
87
88     @Override
89     public Type getType() {
90         return this.type;
91     }
92
93     @Override
94     public String getNullableDescription() {
95         return this.nullableDescription;
96     }
97
98     @Override
99     public String getNullableDefault() {
100         return this.nullableDefault;
101     }
102
103     @Override
104     public boolean equals(final Object o) {
105         if (this == o) {
106             return true;
107         }
108         if ((o == null) || (getClass() != o.getClass())) {
109             return false;
110         }
111         if (!super.equals(o)) {
112             return false;
113         }
114
115         final JavaAttribute that = (JavaAttribute) o;
116
117         if (this.nullableDefault != null ? !this.nullableDefault
118                 .equals(that.nullableDefault) : that.nullableDefault != null) {
119             return false;
120         }
121         if (this.nullableDescription != null ? !this.nullableDescription
122                 .equals(that.nullableDescription)
123                 : that.nullableDescription != null) {
124             return false;
125         }
126         if (this.type != null ? !this.type.equals(that.type) : that.type != null) {
127             return false;
128         }
129
130         return true;
131     }
132
133     @Override
134     public int hashCode() {
135         int result = super.hashCode();
136         result = (31 * result) + (this.type != null ? this.type.hashCode() : 0);
137         result = (31
138                 * result)
139                 + (this.nullableDescription != null ? this.nullableDescription.hashCode()
140                         : 0);
141         result = (31 * result)
142                 + (this.nullableDefault != null ? this.nullableDefault.hashCode() : 0);
143         return result;
144     }
145
146     @Override
147     public String toString() {
148         return "JavaAttribute{" + getAttributeYangName() + "," + "type=" + this.type
149                 + '}';
150     }
151
152     @Override
153     public OpenType<?> getOpenType() {
154         final TypeDefinition<?> baseTypeDefinition = getBaseType(this.typeProviderWrapper, this.typeDefinition);
155         final Type baseType = this.typeProviderWrapper.getType(baseTypeDefinition, baseTypeDefinition);
156
157         if (isArray()) {
158             return getArrayType();
159         } else if (isEnum()) {
160             return getEnumType(baseTypeDefinition);
161         } else if (isUnion()) {
162             return getCompositeTypeForUnion(baseTypeDefinition);
163         } else if (isDerivedType(baseType, getType())) {
164             return getCompositeType(baseType, baseTypeDefinition);
165         } else if (isIdentityRef()) {
166             return getCompositeTypeForIdentity();
167         }
168
169         return getSimpleType(getType());
170     }
171
172     private OpenType<?> getEnumType(final TypeDefinition<?> baseType) {
173         final String fullyQualifiedName = this.typeProviderWrapper.getType(this.node, getTypeDefinition()).getFullyQualifiedName();
174         final String[] items = {"instance"};
175         final String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
176
177         try {
178             return new CompositeType(fullyQualifiedName, description, items, items, new OpenType[]{SimpleType.STRING});
179         } catch (final OpenDataException e) {
180             throw new RuntimeException("Unable to create enum type" + fullyQualifiedName + " as open type", e);
181         }
182     }
183
184     public boolean isIdentityRef() {
185         return this.typeDefinition instanceof IdentityrefTypeDefinition;
186     }
187
188     private OpenType<?> getCompositeTypeForUnion(final TypeDefinition<?> baseTypeDefinition) {
189         Preconditions.checkArgument(baseTypeDefinition instanceof UnionTypeDefinition,
190                 "Expected %s instance but was %s", UnionTypeDefinition.class, baseTypeDefinition);
191
192         final List<TypeDefinition<?>> types = ((UnionTypeDefinition) baseTypeDefinition).getTypes();
193
194         final String[] itemNames = new String[types.size()+1];
195         final OpenType<?>[] itemTypes = new OpenType[itemNames.length];
196
197         addArtificialPropertyToUnionCompositeType(baseTypeDefinition, itemNames, itemTypes);
198
199         final String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
200
201         int i = 1;
202         for (final TypeDefinition<?> innerTypeDefinition : types) {
203
204             final Type innerType = this.typeProviderWrapper.getType(innerTypeDefinition, innerTypeDefinition);
205
206             final TypeDefinition<?> baseInnerTypeDefinition = getBaseType(this.typeProviderWrapper, innerTypeDefinition);
207             final Type innerTypeBaseType = this.typeProviderWrapper.getType(baseInnerTypeDefinition, baseInnerTypeDefinition);
208
209             OpenType<?> innerCompositeType;
210
211             if(isDerivedType(innerTypeBaseType, innerType)) {
212                 innerCompositeType = baseInnerTypeDefinition instanceof UnionTypeDefinition ?
213                         getCompositeTypeForUnion(baseInnerTypeDefinition) :
214                         getCompositeType(innerTypeBaseType, baseInnerTypeDefinition);
215             } else {
216                 innerCompositeType = SimpleTypeResolver.getSimpleType(innerType);
217             }
218
219             itemNames[i] = this.typeProviderWrapper.getJMXParamForUnionInnerType(innerTypeDefinition);
220             itemTypes[i++] = innerCompositeType;
221         }
222
223         final String[] descriptions = itemNames.clone();
224         descriptions[0] = DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION;
225
226         try {
227             return new CompositeType(getUpperCaseCammelCase(), description, itemNames, descriptions, itemTypes);
228         } catch (final OpenDataException e) {
229             throw new RuntimeException("Unable to create " + CompositeType.class + " with inner elements "
230                     + Arrays.toString(itemTypes), e);
231         }
232     }
233
234     public static final Class<Character> TYPE_OF_ARTIFICIAL_UNION_PROPERTY = char.class;
235
236     private void addArtificialPropertyToUnionCompositeType(final TypeDefinition<?> baseTypeDefinition, final String[] itemNames, final OpenType<?>[] itemTypes) {
237         final String artificialPropertyName = this.typeProviderWrapper.getJMXParamForBaseType(baseTypeDefinition);
238         itemNames[0] = artificialPropertyName;
239
240         final OpenType<?> artificialPropertyType = getArrayOpenTypeForSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName(),
241                 SimpleTypeResolver.getSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName()));
242         itemTypes[0] = artificialPropertyType;
243     }
244
245     private OpenType<?> getSimpleType(final Type type) {
246         final SimpleType<?> simpleType = SimpleTypeResolver.getSimpleType(type);
247         return simpleType;
248     }
249
250     private OpenType<?> getCompositeType(final Type baseType, final TypeDefinition<?> baseTypeDefinition) {
251
252         final SimpleType<?> innerItemType = SimpleTypeResolver.getSimpleType(baseType);
253         final String innerItemName = this.typeProviderWrapper.getJMXParamForBaseType(baseTypeDefinition);
254
255         final String[] itemNames = new String[]{innerItemName};
256         final String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
257
258         final OpenType<?>[] itemTypes = new OpenType[]{innerItemType};
259         try {
260             return new CompositeType(getUpperCaseCammelCase(), description, itemNames, itemNames, itemTypes);
261         } catch (final OpenDataException e) {
262             throw new RuntimeException("Unable to create " + CompositeType.class + " with inner element of type "
263                     + itemTypes, e);
264         }
265     }
266
267     public OpenType<?> getCompositeTypeForIdentity() {
268         final String[] itemNames = new String[]{IdentityAttributeRef.QNAME_ATTR_NAME};
269         final String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
270         final OpenType<?>[] itemTypes = new OpenType[]{SimpleType.STRING};
271
272         try {
273             return new CompositeType(getUpperCaseCammelCase(), description, itemNames, itemNames, itemTypes);
274         } catch (final OpenDataException e) {
275             throw new RuntimeException("Unable to create " + CompositeType.class + " with inner element of type "
276                     + itemTypes, e);
277         }
278     }
279
280     private OpenType<?> getArrayType() {
281         final String innerTypeFullyQName = getInnerType(getType());
282         final SimpleType<?> innerSimpleType = SimpleTypeResolver.getSimpleType(innerTypeFullyQName);
283         return getArrayOpenTypeForSimpleType(innerTypeFullyQName, innerSimpleType);
284     }
285
286     private OpenType<?> getArrayOpenTypeForSimpleType(final String innerTypeFullyQName, final SimpleType<?> innerSimpleType) {
287         try {
288             final ArrayType<Object> arrayType = isPrimitive(innerTypeFullyQName) ? new ArrayType<>(innerSimpleType, true)
289                     : new ArrayType<>(1, innerSimpleType);
290             return arrayType;
291         } catch (final OpenDataException e) {
292             throw new RuntimeException("Unable to create " + ArrayType.class + " with inner element of type "
293                     + innerSimpleType, e);
294         }
295     }
296
297     // TODO verify
298     private boolean isPrimitive(final String innerTypeFullyQName) {
299         if (innerTypeFullyQName.contains(".")) {
300             return false;
301         }
302
303         return true;
304     }
305
306     private boolean isArray() {
307         return this.type.getName().endsWith("[]");
308     }
309
310     private boolean isDerivedType(final Type baseType, final Type currentType) {
311         return baseType.equals(currentType) == false;
312     }
313
314     private static String getInnerType(final Type type) {
315         final String fullyQualifiedName = type.getFullyQualifiedName();
316         return fullyQualifiedName.substring(0, fullyQualifiedName.length() - 2);
317     }
318
319 }