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