2 * Copyright 2017 Huawei Technologies Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.vnfsdk.marketplace.wrapper;
19 import java.io.BufferedInputStream;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.nio.charset.StandardCharsets;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Objects;
29 import java.util.concurrent.Callable;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Executors;
33 import javax.ws.rs.core.HttpHeaders;
34 import javax.ws.rs.core.MediaType;
35 import javax.ws.rs.core.Response;
36 import javax.ws.rs.core.Response.Status;
38 import org.apache.commons.lang3.StringUtils;
39 import org.eclipse.jetty.http.HttpStatus;
40 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
41 import org.onap.vnfsdk.marketplace.common.CommonConstant;
42 import org.onap.vnfsdk.marketplace.common.CommonErrorResponse;
43 import org.onap.vnfsdk.marketplace.common.FileUtil;
44 import org.onap.vnfsdk.marketplace.common.RestUtil;
45 import org.onap.vnfsdk.marketplace.common.ToolUtil;
46 import org.onap.vnfsdk.marketplace.db.entity.PackageData;
47 import org.onap.vnfsdk.marketplace.db.exception.ErrorCodeException;
48 import org.onap.vnfsdk.marketplace.db.exception.MarketplaceResourceException;
49 import org.onap.vnfsdk.marketplace.db.resource.PackageManager;
50 import org.onap.vnfsdk.marketplace.db.util.MarketplaceDbUtil;
51 import org.onap.vnfsdk.marketplace.entity.request.PackageBasicInfo;
52 import org.onap.vnfsdk.marketplace.entity.response.PackageMeta;
53 import org.onap.vnfsdk.marketplace.entity.response.UploadPackageResponse;
54 import org.onap.vnfsdk.marketplace.filemanage.FileManagerFactory;
55 import org.onap.vnfsdk.marketplace.onboarding.entity.OnBoardingOperResult;
56 import org.onap.vnfsdk.marketplace.onboarding.entity.OnBoardingResult;
57 import org.onap.vnfsdk.marketplace.onboarding.entity.OnBoardingSteps;
58 import org.onap.vnfsdk.marketplace.onboarding.entity.OnBoradingRequest;
59 import org.onap.vnfsdk.marketplace.onboarding.hooks.functiontest.FunctionTestExceutor;
60 import org.onap.vnfsdk.marketplace.onboarding.hooks.functiontest.FunctionTestHook;
61 import org.onap.vnfsdk.marketplace.onboarding.hooks.validatelifecycle.ValidateLifecycleTestResponse;
62 import org.onap.vnfsdk.marketplace.onboarding.onboardmanager.OnBoardingHandler;
63 import org.open.infc.grpc.Result;
64 import org.open.infc.grpc.client.OpenRemoteCli;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
68 public class PackageWrapper {
70 private static PackageWrapper packageWrapper;
72 private static final Logger LOG = LoggerFactory.getLogger(PackageWrapper.class);
74 private static final boolean DISABLE_VALIDATION = true;
76 private static final String FILE_FORMAT = ".csar";
79 * get PackageWrapper instance.
81 * @return package wrapper instance
83 public static PackageWrapper getInstance() {
84 if(packageWrapper == null) {
85 packageWrapper = new PackageWrapper();
87 return packageWrapper;
90 public Response updateValidateStatus(InputStream inputStream) throws IOException {
91 String reqParam = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
92 LOG.info("updateValidateStatus request param:{}" , reqParam);
93 if(StringUtils.isBlank(reqParam)) {
94 LOG.error("The updateValidateStatus request params can't be null");
95 return Response.status(Status.EXPECTATION_FAILED).build();
98 ValidateLifecycleTestResponse lyfValidateResp = null;
99 // TBD - Use Gson - jackson has security issue/
101 if(!checkOperationSucess(lyfValidateResp)) {
102 return Response.status(Status.EXPECTATION_FAILED).build();
105 String funcTestResponse = FunctionTestExceutor.executeFunctionTest(reqParam);
106 if(null == funcTestResponse) {
107 return Response.status(Status.EXPECTATION_FAILED).build();
110 if(!funcTestResponse.contains(CommonConstant.SUCCESS_STR)) {
111 return Response.status(Status.EXPECTATION_FAILED).build();
114 return Response.ok().build();
117 private boolean checkOperationSucess(ValidateLifecycleTestResponse lyfValidateResp) {
118 boolean bOperStatus = false;
119 if(null == lyfValidateResp) {
120 LOG.error("ValidateLifecycleTestResponse is NUll !!!");
123 if(lyfValidateResp.getLifecycleStatus().equalsIgnoreCase(CommonConstant.SUCCESS_STR)
124 && lyfValidateResp.getValidateStatus().equalsIgnoreCase(CommonConstant.SUCCESS_STR)) {
125 String lyfValidateResponse = lyfValidateResp.getLifecycleStatus() + File.separator+lyfValidateResp.getValidateStatus();
126 LOG.error("Lifecycle/Validation Response failed :{}" , lyfValidateResponse);
133 * query package list by condition.
135 * @param name package name
136 * @param provider package provider
137 * @param version package version
138 * @param deletionPending package deletionPending
139 * @param type package type
142 public Response queryPackageListByCond(String name, String provider, String version, String deletionPending,
144 List<PackageData> dbresult = new ArrayList<>();
145 List<PackageMeta> result = new ArrayList<>();
146 if (LOG.isInfoEnabled()) {
147 LOG.info("query package info.name:{} provider:{} version{} deletionPending{} type:{}" , loggerPatternBreaking(name) , loggerPatternBreaking(provider) , loggerPatternBreaking(version)
148 , loggerPatternBreaking(deletionPending) , loggerPatternBreaking(type));
152 dbresult = PackageManager.getInstance().queryPackage(name, provider, version, deletionPending, type);
153 result = PackageWrapperUtil.packageDataList2PackageMetaList(dbresult);
154 return Response.ok(ToolUtil.objectToString(result)).build();
155 } catch(MarketplaceResourceException e1) {
156 LOG.error("query package by csarId from db error ! ", e1);
157 return RestUtil.getRestException(e1.getMessage());
161 private String loggerPatternBreaking(String loggerInput) {
162 return Objects.nonNull(loggerInput) ? loggerInput.replaceAll("[\n\r\t]", "_") : StringUtils.EMPTY;
167 * query package by id.
169 * @param csarId package id
172 public Response queryPackageById(String csarId) {
173 PackageData dbResult = PackageWrapperUtil.getPackageInfoById(csarId);
174 PackageMeta result = PackageWrapperUtil.packageData2PackageMeta(dbResult);
175 return Response.ok(ToolUtil.objectToString(result)).build();
181 * @param uploadedInputStream inputStream
182 * @param fileDetail package detail
183 * @param head http header
185 * @throws Exception e
187 public Response uploadPackage(InputStream uploadedInputStream, FormDataContentDisposition fileDetail,
188 String details, HttpHeaders head) {
189 LOG.info("Upload/Reupload request Received !!!!");
191 String packageId = MarketplaceDbUtil.generateId();
192 return handlePackageUpload(packageId, uploadedInputStream, fileDetail, details, head);
193 } catch(IOException e) {
194 LOG.error("can't get package id", e);
196 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
199 private UploadPackageResponse manageUpload(String packageId, String fileName, String fileLocation, String details,
200 String contentRange) throws ErrorCodeException {
201 String localDirName = ToolUtil.getTempDir(CommonConstant.CATALOG_CSAR_DIR_NAME, fileName);
202 PackageBasicInfo basicInfo = PackageWrapperUtil.getPacageBasicInfo(fileLocation);
203 UploadPackageResponse result = new UploadPackageResponse();
204 Boolean isEnd = PackageWrapperUtil.isUploadEnd(contentRange);
205 if(Boolean.TRUE.equals(isEnd)) {
206 PackageMeta packageMeta =
207 PackageWrapperUtil.getPackageMeta(packageId, fileName, fileLocation, basicInfo, details);
209 String path = basicInfo.getType().toString() + File.separator + basicInfo.getProvider() + File.separator
210 + packageMeta.getCsarId() + File.separator + fileName.replace(FILE_FORMAT, "") + File.separator
211 + basicInfo.getVersion();
213 String dowloadUri = File.separator + path + File.separator;
214 packageMeta.setDownloadUri(dowloadUri);
216 String jsonPackageMeta = ToolUtil.objectToString(packageMeta);
217 if (LOG.isInfoEnabled()) {
218 LOG.info("dest path is : {}" , loggerPatternBreaking(path));
219 LOG.info("packageMeta = {}" , loggerPatternBreaking(jsonPackageMeta));
223 PackageData packageData = PackageWrapperUtil.getPackageData(packageMeta);
225 List<PackageData> lstPkgData =
226 PackageManager.getInstance().queryPackage(packageMeta.getName(), "", "", "", "");
227 if(!lstPkgData.isEmpty()) {
228 LOG.error("Package name is not unique");
229 throw new ErrorCodeException(HttpStatus.INTERNAL_SERVER_ERROR_500, "Package name already exists");
232 String destPath = File.separator + path + File.separator + File.separator;
233 boolean uploadResult = FileManagerFactory.createFileManager().upload(localDirName, destPath);
235 OnBoradingRequest oOnboradingRequest = new OnBoradingRequest();
236 oOnboradingRequest.setCsarId(packageId);
237 oOnboradingRequest.setPackageName(fileName);
238 oOnboradingRequest.setPackagePath(localDirName);
240 packageData.setCsarId(packageId);
241 packageData.setDownloadCount(-1);
242 PackageData packateDbData = PackageManager.getInstance().addPackage(packageData);
244 String jsonPackageDbData = ToolUtil.objectToString(packateDbData);
245 if (LOG.isInfoEnabled()) {
246 LOG.info("Store package data to database succed ! packateDbData = {}"
247 , loggerPatternBreaking(jsonPackageDbData));
248 LOG.info("upload package file end, fileName:{}" , loggerPatternBreaking(fileName));
252 result.setCsarId(packateDbData.getCsarId());
254 addOnBoardingRequest(oOnboradingRequest);
256 String jsonoOnboradingRequest = ToolUtil.objectToString(oOnboradingRequest);
257 LOG.info("OnboradingRequest Data : {}" , jsonoOnboradingRequest);
259 } catch(NullPointerException e) {
260 String jsonBasicInfo = ToolUtil.objectToString(basicInfo);
261 LOG.error("Package basicInfo is incorrect ! basicIonfo = {} {}" , jsonBasicInfo, e);
269 * Interface for Uploading package
272 * @param uploadedInputStream
277 * @throws IOException
278 * @throws MarketplaceResourceException
280 private Response handlePackageUpload(String packageId, InputStream uploadedInputStream,
281 FormDataContentDisposition fileDetail, String details, HttpHeaders head) throws IOException {
282 boolean bResult = handleDataValidate(packageId, uploadedInputStream, fileDetail);
284 LOG.error("Validation of Input received for Package Upload failed !!!");
285 return Response.status(Status.EXPECTATION_FAILED)
286 .entity(new CommonErrorResponse("Input package is empty or exception happened during validation"))
290 String fileName = "temp_" + packageId + FILE_FORMAT;
291 if(null != fileDetail) {
292 String jsonFileDetail = ToolUtil.objectToString(fileDetail);
293 if(LOG.isInfoEnabled()) {
294 LOG.info("the fileDetail = {}" , loggerPatternBreaking(jsonFileDetail));
298 fileName = ToolUtil.processFileName(fileDetail.getFileName());
301 String localDirName = ToolUtil.getTempDir(CommonConstant.CATALOG_CSAR_DIR_NAME, fileName);
303 String contentRange = null;
305 contentRange = head.getHeaderString(CommonConstant.HTTP_HEADER_CONTENT_RANGE);
307 if(LOG.isInfoEnabled()) {
308 LOG.info("store package chunk file, fileName:{} contentRange:{}", loggerPatternBreaking(fileName) , loggerPatternBreaking(contentRange));
311 if(ToolUtil.isEmptyString(contentRange)) {
312 int fileSize = uploadedInputStream.available();
313 contentRange = "0-" + fileSize + "/" + fileSize;
316 String fileLocation = ToolUtil.storeChunkFileInLocal(localDirName, fileName, uploadedInputStream);
317 if(LOG.isInfoEnabled()) {
318 LOG.info("the fileLocation when upload package is :{}", loggerPatternBreaking(fileLocation));
321 uploadedInputStream.close();
323 if (!DISABLE_VALIDATION) {
325 Result result = OpenRemoteCli.run("localhost", 50051, null, Arrays.asList( "--product", "onap-vtp", "csar-validate", "--csar", fileLocation, "--format", "json" ));
326 LOG.info("CSAR validation is successful{}" , result.getOutput());
328 int exitCode = result.getExitCode();
329 String output = result.getOutput();
331 if((exitCode != 0) || !output.contains("\"error\":\"SUCCESS\"")) {
332 LOG.error("Could not validate failed");
333 return Response.status(Status.EXPECTATION_FAILED).entity(new CommonErrorResponse(output))
336 } catch (Exception e) {
337 LOG.error("CSAR validation panicked", e);
338 return Response.serverError().entity(
339 new CommonErrorResponse("Exception occurred while validating csar package:" + e.getMessage()))
344 UploadPackageResponse result = null;
346 result = manageUpload(packageId, fileName, fileLocation, details, contentRange);
347 } catch(ErrorCodeException e) {
348 LOG.error("ErrorCodeException occurs ",e);
349 return Response.status(Status.EXPECTATION_FAILED)
350 .entity(new CommonErrorResponse("Package Name already exists")).build();
353 return Response.ok(ToolUtil.objectToString(result), MediaType.APPLICATION_JSON).build();
355 return Response.serverError().build();
360 * Execute OnBarding request
362 * @param oOnboradingRequest
364 private void addOnBoardingRequest(final OnBoradingRequest oOnboradingRequest) {
365 ExecutorService es = Executors.newFixedThreadPool(CommonConstant.ONBOARDING_THREAD_COUNT);
366 Callable<Integer> callableInteger = () -> {
367 new OnBoardingHandler().handleOnBoardingReq(oOnboradingRequest);
368 return CommonConstant.SUCESS;
370 es.submit(callableInteger);
374 * delete package by package id.
376 * @param csarId package id
379 public Response delPackage(String csarId) {
380 if(LOG.isInfoEnabled()) {
381 LOG.info("delete package info.csarId:{}" , loggerPatternBreaking(csarId));
384 if(ToolUtil.isEmptyString(csarId)) {
385 LOG.error("delete package fail, csarid is null");
386 return Response.serverError().build();
388 deletePackageDataById(csarId);
389 return Response.ok().build();
393 * Delete Package by CSAR ID
397 private void deletePackageDataById(String csarId) {
398 String packagePath = PackageWrapperUtil.getPackagePath(csarId);
399 if(packagePath == null) {
400 LOG.error("package path is null! ");
404 FileManagerFactory.createFileManager().delete(packagePath);
405 // Delete Results Data
406 FileManagerFactory.createFileManager().delete(File.separator + csarId);
408 // delete package data from database
410 PackageManager.getInstance().deletePackage(csarId);
411 } catch(MarketplaceResourceException e1) {
412 String message = e1.getMessage();
413 LOG.error("delete package by csarId from db error ! {} {}" , message, e1);
418 * download package by package id.
420 * @param csarId package id
423 public Response downloadCsarPackagesById(String csarId) {
424 PackageData packageData = PackageWrapperUtil.getPackageInfoById(csarId);
426 String packageName = packageData.getName();
427 String path = org.onap.vnfsdk.marketplace.filemanage.http.ToolUtil.getHttpServerAbsolutePath()
428 + File.separatorChar + packageData.getType() + File.separatorChar + packageData.getProvider()
429 + File.separatorChar + packageData.getCsarId() + File.separator + packageName + File.separatorChar
430 + packageData.getVersion() + File.separator + packageName + FILE_FORMAT;
432 LOG.info("downloadCsarPackagesById path is : {}" , path);
434 File csarFile = new File(path);
435 if(!csarFile.exists()) {
436 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
439 LOG.info("downloadCsarPackagesById ABS path is : {}" , csarFile.getAbsolutePath());
442 InputStream fis = new BufferedInputStream(new FileInputStream(csarFile.getAbsolutePath()));
443 return Response.ok(fis).header("Content-Disposition", "attachment; filename=\"" + csarFile.getName() + "\"")
445 } catch(Exception e1) {
446 LOG.error("download vnf package fail.", e1);
447 return RestUtil.getRestException(e1.getMessage());
452 * get package file uri.
454 * @param csarId package id
455 * @param relativePath file relative path
458 public Response getCsarFileUri(String csarId) {
459 return downloadCsarPackagesById(csarId);
463 * Interface to Update Download count for CSAR ID
468 public Response updateDwonloadCount(String csarId) {
469 return handleDownladCountUpdate(csarId) ? Response.ok().build()
470 : Response.status(Status.EXPECTATION_FAILED).build();
474 * Handle downlowa count update
479 private boolean handleDownladCountUpdate(String csarId) {
480 boolean bupdateSucess = false;
482 PackageManager.getInstance().updateDownloadCount(csarId);
483 bupdateSucess = true;
484 } catch(Exception exp) {
485 LOG.error("Updating Donwload count failed for Package with ID !!! : {} {}" , exp.getMessage(), exp);
487 return bupdateSucess;
491 * Interface to Re upload Package
494 * @param uploadedInputStream
501 public Response reUploadPackage(String csarId, InputStream uploadedInputStream,
502 FormDataContentDisposition fileDetail, String details, HttpHeaders head)
504 LOG.info("Reupload request Received !!!!");
506 // STEP 1: Validate Input Data
507 // ----------------------------
508 boolean bResult = handleDataValidate(csarId, uploadedInputStream, fileDetail);
510 LOG.error("Validation of Input received for Package Upload failed during Reload!!!");
511 return Response.status(Status.EXPECTATION_FAILED).build();
515 // STEP 2: Delete All Package Data based on package id
516 // ----------------------------------------------------
517 deletePackageDataById(csarId);
519 // STEP 3: upload package with same package id
520 // -------------------------------------------
521 return handlePackageUpload(csarId, uploadedInputStream, fileDetail, details, head);
522 } catch(IOException e) {
523 LOG.error("delete package failed", e);
525 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
529 * Interface to get OnBoarding Result by Operation Type
536 public Response getOnBoardingResult(String csarId, String operTypeId, String operId) {
537 if(LOG.isInfoEnabled()) {
538 LOG.info("getOnBoardingResult request csarId:{} operTypeId:{} operId:{}", loggerPatternBreaking(csarId) , loggerPatternBreaking(operTypeId) , loggerPatternBreaking(operId));
543 PackageData packageData = PackageWrapperUtil.getPackageInfoById(csarId);
544 if(null == packageData) {
545 return Response.status(Response.Status.PRECONDITION_FAILED).build();
548 handleDelayExec(operId);
550 OnBoardingResult oOnBoardingResult = FunctionTestHook.getOnBoardingResult(packageData);
551 if(null == oOnBoardingResult) {
552 return Response.status(Response.Status.PRECONDITION_FAILED).build();
554 filterOnBoardingResultByOperId(oOnBoardingResult, operId);
556 String strResult = ToolUtil.objectToString(oOnBoardingResult);
557 LOG.info("getOnBoardingResult response : {}" , strResult);
558 return Response.ok(strResult, "application/json").build();
559 } catch(NullPointerException e) {
560 LOG.error("Null param in getOnBoardingResult", e);
561 return Response.status(Response.Status.BAD_REQUEST).build();
565 private void filterOnBoardingResultByOperId(OnBoardingResult oOnBoardingResult, String operId) {
566 if(0 == operId.compareToIgnoreCase("all")) {
569 if(0 == operId.compareToIgnoreCase("download")) {
570 List<OnBoardingOperResult> operResultListTemp = new ArrayList<>();
571 OnBoardingOperResult operResultListTmp = new OnBoardingOperResult();
572 operResultListTmp.setOperId("download");
573 operResultListTmp.setStatus(0);
574 operResultListTemp.add(operResultListTmp);
575 oOnBoardingResult.setOperResult(operResultListTemp);
578 List<OnBoardingOperResult> operResultListOut = new ArrayList<>();
579 List<OnBoardingOperResult> operResultList = oOnBoardingResult.getOperResult();
580 for(OnBoardingOperResult operResult : operResultList) {
581 if(0 == operResult.getOperId().compareToIgnoreCase(operId)) {
582 operResultListOut.add(operResult);
585 oOnBoardingResult.setOperResult(operResultListOut);
589 * Interface to get OnBoarding Status by Operation ID
595 public Response getOperResultByOperTypeId(String csarId, String operTypeId) {
596 if(LOG.isErrorEnabled()) {
597 LOG.error("getOnBoardingResult request : csarId:{} operTypeId:{}" , loggerPatternBreaking(csarId) , loggerPatternBreaking(operTypeId));
600 if(null == csarId || null == operTypeId || csarId.isEmpty() || operTypeId.isEmpty()) {
601 return Response.status(Status.BAD_REQUEST).build();
604 PackageData packageData = PackageWrapperUtil.getPackageInfoById(csarId);
605 if(null == packageData) {
606 if(LOG.isErrorEnabled()) {
607 LOG.error("Failed to find package for PackageID:{}" , loggerPatternBreaking(csarId));
610 return Response.status(Status.PRECONDITION_FAILED).build();
613 // Get result key to fetch Function Test Results
614 // ---------------------------------------------
615 String strResult = FunctionTestHook.getFuncTestResults(packageData);
616 if(null == strResult) {
617 LOG.error("NULL reponse for getOperResultByOperTypeId response :{}" , strResult);
618 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
620 LOG.info("getOperResultByOperTypeId response :{}" , strResult);
621 return Response.ok(strResult, MediaType.APPLICATION_JSON).build();
624 private boolean handleDataValidate(String packageId, InputStream uploadedInputStream,
625 FormDataContentDisposition fileDetail) {
626 boolean bvalidateOk = false;
627 if((null != uploadedInputStream) && (fileDetail != null) && !ToolUtil.isEmptyString(packageId)) {
634 * Interface to get OnBoarding Steps
638 public Response getOnBoardingSteps() {
639 LOG.info("Get OnBoarding Steps request Received !!!");
641 String filePath = org.onap.vnfsdk.marketplace.filemanage.http.ToolUtil.getAppDeployPath() + File.separator
642 + "generalconfig/OnBoardingSteps.json";
643 LOG.info("Onboarding Steps Json file Path :{}" , filePath);
645 OnBoardingSteps oOnBoardingSteps =
646 (OnBoardingSteps)FileUtil.readJsonDatafFromFile(filePath, OnBoardingSteps.class);
647 if(null == oOnBoardingSteps) {
648 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
650 String strResult = ToolUtil.objectToString(oOnBoardingSteps);
651 LOG.info("getOnBoardingSteps response :{}" , strResult);
652 return Response.ok(strResult, MediaType.APPLICATION_JSON).build();
655 private void handleDelayExec(String operId) {
656 if(0 == operId.compareToIgnoreCase(CommonConstant.FunctionTest.FUNCTEST_EXEC)) {
659 } catch(InterruptedException e) {
660 LOG.info("handleDelayExex response : ", e);
661 Thread.currentThread().interrupt();