Support for associating node types to models 03/122103/4
authoraribeiro <anderson.ribeiro@est.tech>
Tue, 18 May 2021 19:57:07 +0000 (20:57 +0100)
committerChristophe Closset <christophe.closset@intl.att.com>
Mon, 5 Jul 2021 14:36:03 +0000 (14:36 +0000)
Issue-ID: SDC-3597
Signed-off-by: aribeiro <anderson.ribeiro@est.tech>
Signed-off-by: MichaelMorris <michael.morris@est.tech>
Change-Id: Icd0066240b78ba98d8f0efab66d11756f18cb251

43 files changed:
catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/UploadResourceException.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourceUploadServlet.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaMetadata.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/ResourceImportManagerTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogicTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/path/beans/ForwardingPathToscaOperationFacade.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/path/utils/GraphTestUtils.java
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ArchiveEndpointTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ResourceUploadServletTest.java [new file with mode: 0644]
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java
catalog-be/src/test/resources/node-types/TestNodeType001.yml [new file with mode: 0644]
catalog-be/src/test/resources/node-types/TestNodeType001.zip [new file with mode: 0644]
catalog-be/src/test/resources/node-types/TestNodeType002.zip [new file with mode: 0644]
catalog-be/src/test/resources/node-types/invalid.json [new file with mode: 0644]
catalog-be/src/test/resources/node-types/nodeTypeWithEmptyModels.json [new file with mode: 0644]
catalog-be/src/test/resources/node-types/nodeTypeWithModelsField.json [new file with mode: 0644]
catalog-be/src/test/resources/node-types/nodeTypeWithoutModelsField.json [new file with mode: 0644]
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionaryExtractor.java
catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/Component.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadResourceInfo.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/datamodel/ToscaElement.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTypeOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/StorageOperationStatus.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/UploadResourceInfoTest.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/JsonObjectTest.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/GraphPropertyEnum.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFieldsExtractor.java

index b277aee..c87e1e3 100644 (file)
@@ -2495,3 +2495,27 @@ errors:
         message: "Could not read imports zip.",
         messageId: "SVC4147"
     }
+
+    #---------SVC4148------------------------------
+    # %1 - "Model name"
+    MODEL_NOT_FOUND: {
+        code: 404,
+        message: "Error: Model name '%1' not found. Please, make sure the model is created.",
+        messageId: "SVC4148"
+    }
+
+    #---------SVC4149------------------------------
+    MODEL_NAME_CANNOT_BE_EMPTY: {
+        code: 409,
+        message: "Error: Model name cannot be empty.",
+        messageId: "SVC4149"
+    }
+
+    #-----------SVC4150---------------------------
+    # %1 - "Component name"
+    # %2 - "Model name"
+    COMPONENT_WITH_MODEL_ALREADY_EXIST: {
+        code: 409,
+        message: "Error: Component %1 with Model %2 already exist.",
+        messageId: "SVC4150"
+    }
index 2e54ff7..bce343e 100644 (file)
@@ -425,7 +425,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     private Component getOrigComponentForServiceProxy(org.openecomp.sdc.be.model.Component containerComponent, ComponentInstance resourceInstance) {
-        Either<Component, StorageOperationStatus> serviceProxyOrigin = toscaOperationFacade.getLatestByName(SERVICE_PROXY);
+        Either<Component, StorageOperationStatus> serviceProxyOrigin = toscaOperationFacade.getLatestByName(SERVICE_PROXY, null);
         if (isServiceProxyOrigin(serviceProxyOrigin)) {
             throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(serviceProxyOrigin.right().value()));
         }
@@ -527,7 +527,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 validateInstanceName(resourceInstance);
                 if (originType == OriginTypeEnum.ServiceProxy) {
                     log.debug("enter createRealComponentInstance,originType equals ServiceProxy");
-                    Either<Component, StorageOperationStatus> serviceProxyOrigin = toscaOperationFacade.getLatestByName(SERVICE_PROXY);
+                    Either<Component, StorageOperationStatus> serviceProxyOrigin = toscaOperationFacade.getLatestByName(SERVICE_PROXY, null);
                     if (isServiceProxyOrigin(serviceProxyOrigin)) {
                         throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(serviceProxyOrigin.right().value()));
                     }
@@ -2839,7 +2839,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 newComponentInstance.setOriginType(originType);
                 if (originType == OriginTypeEnum.ServiceProxy) {
                     Either<Component, StorageOperationStatus> serviceProxyOrigin = toscaOperationFacade
-                        .getLatestByName(SERVICE_PROXY);
+                        .getLatestByName(SERVICE_PROXY, null);
                     if (isServiceProxyOrigin(serviceProxyOrigin)) {
                         throw new ByActionStatusComponentException(
                             componentsUtils.convertFromStorageResponse(serviceProxyOrigin.right().value()));
index a048af4..6eb806d 100644 (file)
@@ -34,6 +34,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
+
+/**
+ * This class is responsible for handling the business logic of a Model.
+ */
 @Component("modelBusinessLogic")
 public class ModelBusinessLogic {
 
index 99ceb21..f5b890e 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.openecomp.sdc.be.components.impl;
 
-import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toMap;
 import static java.util.stream.Collectors.toSet;
@@ -44,6 +43,7 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Function;
@@ -1314,6 +1314,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
         resourceMetaData.setContactId(user.getUserId());
         resourceMetaData.setVendorName(resourceVf.getVendorName());
         resourceMetaData.setVendorRelease(resourceVf.getVendorRelease());
+        resourceMetaData.setModel(resourceVf.getModel());
         // Setting tag
         final List<String> tags = new ArrayList<>();
         tags.add(resourceMetaData.getName());
@@ -1346,6 +1347,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
         cvfc.setCreatorUserId(csarInfo.getModifier().getUserId());
         cvfc.setVendorName(resourceVf.getVendorName());
         cvfc.setVendorRelease(resourceVf.getVendorRelease());
+        cvfc.setModel(resourceVf.getModel());
         cvfc.setResourceVendorModelNumber(resourceVf.getResourceVendorModelNumber());
         cvfc.setToscaResourceName(buildNestedToscaResourceName(ResourceTypeEnum.CVFC.name(), csarInfo.getVfResourceName(), nodeName).getLeft());
         cvfc.setInvariantUUID(UniqueIdBuilder.buildInvariantUUID());
@@ -1892,7 +1894,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
             throw e;
         }
     }
-    
+
     private boolean nodeTypeAlreadyExists(final String toscaResourceName) {
         return toscaOperationFacade.getLatestByToscaResourceName(toscaResourceName).isLeft();
     }
@@ -3277,10 +3279,11 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
         ImmutablePair<Resource, ActionStatus> result = null;
         // check if resource already exists (search by tosca name = type)
         final boolean isNestedResource = isNestedResourceUpdate(csarInfo, nodeName);
+        final String resourceName = resource.getToscaResourceName();
         final Either<Resource, StorageOperationStatus> latestByToscaName = toscaOperationFacade
-            .getLatestByToscaResourceName(resource.getToscaResourceName());
-        if (latestByToscaName.isLeft()) {
-            Resource foundResource = latestByToscaName.left().value();
+            .getLatestByToscaResourceNameAndModel(resourceName, resource.getModel());
+        if (latestByToscaName.isLeft() && Objects.nonNull(latestByToscaName.left().value())) {
+            final Resource foundResource = latestByToscaName.left().value();
             // we don't allow updating names of top level types
             if (!isNestedResource && !StringUtils.equals(resource.getName(), foundResource.getName())) {
                 BeEcompErrorManager.getInstance()
@@ -3349,7 +3352,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
     }
 
     public boolean isResourceExist(String resourceName) {
-        Either<Resource, StorageOperationStatus> latestByName = toscaOperationFacade.getLatestByName(resourceName);
+        Either<Resource, StorageOperationStatus> latestByName = toscaOperationFacade.getLatestByName(resourceName, null);
         return latestByName.isLeft();
     }
 
@@ -3464,6 +3467,9 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
         if (newResource.getResourceVendorModelNumber() == null) {
             newResource.setResourceVendorModelNumber(oldResource.getResourceVendorModelNumber());
         }
+        if (newResource.getModel() == null) {
+            newResource.setModel(oldResource.getModel());
+        }
         if (newResource.getContactId() == null) {
             newResource.setContactId(oldResource.getContactId());
         }
@@ -3749,10 +3755,12 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
     }
 
     private Resource createResourceTransaction(Resource resource, User user, boolean isNormative) {
-        // validate resource name uniqueness
-        log.debug("validate resource name");
-        Either<Boolean, StorageOperationStatus> eitherValidation = toscaOperationFacade
-            .validateComponentNameExists(resource.getName(), resource.getResourceType(), resource.getComponentType());
+        final String resourceName = resource.getName();
+        final String modelName = resource.getModel();
+        final ResourceTypeEnum resourceType = resource.getResourceType();
+        final ComponentTypeEnum componentType = resource.getComponentType();
+        final Either<Boolean, StorageOperationStatus> eitherValidation = toscaOperationFacade
+            .validateComponentNameAndModelExists(resourceName, modelName, resourceType, componentType);
         if (eitherValidation.isRight()) {
             loggerSupportability.log(LoggerSupportabilityActions.VALIDATE_NAME, resource.getComponentMetadataForSupportLog(), StatusCode.ERROR,
                 "ERROR while validate component name {} Status is: {}", resource.getName(), eitherValidation.right().value());
index b1841e5..77d8f89 100644 (file)
@@ -171,19 +171,7 @@ public class ResourceImportManager {
             setMetaDataFromJson(resourceMetaData, resource);
             populateResourceFromYaml(resourceYml, resource);
             validationFunction.apply(resource);
-            if (!createNewVersion) {
-                Either<Resource, StorageOperationStatus> latestByName = toscaOperationFacade.getLatestByName(resource.getName());
-                if (latestByName.isLeft()) {
-                    throw new ByActionStatusComponentException(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, resource.getName());
-                }
-            } else if (!isCsarPresent(csarInfo)) {
-                final Either<Resource, StorageOperationStatus> component = toscaOperationFacade
-                    .getComponentByNameAndVendorRelease(resource.getComponentType(), resource.getName(), resource.getVendorRelease(),
-                        JsonParseFlagEnum.ParseAll);
-                if (component.isLeft()) {
-                    throw new ByActionStatusComponentException(ActionStatus.COMPONENT_VERSION_ALREADY_EXIST, resource.getName());
-                }
-            }
+            checkResourceExistsBeforeCreate(createNewVersion, csarInfo, resource);
             resource = resourceBusinessLogic
                 .createOrUpdateResourceByImport(resource, creator, true, isInTransaction, needLock, csarInfo, nodeName, isNested).left;
             Resource changeStateResponse;
@@ -210,6 +198,35 @@ public class ResourceImportManager {
         return responsePair;
     }
 
+    private void checkResourceExistsBeforeCreate(final boolean createNewVersion, final CsarInfo csarInfo, final Resource resource) {
+        final String resourceName = resource.getName();
+        final String model = resource.getModel();
+        final Either<Resource, StorageOperationStatus> latestByToscaName = toscaOperationFacade
+            .getLatestByToscaResourceNameAndModel(resourceName, model);
+        if (latestByToscaName.isLeft()) {
+            final Resource foundResource = latestByToscaName.left().value();
+            validateComponentWithModelExist(resourceName, model, foundResource);
+            if (!createNewVersion) {
+                throw new ByActionStatusComponentException(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, resourceName);
+            }
+            if (!isCsarPresent(csarInfo)) {
+                final Either<Resource, StorageOperationStatus> component = toscaOperationFacade
+                    .getComponentByNameAndVendorRelease(resource.getComponentType(), resource.getName(), resource.getVendorRelease(),
+                        JsonParseFlagEnum.ParseAll);
+                if (component.isLeft()) {
+                    validateComponentWithModelExist(resourceName, model, foundResource);
+                    throw new ByActionStatusComponentException(ActionStatus.COMPONENT_VERSION_ALREADY_EXIST, resource.getName());
+                }
+            }
+        }
+    }
+
+    private void validateComponentWithModelExist(final String resourceName, final String model, final Resource foundResource) {
+        if (model != null && toscaOperationFacade.isNodeAssociatedToModel(model, foundResource).isPresent()) {
+            throw new ByActionStatusComponentException(ActionStatus.COMPONENT_WITH_MODEL_ALREADY_EXIST, resourceName, model);
+        }
+    }
+
     private boolean isCsarPresent(final CsarInfo csarInfo) {
         return csarInfo != null && StringUtils.isNotEmpty(csarInfo.getCsarUUID());
     }
@@ -246,6 +263,9 @@ public class ResourceImportManager {
             if (resourceMetaData.getVendorRelease() != null) {
                 resource.setVendorRelease(resourceMetaData.getVendorRelease());
             }
+            if (resourceMetaData.getModel() != null) {
+                resource.setModel(resourceMetaData.getModel());
+            }
         }
     }
 
index a87fdb6..ccaadba 100644 (file)
@@ -994,7 +994,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
 
     private Component getForwardingPathOriginComponent() {
         Either<Component, StorageOperationStatus> forwardingPathOrigin = toscaOperationFacade
-            .getLatestByName(ForwardingPathUtils.FORWARDING_PATH_NODE_NAME);
+            .getLatestByName(ForwardingPathUtils.FORWARDING_PATH_NODE_NAME, null);
         if (forwardingPathOrigin.isRight()) {
             StorageOperationStatus errorStatus = forwardingPathOrigin.right().value();
             log.debug("Failed to fetch normative forwarding path resource by tosca name, error {}", errorStatus);
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/UploadResourceException.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/UploadResourceException.java
new file mode 100644 (file)
index 0000000..de7a47c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdc.be.components.impl.exceptions;
+
+import lombok.Data;
+import org.openecomp.sdc.be.exception.BusinessException;
+import org.openecomp.sdc.exception.ResponseFormat;
+
+@Data
+public class UploadResourceException extends BusinessException {
+
+    private final ResponseFormat responseFormat;
+
+}
index 9cf8f67..bdc9ffc 100644 (file)
@@ -27,11 +27,8 @@ import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.servers.Server;
-import io.swagger.v3.oas.annotations.servers.Servers;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.tags.Tags;
 import java.io.File;
-import java.io.FileNotFoundException;
 import javax.inject.Inject;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
@@ -48,19 +45,23 @@ import javax.ws.rs.core.Response;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
+import org.openecomp.sdc.be.components.impl.ModelBusinessLogic;
 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.exception.BusinessException;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.impl.ServletUtils;
 import org.openecomp.sdc.be.model.UploadResourceInfo;
 import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
 import org.openecomp.sdc.be.user.UserBusinessLogic;
 import org.openecomp.sdc.common.api.Constants;
 import org.openecomp.sdc.common.datastructure.Wrapper;
-import org.openecomp.sdc.common.log.wrappers.Logger;
-import org.openecomp.sdc.common.zip.exception.ZipException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
 
 /**
@@ -68,8 +69,8 @@ import org.springframework.stereotype.Controller;
  */
 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
 @Path("/v1/catalog/upload")
-@Tags({@Tag(name = "SDCE-2 APIs")})
-@Servers({@Server(url = "/sdc2/rest")})
+@Tag(name = "SDCE-2 APIs")
+@Server(url = "/sdc2/rest")
 @Controller
 public class ResourceUploadServlet extends AbstractValidationsServlet {
 
@@ -77,12 +78,16 @@ public class ResourceUploadServlet extends AbstractValidationsServlet {
     public static final String CSAR_TYPE_RESOURCE = "csar";
     public static final String USER_TYPE_RESOURCE = "user-resource";
     public static final String USER_TYPE_RESOURCE_UI_IMPORT = "user-resource-ui-import";
-    private static final Logger log = Logger.getLogger(ResourceUploadServlet.class);
+    private static final Logger log = LoggerFactory.getLogger(ResourceUploadServlet.class);
+
+    private ModelBusinessLogic modelBusinessLogic;
 
     @Inject
     public ResourceUploadServlet(UserBusinessLogic userBusinessLogic, ComponentInstanceBusinessLogic componentInstanceBL,
-                                 ComponentsUtils componentsUtils, ServletUtils servletUtils, ResourceImportManager resourceImportManager) {
+                                 ComponentsUtils componentsUtils, ServletUtils servletUtils, ResourceImportManager resourceImportManager,
+                                 ModelBusinessLogic modelBusinessLogic) {
         super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
+        this.modelBusinessLogic = modelBusinessLogic;
     }
 
     @POST
@@ -103,8 +108,8 @@ public class ResourceUploadServlet extends AbstractValidationsServlet {
         @Parameter(description = "ContentDisposition") @FormDataParam("resourceZip") FormDataContentDisposition contentDispositionHeader,
         @Parameter(description = "resourceMetadata") @FormDataParam("resourceMetadata") String resourceInfoJsonString,
         @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
-        // updateResourse Query Parameter if false checks if already exist
-        @DefaultValue("true") @QueryParam("createNewVersion") boolean createNewVersion) throws FileNotFoundException, ZipException {
+        // updateResource Query Parameter if false checks if already exist
+        @DefaultValue("true") @QueryParam("createNewVersion") boolean createNewVersion) {
         try {
             Wrapper<Response> responseWrapper = new Wrapper<>();
             Wrapper<User> userWrapper = new Wrapper<>();
@@ -112,12 +117,14 @@ public class ResourceUploadServlet extends AbstractValidationsServlet {
             Wrapper<String> yamlStringWrapper = new Wrapper<>();
             String url = request.getMethod() + " " + request.getRequestURI();
             log.debug("Start handle request of {}", url);
-            // When we get an errorResponse it will be filled into the
-
-            // responseWrapper
+            // When we get an errorResponse it will be filled into the responseWrapper
             validateAuthorityType(responseWrapper, resourceAuthority);
             ResourceAuthorityTypeEnum resourceAuthorityEnum = ResourceAuthorityTypeEnum.findByUrlPath(resourceAuthority);
             commonGeneralValidations(responseWrapper, userWrapper, uploadResourceInfoWrapper, resourceAuthorityEnum, userId, resourceInfoJsonString);
+            final String modelNameToBeAssociated = uploadResourceInfoWrapper.getInnerElement().getModel();
+            if (modelNameToBeAssociated != null) {
+                validateModel(modelNameToBeAssociated);
+            }
             fillPayload(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(), resourceInfoJsonString,
                 resourceAuthorityEnum, file);
             // PayLoad Validations
@@ -132,10 +139,23 @@ public class ResourceUploadServlet extends AbstractValidationsServlet {
                     yamlStringWrapper.getInnerElement(), resourceAuthorityEnum, createNewVersion, null);
             }
             return responseWrapper.getInnerElement();
-        } catch (Exception e) {
-            BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Upload Resource");
-            log.debug("upload resource failed with exception", e);
+        } catch (final BusinessException e) {
             throw e;
+        } catch (final Exception e) {
+            var errorMsg = String.format("Unexpected error while uploading Resource '%s'", resourceInfoJsonString);
+            BeEcompErrorManager.getInstance().logBeRestApiGeneralError(errorMsg);
+            log.error(errorMsg, e);
+            return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
+        }
+    }
+
+    /**
+     * The Model field is an optional entry when uploading a resource. If the field is present, it validates if the Model name exists.
+     * @param modelName Model names declared on the resource json representation
+     */
+    private void validateModel(final String modelName) {
+        if (modelBusinessLogic.findModel(modelName).isEmpty()) {
+            throw ModelOperationExceptionSupplier.invalidModel(modelName).get();
         }
     }
 
@@ -148,7 +168,8 @@ public class ResourceUploadServlet extends AbstractValidationsServlet {
         // @formatter:on
 
         private String urlPath;
-        private boolean isBackEndImport, isUserTypeResource;
+        private boolean isBackEndImport;
+        private boolean isUserTypeResource;
 
         public static ResourceAuthorityTypeEnum findByUrlPath(String urlPath) {
             ResourceAuthorityTypeEnum found = null;
@@ -161,7 +182,7 @@ public class ResourceUploadServlet extends AbstractValidationsServlet {
             return found;
         }
 
-        private ResourceAuthorityTypeEnum(String urlPath, boolean isBackEndImport, boolean isUserTypeResource) {
+        ResourceAuthorityTypeEnum(String urlPath, boolean isBackEndImport, boolean isUserTypeResource) {
             this.urlPath = urlPath;
             this.isBackEndImport = isBackEndImport;
             this.isUserTypeResource = isUserTypeResource;
index f193510..52ced65 100644 (file)
@@ -472,6 +472,7 @@ public class ToscaExportHandler {
                 toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR.getPresentation(), resource.getVendorName());
                 toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_RELEASE.getPresentation(), resource.getVendorRelease());
                 toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_MODEL_NUMBER.getPresentation(), resource.getResourceVendorModelNumber());
+                toscaMetadata.put(JsonPresentationFields.MODEL.getPresentation(), resource.getModel());
                 break;
             case SERVICE:
                 Service service = (Service) component;
@@ -1122,7 +1123,7 @@ public class ToscaExportHandler {
             return res;
         }
         Either<Resource, StorageOperationStatus> serviceProxyOrigin = toscaOperationFacade
-            .getLatestByName("serviceProxy");
+            .getLatestByName("serviceProxy", null);
         if (serviceProxyOrigin.isRight()) {
             log.debug("Failed to fetch normative service proxy resource by tosca name, error {}",
                 serviceProxyOrigin.right().value());
index 97dab36..54d382f 100644 (file)
@@ -44,6 +44,7 @@ public class ToscaMetadata implements IToscaMetadata {
     private String sourceModelName;
     private String sourceModelUuid;
     private String serviceFunction;
+    private String model;
 
     public String getName() {
         return name;
@@ -232,4 +233,12 @@ public class ToscaMetadata implements IToscaMetadata {
     public void setEnvironmentContext(String environmentContext) {
         this.environmentContext = environmentContext;
     }
+
+    public String getModel() {
+        return model;
+    }
+
+    public void setModel(String model) {
+        this.model = model;
+    }
 }
index 622027d..f56ff2e 100644 (file)
@@ -28,9 +28,9 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.when;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
 
 import fj.data.Either;
 import java.io.IOException;
@@ -38,6 +38,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -57,7 +58,6 @@ import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
 import org.openecomp.sdc.be.config.Configuration;
 import org.openecomp.sdc.be.config.ConfigurationManager;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
-import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
@@ -106,6 +106,7 @@ public class ResourceImportManagerTest {
         importManager = new ResourceImportManager(componentsUtils, capabilityTypeOperation, interfaceDefinitionHandler);
         importManager.setAuditingManager(auditingManager);
         when(toscaOperationFacade.getLatestByToscaResourceName(Mockito.anyString())).thenReturn(Either.left(null));
+        when(toscaOperationFacade.getLatestByToscaResourceNameAndModel(Mockito.anyString(), Mockito.any())).thenReturn(Either.left(null));
         importManager.setResponseFormatManager(responseFormatManager);
         importManager.setResourceBusinessLogic(resourceBusinessLogic);
         importManager.setToscaOperationFacade(toscaOperationFacade);
@@ -123,7 +124,8 @@ public class ResourceImportManagerTest {
     public void beforeTest() {
         Mockito.reset(auditingManager, responseFormatManager, resourceBusinessLogic, userAdmin);
         Either<Component, StorageOperationStatus> notFound = Either.right(StorageOperationStatus.NOT_FOUND);
-        when(toscaOperationFacade.getComponentByNameAndVendorRelease(any(ComponentTypeEnum.class), anyString(), anyString(), any(JsonParseFlagEnum.class))).thenReturn(notFound);
+        when(toscaOperationFacade.getComponentByNameAndVendorRelease(any(ComponentTypeEnum.class), anyString(), anyString(),
+            any(JsonParseFlagEnum.class))).thenReturn(notFound);
     }
 
     @Test
@@ -301,12 +303,15 @@ public class ResourceImportManagerTest {
         setResourceBusinessLogicMock();
 
         Either<Component, StorageOperationStatus> notFound = Either.left(Mockito.mock(Resource.class));
-        when(toscaOperationFacade.getComponentByNameAndVendorRelease(any(ComponentTypeEnum.class), anyString(), anyString(), any(JsonParseFlagEnum.class))).thenReturn(notFound);
+        when(toscaOperationFacade.getComponentByNameAndVendorRelease(any(ComponentTypeEnum.class), anyString(), anyString(),
+            any(JsonParseFlagEnum.class))).thenReturn(notFound);
         
         String jsonContent = ImportUtilsTest.loadFileNameToJsonString("normative-types-new-blockStorage.yml");
         
         ComponentException errorInfoFromTest = null;
         try {
+            when(toscaOperationFacade
+                .getLatestByToscaResourceNameAndModel(resourceMD.getName(), StringUtils.EMPTY)).thenReturn(Either.left(new Resource()));
             importManager.importNormativeResource(jsonContent, resourceMD, user, true, true);
         }catch (ComponentException e){
             errorInfoFromTest = e;
index 17078bc..fe2f3ba 100644 (file)
@@ -45,7 +45,6 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import javax.servlet.ServletContext;
-
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.junit.Assert;
 import org.junit.Before;
@@ -90,7 +89,18 @@ import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
 import org.openecomp.sdc.be.facade.operations.CatalogOperation;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
-import org.openecomp.sdc.be.model.*;
+import org.openecomp.sdc.be.model.ArtifactDefinition;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.ComponentParametersView;
+import org.openecomp.sdc.be.model.DataTypeDefinition;
+import org.openecomp.sdc.be.model.GroupDefinition;
+import org.openecomp.sdc.be.model.InputDefinition;
+import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
+import org.openecomp.sdc.be.model.LifecycleStateEnum;
+import org.openecomp.sdc.be.model.NodeTypeInfo;
+import org.openecomp.sdc.be.model.PropertyDefinition;
+import org.openecomp.sdc.be.model.Resource;
+import org.openecomp.sdc.be.model.User;
 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
@@ -455,6 +465,9 @@ public class ResourceBusinessLogicTest {
                Resource resource = createResourceObject(false);
                Resource createdResource = null;
                try {
+                       when(toscaOperationFacade
+                               .validateComponentNameAndModelExists(resource.getName(), null,  ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE))
+                               .thenReturn(Either.left(false));
                        createdResource = bl.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, user, null, null);
                        assertThat(createResourceObject(true)).isEqualTo(createdResource);
                } catch (ComponentException e) {
@@ -561,6 +574,9 @@ public class ResourceBusinessLogicTest {
                resourceExist.getTags()
                                .add(resourceName);
                validateUserRoles(Role.ADMIN, Role.DESIGNER);
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resourceName, null,  ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(true));
                try {
                        bl.createResource(resourceExist, AuditingActionEnum.CREATE_RESOURCE, user, null, null);
                } catch (ComponentException e) {
@@ -673,7 +689,9 @@ public class ResourceBusinessLogicTest {
        private void testResourceIconMissing() {
                Resource resourceExist = createResourceObject(false);
                resourceExist.setIcon(null);
-
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resourceExist.getName(), null,  ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
                try {
                        bl.createResource(resourceExist, AuditingActionEnum.CREATE_RESOURCE, user, null, null);
                } catch (ComponentException e) {
@@ -1541,6 +1559,9 @@ public class ResourceBusinessLogicTest {
                createRoot();
                Resource resourceExist = createResourceObject(false);
                validateUserRoles(Role.ADMIN, Role.DESIGNER);
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resourceExist.getName(), null,  ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
                Resource createdResource = bl.createResource(resourceExist, AuditingActionEnum.CREATE_RESOURCE, user, null,
                                null);
                createdResource.setLastUpdaterUserId(user.getUserId());
@@ -1549,6 +1570,8 @@ public class ResourceBusinessLogicTest {
                Either<Component, StorageOperationStatus> getCompLatestResult = Either.left(createdResource);
                when(toscaOperationFacade.getLatestByToscaResourceName(resourceExist.getToscaResourceName()))
                                .thenReturn(getCompLatestResult);
+               when(toscaOperationFacade.getLatestByToscaResourceNameAndModel(resourceExist.getToscaResourceName(), null))
+                       .thenReturn(getCompLatestResult);
                when(toscaOperationFacade.overrideComponent(any(Resource.class), any(Resource.class)))
                                .thenReturn(getLatestResult);
 
@@ -1570,6 +1593,9 @@ public class ResourceBusinessLogicTest {
        public void createOrUpdateResourceCertified() {
                createRoot();
                Resource resourceExist = createResourceObject(false);
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resourceExist.getName(), null,  ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
                validateUserRoles(Role.ADMIN, Role.DESIGNER);
                Resource createdResource = bl.createResource(resourceExist, AuditingActionEnum.CREATE_RESOURCE, user, null,
                                null);
@@ -1580,8 +1606,8 @@ public class ResourceBusinessLogicTest {
 
                Either<Resource, StorageOperationStatus> getLatestResult = Either.left(createdResource);
                Either<Component, StorageOperationStatus> getCompLatestResult = Either.left(createdResource);
-               when(toscaOperationFacade.getLatestByToscaResourceName(resourceExist.getToscaResourceName()))
-                               .thenReturn(getCompLatestResult);
+               when(toscaOperationFacade.getLatestByToscaResourceNameAndModel(resourceExist.getToscaResourceName(), null))
+                       .thenReturn(getCompLatestResult);
                when(toscaOperationFacade.overrideComponent(any(Resource.class), any(Resource.class)))
                                .thenReturn(getLatestResult);
 
@@ -1608,12 +1634,12 @@ public class ResourceBusinessLogicTest {
                Resource resourceToUpdtae = createResourceObject(false);
 
                Either<Component, StorageOperationStatus> getLatestResult = Either.right(StorageOperationStatus.NOT_FOUND);
-               when(toscaOperationFacade.getLatestByName(resourceToUpdtae.getName())).thenReturn(getLatestResult);
-
-               Either<Component, StorageOperationStatus> getLatestToscaNameResult = Either
-                               .right(StorageOperationStatus.NOT_FOUND);
-               when(toscaOperationFacade.getLatestByToscaResourceName(resourceToUpdtae.getToscaResourceName()))
-                               .thenReturn(getLatestToscaNameResult);
+               when(toscaOperationFacade.getLatestByName(resourceToUpdtae.getName(), null)).thenReturn(getLatestResult);
+               when(toscaOperationFacade.getLatestByToscaResourceNameAndModel(resourceToUpdtae.getToscaResourceName(), null))
+                       .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resourceToUpdtae.getName(), null,  ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
 
                ImmutablePair<Resource, ActionStatus> createOrUpdateResource = bl
                                .createOrUpdateResourceByImport(resourceToUpdtae, user, false, false, false, null, null, false);
@@ -1651,13 +1677,19 @@ public class ResourceBusinessLogicTest {
                String nestedResourceName = bl.buildNestedToscaResourceName(resourceToUpdate.getResourceType()
                                .name(), csarInfo.getVfResourceName(), nodeName)
                                .getRight();
-               when(toscaOperationFacade.getLatestByName(resourceToUpdate.getName()))
+               when(toscaOperationFacade.getLatestByName(resourceToUpdate.getName(), null))
                                .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
                when(toscaOperationFacade.getLatestByToscaResourceName(resourceToUpdate.getToscaResourceName()))
                                .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
                when(toscaOperationFacade.getLatestByToscaResourceName(nestedResourceName))
                                .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
 
+               when(toscaOperationFacade.getLatestByToscaResourceNameAndModel(resourceToUpdate.getToscaResourceName(), null))
+                       .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resourceToUpdate.getName(), null,  ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
+
                ImmutablePair<Resource, ActionStatus> createOrUpdateResource = bl
                                .createOrUpdateResourceByImport(resourceToUpdate, user, false, false, false, csarInfo, nodeName, false);
                assertThat(createOrUpdateResource).isNotNull();
@@ -1683,10 +1715,12 @@ public class ResourceBusinessLogicTest {
                String nestedResourceName = bl.buildNestedToscaResourceName(resourceToUpdate.getResourceType()
                                .name(), csarInfo.getVfResourceName(), nodeName)
                                .getRight();
-               when(toscaOperationFacade.getLatestByName(resourceToUpdate.getName()))
+               when(toscaOperationFacade.getLatestByName(resourceToUpdate.getName(), null))
                                .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
                when(toscaOperationFacade.getLatestByToscaResourceName(resourceToUpdate.getToscaResourceName()))
                                .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
+               when(toscaOperationFacade.getLatestByToscaResourceNameAndModel(resourceToUpdate.getToscaResourceName(), null))
+                       .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
                when(toscaOperationFacade.getLatestByToscaResourceName(nestedResourceName))
                                .thenReturn(Either.left(resourceResponse));
                when(toscaOperationFacade.overrideComponent(any(Resource.class), any(Resource.class)))
@@ -2067,6 +2101,9 @@ public class ResourceBusinessLogicTest {
                when(genericTypeBusinessLogic.generateInputsFromGenericTypeProperties(genericVF)).thenCallRealMethod();
                when(genericTypeBusinessLogic.convertGenericTypePropertiesToInputsDefintion(genericVF.getProperties(),
                                resource.getUniqueId())).thenCallRealMethod();
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resource.getName(), null,  ResourceTypeEnum.VF, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
                Resource createdResource = bl.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, user, null, null);
                assertThat(createdResource).isNotNull();
                return createdResource;
@@ -2092,6 +2129,9 @@ public class ResourceBusinessLogicTest {
                when(genericTypeBusinessLogic.generateInputsFromGenericTypeProperties(genericCR)).thenCallRealMethod();
                when(genericTypeBusinessLogic.convertGenericTypePropertiesToInputsDefintion(genericCR.getProperties(),
                                resource.getUniqueId())).thenCallRealMethod();
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resource.getName(), null,  ResourceTypeEnum.CR, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
                Resource createdResource = bl.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, user, null, null);
                assertThat(createdResource).isNotNull();
                return createdResource;
@@ -2110,6 +2150,9 @@ public class ResourceBusinessLogicTest {
                when(genericTypeBusinessLogic.generateInputsFromGenericTypeProperties(genericPNF)).thenCallRealMethod();
                when(genericTypeBusinessLogic.convertGenericTypePropertiesToInputsDefintion(genericPNF.getProperties(),
                                resource.getUniqueId())).thenCallRealMethod();
+               when(toscaOperationFacade
+                       .validateComponentNameAndModelExists(resource.getName(), null,  ResourceTypeEnum.PNF, ComponentTypeEnum.RESOURCE))
+                       .thenReturn(Either.left(false));
                Resource createdResource = bl.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, user, null, null);
                assertThat(createdResource).isNotNull();
                return createdResource;
index 7102ed2..3774332 100644 (file)
@@ -21,6 +21,7 @@
 package org.openecomp.sdc.be.components.path.beans;
 
 import fj.data.Either;
+import org.apache.commons.lang3.StringUtils;
 import org.openecomp.sdc.be.impl.ForwardingPathUtils;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.Resource;
@@ -44,13 +45,13 @@ public class ForwardingPathToscaOperationFacade extends ToscaOperationFacade {
     }
 
     @Override
-    public <T extends Component> Either<T, StorageOperationStatus> getLatestByName(String resourceName) {
+    public <T extends Component> Either<T, StorageOperationStatus> getLatestByName(String resourceName, String model) {
         if(resourceName.equals(ForwardingPathUtils.FORWARDING_PATH_NODE_NAME) || resourceName.equals(ForwardingPathUtils.FORWARDER_CAPABILITY)){
             Resource component = new Resource();
             component.setToscaResourceName(GENERIC_SERVICE_NAME);
             return Either.left((T)component);
         }
-        return super.getLatestByName(resourceName);
+        return super.getLatestByName(resourceName, null);
     }
 
     @Override
index be20beb..0456988 100644 (file)
@@ -73,6 +73,7 @@ public final class GraphTestUtils {
         vertex.addMetadataProperty(GraphPropertyEnum.UNIQUE_ID, uuid);
         vertex.addMetadataProperty(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
         vertex.addMetadataProperty(GraphPropertyEnum.RESOURCE_TYPE, type.name());
+        vertex.addMetadataProperty(GraphPropertyEnum.MODEL, type.name());
         vertex.addMetadataProperty(GraphPropertyEnum.IS_ABSTRACT, false);
         for (Map.Entry<GraphPropertyEnum, Object> prop : metadataProps.entrySet()) {
             vertex.addMetadataProperty(prop.getKey(), prop.getValue());
index 4359270..faede3d 100644 (file)
@@ -92,6 +92,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.TopologyTemplateOper
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.servlets.exception.ComponentExceptionMapper;
 import org.openecomp.sdc.be.servlets.exception.DefaultExceptionMapper;
 import org.openecomp.sdc.be.servlets.exception.StorageExceptionMapper;
@@ -261,6 +262,11 @@ class ArchiveEndpointTest extends JerseyTest {
             return new ContainerInstanceTypesData();
         }
 
+        @Bean
+        ModelOperation modelOperation() {
+            return new ModelOperation(null, null, null);
+        }
+
         private void initGraphForTest() {
             //Create Catalog Root
             catalogVertex = GraphTestUtils.createRootCatalogVertex(janusGraphDao);
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ResourceUploadServletTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ResourceUploadServletTest.java
new file mode 100644 (file)
index 0000000..31152c6
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdc.be.servlets;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Optional;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jetty.http.HttpStatus;
+import org.glassfish.hk2.utilities.binding.AbstractBinder;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
+import org.openecomp.sdc.be.components.impl.ModelBusinessLogic;
+import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
+import org.openecomp.sdc.be.components.impl.ResourceImportManager;
+import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
+import org.openecomp.sdc.be.components.validation.UserValidations;
+import org.openecomp.sdc.be.config.ConfigurationManager;
+import org.openecomp.sdc.be.config.SpringConfig;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.impl.ComponentsUtils;
+import org.openecomp.sdc.be.impl.ServletUtils;
+import org.openecomp.sdc.be.impl.WebAppContextWrapper;
+import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.Resource;
+import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.servlets.builder.ServletResponseBuilder;
+import org.openecomp.sdc.be.servlets.exception.OperationExceptionMapper;
+import org.openecomp.sdc.be.user.Role;
+import org.openecomp.sdc.be.user.UserBusinessLogic;
+import org.openecomp.sdc.common.api.ConfigurationSource;
+import org.openecomp.sdc.common.api.Constants;
+import org.openecomp.sdc.common.impl.ExternalConfiguration;
+import org.openecomp.sdc.common.impl.FSConfigurationSource;
+import org.openecomp.sdc.exception.ResponseFormat;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+
+@TestInstance(Lifecycle.PER_CLASS)
+class ResourceUploadServletTest extends JerseyTest {
+    private static final String USER_ID = "cs0008";
+
+    @Mock
+    private HttpServletRequest request;
+    @Mock
+    private HttpSession session;
+    @Mock
+    private ServletContext servletContext;
+    @Mock
+    private WebAppContextWrapper webAppContextWrapper;
+    @Mock
+    private WebApplicationContext webApplicationContext;
+    @Mock
+    private UserBusinessLogic userBusinessLogic;
+    @Mock
+    private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
+    @Mock
+    private ComponentsUtils componentsUtils;
+    @Mock
+    private ServletUtils servletUtils;
+    @Mock
+    private ResourceImportManager resourceImportManager;
+    @Mock
+    private ResourceBusinessLogic resourceBusinessLogic;
+    @Mock
+    private ResponseFormat responseFormat;
+    @Mock
+    private UserValidations userValidations;
+    @Mock
+    private ModelBusinessLogic modelBusinessLogic;
+    @Mock
+    private ResponseFormatManager responseFormatManager;
+    private final String modelName = "ETSI-SOL001-331";
+
+    private final String rootPath = "/v1/catalog/upload/multipart";
+    private Response response;
+    private User user;
+
+    @BeforeAll
+    public void initClass() {
+        when(request.getSession()).thenReturn(session);
+        when(session.getServletContext()).thenReturn(servletContext);
+        when(servletContext.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR))
+            .thenReturn(webAppContextWrapper);
+        when(webAppContextWrapper.getWebAppContext(servletContext)).thenReturn(webApplicationContext);
+        when(webApplicationContext.getBean(ModelBusinessLogic.class)).thenReturn(modelBusinessLogic);
+        when(request.getHeader(Constants.USER_ID_HEADER)).thenReturn(USER_ID);
+        when(webApplicationContext.getBean(ServletUtils.class)).thenReturn(servletUtils);
+        when(servletUtils.getComponentsUtils()).thenReturn(componentsUtils);
+        final String appConfigDir = "src/test/resources/config/catalog-be";
+        final ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), appConfigDir);
+        final ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
+        final org.openecomp.sdc.be.config.Configuration configuration = new org.openecomp.sdc.be.config.Configuration();
+        configuration.setJanusGraphInMemoryGraph(true);
+        configurationManager.setConfiguration(configuration);
+        ExternalConfiguration.setAppName("catalog-be");
+    }
+
+    @BeforeEach
+    void resetMock() throws Exception {
+        super.setUp();
+        initTestData();
+    }
+
+    @AfterEach
+    void after() throws Exception {
+        super.tearDown();
+    }
+
+    private void initTestData() {
+        user = new User();
+        user.setUserId(USER_ID);
+        user.setRole(Role.ADMIN.name());
+        when(userBusinessLogic.getUser(USER_ID)).thenReturn(user);
+    }
+
+    @Override
+    protected ResourceConfig configure() {
+        MockitoAnnotations.openMocks(this);
+        forceSet(TestProperties.CONTAINER_PORT, "0");
+        final ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
+        return new ResourceConfig(ResourceUploadServlet.class)
+            .register(new AbstractBinder() {
+                @Override
+                protected void configure() {
+                    bind(request).to(HttpServletRequest.class);
+                    bind(userBusinessLogic).to(UserBusinessLogic.class);
+                    bind(componentInstanceBusinessLogic).to(ComponentInstanceBusinessLogic.class);
+                    bind(componentsUtils).to(ComponentsUtils.class);
+                    bind(servletUtils).to(ServletUtils.class);
+                    bind(resourceImportManager).to(ResourceImportManager.class);
+                    bind(resourceBusinessLogic).to(ResourceBusinessLogic.class);
+                    bind(modelBusinessLogic).to(ModelBusinessLogic.class);
+                    bind(userValidations).to(UserValidations.class);
+                }
+            })
+            .register(new OperationExceptionMapper(new ServletResponseBuilder(), responseFormatManager))
+            .register(MultiPartFeature.class)
+            .property("contextConfig", context);
+    }
+
+    @Override
+    protected void configureClient(final ClientConfig config) {
+        config.register(MultiPartFeature.class);
+    }
+
+    @Test
+    void uploadMultipartWithModelSuccessTest() throws IOException, ParseException, URISyntaxException {
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.OK_200);
+        when(componentsUtils.getResponseFormat(ActionStatus.CREATED)).thenReturn(responseFormat);
+        when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
+        when(userBusinessLogic.getUser(anyString())).thenReturn(user);
+        when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
+        when(resourceImportManager.importNormativeResource(anyString(), any(), any(), anyBoolean(), anyBoolean()))
+            .thenReturn(new ImmutablePair<>(new Resource(), ActionStatus.CREATED));
+        when(modelBusinessLogic.findModel(modelName)).thenReturn(Optional.of(new Model(modelName)));
+        response = target().path(rootPath).request(MediaType.APPLICATION_JSON)
+            .header(Constants.USER_ID_HEADER, USER_ID)
+            .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType001.zip",
+                "src/test/resources/node-types/nodeTypeWithModelsField.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
+        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK_200);
+    }
+
+    @Test
+    void uploadMultipartWithoutModelsFieldSuccessTest() throws IOException, ParseException, URISyntaxException {
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.OK_200);
+        when(componentsUtils.getResponseFormat(ActionStatus.CREATED)).thenReturn(responseFormat);
+        when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
+        when(userBusinessLogic.getUser(anyString())).thenReturn(user);
+        when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
+        when(resourceImportManager.importNormativeResource(anyString(), any(), any(), anyBoolean(), anyBoolean()))
+            .thenReturn(new ImmutablePair<>(new Resource(), ActionStatus.CREATED));
+        response = target().path(rootPath).request(MediaType.APPLICATION_JSON)
+            .header(Constants.USER_ID_HEADER, USER_ID)
+            .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType002.zip",
+                "src/test/resources/node-types/nodeTypeWithoutModelsField.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
+        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK_200);
+    }
+
+    @Test
+    void uploadMultipartFailWithEmptyModelsTest() throws IOException, ParseException, URISyntaxException {
+        when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
+        when(userBusinessLogic.getUser(anyString())).thenReturn(user);
+        when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
+        when(modelBusinessLogic.findModel("")).thenReturn(Optional.empty());
+        response = target().path(rootPath).request(MediaType.APPLICATION_JSON)
+            .header(Constants.USER_ID_HEADER, USER_ID)
+            .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType002.zip",
+                "src/test/resources/node-types/nodeTypeWithEmptyModels.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
+        assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
+    }
+
+    @Test
+    void uploadMultipartFailWithModelNotFoundTest() throws IOException, ParseException, URISyntaxException {
+        when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
+        when(userBusinessLogic.getUser(anyString())).thenReturn(user);
+        when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
+        when(modelBusinessLogic.findModel(modelName)).thenReturn(Optional.empty());
+        response = target().path(rootPath).request(MediaType.APPLICATION_JSON)
+            .header(Constants.USER_ID_HEADER, USER_ID)
+            .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType001.zip",
+                "src/test/resources/node-types/nodeTypeWithModelsField.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
+        assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
+    }
+
+    @Test
+    void uploadMultipartThrowsBusinessExceptionTest() throws IOException, ParseException, URISyntaxException {
+        when(servletUtils.getUserAdmin()).thenReturn(userBusinessLogic);
+        when(userBusinessLogic.getUser(anyString())).thenReturn(user);
+        when(resourceBusinessLogic.validatePropertiesDefaultValues(any())).thenReturn(true);
+        response = target().path(rootPath).request(MediaType.APPLICATION_JSON)
+            .header(Constants.USER_ID_HEADER, USER_ID)
+            .post(Entity.entity(buildFormDataMultiPart("node-types/TestNodeType001.zip",
+                "src/test/resources/node-types/invalid.json"), MediaType.MULTIPART_FORM_DATA), Response.class);
+        assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
+    }
+
+    private String getInputData(final String jsonFilename) throws IOException, ParseException {
+        final JSONObject inputData = (JSONObject) new JSONParser().parse(
+            new FileReader(jsonFilename));
+        return inputData.toJSONString();
+    }
+
+    private File getFile(final String fileName) throws URISyntaxException {
+        final URL resource = this.getClass().getClassLoader().getResource(fileName);
+        if (resource == null) {
+            throw new IllegalArgumentException("file not found! " + fileName);
+        }
+        return new File(resource.toURI());
+    }
+
+    private FormDataMultiPart buildFormDataMultiPart(final String zipFilePath, final String inputJsonData)
+        throws IOException, ParseException, URISyntaxException {
+        final FileDataBodyPart filePart = new FileDataBodyPart("resourceZip", getFile(zipFilePath));
+        final FormDataMultiPart multipartEntity = new FormDataMultiPart();
+        multipartEntity.bodyPart(filePart);
+        multipartEntity.field("resourceMetadata", getInputData(inputJsonData));
+        return  multipartEntity;
+    }
+}
index 202cf01..acd4cb4 100644 (file)
@@ -735,7 +735,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
             .thenReturn(Either.left(new ToscaNodeType()));
         when(toscaOperationFacade.getToscaFullElement("uid")).thenReturn(Either.left(component));
         when(toscaOperationFacade.getToscaFullElement("sourceModelUid")).thenReturn(Either.left(component));
-        when(toscaOperationFacade.getLatestByName("serviceProxy")).thenReturn(Either.left(new Resource()));
+        when(toscaOperationFacade.getLatestByName("serviceProxy", null)).thenReturn(Either.left(new Resource()));
         when(toscaOperationFacade.getToscaElement(any(String.class), any(ComponentParametersView.class))).thenReturn(Either.left(new Resource()));
 
         final Map<String, String[]> substitutionMappingMap = new HashMap<>();
@@ -859,7 +859,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
             .thenReturn(Either.left(new ToscaNodeType()));
         when(toscaOperationFacade.getToscaFullElement("uid")).thenReturn(Either.left(component));
         when(toscaOperationFacade.getToscaFullElement("sourceModelUid")).thenReturn(Either.left(component));
-        when(toscaOperationFacade.getLatestByName("serviceProxy")).thenReturn(Either.left(new Resource()));
+        when(toscaOperationFacade.getLatestByName("serviceProxy", null)).thenReturn(Either.left(new Resource()));
         when(toscaOperationFacade.getToscaElement(any(String.class), any(ComponentParametersView.class))).thenReturn(Either.left(new Resource()));
 
         final Map<String, String[]> substitutionMappingMap = new HashMap<>();
@@ -1135,7 +1135,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
         componentInstances.add(instance);
         container.setComponentInstances(componentInstances);
 
-        when(toscaOperationFacade.getLatestByName("serviceProxy"))
+        when(toscaOperationFacade.getLatestByName("serviceProxy", null))
             .thenReturn(Either.right(StorageOperationStatus.BAD_REQUEST));
 
         // test when getLatestByName return is right
@@ -1188,7 +1188,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
         componentInstances.add(instance);
         container.setComponentInstances(componentInstances);
 
-        when(toscaOperationFacade.getLatestByName("serviceProxy")).thenReturn(Either.left(new Resource()));
+        when(toscaOperationFacade.getLatestByName("serviceProxy", null)).thenReturn(Either.left(new Resource()));
 
         ComponentParametersView parameterView = new ComponentParametersView();
         parameterView.disableAll();
diff --git a/catalog-be/src/test/resources/node-types/TestNodeType001.yml b/catalog-be/src/test/resources/node-types/TestNodeType001.yml
new file mode 100644 (file)
index 0000000..6a31257
--- /dev/null
@@ -0,0 +1,18 @@
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+node_types:
+  tosca.nodes.nfv.TestNodeType001:
+    derived_from: tosca.nodes.Root
+    description: The generic abstract type from which all VNF specific abstract node types shall be derived to form, together with other node types, the TOSCA service template(s) representing the VNFD
+    properties:
+      descriptor_id: # instead of vnfd_id
+        type: string # GUID
+        description: Globally unique identifier of the VNFD
+        required: true
+      descriptor_version: # instead of vnfd_version
+        type: string
+        description: Identifies the version of the VNFD
+        required: true
+      provider: # instead of vnf_provider
+        type: string
+        description: Provider of the VNF and of the VNFD
+        required: true
diff --git a/catalog-be/src/test/resources/node-types/TestNodeType001.zip b/catalog-be/src/test/resources/node-types/TestNodeType001.zip
new file mode 100644 (file)
index 0000000..047088c
Binary files /dev/null and b/catalog-be/src/test/resources/node-types/TestNodeType001.zip differ
diff --git a/catalog-be/src/test/resources/node-types/TestNodeType002.zip b/catalog-be/src/test/resources/node-types/TestNodeType002.zip
new file mode 100644 (file)
index 0000000..1185e3f
Binary files /dev/null and b/catalog-be/src/test/resources/node-types/TestNodeType002.zip differ
diff --git a/catalog-be/src/test/resources/node-types/invalid.json b/catalog-be/src/test/resources/node-types/invalid.json
new file mode 100644 (file)
index 0000000..0db3279
--- /dev/null
@@ -0,0 +1,3 @@
+{
+
+}
diff --git a/catalog-be/src/test/resources/node-types/nodeTypeWithEmptyModels.json b/catalog-be/src/test/resources/node-types/nodeTypeWithEmptyModels.json
new file mode 100644 (file)
index 0000000..535f740
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "payloadName": "TestNodeType002.yml",
+  "contactId": "jh0003",
+  "name": "TestNodeType002",
+  "description": "TestUploadNodeType002",
+  "resourceIconPath": "compute",
+  "resourceType": "VFC",
+  "categories": [{
+    "name": "Generic",
+    "subcategories": [{
+      "name": "Infrastructure"
+    }]
+  }],
+  "tags": ["TestUploadNodeType002"],
+  "model": ""
+}
diff --git a/catalog-be/src/test/resources/node-types/nodeTypeWithModelsField.json b/catalog-be/src/test/resources/node-types/nodeTypeWithModelsField.json
new file mode 100644 (file)
index 0000000..03e28e3
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "payloadName": "TestNodeType001.yml",
+  "contactId": "jh0003",
+  "name": "TestNodeType001",
+  "description": "TestUploadNodeType001",
+  "resourceIconPath": "compute",
+  "resourceType": "VFC",
+  "categories": [{
+    "name": "Generic",
+    "subcategories": [{
+      "name": "Infrastructure"
+    }]
+  }],
+  "tags": ["TestUploadNodeType001"],
+  "model": "ETSI-SOL001-331"
+}
diff --git a/catalog-be/src/test/resources/node-types/nodeTypeWithoutModelsField.json b/catalog-be/src/test/resources/node-types/nodeTypeWithoutModelsField.json
new file mode 100644 (file)
index 0000000..3c0eb14
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "payloadName": "TestNodeType002.yml",
+  "contactId": "jh0003",
+  "name": "TestNodeType002",
+  "description": "TestUploadNodeType002",
+  "resourceIconPath": "compute",
+  "resourceType": "VFC",
+  "categories": [{
+    "name": "Generic",
+    "subcategories": [{
+      "name": "Infrastructure"
+    }]
+  }],
+  "tags": ["TestUploadNodeType002"]
+}
index ed448c1..4728833 100644 (file)
@@ -52,7 +52,8 @@ public enum ActionStatus {
     // Category related
     COMPONENT_MISSING_CATEGORY, COMPONENT_INVALID_CATEGORY, COMPONENT_ELEMENT_INVALID_NAME_FORMAT, COMPONENT_ELEMENT_INVALID_NAME_LENGTH, COMPONENT_CATEGORY_ALREADY_EXISTS, COMPONENT_CATEGORY_NOT_FOUND, COMPONENT_SUB_CATEGORY_NOT_FOUND_FOR_CATEGORY, COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY,
     // Model related
-    MODEL_ALREADY_EXISTS, INVALID_MODEL, MODEL_IMPORTS_IS_EMPTY, COULD_NOT_READ_MODEL_IMPORTS,
+    MODEL_ALREADY_EXISTS, INVALID_MODEL, MODEL_IMPORTS_IS_EMPTY, COULD_NOT_READ_MODEL_IMPORTS, MODEL_NOT_FOUND, MODEL_NAME_CANNOT_BE_EMPTY,
+    COMPONENT_WITH_MODEL_ALREADY_EXIST,
     // Service API URL
     INVALID_SERVICE_API_URL,
     // Property related
index a940c8d..cbfee5e 100644 (file)
@@ -50,6 +50,7 @@ public enum GraphPropertiesDictionary {
     CONTACT_ID                 ("contactId",                           String.class,                           false,          false),
     VENDOR_NAME                        ("vendorName",                          String.class,                           false,          false),
     VENDOR_RELEASE             ("vendorRelease",                       String.class,                           false,          false),
+    MODEL               ("model",                              String.class,                           false,          false),
     CONFORMANCE_LEVEL  ("conformanceLevel",            String.class,                           false,          false),
     ICON                               ("icon",                                        String.class,                           false,          false),
     TAGS                               ("tags",                                        String.class,                   false,          false),
index 0701da5..ed1dc29 100644 (file)
@@ -136,6 +136,10 @@ public class GraphPropertiesDictionaryExtractor {
         return (String) properties.get(GraphPropertiesDictionary.VENDOR_RELEASE.getProperty());
     }
 
+    public String getModel() {
+        return (String) properties.get(GraphPropertiesDictionary.MODEL.getProperty());
+    }
+
     public Boolean isAbstract() {
         return (Boolean) properties.get(GraphPropertiesDictionary.IS_ABSTRACT.getProperty());
     }
index 0341be7..602d53e 100644 (file)
@@ -62,6 +62,7 @@ public abstract class ComponentMetadataData extends GraphNode {
         metadataDataDefinition.setCsarVersion(extractor.getCsarVersion());
         metadataDataDefinition.setImportedToscaChecksum(extractor.getImportedToscaChecksum());
         metadataDataDefinition.setInvariantUUID(extractor.getInvariantUuid());
+        metadataDataDefinition.setModel(extractor.getModel());
         componentInstanceCounter = extractor.getInstanceCounter();
     }
 
@@ -90,6 +91,7 @@ public abstract class ComponentMetadataData extends GraphNode {
         addIfExists(map, GraphPropertiesDictionary.CSAR_VERSION, metadataDataDefinition.getCsarVersion());
         addIfExists(map, GraphPropertiesDictionary.IMPORTED_TOSCA_CHECKSUM, metadataDataDefinition.getImportedToscaChecksum());
         addIfExists(map, GraphPropertiesDictionary.INVARIANT_UUID, metadataDataDefinition.getInvariantUUID());
+        addIfExists(map, GraphPropertiesDictionary.MODEL, metadataDataDefinition.getModel());
         return map;
     }
 
index dee4088..1b5038e 100644 (file)
@@ -104,6 +104,14 @@ public abstract class Component implements PropertiesOwner {
         componentMetadataDefinition.getMetadataDataDefinition().setCategorySpecificMetadata(categorySpecificMetadata);
     }
 
+    public String getModel() {
+        return getComponentMetadataDefinition().getMetadataDataDefinition().getModel();
+    }
+
+    public void setModel(final String model) {
+        getComponentMetadataDefinition().getMetadataDataDefinition().setModel(model);
+    }
+
     @JsonIgnore
     public ComponentMetadataDefinition getComponentMetadataDefinition() {
         return componentMetadataDefinition;
index d6151c3..752fad2 100644 (file)
@@ -35,15 +35,17 @@ public class UploadResourceInfo {
     private List<UploadArtifactInfo> artifactList;
     private String contactId, name, resourceIconPath, icon, vendorName, vendorRelease, resourceVendorModelNumber;
     private String resourceType = "VFC";
+    private String model;
 
     public UploadResourceInfo(String payload, String payloadName, String description, String category, List<String> tags,
-                              List<UploadArtifactInfo> artifactsList) {
+                              List<UploadArtifactInfo> artifactsList, String modelName) {
         super();
         this.payloadData = payload;
         this.payloadName = payloadName;
         this.description = description;
         this.tags = tags;
         this.artifactList = artifactsList;
+        this.model = modelName;
         if (category != null) {
             String[] arr = category.split("/");
             if (arr.length >= 2) {
@@ -101,6 +103,14 @@ public class UploadResourceInfo {
         this.artifactList = artifactsList;
     }
 
+    public String getModel() {
+        return model;
+    }
+
+    public void setModel(final String model) {
+        this.model = model;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
@@ -116,6 +126,7 @@ public class UploadResourceInfo {
         result = prime * result + ((tags == null) ? 0 : tags.hashCode());
         result = prime * result + ((vendorName == null) ? 0 : vendorName.hashCode());
         result = prime * result + ((vendorRelease == null) ? 0 : vendorRelease.hashCode());
+        result = prime * result + ((model == null) ? 0 : model.hashCode());
         result = prime * result + ((resourceVendorModelNumber == null) ? 0 : resourceVendorModelNumber.hashCode());
         return result;
     }
@@ -195,6 +206,13 @@ public class UploadResourceInfo {
         } else if (!tags.equals(other.tags)) {
             return false;
         }
+        if (model == null) {
+            if (other.model != null) {
+                return false;
+            }
+        } else if (!model.equals(other.model)) {
+            return false;
+        }
         if (vendorName == null) {
             if (other.vendorName != null) {
                 return false;
index c176ec8..38fb83b 100644 (file)
@@ -59,6 +59,7 @@ public abstract class ToscaElement {
     private Map<String, MapPropertiesDataDefinition> capabilitiesProperties;
     private Map<String, ListRequirementDataDefinition> requirements;
     private Map<String, DataTypeDataDefinition> dataTypes;
+    private String model;
     // User
     private String creatorUserId;
     private String creatorFullName;
index 3369d65..21c25a2 100644 (file)
@@ -137,6 +137,11 @@ public class NodeTypeOperation extends ToscaElementOperation {
         if (addAdditionalInformation != StorageOperationStatus.OK) {
             return Either.right(addAdditionalInformation);
         }
+        final StorageOperationStatus associateNodeTypeToModel = associateResourceMetadataToModel(nodeTypeVertex, nodeType);
+        if (associateNodeTypeToModel != StorageOperationStatus.OK) {
+            return Either.right(associateNodeTypeToModel);
+        }
+
         return Either.left(nodeType);
     }
 
index 884f040..eb85090 100644 (file)
@@ -73,8 +73,10 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.NodeType;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
 import org.openecomp.sdc.be.utils.TypeUtils;
 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
@@ -95,6 +97,8 @@ public abstract class ToscaElementOperation extends BaseOperation {
     private static Logger log = Logger.getLogger(ToscaElementOperation.class.getName());
     @Autowired
     protected CategoryOperation categoryOperation;
+    @Autowired
+    protected ModelOperation modelOperation;
 
     public static DataTypeDefinition createDataType(final String dataTypeName) {
         final DataTypeDefinition dataType = new DataTypeDefinition();
@@ -339,6 +343,7 @@ public abstract class ToscaElementOperation extends BaseOperation {
         nodeTypeVertex.addMetadataProperty(GraphPropertyEnum.IS_ARCHIVED, toscaElement.getMetadataValue(JsonPresentationFields.IS_ARCHIVED));
         nodeTypeVertex.addMetadataProperty(GraphPropertyEnum.ARCHIVE_TIME, toscaElement.getMetadataValue(JsonPresentationFields.ARCHIVE_TIME));
         nodeTypeVertex.addMetadataProperty(GraphPropertyEnum.IS_VSP_ARCHIVED, toscaElement.getMetadataValue(JsonPresentationFields.IS_VSP_ARCHIVED));
+        nodeTypeVertex.addMetadataProperty(GraphPropertyEnum.MODEL, toscaElement.getMetadataValue(JsonPresentationFields.MODEL));
         toscaElement.getMetadata().entrySet().stream().filter(e -> e.getValue() != null)
             .forEach(e -> nodeTypeVertex.setJsonMetadataField(e.getKey(), e.getValue()));
         nodeTypeVertex.setUniqueId(toscaElement.getUniqueId());
@@ -420,6 +425,29 @@ public abstract class ToscaElementOperation extends BaseOperation {
         return StorageOperationStatus.OK;
     }
 
+    protected StorageOperationStatus associateResourceMetadataToModel(final GraphVertex nodeTypeVertex, final ToscaElement nodeType) {
+        if (nodeType.getMetadataValue(JsonPresentationFields.MODEL) == null) {
+            return StorageOperationStatus.OK;
+        }
+        final String model = ((String) nodeType.getMetadataValue(JsonPresentationFields.MODEL));
+        final JanusGraphOperationStatus createEdge = janusGraphDao
+            .createEdge(getModelVertex(model), nodeTypeVertex, EdgeLabelEnum.MODEL_ELEMENT, new HashMap<>());
+        if (createEdge != JanusGraphOperationStatus.OK) {
+            log.trace("Failed to associate resource {} to model {}", nodeType.getUniqueId(), model);
+            return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createEdge);
+        }
+        return StorageOperationStatus.OK;
+    }
+
+    private GraphVertex getModelVertex(final String modelName) {
+        log.debug("getModelVertex: fetching model {}", modelName);
+        final Optional<GraphVertex> modelVertexByNameOptional = modelOperation.findModelVertexByName(modelName);
+        if (modelVertexByNameOptional.isEmpty()) {
+            throw ModelOperationExceptionSupplier.invalidModel(modelName).get();
+        }
+        return modelVertexByNameOptional.get();
+    }
+
     protected Either<GraphVertex, StorageOperationStatus> getResourceCategoryVertex(String elementId, String subcategoryName, String categoryName) {
         Either<GraphVertex, StorageOperationStatus> category = categoryOperation.getCategory(categoryName, VertexTypeEnum.RESOURCE_CATEGORY);
         if (category.isRight()) {
index 205a48e..814ac01 100644 (file)
@@ -39,6 +39,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.BiPredicate;
@@ -112,7 +113,6 @@ import org.openecomp.sdc.be.model.catalog.CatalogComponent;
 import org.openecomp.sdc.be.model.jsonjanusgraph.config.ContainerInstanceTypesData;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
-import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
 import org.openecomp.sdc.be.model.operations.StorageException;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
@@ -348,19 +348,57 @@ public class ToscaOperationFacade {
         return ModelConverter.isAtomicComponent(component) ? nodeTypeOperation : topologyTemplateOperation;
     }
 
+    public <T extends Component> Either<T, StorageOperationStatus> getLatestByToscaResourceNameAndModel(final String toscaResourceName,
+                                                                                                        final String model) {
+        return getLatestByNameAndModel(toscaResourceName, JsonParseFlagEnum.ParseMetadata, new ComponentParametersView(), model);
+    }
+
+    private <T extends Component> Either<T, StorageOperationStatus> getLatestByNameAndModel(final String nodeName,
+                                                                                            final JsonParseFlagEnum parseFlag,
+                                                                                            final ComponentParametersView filter,
+                                                                                            final String model) {
+        Either<T, StorageOperationStatus> result;
+        final Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
+        final Map<GraphPropertyEnum, Object> propertiesNotToMatch = new EnumMap<>(GraphPropertyEnum.class);
+        propertiesToMatch.put(GraphPropertyEnum.TOSCA_RESOURCE_NAME, nodeName);
+        propertiesToMatch.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
+        propertiesToMatch.put(GraphPropertyEnum.MODEL, model);
+        propertiesNotToMatch.put(GraphPropertyEnum.IS_DELETED, true);
+        final Either<List<GraphVertex>, JanusGraphOperationStatus> highestResources = janusGraphDao
+            .getByCriteria(null, propertiesToMatch, propertiesNotToMatch, parseFlag);
+        if (highestResources.isRight()) {
+            final JanusGraphOperationStatus status = highestResources.right().value();
+            log.debug("failed to find resource with name {}. status={} ", nodeName, status);
+            result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
+            return result;
+        }
+        final List<GraphVertex> resources = highestResources.left().value();
+        double version = 0.0;
+        GraphVertex highestResource = null;
+        for (final GraphVertex vertex : resources) {
+            final Object versionObj = vertex.getMetadataProperty(GraphPropertyEnum.VERSION);
+            double resourceVersion = Double.parseDouble((String) versionObj);
+            if (resourceVersion > version) {
+                version = resourceVersion;
+                highestResource = vertex;
+            }
+        }
+        return getToscaElementByOperation(highestResource, filter);
+    }
+
     public <T extends Component> Either<T, StorageOperationStatus> getLatestByToscaResourceName(String toscaResourceName) {
-        return getLatestByName(GraphPropertyEnum.TOSCA_RESOURCE_NAME, toscaResourceName);
+        return getLatestByName(GraphPropertyEnum.TOSCA_RESOURCE_NAME, toscaResourceName, null);
     }
 
     public <T extends Component> Either<T, StorageOperationStatus> getFullLatestComponentByToscaResourceName(String toscaResourceName) {
         ComponentParametersView fetchAllFilter = new ComponentParametersView();
         fetchAllFilter.setIgnoreServicePath(true);
         fetchAllFilter.setIgnoreCapabiltyProperties(false);
-        return getLatestByName(GraphPropertyEnum.TOSCA_RESOURCE_NAME, toscaResourceName, JsonParseFlagEnum.ParseAll, fetchAllFilter);
+        return getLatestByName(GraphPropertyEnum.TOSCA_RESOURCE_NAME, toscaResourceName, JsonParseFlagEnum.ParseAll, fetchAllFilter, null);
     }
 
-    public <T extends Component> Either<T, StorageOperationStatus> getLatestByName(String resourceName) {
-        return getLatestByName(GraphPropertyEnum.NAME, resourceName);
+    public <T extends Component> Either<T, StorageOperationStatus> getLatestByName(String resourceName, String modelName) {
+        return getLatestByName(GraphPropertyEnum.NAME, resourceName, modelName);
     }
 
     public StorageOperationStatus validateCsarUuidUniqueness(String csarUUID) {
@@ -483,6 +521,25 @@ public class ToscaOperationFacade {
         return predicateCriteria;
     }
 
+    public Optional<GraphVertex> isNodeAssociatedToModel(final String model, Resource resource) {
+        return getNodeModelVertices(resource, model);
+    }
+
+    public Optional<GraphVertex> getNodeModelVertices(final Resource resource, final String model) {
+        final Either<GraphVertex, JanusGraphOperationStatus> vertex = janusGraphDao
+            .getVertexById(resource.getUniqueId(), JsonParseFlagEnum.NoParse);
+        if (vertex.isRight() || Objects.isNull(vertex.left().value())) {
+            return Optional.empty();
+        }
+        final Either<List<GraphVertex>, JanusGraphOperationStatus> nodeModelVertices = janusGraphDao
+            .getParentVertices(vertex.left().value(), EdgeLabelEnum.MODEL_ELEMENT, JsonParseFlagEnum.NoParse);
+        if (nodeModelVertices.isRight() || Objects.isNull(nodeModelVertices.left().value())) {
+            return Optional.empty();
+        }
+        return nodeModelVertices.left().value().stream().filter(graphVertex -> graphVertex.getMetadataProperty(GraphPropertyEnum.NAME).equals(model))
+            .findFirst();
+    }
+
     private boolean isValidForVendorRelease(final GraphVertex resource, final String vendorRelease) {
         if (!vendorRelease.equals("1.0")) {
             try {
@@ -733,18 +790,19 @@ public class ToscaOperationFacade {
     }
 
     private <T extends Component> Either<T, StorageOperationStatus> getLatestByName(GraphPropertyEnum property, String nodeName,
-                                                                                    JsonParseFlagEnum parseFlag) {
-        return getLatestByName(property, nodeName, parseFlag, new ComponentParametersView());
+                                                                                    JsonParseFlagEnum parseFlag, String modelName) {
+        return getLatestByName(property, nodeName, parseFlag, new ComponentParametersView(), modelName);
     }
-    // endregion
 
     private <T extends Component> Either<T, StorageOperationStatus> getLatestByName(GraphPropertyEnum property, String nodeName,
-                                                                                    JsonParseFlagEnum parseFlag, ComponentParametersView filter) {
+                                                                                    JsonParseFlagEnum parseFlag, ComponentParametersView filter,
+                                                                                    String model) {
         Either<T, StorageOperationStatus> result;
         Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
         Map<GraphPropertyEnum, Object> propertiesNotToMatch = new EnumMap<>(GraphPropertyEnum.class);
         propertiesToMatch.put(property, nodeName);
         propertiesToMatch.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
+        propertiesToMatch.put(GraphPropertyEnum.MODEL, model);
         propertiesNotToMatch.put(GraphPropertyEnum.IS_DELETED, true);
         Either<List<GraphVertex>, JanusGraphOperationStatus> highestResources = janusGraphDao
             .getByCriteria(null, propertiesToMatch, propertiesNotToMatch, parseFlag);
@@ -769,8 +827,8 @@ public class ToscaOperationFacade {
     }
 
     // region - Component Get By ..
-    private <T extends Component> Either<T, StorageOperationStatus> getLatestByName(GraphPropertyEnum property, String nodeName) {
-        return getLatestByName(property, nodeName, JsonParseFlagEnum.ParseMetadata);
+    private <T extends Component> Either<T, StorageOperationStatus> getLatestByName(GraphPropertyEnum property, String nodeName, String modelName) {
+        return getLatestByName(property, nodeName, JsonParseFlagEnum.ParseMetadata, modelName);
     }
 
     public <T extends Component> Either<List<T>, StorageOperationStatus> getBySystemName(ComponentTypeEnum componentType, String systemName) {
@@ -841,8 +899,8 @@ public class ToscaOperationFacade {
     }
 
     public <T extends Component> Either<T, StorageOperationStatus> getComponentByNameAndVendorRelease(final ComponentTypeEnum componentType,
-                                                                                                      final String name, final String vendorRelease,
-                                                                                                      final JsonParseFlagEnum parseFlag) {
+        final String name, final String vendorRelease,
+        final JsonParseFlagEnum parseFlag) {
         Map<GraphPropertyEnum, Object> hasProperties = new EnumMap<>(GraphPropertyEnum.class);
         Map<GraphPropertyEnum, Object> hasNotProperties = new EnumMap<>(GraphPropertyEnum.class);
         hasProperties.put(GraphPropertyEnum.NAME, name);
@@ -851,8 +909,8 @@ public class ToscaOperationFacade {
             hasProperties.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name());
         }
         Map<String, Entry<JanusGraphPredicate, Object>> predicateCriteria = getVendorVersionPredicate(vendorRelease);
-        Either<List<GraphVertex>, JanusGraphOperationStatus> getResourceRes = janusGraphDao
-            .getByCriteria(null, hasProperties, hasNotProperties, predicateCriteria, parseFlag);
+        Either<List<GraphVertex>, JanusGraphOperationStatus> getResourceRes = janusGraphDao.getByCriteria(null, hasProperties, hasNotProperties,
+            predicateCriteria, parseFlag);
         if (getResourceRes.isRight()) {
             JanusGraphOperationStatus status = getResourceRes.right().value();
             log.debug("failed to find resource with name {}, version {}. Status is {} ", name, predicateCriteria, status);
@@ -2006,16 +2064,11 @@ public class ToscaOperationFacade {
         }
         return result;
     }
-
     public Either<Boolean, StorageOperationStatus> validateComponentNameUniqueness(String name, ResourceTypeEnum resourceType,
                                                                                    ComponentTypeEnum componentType) {
-        VertexTypeEnum vertexType = ModelConverter.isAtomicComponent(resourceType) ? VertexTypeEnum.NODE_TYPE : VertexTypeEnum.TOPOLOGY_TEMPLATE;
         String normalizedName = ValidationUtils.normaliseComponentName(name);
-        Map<GraphPropertyEnum, Object> properties = new EnumMap<>(GraphPropertyEnum.class);
-        properties.put(GraphPropertyEnum.NORMALIZED_NAME, normalizedName);
-        properties.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name());
         Either<List<GraphVertex>, JanusGraphOperationStatus> vertexEither = janusGraphDao
-            .getByCriteria(vertexType, properties, JsonParseFlagEnum.NoParse);
+            .getByCriteria(getVertexTypeEnum(resourceType), propertiesToMatch(normalizedName, componentType), JsonParseFlagEnum.NoParse);
         if (vertexEither.isRight() && vertexEither.right().value() != JanusGraphOperationStatus.NOT_FOUND) {
             log.debug("failed to get vertex from graph with property normalizedName: {}", normalizedName);
             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(vertexEither.right().value()));
@@ -2023,6 +2076,41 @@ public class ToscaOperationFacade {
         return Either.left(CollectionUtils.isEmpty(vertexEither.isLeft() ? vertexEither.left().value() : null));
     }
 
+    public Either<Boolean, StorageOperationStatus> validateComponentNameAndModelExists(final String resourceName, final String model,
+                                                                                       final ResourceTypeEnum resourceType,
+                                                                                       final ComponentTypeEnum componentType) {
+        Either<Boolean, StorageOperationStatus> result = validateComponentNameAndModelUniqueness(resourceName, model, resourceType, componentType);
+        if (result.isLeft()) {
+            result = Either.left(!result.left().value());
+        }
+        return result;
+    }
+
+    private Either<Boolean, StorageOperationStatus> validateComponentNameAndModelUniqueness(final String resourceName, final String modelName,
+                                                                                            final ResourceTypeEnum resourceType,
+                                                                                            final ComponentTypeEnum componentType) {
+        final String normalizedName = ValidationUtils.normaliseComponentName(resourceName);
+        final Either<List<GraphVertex>, JanusGraphOperationStatus> vertexEither = janusGraphDao
+            .getByCriteria(getVertexTypeEnum(resourceType), propertiesToMatch(normalizedName, componentType), null, null, JsonParseFlagEnum.NoParse);
+        if (vertexEither.isRight() && vertexEither.right().value() != JanusGraphOperationStatus.NOT_FOUND) {
+            log.debug("failed to get vertex from graph with property normalizedName: {} and model: {}", normalizedName, modelName);
+            return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(vertexEither.right().value()));
+        }
+        return Either.left(CollectionUtils.isEmpty(vertexEither.isLeft() ? vertexEither.left().value().stream()
+            .filter(graphVertex -> graphVertex.getMetadataProperty(GraphPropertyEnum.NAME).equals(modelName)).collect(Collectors.toList()) : null));
+    }
+
+    private VertexTypeEnum getVertexTypeEnum(final ResourceTypeEnum resourceType) {
+        return ModelConverter.isAtomicComponent(resourceType) ? VertexTypeEnum.NODE_TYPE : VertexTypeEnum.TOPOLOGY_TEMPLATE;
+    }
+
+    private Map<GraphPropertyEnum, Object> propertiesToMatch(final String normalizedName, final ComponentTypeEnum componentType) {
+        final Map<GraphPropertyEnum, Object> properties = new EnumMap<>(GraphPropertyEnum.class);
+        properties.put(GraphPropertyEnum.NORMALIZED_NAME, normalizedName);
+        properties.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name());
+        return properties;
+    }
+
     private void fillNodeTypePropsMap(final Map<GraphPropertyEnum, Object> hasProps, final Map<GraphPropertyEnum, Object> hasNotProps,
                                       final String internalComponentType) {
         final Configuration configuration = ConfigurationManager.getConfigurationManager().getConfiguration();
@@ -3242,6 +3330,6 @@ public class ToscaOperationFacade {
     }
 
     public <T extends Component> Either<T, StorageOperationStatus> getLatestByServiceName(String serviceName) {
-        return getLatestByName(GraphPropertyEnum.NAME, serviceName);
+        return getLatestByName(GraphPropertyEnum.NAME, serviceName, null);
     }
 }
index 225a068..1932709 100644 (file)
@@ -718,6 +718,9 @@ public class ModelConverter {
         component.setSystemName((String) toscaElement.getMetadataValue(JsonPresentationFields.SYSTEM_NAME));
         component.setDerivedFromGenericType(toscaElement.getDerivedFromGenericType());
         component.setDerivedFromGenericVersion(toscaElement.getDerivedFromGenericVersion());
+        if(toscaElement.getModel() != null) {
+            component.setModel(toscaElement.getModel());
+        }
         Map<String, PropertyDataDefinition> properties = toscaElement.getProperties();
         if (MapUtils.isNotEmpty(properties)) {
             List<PropertyDefinition> propertiesMap = properties.values().stream().map(x -> new PropertyDefinition(x)).collect(Collectors.toList());
@@ -733,6 +736,7 @@ public class ModelConverter {
             resource.setToscaResourceName((String) toscaElement.getMetadataValue(JsonPresentationFields.TOSCA_RESOURCE_NAME));
             resource.setVendorName((String) toscaElement.getMetadataValue(JsonPresentationFields.VENDOR_NAME));
             resource.setVendorRelease((String) toscaElement.getMetadataValue(JsonPresentationFields.VENDOR_RELEASE));
+            resource.setModel((String) toscaElement.getMetadataValue(JsonPresentationFields.MODEL));
             // field isn't mandatory , but shouldn't be null(should be an empty string instead)
             if (((String) toscaElement.getMetadataValue(JsonPresentationFields.RESOURCE_VENDOR_MODEL_NUMBER)) != null) {
                 resource.setResourceVendorModelNumber((String) toscaElement.getMetadataValue(JsonPresentationFields.RESOURCE_VENDOR_MODEL_NUMBER));
@@ -1294,6 +1298,7 @@ public class ModelConverter {
             toscaElement.setMetadataValue(JsonPresentationFields.TOSCA_RESOURCE_NAME, ((Resource) component).getToscaResourceName());
             toscaElement.setMetadataValue(JsonPresentationFields.VENDOR_NAME, ((Resource) component).getVendorName());
             toscaElement.setMetadataValue(JsonPresentationFields.VENDOR_RELEASE, ((Resource) component).getVendorRelease());
+            toscaElement.setMetadataValue(JsonPresentationFields.MODEL, component.getModel());
             // field isn't mandatory , but shouldn't be null(should be an empty string instead)
             if (((Resource) component).getResourceVendorModelNumber() != null) {
                 toscaElement
index 3c8521a..4fbb5fb 100644 (file)
@@ -41,6 +41,7 @@ public enum StorageOperationStatus {
     OPERATION_NOT_SUPPORTED,
     CATEGORY_NOT_FOUND,
     PARENT_RESOURCE_NOT_FOUND,
+    MODEL_NOT_FOUND,
     MULTIPLE_PARENT_RESOURCE_FOUND,
     INCONSISTENCY,
     GRAPH_IS_NOT_AVAILABLE,
index 4674356..7af24fc 100644 (file)
@@ -36,8 +36,8 @@ public class UploadResourceInfoTest {
 
        @Test
        public void testCtor() throws Exception {
-               new UploadResourceInfo("mock", "mock", "mock", "mock/mock/mock", new LinkedList<>(), new LinkedList<>());
-
+               new UploadResourceInfo("mock", "mock", "mock", "mock/mock/mock", new LinkedList<>(), new LinkedList<>(),
+                       "modelName");
        }
 
        @Test
index b0f2fa5..a19e7c4 100644 (file)
@@ -263,6 +263,7 @@ public class ToscaOperationFacadeTest {
         Map<GraphPropertyEnum, Object> propertiesNotToMatch = new EnumMap<>(GraphPropertyEnum.class);
         propertiesToMatch.put(GraphPropertyEnum.TOSCA_RESOURCE_NAME, "toscaResourceName");
         propertiesToMatch.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
+        propertiesToMatch.put(GraphPropertyEnum.MODEL, null);
         propertiesNotToMatch.put(GraphPropertyEnum.IS_DELETED, true);
 
         when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, propertiesNotToMatch, JsonParseFlagEnum.ParseAll))
@@ -441,6 +442,7 @@ public class ToscaOperationFacadeTest {
         Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
         propertiesToMatch.put(GraphPropertyEnum.TOSCA_RESOURCE_NAME, toscaResourceName);
         propertiesToMatch.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
+        propertiesToMatch.put(GraphPropertyEnum.MODEL, null);
         Map<GraphPropertyEnum, Object> propertiesNotToMatch = new EnumMap<>(GraphPropertyEnum.class);
         propertiesNotToMatch.put(GraphPropertyEnum.IS_DELETED, true);
 
index a201b30..787aca1 100644 (file)
@@ -7,9 +7,9 @@
  * 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.
 
 package org.openecomp.sdc.be.model.operations;
 
+import static org.junit.Assert.assertEquals;
+
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import org.junit.Before;
 import org.junit.Test;
 import org.openecomp.sdc.be.model.UploadResourceInfo;
 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
 import org.openecomp.sdc.common.api.UploadArtifactInfo;
 
-import java.io.IOException;
-import java.util.ArrayList;
-
-import static org.junit.Assert.assertEquals;
-
 public class JsonObjectTest {
 
     private ObjectMapper mapper;
     UploadResourceInfo inputObjectRef;
     private final String INPUT_RESOURCE_STRING = "{  \"payloadData\" : \"My Test Object\",  \"payloadName\" : \"TestName\", " + "  \"description\":\"my_description\",\"tags\":[\"tag1\"], "
-            + "\"artifactList\" : [ {    \"artifactName\" : \"myArtifact0\",  \"artifactPath\" : \"scripts/\",  \"artifactType\" : \"PUPPET\",   " + " \"artifactDescription\" : \"This is Description\",    \"artifactData\" : null  }, "
-            + "{    \"artifactName\" : \"myArtifact1\",  \"artifactPath\" : \"scripts/\", \"artifactType\" : \"PUPPET\",    \"artifactDescription\" : \"This is Description\", "
-            + "   \"artifactData\" : null  } ], \"contactId\" : null, \"name\" : null, \"resourceIconPath\" : null, \"vendorName\" : null, \"vendorRelease\" : null , \"resourceType\" : \"VFC\" }";
+        + "\"artifactList\" : [ {    \"artifactName\" : \"myArtifact0\",  \"artifactPath\" : \"scripts/\",  \"artifactType\" : \"PUPPET\",   " + " \"artifactDescription\" : \"This is Description\",    \"artifactData\" : null  }, "
+        + "{    \"artifactName\" : \"myArtifact1\",  \"artifactPath\" : \"scripts/\", \"artifactType\" : \"PUPPET\",    \"artifactDescription\" : \"This is Description\", "
+        + "   \"artifactData\" : null  } ], \"contactId\" : null, \"name\" : null, \"resourceIconPath\" : null, \"vendorName\" : null, \"vendorRelease\" : null , \"resourceType\" : \"VFC\", \"model\":\"model1\"}";
 
     @Before
     public void setup() {
         mapper = new ObjectMapper();
-        ArrayList<UploadArtifactInfo> artifactList = new ArrayList<>();
+        final ArrayList<UploadArtifactInfo> artifactList = new ArrayList<>();
         for (int i = 0; i < 2; i++) {
             UploadArtifactInfo artifactInfo = new UploadArtifactInfo("myArtifact" + i, "scripts/", ArtifactTypeEnum.PUPPET, "This is Description");
             artifactList.add(artifactInfo);
         }
-        ArrayList<String> tags = new ArrayList<>();
-        tags.add("tag1");
-        inputObjectRef = new UploadResourceInfo("My Test Object", "TestName", "my_description", null, tags, artifactList);
-
+        inputObjectRef = new UploadResourceInfo("My Test Object", "TestName", "my_description", null,
+            Arrays.asList("tag1"), artifactList, "model1");
     }
 
     @Test
-    public void testStringToUploadResourceInfo() throws JsonParseException, JsonMappingException, IOException {
-        UploadResourceInfo resourceObjectTest = mapper.readValue(INPUT_RESOURCE_STRING, UploadResourceInfo.class);
+    public void testStringToUploadResourceInfo() throws IOException {
+        final UploadResourceInfo resourceObjectTest = mapper.readValue(INPUT_RESOURCE_STRING, UploadResourceInfo.class);
         assertEquals(inputObjectRef, resourceObjectTest);
 
     }
@@ -72,4 +70,4 @@ public class JsonObjectTest {
         assertEquals(unFormattedString, INPUT_RESOURCE_STRING.replace("\n", "").replace("\t", "").replace(" ", ""));
 
     }
-}
+}
\ No newline at end of file
index ebccc6c..849153b 100644 (file)
@@ -132,6 +132,9 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio
     @Getter
     @Setter
     private Map<String, String> categorySpecificMetadata;
+    @Getter
+    @Setter
+    private String model;
 
     public ComponentMetadataDataDefinition(ComponentMetadataDataDefinition other) {
         this.uniqueId = other.getUniqueId();
@@ -159,6 +162,7 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio
         this.isVspArchived = other.isVspArchived;
         this.archiveTime = other.getArchiveTime();
         this.categorySpecificMetadata = other.getCategorySpecificMetadata();
+        this.model = other.getModel();
     }
 
     public ComponentMetadataDataDefinition(JsonPresentationFieldsExtractor extractor) {
@@ -185,6 +189,7 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio
         this.isArchived = extractor.isArchived();
         this.isVspArchived = extractor.isVspArchived();
         this.archiveTime = extractor.getArchiveTime();
+        this.model = extractor.getModel();
     }
 
     public void setUniqueId(String uniqueId) {
index 0ed0bd2..8f547cf 100644 (file)
@@ -55,15 +55,16 @@ public enum GraphPropertyEnum {
     ICONS("icons", String.class, false, false),
     METADATA_KEYS("metadataKeys", String.class, false, false),
     USE_SUBSTITUTION_FOR_NESTED_SERVICES("useServiceSubstitutionForNestedServices", Boolean.class, false, false),
-
     DATA_TYPES("data_types", Map.class, false, false),
-
     //Archive/Restore
-    IS_ARCHIVED("isArchived", Boolean.class, false, true), IS_VSP_ARCHIVED("isVspArchived", Boolean.class, false, true), ARCHIVE_TIME("archiveTime",
-        Long.class, false, true), PREV_CATALOG_UPDATE_TIME("previousUpdateTime", Long.class, false, true), CURRENT_CATALOG_UPDATE_TIME(
-        "currentUpdateTime", Long.class, false, true),
+    IS_ARCHIVED("isArchived", Boolean.class, false, true),
+    IS_VSP_ARCHIVED("isVspArchived", Boolean.class, false, true),
+    ARCHIVE_TIME("archiveTime", Long.class, false, true),
+    PREV_CATALOG_UPDATE_TIME("previousUpdateTime", Long.class, false, true),
+    CURRENT_CATALOG_UPDATE_TIME("currentUpdateTime", Long.class, false, true),
     //Healing
-    HEALING_VERSION("healVersion", Integer.class, false, true);
+    HEALING_VERSION("healVersion", Integer.class, false, true),
+    MODEL("model", String.class, false, false);
     // @formatter:on
 
     private final String property;
index 185d953..1e8e842 100644 (file)
@@ -68,7 +68,7 @@ public enum JsonPresentationFields {
     DERIVED_FROM_GENERIC_TYPE("derivedFromGenericType", null),
     DERIVED_FROM_GENERIC_VERSION("derivedFromGenericVersion", null),
     SERVICE_FUNCTION("serviceFunction", null),
-    MODELS("models", null),
+    MODEL("model", null),
     DATA_TYPES("data_types", GraphPropertyEnum.DATA_TYPES),
 
     ////Inputs
index c5eb865..2fc2c52 100644 (file)
@@ -165,4 +165,8 @@ public class JsonPresentationFieldsExtractor {
     public String getServiceFunction() {
         return (String) properties.get(JsonPresentationFields.SERVICE_FUNCTION.getPresentation());
     }
+
+    public String getModel() {
+        return (String) properties.get(JsonPresentationFields.MODEL.getPresentation());
+    }
 }