blob: 72d9cbe9ddd052a205339f94012cd6eea3231478 [file] [log] [blame]
Vidyashree Rama3c503612017-05-10 13:55:34 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Vidyashree Rama3c503612017-05-10 13:55:34 +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.yang.web;
18
19import org.apache.commons.io.IOUtils;
20import org.glassfish.jersey.media.multipart.FormDataBodyPart;
21import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
22import org.glassfish.jersey.media.multipart.FormDataMultiPart;
23import org.onosproject.rest.AbstractWebResource;
24import org.onosproject.yang.compiler.api.YangCompilationParam;
25import org.onosproject.yang.compiler.api.YangCompilerService;
26import org.onosproject.yang.compiler.datamodel.YangNode;
Vidyashree Rama0c49b9a2017-06-02 11:54:19 +053027import org.onosproject.yang.compiler.tool.DefaultYangCompilationParam;
Thomas Vachuska89534452017-07-28 10:20:12 -070028import org.onosproject.yang.compiler.tool.YangCompilerManager;
Vidyashree Rama3c503612017-05-10 13:55:34 +053029import org.onosproject.yang.model.YangModel;
30import org.onosproject.yang.runtime.DefaultModelRegistrationParam;
31import org.onosproject.yang.runtime.ModelRegistrationParam;
32import org.onosproject.yang.runtime.YangModelRegistry;
33
34import javax.ws.rs.Consumes;
35import javax.ws.rs.POST;
36import javax.ws.rs.Path;
37import javax.ws.rs.core.MediaType;
38import javax.ws.rs.core.Response;
39import java.io.File;
40import java.io.FileOutputStream;
41import java.io.IOException;
42import java.io.InputStream;
Vidyashree Rama0c49b9a2017-06-02 11:54:19 +053043import java.nio.file.Paths;
Vidyashree Rama00449232017-06-21 09:41:07 +053044import java.util.Enumeration;
Vidyashree Rama3c503612017-05-10 13:55:34 +053045import java.util.HashMap;
46import java.util.LinkedList;
47import java.util.List;
48import java.util.Map;
Vidyashree Rama00449232017-06-21 09:41:07 +053049import java.util.zip.ZipEntry;
50import java.util.zip.ZipFile;
Vidyashree Rama3c503612017-05-10 13:55:34 +053051
Thomas Vachuska89534452017-07-28 10:20:12 -070052import static org.onosproject.yang.compiler.tool.YangCompilerManager.deSerializeDataModel;
53import static org.onosproject.yang.compiler.tool.YangCompilerManager.processYangModel;
Vidyashree Rama3c503612017-05-10 13:55:34 +053054import static org.onosproject.yang.compiler.utils.io.impl.YangIoUtils.deleteDirectory;
Vidyashree Rama3c503612017-05-10 13:55:34 +053055
Vidyashree Rama3c503612017-05-10 13:55:34 +053056/**
57 * Yang files upload resource.
58 */
Vidyashree Rama00449232017-06-21 09:41:07 +053059@Path("models")
Vidyashree Rama3c503612017-05-10 13:55:34 +053060public class YangWebResource extends AbstractWebResource {
61 private static final String YANG_FILE_EXTENSION = ".yang";
62 private static final String SER_FILE_EXTENSION = ".ser";
Vidyashree Rama00449232017-06-21 09:41:07 +053063 private static final String JAR_FILE_EXTENSION = ".jar";
64 private static final String ZIP_FILE_EXTENSION = ".zip";
Vidyashree Rama3c503612017-05-10 13:55:34 +053065 private static final String REGISTER = "register";
66 private static final String UNREGISTER = "unregister";
67 private static final String CODE_GEN_DIR = "target/generated-sources/";
Vidyashree Rama00449232017-06-21 09:41:07 +053068 private static final String YANG_RESOURCES = "target/yang/resources/";
Vidyashree Rama3c503612017-05-10 13:55:34 +053069 private static final String SERIALIZED_FILE_NAME = "YangMetaData.ser";
70 private static final String UNKNOWN_KEY = "Key must be either register " +
71 "or unregister.";
Vidyashree Rama00449232017-06-21 09:41:07 +053072 private static final String SLASH = "/";
Vidyashree Rama3c503612017-05-10 13:55:34 +053073
74 /**
75 * Compiles and registers the given yang files.
76 *
77 * @param formData YANG files or ser files
78 * @return 200 OK
79 * @throws IOException when fails to generate a file
80 */
Vidyashree Rama3c503612017-05-10 13:55:34 +053081 @POST
82 @Consumes(MediaType.MULTIPART_FORM_DATA)
83 public Response upload(FormDataMultiPart formData) throws IOException {
84 Map<String, List<File>> input = parseInputData(formData);
85
86 for (Map.Entry<String, List<File>> entry : input.entrySet()) {
87 deleteDirectory(CODE_GEN_DIR);
Vidyashree Rama00449232017-06-21 09:41:07 +053088 deleteDirectory(YANG_RESOURCES);
Vidyashree Rama3c503612017-05-10 13:55:34 +053089
90 YangCompilerService liveCompiler = get(YangCompilerService.class);
91 liveCompiler.compileYangFiles(createCompilationParam(
92 entry.getValue()));
93
94 YangModelRegistry modelRegistry = get(YangModelRegistry.class);
95 String key = entry.getKey();
96 if (key.equalsIgnoreCase(REGISTER)) {
97 modelRegistry.registerModel(getModelRegParam());
98 } else if (key.equalsIgnoreCase(UNREGISTER)) {
99 modelRegistry.unregisterModel(getModelRegParam());
100 } else {
101 return Response.serverError().entity(UNKNOWN_KEY).build();
102 }
103 }
104
105 // TODO : create bundles
106
107 return Response.status(200).build();
108 }
109
110 private File getInputFile(InputStream stream, String fileName)
111 throws IOException {
112 byte[] content = IOUtils.toByteArray(stream);
113 File file = new File(fileName);
114 if (!file.exists()) {
115 file.createNewFile();
116 }
117 FileOutputStream fop = new FileOutputStream(file);
118 fop.write(content);
119 fop.flush();
120 fop.close();
121 return file;
122 }
123
124 private Map<String, List<File>> parseInputData(FormDataMultiPart formData)
125 throws IOException {
126 Map<String, List<File>> input = new HashMap<>();
127 Map<String, List<FormDataBodyPart>> fieldsByName = formData.getFields();
128 for (Map.Entry<String, List<FormDataBodyPart>> entry :
129 fieldsByName.entrySet()) {
130 List<File> inputFiles = new LinkedList<>();
131 for (FormDataBodyPart field : entry.getValue()) {
132 InputStream stream = field.getEntityAs(InputStream.class);
133 FormDataContentDisposition content = field
134 .getFormDataContentDisposition();
135 String fileName = content.getFileName();
136 inputFiles.add(getInputFile(stream, fileName));
137 }
138 input.put(entry.getKey(), inputFiles);
139 }
140 return input;
141 }
142
143 private YangCompilationParam createCompilationParam(List<File> inputFiles)
144 throws IOException {
Thomas Vachuska89534452017-07-28 10:20:12 -0700145 DefaultYangCompilationParam.Builder builder = DefaultYangCompilationParam.builder();
Vidyashree Rama3c503612017-05-10 13:55:34 +0530146 for (File file : inputFiles) {
Vidyashree Rama00449232017-06-21 09:41:07 +0530147 if (file.getName().endsWith(JAR_FILE_EXTENSION)
148 || file.getName().endsWith(ZIP_FILE_EXTENSION)) {
149 List<File> files = decompressFile(file);
150
151 for (File f : files) {
Thomas Vachuska89534452017-07-28 10:20:12 -0700152 addToParam(builder, f);
Vidyashree Rama00449232017-06-21 09:41:07 +0530153 }
154 } else {
Thomas Vachuska89534452017-07-28 10:20:12 -0700155 addToParam(builder, file);
Vidyashree Rama3c503612017-05-10 13:55:34 +0530156 }
157 }
Thomas Vachuska89534452017-07-28 10:20:12 -0700158 builder.setCodeGenDir(Paths.get(CODE_GEN_DIR));
159 builder.setMetadataGenDir(Paths.get(YANG_RESOURCES));
160 return builder.build();
Vidyashree Rama00449232017-06-21 09:41:07 +0530161 }
162
Thomas Vachuska89534452017-07-28 10:20:12 -0700163 private void addToParam(DefaultYangCompilationParam.Builder builder,
Vidyashree Rama00449232017-06-21 09:41:07 +0530164 File file) {
165 if (file.getName().endsWith(YANG_FILE_EXTENSION)) {
Thomas Vachuska89534452017-07-28 10:20:12 -0700166 builder.addYangFile(Paths.get(file.getAbsolutePath()));
Vidyashree Rama00449232017-06-21 09:41:07 +0530167 } else if (file.getName().endsWith(SER_FILE_EXTENSION)) {
Thomas Vachuska89534452017-07-28 10:20:12 -0700168 builder.addDependentSchema(Paths.get(file.getAbsolutePath()));
Vidyashree Rama00449232017-06-21 09:41:07 +0530169 }
Vidyashree Rama3c503612017-05-10 13:55:34 +0530170 }
171
172 private ModelRegistrationParam getModelRegParam() throws IOException {
Vidyashree Rama00449232017-06-21 09:41:07 +0530173 String metaPath = YANG_RESOURCES + SERIALIZED_FILE_NAME;
Vidyashree Rama3c503612017-05-10 13:55:34 +0530174 List<YangNode> curNodes = getYangNodes(metaPath);
Thomas Vachuska89534452017-07-28 10:20:12 -0700175 // FIXME: extract or derive the model id from the web request
176 String modelId = "unknown";
Vidyashree Rama3c503612017-05-10 13:55:34 +0530177 if (curNodes != null && !curNodes.isEmpty()) {
Thomas Vachuska89534452017-07-28 10:20:12 -0700178 YangModel model = processYangModel(metaPath, curNodes, modelId, false);
Vidyashree Rama3c503612017-05-10 13:55:34 +0530179 return DefaultModelRegistrationParam.builder()
180 .setYangModel(model).build();
181 }
182 return null;
183 }
184
185 private List<YangNode> getYangNodes(String path) throws IOException {
Vidyashree Rama00449232017-06-21 09:41:07 +0530186 List<YangNode> nodes = new LinkedList<>();
Vidyashree Rama3c503612017-05-10 13:55:34 +0530187 File file = new File(path);
188 if (file.getName().endsWith(SER_FILE_EXTENSION)) {
Thomas Vachuska89534452017-07-28 10:20:12 -0700189 nodes.addAll(YangCompilerManager.getYangNodes(deSerializeDataModel(file.toString())));
Vidyashree Rama3c503612017-05-10 13:55:34 +0530190 }
191 return nodes;
192 }
Vidyashree Rama00449232017-06-21 09:41:07 +0530193
194 private static List<File> decompressFile(File jarFile)
195 throws IOException {
196 ZipFile zip = new ZipFile(jarFile);
197 final List<File> unzipedFiles = new LinkedList<>();
198
199 // first get all directories,
200 // then make those directory on the destination Path
201 for (Enumeration<? extends ZipEntry> enums = zip.entries();
202 enums.hasMoreElements();) {
203 ZipEntry entry = enums.nextElement();
204
205 String fileName = YANG_RESOURCES + entry.getName();
206 File f = new File(fileName);
207
208 if (fileName.endsWith(SLASH)) {
209 f.mkdirs();
210 }
211 }
212
213 //now create all files
214 for (Enumeration<? extends ZipEntry> enums = zip.entries();
215 enums.hasMoreElements();) {
216 ZipEntry entry = enums.nextElement();
217 String fileName = YANG_RESOURCES + entry.getName();
218 File f = new File(fileName);
219
220 if (!fileName.endsWith(SLASH)) {
221 InputStream is = zip.getInputStream(entry);
222 FileOutputStream fos = new FileOutputStream(f);
223
224 // write contents of 'is' to 'fos'
225 while (is.available() > 0) {
226 fos.write(is.read());
227 }
228 unzipedFiles.add(f);
229 fos.close();
230 is.close();
231 }
232 }
233 return unzipedFiles;
234 }
Vidyashree Rama3c503612017-05-10 13:55:34 +0530235}