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