[ONOS-5080] YANG object builder coding

Change-Id: Ibef332b58f197a2f6626ee9b6d791b80002e2dfd
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/yob/YobHandler.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/yob/YobHandler.java
new file mode 100755
index 0000000..7e12be3
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/yob/YobHandler.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yms.app.yob;
+
+import org.onosproject.yangutils.datamodel.RpcNotificationContainer;
+import org.onosproject.yangutils.datamodel.YangBinary;
+import org.onosproject.yangutils.datamodel.YangSchemaNode;
+import org.onosproject.yangutils.datamodel.YangType;
+import org.onosproject.yms.app.ydt.YdtExtendedContext;
+import org.onosproject.yms.app.ysr.YangSchemaRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import static org.onosproject.yangutils.utils.io.impl.YangIoUtils.getCapitalCase;
+import static org.onosproject.yms.app.ydt.AppType.YOB;
+import static org.onosproject.yms.app.yob.YobConstants.DATA_TYPE_NOT_SUPPORT;
+import static org.onosproject.yms.app.yob.YobConstants.FAIL_TO_LOAD_CLASS;
+import static org.onosproject.yms.app.yob.YobConstants.FAIL_TO_LOAD_CONSTRUCTOR;
+import static org.onosproject.yms.app.yob.YobConstants.FROM_STRING;
+import static org.onosproject.yms.app.yob.YobConstants.OF;
+import static org.onosproject.yms.app.yob.YobConstants.PERIOD;
+import static org.onosproject.yms.app.yob.YobWorkBench.getQualifiedDefaultClassName;
+
+/**
+ * Represents a YANG object builder handler to process the ydt content and
+ * build yang object.
+ */
+abstract class YobHandler {
+
+    private static final Logger log = LoggerFactory.getLogger(YobHandler.class);
+
+    /**
+     * reference to YANG schema registry.
+     */
+    private YangSchemaRegistry registry;
+
+    /**
+     * Creates a YANG builder object.
+     *
+     * @param curYdtNode  ydtExtendedContext is used to get
+     *                    application related information maintained
+     *                    in YDT
+     * @param rootYdtNode ydtRootNode is refers to module node
+     * @param registry    registry
+     */
+    public void createYangBuilderObject(YdtExtendedContext curYdtNode,
+                                        YdtExtendedContext rootYdtNode,
+                                        YangSchemaRegistry registry) {
+        String setterName = null;
+        YangSchemaNode node = curYdtNode.getYangSchemaNode();
+
+        String qualName = getQualifiedDefaultClassName(node);
+        ClassLoader classLoader = getClassLoader(registry, qualName,
+                                                 curYdtNode);
+
+        if (curYdtNode != rootYdtNode) {
+            setterName = node.getJavaAttributeName();
+        }
+
+        Object builderObject = new YobWorkBench(node, classLoader,
+                                                qualName, setterName);
+
+        curYdtNode.addAppInfo(YOB, builderObject);
+    }
+
+    /**
+     * Sets the YANG built object in corresponding parent class method.
+     *
+     * @param ydtNode        ydtExtendedContext is used to get application
+     *                       related information maintained in YDT
+     * @param schemaRegistry YANG schema registry
+     */
+    public void setObjectInParent(YdtExtendedContext ydtNode,
+                                  YangSchemaRegistry schemaRegistry) {
+    }
+
+    /**
+     * Builds the object.
+     *
+     * @param ydtNode        ydtExtendedContext is used to get
+     *                       application related
+     *                       information maintained in YDT
+     * @param ydtRootNode    ydtRootNode
+     * @param schemaRegistry YANG schema registry
+     */
+    public void buildObjectFromBuilder(YdtExtendedContext ydtNode,
+                                       YdtExtendedContext ydtRootNode,
+                                       YangSchemaRegistry schemaRegistry) {
+        YobWorkBench yobWorkBench = (YobWorkBench) ydtNode.getAppInfo(YOB);
+        yobWorkBench.buildObject(ydtNode, ydtRootNode);
+    }
+
+    /**
+     * This method is used to set data from string value in parent method.
+     *
+     * @param type                refers to YANG type
+     * @param leafValue           leafValue argument is used to set the value
+     *                            in method
+     * @param parentSetterMethod  Invokes the underlying method represented
+     *                            by this parentSetterMethod
+     * @param parentBuilderObject the parentBuilderObject is to invoke the
+     *                            underlying method
+     * @param ydtExtendedContext  ydtExtendedContext is used to get
+     *                            application related
+     *                            information maintained in YDT
+     * @throws InvocationTargetException throws InvocationTargetException
+     * @throws IllegalAccessException    throws IllegalAccessException
+     * @throws NoSuchMethodException     throws NoSuchMethodException
+     */
+    void setDataFromStringValue(YangType<?> type, String leafValue,
+                                Method parentSetterMethod,
+                                Object parentBuilderObject,
+                                YdtExtendedContext ydtExtendedContext)
+            throws InvocationTargetException, IllegalAccessException,
+            NoSuchMethodException {
+        switch (type.getDataType()) {
+            case INT8: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          Byte.parseByte(leafValue));
+                break;
+            }
+            case UINT8:
+            case INT16: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          Short.parseShort(leafValue));
+                break;
+            }
+            case UINT16:
+            case INT32: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          Integer.parseInt(leafValue));
+                break;
+            }
+            case UINT32:
+            case INT64: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          Long.parseLong(leafValue));
+                break;
+            }
+            case UINT64: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          new BigInteger(leafValue));
+                break;
+            }
+            case EMPTY:
+            case BOOLEAN: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          Boolean.parseBoolean(leafValue));
+                break;
+            }
+            case STRING: {
+                parentSetterMethod.invoke(parentBuilderObject, leafValue);
+                break;
+            }
+            case BINARY: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          new YangBinary(leafValue));
+                break;
+            }
+            case BITS: {
+                //TODO
+                break;
+            }
+            case DECIMAL64: {
+                parentSetterMethod.invoke(parentBuilderObject,
+                                          new BigDecimal(leafValue));
+                break;
+            }
+            case DERIVED: {
+                parseDerivedTypeInfo(ydtExtendedContext, parentSetterMethod,
+                                     parentBuilderObject, leafValue, false);
+                break;
+            }
+            case UNION: {
+                // TODO
+                break;
+            }
+            case LEAFREF: {
+                // TODO
+                break;
+            }
+            case ENUMERATION: {
+                parseDerivedTypeInfo(ydtExtendedContext, parentSetterMethod,
+                                     parentBuilderObject, leafValue, true);
+                break;
+            }
+            default: {
+                log.error(DATA_TYPE_NOT_SUPPORT);
+            }
+        }
+    }
+
+    /**
+     * To set data into parent setter method from string value for derived type.
+     *
+     * @param leafValue           leafValue argument is used to set the value
+     *                            in method
+     * @param parentSetterMethod  Invokes the underlying method represented
+     *                            by this parentSetterMethod
+     * @param parentBuilderObject the parentBuilderObject is to invoke the
+     *                            underlying method
+     * @param ydtExtendedContext  ydtExtendedContext is used to get
+     *                            application related
+     *                            information maintained in YDT
+     * @param isEnum              isEnum parameter is used to check whether
+     *                            type is enum or derived
+     *                            information maintained in YDT
+     * @throws InvocationTargetException throws InvocationTargetException
+     * @throws IllegalAccessException    throws IllegalAccessException
+     * @throws NoSuchMethodException     throws NoSuchMethodException
+     */
+    private void parseDerivedTypeInfo(YdtExtendedContext ydtExtendedContext,
+                                      Method parentSetterMethod,
+                                      Object parentBuilderObject,
+                                      String leafValue, boolean isEnum)
+            throws InvocationTargetException, IllegalAccessException,
+            NoSuchMethodException {
+        Class<?> childSetClass = null;
+        Constructor<?> childConstructor = null;
+        Object childValue = null;
+        Object childObject = null;
+        Method childMethod = null;
+
+        YangSchemaNode yangJavaModule = ydtExtendedContext.getYangSchemaNode();
+        String packageName = yangJavaModule.getJavaPackage();
+        String className = getCapitalCase(
+                yangJavaModule.getJavaClassNameOrBuiltInType());
+        String qualifiedClassName = packageName + PERIOD + className;
+        ClassLoader classLoader = getClassLoader(registry,
+                                                 qualifiedClassName,
+                                                 ydtExtendedContext);
+        try {
+            childSetClass = classLoader.loadClass(qualifiedClassName);
+        } catch (ClassNotFoundException e) {
+            log.error(FAIL_TO_LOAD_CLASS + packageName + PERIOD + className);
+        }
+        if (!isEnum) {
+
+            if (childSetClass != null) {
+                childConstructor = childSetClass.getDeclaredConstructor();
+            }
+
+            if (childConstructor != null) {
+                childConstructor.setAccessible(true);
+            }
+            try {
+                if (childConstructor != null) {
+                    childObject = childConstructor.newInstance();
+                }
+            } catch (InstantiationException e) {
+                log.error(FAIL_TO_LOAD_CONSTRUCTOR + className);
+            }
+            if (childSetClass != null) {
+                childMethod = childSetClass
+                        .getDeclaredMethod(FROM_STRING, String.class);
+            }
+        } else {
+            if (childSetClass != null) {
+                childMethod = childSetClass.getDeclaredMethod(OF, String.class);
+            }
+            //leafValue = JavaIdentifierSyntax.getEnumJavaAttribute(leafValue);
+            //leafValue = leafValue.toUpperCase();
+        }
+        if (childMethod != null) {
+            childValue = childMethod.invoke(childObject, leafValue);
+        }
+
+        parentSetterMethod.invoke(parentBuilderObject, childValue);
+    }
+
+    /**
+     * Updates class loader for all the classes.
+     *
+     * @param registry           YANG schema registry
+     * @param context            YDT context
+     * @param qualifiedClassName qualified class name
+     * @return current class loader
+     */
+    private ClassLoader getClassLoader(YangSchemaRegistry registry,
+                                       String qualifiedClassName,
+                                       YdtExtendedContext context) {
+
+        YangSchemaNode yangSchemaNode = context.getYangSchemaNode();
+        if (yangSchemaNode instanceof RpcNotificationContainer) {
+            Class<?> regClass = registry.getRegisteredClass(yangSchemaNode,
+                                                            qualifiedClassName);
+            return regClass.getClassLoader();
+        } else {
+
+            YdtExtendedContext parent =
+                    (YdtExtendedContext) context.getParent();
+            YobWorkBench parentBuilderContainer =
+                    (YobWorkBench) parent.getAppInfo(YOB);
+            Object parentObj =
+                    parentBuilderContainer.getParentBuilder(context, registry);
+            return parentObj.getClass().getClassLoader();
+        }
+    }
+
+    /**
+     * Returns the YANG schema registry.
+     *
+     * @return registry YANG schema registry
+     */
+    public YangSchemaRegistry getRegistry() {
+        return registry;
+    }
+
+    /**
+     * Sets the YANG schema registry.
+     *
+     * @param registry YANG schema registry
+     */
+    public void setRegistry(YangSchemaRegistry registry) {
+        this.registry = registry;
+    }
+}