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