blob: 36ce736c8ee2b22147b65f4df2f6e4eb487ebbbc [file] [log] [blame]
Rama-Huaweib711e5c2016-08-31 07:55:46 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Rama-Huaweib711e5c2016-08-31 07:55:46 +05303 *
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.yob;
18
Rama-Huaweib711e5c2016-08-31 07:55:46 +053019import org.onosproject.yangutils.datamodel.YangSchemaNode;
20import org.onosproject.yangutils.datamodel.YangSchemaNodeContextInfo;
21import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier;
22import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
23import org.onosproject.yms.app.ydt.YdtExtendedContext;
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053024import org.onosproject.yms.app.yob.exception.YobException;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053025import org.onosproject.yms.app.ysr.YangSchemaRegistry;
Vidyashree Rama6160be12016-11-24 13:43:31 +053026import org.onosproject.yms.ydt.YdtContextOperationType;
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053027import org.onosproject.yms.ydt.YdtType;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053028import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
31import java.lang.reflect.Field;
32import java.lang.reflect.InvocationTargetException;
33import java.lang.reflect.Method;
34import java.lang.reflect.ParameterizedType;
35import java.util.HashMap;
36import java.util.Map;
37
38import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_AUGMENT_NODE;
39import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_CHOICE_NODE;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053040import static org.onosproject.yms.app.ydt.AppType.YOB;
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053041import static org.onosproject.yms.app.yob.YobConstants.ADD_AUGMENT_METHOD;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053042import static org.onosproject.yms.app.yob.YobConstants.ADD_TO;
43import static org.onosproject.yms.app.yob.YobConstants.BUILD;
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053044import static org.onosproject.yms.app.yob.YobConstants.E_FAIL_TO_BUILD;
45import static org.onosproject.yms.app.yob.YobConstants.E_FAIL_TO_GET_FIELD;
46import static org.onosproject.yms.app.yob.YobConstants.E_FAIL_TO_GET_METHOD;
47import static org.onosproject.yms.app.yob.YobConstants.E_FAIL_TO_INVOKE_METHOD;
48import static org.onosproject.yms.app.yob.YobConstants.E_FAIL_TO_LOAD_CLASS;
49import static org.onosproject.yms.app.yob.YobConstants.E_HAS_NO_CHILD;
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053050import static org.onosproject.yms.app.yob.YobConstants.E_SET_OP_TYPE_FAIL;
51import static org.onosproject.yms.app.yob.YobConstants.L_FAIL_TO_BUILD;
52import static org.onosproject.yms.app.yob.YobConstants.L_FAIL_TO_GET_FIELD;
53import static org.onosproject.yms.app.yob.YobConstants.L_FAIL_TO_GET_METHOD;
54import static org.onosproject.yms.app.yob.YobConstants.L_FAIL_TO_INVOKE_METHOD;
Vidyashree Rama6160be12016-11-24 13:43:31 +053055import static org.onosproject.yms.app.yob.YobConstants.ONOS_YANG_OP_TYPE;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053056import static org.onosproject.yms.app.yob.YobConstants.OP_TYPE;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053057import static org.onosproject.yms.app.yob.YobConstants.VALUE_OF;
Vidyashree Rama6160be12016-11-24 13:43:31 +053058import static org.onosproject.yms.app.yob.YobConstants.YANG;
59import static org.onosproject.yms.app.yob.YobUtils.getCapitalCase;
60import static org.onosproject.yms.app.yob.YobUtils.getModuleInterface;
61import static org.onosproject.yms.app.yob.YobUtils.getQualifiedDefaultClass;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053062import static org.onosproject.yms.ydt.YdtType.MULTI_INSTANCE_NODE;
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053063import static org.onosproject.yms.ydt.YdtType.SINGLE_INSTANCE_NODE;
Rama-Huaweib711e5c2016-08-31 07:55:46 +053064
65/**
66 * Represents the YANG object builder's work bench corresponding to a YANG data
67 * tree node.
68 */
69class YobWorkBench {
70
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053071 private static final Logger log =
72 LoggerFactory.getLogger(YobWorkBench.class);
Rama-Huaweib711e5c2016-08-31 07:55:46 +053073
74 /**
75 * Class loader to be used to load the class.
76 */
77 private ClassLoader classLoader;
78
79 /**
80 * Map of the non schema descendant objects.
81 */
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +053082 private Map<YangSchemaNodeIdentifier, YobWorkBench> attributeMap =
83 new HashMap<>();
Rama-Huaweib711e5c2016-08-31 07:55:46 +053084
85 /**
86 * Reference for data-model schema node.
87 */
88 private YangSchemaNode yangSchemaNode;
89
90 /**
91 * builder object or the built object corresponding to the current schema
92 * node.
93 */
94 private YobBuilderOrBuiltObject builderOrBuiltObject;
95
96 /**
97 * Setter method to be used in parent builder.
98 */
99 private String setterInParent;
100
101 /**
102 * Returns the builder container with the mapping schema being initialized.
103 *
104 * @param yangSchemaNode mapping schema node
105 * @param classLoader class loader
106 * @param qualifiedClassName qualified class name
107 * @param setterInParent setter method in parent
108 */
109 YobWorkBench(YangSchemaNode yangSchemaNode, ClassLoader classLoader,
110 String qualifiedClassName, String setterInParent) {
111 this.yangSchemaNode = yangSchemaNode;
112 this.classLoader = classLoader;
113 this.setterInParent = setterInParent;
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530114 this.builderOrBuiltObject =
115 new YobBuilderOrBuiltObject(qualifiedClassName, classLoader);
Rama-Huaweib711e5c2016-08-31 07:55:46 +0530116 }
117
118 /**
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530119 * Set the attribute in a builder object.
120 *
Vidyashree Rama6160be12016-11-24 13:43:31 +0530121 * @param builder builder object in which the attribute needs to be set
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530122 * @param setter setter method in parent
123 * @param nodeType type of node to set
124 * @param attribute attribute to set in the builder
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530125 */
126 private static void setObjectInBuilder(Object builder, String setter,
127 YdtType nodeType, Object attribute) {
128 Class<?> builderClass = builder.getClass();
129 String builderClassName = builderClass.getName();
130 try {
131 Class<?> type = null;
132 Field fieldName = builderClass.getDeclaredField(setter);
133 if (fieldName != null) {
134 type = fieldName.getType();
135 }
136
137 Method method;
138 if (nodeType == MULTI_INSTANCE_NODE) {
139 if (fieldName != null) {
140 ParameterizedType genericTypes =
141 (ParameterizedType) fieldName.getGenericType();
142 type = (Class<?>) genericTypes.getActualTypeArguments()[0];
143 }
144 method = builderClass.getDeclaredMethod(
145 ADD_TO + getCapitalCase(setter), type);
146 } else {
147 method = builderClass.getDeclaredMethod(setter, type);
148 }
149
150 method.invoke(builder, attribute);
151 } catch (NoSuchFieldException e) {
152 log.error(L_FAIL_TO_GET_FIELD, builderClassName);
153 throw new YobException(E_FAIL_TO_GET_FIELD + builderClassName);
154 } catch (NoSuchMethodException e) {
155 log.error(L_FAIL_TO_GET_METHOD, builderClassName);
156 throw new YobException(E_FAIL_TO_GET_METHOD + builderClassName);
157 } catch (InvocationTargetException | IllegalAccessException e) {
158 log.error(L_FAIL_TO_INVOKE_METHOD, builderClassName);
159 throw new YobException(E_FAIL_TO_INVOKE_METHOD + builderClassName);
160 }
161 }
162
163 private static void addInAugmentation(Object builder, String className,
164 Object instance) {
165 Class<?>[] interfaces = instance.getClass().getInterfaces();
166 if (interfaces == null) {
167 throw new YobException(E_FAIL_TO_LOAD_CLASS + className);
168 }
169
170 int i;
171 for (i = 0; i < interfaces.length; i++) {
172 if (interfaces[i].getName().equals(className)) {
173 break;
174 }
175 }
176 if (i == interfaces.length) {
177 throw new YobException(E_FAIL_TO_LOAD_CLASS + className);
178 }
179
180 Class<?> builderClass = builder.getClass();
181 String builderClassName = builderClass.getName();
182 try {
183
184 Method method = builderClass.getDeclaredMethod(ADD_AUGMENT_METHOD,
185 Object.class,
186 Class.class);
187 method.invoke(builder, instance, interfaces[i]);
188 } catch (NoSuchMethodException e) {
189 log.error(L_FAIL_TO_GET_METHOD, builderClassName);
190 throw new YobException(E_FAIL_TO_GET_METHOD + builderClassName);
191 } catch (InvocationTargetException | IllegalAccessException e) {
192 log.error(L_FAIL_TO_INVOKE_METHOD, builderClassName);
193 throw new YobException(E_FAIL_TO_INVOKE_METHOD + builderClassName);
194 }
195
196 }
197
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530198 /**
199 * Creates a new builder container object corresponding to a context
200 * switch schema node.
201 *
202 * @param childContext schema context of immediate child
203 * @param targetNode final node whose parent builder is
204 * required
205 * @param curWorkBench current context builder container
206 * @param registry schema registry
207 * @return new builder container object corresponding to a context
208 * switch schema node
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530209 */
210 private static YobWorkBench getNewChildWorkBench(
211 YangSchemaNodeContextInfo childContext,
212 YangSchemaNodeIdentifier targetNode, YobWorkBench curWorkBench,
213 YangSchemaRegistry registry) {
214
215 YangSchemaNode ctxSwitchedNode = childContext.getContextSwitchedNode();
216 String name;
217
Vidyashree Rama6160be12016-11-24 13:43:31 +0530218 /* This is the first child trying to set its object in the
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530219 current context. */
220 String setterInParent = ctxSwitchedNode.getJavaAttributeName();
221
222 /* If current switched context is choice, then case class needs to be
223 used. */
224 if (ctxSwitchedNode.getYangSchemaNodeType() == YANG_CHOICE_NODE) {
225 try {
226 childContext = ctxSwitchedNode.getChildSchema(targetNode);
227 ctxSwitchedNode = childContext.getContextSwitchedNode();
Vidyashree Rama6160be12016-11-24 13:43:31 +0530228 name = getQualifiedDefaultClass(
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530229 childContext.getContextSwitchedNode());
230
231 } catch (DataModelException e) {
232 throw new YobException(ctxSwitchedNode.getName() +
233 E_HAS_NO_CHILD +
234 targetNode.getName());
235 }
236 } else if (ctxSwitchedNode.getYangSchemaNodeType() ==
237 YANG_AUGMENT_NODE) {
Vidyashree Rama6160be12016-11-24 13:43:31 +0530238 name = getQualifiedDefaultClass(ctxSwitchedNode);
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530239 setterInParent = YobUtils.getQualifiedinterface(ctxSwitchedNode);
240 } else {
Vidyashree Rama6160be12016-11-24 13:43:31 +0530241 name = getQualifiedDefaultClass(childContext.getSchemaNode());
VinodKumarS-Huawei7b1733c2016-10-25 13:44:26 +0530242 }
243
244 ClassLoader newClassesLoader = YobUtils.getTargetClassLoader(
245 curWorkBench.classLoader, childContext, registry);
246
247 return new YobWorkBench(ctxSwitchedNode, newClassesLoader, name,
248 setterInParent);
249 }
250
Vidyashree Rama6160be12016-11-24 13:43:31 +0530251 /**
252 * Returns the builder object or the built object corresponding to the
253 * current schema node.
254 *
255 * @return builder or built object
256 */
257 YobBuilderOrBuiltObject getBuilderOrBuiltObject() {
258 return builderOrBuiltObject;
259 }
260
261 /**
262 * Returns the parent builder object in which the child object can be set.
263 *
264 * @param node child YDT node
265 * @param registry schema registry
266 * @return parent builder object
267 */
268 Object getParentBuilder(YdtExtendedContext node,
269 YangSchemaRegistry registry) {
270
271 // Descendant schema node for whom the builder is required.
272 YangSchemaNodeIdentifier targetNode =
273 node.getYangSchemaNode().getYangSchemaNodeIdentifier();
274
275 //Current builder container
276 YobWorkBench curWorkBench = this;
277
278 YangSchemaNode nonSchemaHolder;
279 do {
280
281 //Current Schema node context
282 YangSchemaNodeContextInfo schemaContext;
283 try {
284 //Find the new schema context node.
285 schemaContext = curWorkBench.yangSchemaNode
286 .getChildSchema(targetNode);
287
288 } catch (DataModelException e) {
289 throw new YobException(yangSchemaNode.getName() +
290 E_HAS_NO_CHILD +
291 targetNode.getName());
292 }
293
294 nonSchemaHolder = schemaContext.getContextSwitchedNode();
295
296 //If the descendant schema node is in switched context
297 if (nonSchemaHolder != null) {
298
299 YangSchemaNodeIdentifier nonSchemaIdentifier =
300 nonSchemaHolder.getYangSchemaNodeIdentifier();
301
302 //check if the descendant builder container is already available
303 YobWorkBench childWorkBench =
304 curWorkBench.attributeMap.get(nonSchemaIdentifier);
305
306 if (childWorkBench == null) {
307 YobWorkBench newWorkBench = getNewChildWorkBench(
308 schemaContext, targetNode, curWorkBench, registry);
309
310 curWorkBench.attributeMap.put(nonSchemaIdentifier,
311 newWorkBench);
312 curWorkBench = newWorkBench;
313 } else {
314 curWorkBench = childWorkBench;
315 }
316 }
317
318 } while (nonSchemaHolder != null);
319
320 return curWorkBench.builderOrBuiltObject.getBuilderObject();
321 }
322
323 /**
324 * Set the operation type attribute and build the object from the builder
325 * object, by invoking the build method.
326 *
327 * @param operationType data tree node
328 * @param schemaRegistry YANG schema registry
329 */
330 void buildObject(YdtContextOperationType operationType,
331 YangSchemaRegistry schemaRegistry) {
332
333 buildNonSchemaAttributes(operationType, schemaRegistry);
334
335 Object builderObject = builderOrBuiltObject.getBuilderObject();
336 Class<?> defaultBuilderClass = builderOrBuiltObject.yangBuilderClass;
337
338 //set the operation type
339 setOperationType(operationType, schemaRegistry);
340
341 // Invoking the build method to get built object from build method.
342 try {
343 Method method = defaultBuilderClass.getDeclaredMethod(BUILD);
344 if (method == null) {
345 log.error(L_FAIL_TO_GET_METHOD, defaultBuilderClass.getName());
346 throw new YobException(E_FAIL_TO_GET_METHOD +
347 defaultBuilderClass.getName());
348 }
349 Object builtObject = method.invoke(builderObject);
350 // The built object will be maintained in ydt context and same will
351 // be used while setting into parent method.
352 builderOrBuiltObject.setBuiltObject(builtObject);
353
354 } catch (NoSuchMethodException | InvocationTargetException |
355 IllegalAccessException e) {
356 log.error(L_FAIL_TO_BUILD, defaultBuilderClass.getName());
357 throw new YobException(E_FAIL_TO_BUILD +
358 defaultBuilderClass.getName());
359 }
360 }
361
362 /**
363 * Set the operation type in the built object from the YDT node.
364 * <p>
365 * It needs to be invoked only for the workbench corresponding to the
366 * schema YDT nodes, non schema node without the YDT node should not
367 * invoke this, as it is not applicable to it.
368 *
369 * @param ydtoperation schema data tree node
370 * @param schemaRegistry YANG schema registry
371 */
372 private void setOperationType(YdtContextOperationType ydtoperation,
373 YangSchemaRegistry schemaRegistry) {
374
375 if (ydtoperation == null) {
376 return;
377 }
378
379 Object builderObject = builderOrBuiltObject.getBuilderObject();
380 Class<?> defaultBuilderClass = builderOrBuiltObject.yangBuilderClass;
381 Class<?>[] intfClass = builderOrBuiltObject.yangDefaultClass
382 .getInterfaces();
383 String setterName = YANG + intfClass[0].getSimpleName() + OP_TYPE;
384
385 // Setting the value into YANG node operation type from ydtContext
386 // operation type.
387 try {
388 Class<?> interfaceClass;
389 interfaceClass = getModuleInterface(yangSchemaNode,
390 schemaRegistry);
391 Object operationType;
392 Class<?>[] innerClasses = interfaceClass.getClasses();
393 for (Class<?> innerEnumClass : innerClasses) {
394 if (innerEnumClass.getSimpleName().equals(ONOS_YANG_OP_TYPE)) {
395 Method valueOfMethod = innerEnumClass
396 .getDeclaredMethod(VALUE_OF, String.class);
397 operationType = valueOfMethod.invoke(null, ydtoperation.
398 toString());
399 Field operationTypeField = defaultBuilderClass
400 .getDeclaredField(setterName);
401 operationTypeField.setAccessible(true);
402 operationTypeField.set(builderObject, operationType);
403 break;
404 }
405 }
406 } catch (NoSuchMethodException |
407 InvocationTargetException | IllegalAccessException |
408 IllegalArgumentException e) {
409 log.error(E_SET_OP_TYPE_FAIL);
410 throw new YobException(E_SET_OP_TYPE_FAIL);
411 } catch (NoSuchFieldException e) {
412 log.error(E_SET_OP_TYPE_FAIL);
413 }
414 }
415
416 /**
417 * build the non schema objects and maintain it in the contained schema
418 * node.
419 *
420 * @param operationType contained schema node
421 * @param schemaRegistry YANG schema registry
422 */
423 private void buildNonSchemaAttributes(YdtContextOperationType operationType,
424 YangSchemaRegistry schemaRegistry) {
425 for (Map.Entry<YangSchemaNodeIdentifier, YobWorkBench> entry :
426 attributeMap.entrySet()) {
427 YobWorkBench childWorkBench = entry.getValue();
428 childWorkBench.buildObject(operationType, schemaRegistry);
429
430 if (childWorkBench.yangSchemaNode.getYangSchemaNodeType() ==
431 YANG_AUGMENT_NODE) {
432 addInAugmentation(builderOrBuiltObject.getBuilderObject(),
433 childWorkBench.setterInParent,
434 childWorkBench.getBuilderOrBuiltObject()
435 .getBuiltObject());
436 continue;
437 }
438
439 setObjectInBuilder(
440 builderOrBuiltObject.getBuilderObject(),
441 childWorkBench.setterInParent,
442 SINGLE_INSTANCE_NODE,
443 childWorkBench.getBuilderOrBuiltObject().getBuiltObject());
444 }
445 }
446
447 /**
448 * Sets the YANG built object in corresponding parent class method.
449 *
450 * @param childnode ydtExtendedContext is used to get application
451 * related information maintained in YDT
452 * @param schemaRegistry YANG schema registry
453 */
454 public void setObject(YdtExtendedContext childnode,
455 YangSchemaRegistry schemaRegistry) {
456 Object builder = getParentBuilder(childnode, schemaRegistry);
457 YobWorkBench childWorkBench = (YobWorkBench) childnode.getAppInfo(YOB);
458
459 setObjectInBuilder(builder, childWorkBench.setterInParent,
460 childnode.getYdtType(), childWorkBench
461 .builderOrBuiltObject.getBuiltObject());
462 }
Rama-Huaweib711e5c2016-08-31 07:55:46 +0530463}