YANG live compiler implementation

Change-Id: Ie8dde5ff0c5e338e294a239180dd25800da045d2
diff --git a/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebApplication.java b/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebApplication.java
new file mode 100644
index 0000000..76023b4
--- /dev/null
+++ b/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebApplication.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-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.yang.web;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * YANG rest api web application.
+ */
+public class YangWebApplication extends AbstractWebApplication {
+    @Override
+    public Set<Class<?>> getClasses() {
+        return getClasses(YangWebResource.class);
+    }
+}
+
diff --git a/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebResource.java b/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebResource.java
new file mode 100644
index 0000000..bfe2bfe
--- /dev/null
+++ b/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebResource.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2017-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.yang.web;
+
+import org.apache.commons.io.IOUtils;
+import org.glassfish.jersey.media.multipart.FormDataBodyPart;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.onosproject.rest.AbstractWebResource;
+import org.onosproject.yang.compiler.api.YangCompilationParam;
+import org.onosproject.yang.compiler.api.YangCompilerService;
+import org.onosproject.yang.compiler.datamodel.YangNode;
+import org.onosproject.yang.model.YangModel;
+import org.onosproject.yang.runtime.DefaultModelRegistrationParam;
+import org.onosproject.yang.runtime.ModelRegistrationParam;
+import org.onosproject.yang.runtime.YangModelRegistry;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.onosproject.yang.compiler.datamodel.utils.DataModelUtils.deSerializeDataModel;
+import static org.onosproject.yang.compiler.utils.io.impl.YangIoUtils.deleteDirectory;
+import static org.onosproject.yang.runtime.helperutils.YangApacheUtils.processYangModel;
+
+//import org.onosproject.yang.compiler.tool.DefaultYangCompilationParam;
+
+/**
+ * Yang files upload resource.
+ */
+@Path("live-compiler")
+public class YangWebResource extends AbstractWebResource {
+    private static final String YANG_FILE_EXTENSION = ".yang";
+    private static final String SER_FILE_EXTENSION = ".ser";
+    private static final String REGISTER = "register";
+    private static final String UNREGISTER = "unregister";
+    private static final String CODE_GEN_DIR = "target/generated-sources/";
+    private static final String META_DATA_DIR = "target/yang/resources/";
+    private static final String SERIALIZED_FILE_NAME = "YangMetaData.ser";
+    private static final String UNKNOWN_KEY = "Key must be either register " +
+            "or unregister.";
+
+    /**
+     * Compiles and registers the given yang files.
+     *
+     * @param formData YANG files or ser files
+     * @return 200 OK
+     * @throws IOException when fails to generate a file
+     */
+    @Path("upload")
+    @POST
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    public Response upload(FormDataMultiPart formData) throws IOException {
+        Map<String, List<File>> input = parseInputData(formData);
+
+        for (Map.Entry<String, List<File>> entry : input.entrySet()) {
+            deleteDirectory(CODE_GEN_DIR);
+            deleteDirectory(META_DATA_DIR);
+
+            YangCompilerService liveCompiler = get(YangCompilerService.class);
+            liveCompiler.compileYangFiles(createCompilationParam(
+                    entry.getValue()));
+
+            YangModelRegistry modelRegistry = get(YangModelRegistry.class);
+            String key = entry.getKey();
+            if (key.equalsIgnoreCase(REGISTER)) {
+                modelRegistry.registerModel(getModelRegParam());
+            } else if (key.equalsIgnoreCase(UNREGISTER)) {
+                modelRegistry.unregisterModel(getModelRegParam());
+            } else {
+                return Response.serverError().entity(UNKNOWN_KEY).build();
+            }
+        }
+
+        // TODO : create bundles
+
+        return Response.status(200).build();
+    }
+
+    private File getInputFile(InputStream stream, String fileName)
+            throws IOException {
+        byte[] content = IOUtils.toByteArray(stream);
+        File file = new File(fileName);
+        if (!file.exists()) {
+            file.createNewFile();
+        }
+        FileOutputStream fop = new FileOutputStream(file);
+        fop.write(content);
+        fop.flush();
+        fop.close();
+        return file;
+    }
+
+    private Map<String, List<File>> parseInputData(FormDataMultiPart formData)
+            throws IOException {
+        Map<String, List<File>> input = new HashMap<>();
+        Map<String, List<FormDataBodyPart>> fieldsByName = formData.getFields();
+        for (Map.Entry<String, List<FormDataBodyPart>> entry :
+                fieldsByName.entrySet()) {
+            List<File> inputFiles = new LinkedList<>();
+            for (FormDataBodyPart field : entry.getValue()) {
+                InputStream stream = field.getEntityAs(InputStream.class);
+                FormDataContentDisposition content = field
+                        .getFormDataContentDisposition();
+                String fileName = content.getFileName();
+                inputFiles.add(getInputFile(stream, fileName));
+            }
+            input.put(entry.getKey(), inputFiles);
+        }
+        return input;
+    }
+
+    private YangCompilationParam createCompilationParam(List<File> inputFiles)
+            throws IOException {
+        // TODO : uncomment when yang tools new verison is released.
+        /*YangCompilationParam param = new DefaultYangCompilationParam();
+        for (File file : inputFiles) {
+            if (file.getName().endsWith(YANG_FILE_EXTENSION)) {
+                param.addYangFile(Paths.get(file.getAbsolutePath()));
+            } else if (file.getName().endsWith(SER_FILE_EXTENSION)) {
+                param.addDependentSchema(Paths.get(file.getAbsolutePath()));
+            }
+        }
+        param.setCodeGenDir(Paths.get(CODE_GEN_DIR));
+        param.setMetadataGenDir(Paths.get(META_DATA_DIR));
+        return param;*/
+        return null;
+    }
+
+    private ModelRegistrationParam getModelRegParam() throws IOException {
+        String metaPath = META_DATA_DIR + SERIALIZED_FILE_NAME;
+        List<YangNode> curNodes = getYangNodes(metaPath);
+        if (curNodes != null && !curNodes.isEmpty()) {
+            YangModel model = processYangModel(metaPath, curNodes);
+            return DefaultModelRegistrationParam.builder()
+                    .setYangModel(model).build();
+        }
+        return null;
+    }
+
+    private List<YangNode> getYangNodes(String path) throws IOException {
+        List<YangNode> nodes = new LinkedList<YangNode>();
+        File file = new File(path);
+        if (file.getName().endsWith(SER_FILE_EXTENSION)) {
+            nodes.addAll(deSerializeDataModel(file.toString()));
+        }
+        return nodes;
+    }
+}
diff --git a/apps/yang/web/src/main/java/org/onosproject/yang/web/package-info.java b/apps/yang/web/src/main/java/org/onosproject/yang/web/package-info.java
new file mode 100644
index 0000000..a4b0b3e
--- /dev/null
+++ b/apps/yang/web/src/main/java/org/onosproject/yang/web/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-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.
+ */
+
+/**
+ * YANG web to obtain YANG via REST and provide it to live compiler.
+ */
+package org.onosproject.yang.web;
\ No newline at end of file
diff --git a/apps/yang/web/src/main/webapp/WEB-INF/web.xml b/apps/yang/web/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..ae8c3c1
--- /dev/null
+++ b/apps/yang/web/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-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.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://java.sun.com/xml/ns/javaee"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>YANG LIVE COMPILER REST API v1.0</display-name>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer
+        </servlet-class>
+        <init-param>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.onosproject.yang.web.YangWebApplication
+            </param-value>
+        </init-param>
+        <init-param>
+            <param-name>jersey.config.server.provider.classnames</param-name>
+            <param-value>
+                org.glassfish.jersey.filter.LoggingFilter,
+                org.glassfish.jersey.media.multipart.MultiPartFeature,
+                org.onosproject.yang.web.YangWebApplication
+            </param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>