blob: b81743b7258f06af15b9a08baae662499962f6eb [file] [log] [blame]
janani b05614f12016-10-04 12:55:43 +05301/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.yms.app.ytb;
18
19import org.onosproject.yangutils.datamodel.YangAugment;
20import org.onosproject.yangutils.datamodel.YangCase;
21import org.onosproject.yangutils.datamodel.YangLeafRef;
22import org.onosproject.yangutils.datamodel.YangNode;
23import org.onosproject.yangutils.datamodel.YangNotification;
24import org.onosproject.yangutils.datamodel.YangOutput;
25import org.onosproject.yangutils.datamodel.YangRpc;
26import org.onosproject.yangutils.datamodel.YangType;
27import org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes;
28import org.onosproject.yangutils.translator.tojava.javamodel.JavaLeafInfoContainer;
29import org.onosproject.yms.app.utils.TraversalType;
30import org.onosproject.yms.app.ysr.YangSchemaRegistry;
31import org.onosproject.yms.ydt.YdtContextOperationType;
32
33import java.lang.reflect.InvocationTargetException;
34import java.lang.reflect.Method;
35import java.util.Arrays;
36import java.util.Base64;
37import java.util.HashSet;
38import java.util.List;
39import java.util.Set;
40
41import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_AUGMENT_NODE;
42import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_MULTI_INSTANCE_NODE;
43import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.BOOLEAN;
44import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.DECIMAL64;
45import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.EMPTY;
46import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT16;
47import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT32;
48import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT64;
49import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT8;
50import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.LEAFREF;
51import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT16;
52import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT32;
53import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT64;
54import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT8;
55import static org.onosproject.yms.app.utils.TraversalType.PARENT;
56
57/**
58 * Representation of utility for YANG tree builder.
59 */
60public final class YtbUtil {
61
62 /**
63 * Static attribute for string value having null.
64 */
65 public static final String STR_NULL = "null";
66
67 /**
68 * Static attribute for a dot string.
69 */
70 public static final String PERIOD = ".";
71
72 private static final int ONE = 1;
73 private static final String SCHEMA_NAME_IN_ENUM = "schemaName";
74 private static final String OPERATION_TYPE = "onosYangNodeOperationType";
75 private static final String STR_NONE = "NONE";
76 private static final String EQUALS = "=";
77 private static final String ENUM_LEAF_IDENTIFIER = "$LeafIdentifier";
78 private static final char CLOSE_BRACE = '}';
79 private static final Set<YangDataTypes> PRIMITIVE_TYPES =
80 new HashSet<>(Arrays.asList(INT8, INT16, INT32, INT64, UINT8,
81 UINT16, UINT32, UINT64, DECIMAL64,
82 BOOLEAN, EMPTY));
83
84 // No instantiation.
85 private YtbUtil() {
86 }
87
88 /**
89 * Returns the object of the node from the node info. Getting object for
90 * augment and case differs from other node.
91 *
92 * @param nodeInfo node info of the holder
93 * @param yangNode YANG node of the holder
94 * @return object of the parent
95 */
96 public static Object getParentObjectOfNode(YtbNodeInfo nodeInfo,
97 YangNode yangNode) {
98 Object object;
99 if (yangNode instanceof YangCase) {
100 object = nodeInfo.getCaseObject();
101 } else if (yangNode instanceof YangAugment) {
102 object = nodeInfo.getAugmentObject();
103 } else {
104 object = nodeInfo.getYangObject();
105 }
106 return object;
107 }
108
109 /**
110 * Returns the capital cased first letter of the given string.
111 *
112 * @param name string to be capital cased
113 * @return capital cased string
114 */
115 public static String getCapitalCase(String name) {
116 // TODO: It will be removed if common util is committed.
117 return name.substring(0, 1).toUpperCase() +
118 name.substring(1);
119 }
120
121 /**
122 * Returns the value of an attribute, in a class object. The attribute
123 * name is taken from the YANG node java name.
124 *
125 * @param nodeObj object of the node
126 * @param fieldName name of the attribute
127 * @return object of the attribute
128 * @throws NoSuchMethodException method not found exception
129 */
130 public static Object getAttributeOfObject(Object nodeObj, String fieldName)
131 throws NoSuchMethodException {
132 Class<?> nodeClass = nodeObj.getClass();
133 Method getterMethod;
134 try {
135 getterMethod = nodeClass.getDeclaredMethod(fieldName);
136 return getterMethod.invoke(nodeObj);
137 } catch (InvocationTargetException | IllegalAccessException e) {
138 throw new YtbException(e);
139 }
140 }
141
142 /**
143 * Returns the object of the declared method in parent class by invoking
144 * through the child class object.
145 *
146 * @param parentClass parent class of the declared method
147 * @param childClass child class which inherits the parent class
148 * @param methodName name of the declared method
149 * @return value of the method
150 */
151 public static Object getAttributeFromInheritance(
152 Class<?> parentClass, Object childClass, String methodName) {
153 Method getterMethod;
154 try {
155 getterMethod = parentClass.getDeclaredMethod(methodName);
156 return getterMethod.invoke(childClass);
157 } catch (InvocationTargetException | NoSuchMethodException |
158 IllegalAccessException e) {
159 throw new YtbException(e);
160 }
161 }
162
163 /**
164 * Returns interface class from an implementation class object.
165 *
166 * @param implClassObj implementation class object
167 * @return interface class
168 */
169 public static Class<?> getInterfaceClassFromImplClass(Object implClassObj) {
170 Class<?> implClass = implClassObj.getClass();
171 Class<?>[] interfaces = implClass.getInterfaces();
172 if (interfaces.length > ONE) {
173 // TODO: Need to handle when impl class has more than one interface.
174 throw new YtbException("Implementation class having more than one" +
175 " interface is not handled");
176 }
177 return interfaces[0];
178 }
179
180 /**
181 * Returns the operation type value for a class object. If the operation
182 * type is not set, then none type is returned.
183 *
184 * @param nodeObj node object
185 * @return operation type of the class
186 */
187 public static YdtContextOperationType getOperationTypeOfTheNode(
188 Object nodeObj) {
189 Object opTypeObj;
190 try {
191 opTypeObj = getAttributeOfObject(nodeObj, OPERATION_TYPE);
192 } catch (NoSuchMethodException e) {
193 return YdtContextOperationType.valueOf(STR_NONE);
194 }
195 String opTypeValue = String.valueOf(opTypeObj);
196 if (opTypeValue.equals(STR_NULL)) {
197 opTypeValue = STR_NONE;
198 }
199 return YdtContextOperationType.valueOf(opTypeValue);
200 }
201
202 /**
203 * Returns true, if data type of leaf is primitive data type; false
204 * otherwise.
205 *
206 * @param yangType leaf type
207 * @return true if data type is primitive; false otherwise
208 */
209 public static boolean isTypePrimitive(YangType yangType) {
210 if (yangType.getDataType() == LEAFREF) {
211 YangLeafRef leafRef =
212 (YangLeafRef) yangType.getDataTypeExtendedInfo();
213 return isPrimitiveDataType(leafRef.getEffectiveDataType()
214 .getDataType());
215 }
216 return isPrimitiveDataType(yangType.getDataType());
217 }
218
219 /**
220 * Returns the registered class from the YSR of the module node where
221 * augment is present.
222 *
223 * @param curNode current augment node
224 * @param registry schema registry
225 * @return class loader of module
226 */
227 public static Class<?> getClassLoaderForAugment(
228 YangNode curNode, YangSchemaRegistry registry) {
229 YangNode moduleNode = curNode.getParent();
230 String moduleName = moduleNode.getJavaClassNameOrBuiltInType();
231 String modulePackage = moduleNode.getJavaPackage();
sonu guptaeff184b2016-11-24 12:43:49 +0530232 return registry.getRegisteredClass(moduleNode
233 );
janani b05614f12016-10-04 12:55:43 +0530234 }
235
236 /**
237 * Returns the string true, if the leaf data is actually set; false
238 * otherwise.
239 *
240 * @param nodeObj object if the node
241 * @param javaName java name of the leaf
242 * @param methodName getter method name
243 * @return string value of the boolean method
244 */
245 public static String isValueOrSelectLeafSet(
246 Object nodeObj, String javaName, String methodName) {
247
248 Class<?> nodeClass = nodeObj.getClass();
249 Class<?> interfaceClass = getInterfaceClassFromImplClass(nodeObj);
250
251 // Appends the enum inner package to the interface class package.
252 String enumPackage = interfaceClass.getName() + ENUM_LEAF_IDENTIFIER;
253
254 ClassLoader classLoader = interfaceClass.getClassLoader();
255 Class leafEnum;
256 try {
257 leafEnum = classLoader.loadClass(enumPackage);
258 Method getterMethod = nodeClass.getMethod(methodName, leafEnum);
259 // Gets the value of the enum.
260 Enum<?> value = Enum.valueOf(leafEnum, javaName.toUpperCase());
261 // Invokes the method with the value of enum as param.
262 return String.valueOf(getterMethod.invoke(nodeObj, value));
263 } catch (IllegalAccessException | InvocationTargetException |
264 NoSuchMethodException | ClassNotFoundException e) {
265 throw new YtbException(e);
266 }
267 }
268
269 /**
270 * Returns the string value from the respective data types of the
271 * leaf/leaf-list.
272 * // TODO: Remove this method and append to the data model utils.
273 *
274 * @param fieldObj object of the leaf/leaf-list field
275 * @param dataType type of the leaf/leaf-list
276 * @return string value from the type
277 */
278 public static String getStringFromDataType(Object fieldObj,
279 YangType dataType) {
280 YangDataTypes type = dataType.getDataType();
281 switch (type) {
282 case INT8:
283 case INT16:
284 case INT32:
285 case INT64:
286 case UINT8:
287 case UINT16:
288 case UINT32:
289 case UINT64:
290 case EMPTY:
291 case IDENTITYREF:
292 case STRING:
293 case DECIMAL64:
294 case INSTANCE_IDENTIFIER:
295 case DERIVED:
296 case UNION:
297 //TODO: Generated code has to be changed, it must select
298 // the setting leaf and it must give back the corresponding
299 // toString of that type.
300 case BOOLEAN:
301 case BITS:
302 return getValueFromToStringHelper(String.valueOf(fieldObj));
303
304 case BINARY:
305 return Base64.getEncoder().encodeToString((byte[]) fieldObj);
306
307 case LEAFREF:
308 YangLeafRef leafRef =
309 (YangLeafRef) dataType.getDataTypeExtendedInfo();
310 return getStringFromDataType(fieldObj,
311 leafRef.getEffectiveDataType());
312
313 case ENUMERATION:
314 Object value;
315 try {
316 value = getAttributeOfObject(fieldObj, SCHEMA_NAME_IN_ENUM);
317 } catch (NoSuchMethodException e) {
318 throw new YtbException(e);
319 }
320 return getValueFromToStringHelper(String.valueOf(value));
321
322 default:
323 throw new YtbException("Unsupported data type. Cannot be " +
324 "processed.");
325 }
326 }
327
328 /**
329 * Returns the value, from the toString value which uses toStringHelper.
330 * It gives values in non-usable format(e.g., {value = 5}). But the value
331 * that has to be returned is only 5.So it parses the string and returns
332 * only the value. In certain toString, to string helper is not used, so
333 * the original value is sent without parsing.
334 *
335 * @param rawString raw string
336 * @return parsed value
337 */
338 private static String getValueFromToStringHelper(String rawString) {
339 if (rawString.contains(EQUALS)) {
340 int index = rawString.lastIndexOf(EQUALS);
341 int braceIndex = rawString.indexOf(CLOSE_BRACE);
342 if (index != -1) {
343 return rawString.substring(index + 1, braceIndex);
344 }
345 }
346 return rawString;
347 }
348
349 /**
350 * Returns true, if the data type is primitive; false otherwise.
351 *
352 * @param dataType data type
353 * @return true if the data type is primitive; false otherwise
354 */
355 private static boolean isPrimitiveDataType(YangDataTypes dataType) {
356 return PRIMITIVE_TYPES.contains(dataType);
357 }
358
359 /**
360 * Returns true, if processing of the node is not required; false otherwise.
361 * For the nodes such as notification, RPC, augment there is a different
362 * flow, so these nodes are skipped in normal conditions.
363 *
364 * @param yangNode node to be checked
365 * @return true if node processing is not required; false otherwise.
366 */
367 public static boolean isNonProcessableNode(YangNode yangNode) {
368 return yangNode != null && (yangNode instanceof YangNotification) ||
369 (yangNode instanceof YangRpc) || (yangNode instanceof YangAugment);
370 }
371
372 /**
373 * Returns true, if multi instance node; false otherwise.
374 *
375 * @param yangNode YANG node
376 * @return true, if multi instance node; false otherwise.
377 */
378 public static boolean isMultiInstanceNode(YangNode yangNode) {
379 return yangNode.getYangSchemaNodeType() == YANG_MULTI_INSTANCE_NODE;
380 }
381
382 /**
383 * Returns true, if augment node; false otherwise.
384 *
385 * @param yangNode YANG node
386 * @return true, if augment node; false otherwise.
387 */
388 public static boolean isAugmentNode(YangNode yangNode) {
389 return yangNode.getYangSchemaNodeType() == YANG_AUGMENT_NODE;
390 }
391
392 /**
393 * Returns string for throwing error when empty object is given as input
394 * to YTB.
395 *
396 * @param objName name of the object
397 * @return error message
398 */
399 public static String emptyObjErrMsg(String objName) {
400 return "The " + objName + " given for tree creation cannot be null";
401 }
402
403 /**
404 * Returns the java name for the nodes, leaf/leaf-list.
405 *
406 * @param node YANG node
407 * @return node java name
408 */
409 public static String getJavaName(Object node) {
410 return ((JavaLeafInfoContainer) node).getJavaName(null);
411 }
412
413 /**
414 * Returns true, if the list is not null and non-empty; false otherwise.
415 *
416 * @param object list object
417 * @return true, if the list is not null and non-empty; false otherwise
418 */
419 public static boolean isNonEmpty(List object) {
420 return object != null && !object.isEmpty();
421 }
422
423 /**
424 * Returns true, if the string is not null and non-empty; false otherwise.
425 *
426 * @param str string value
427 * @return true, if the string is not null and non-empty; false otherwise.
428 */
429 public static boolean isNonEmpty(String str) {
430 return str != null && !str.isEmpty();
431 }
432
433 /**
434 * Returns true when the node processing of RPC and notification is
435 * completed; false otherwise. For RPC and notification, processing of
436 * other nodes are invalid, so once node gets completed, it must be stopped.
437 *
438 * @param curNode current node
439 * @param curTraversal current traversal of the node
440 * @return true, if the node processing is completed; false otherwise.
441 */
442 public static boolean isNodeProcessCompleted(
443 YangNode curNode, TraversalType curTraversal) {
444 return (curTraversal == PARENT &&
445 curNode instanceof YangNotification) ||
446 curNode instanceof YangOutput;
447 }
448
449}