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