Add Support for creating model type 66/121466/3
authoraribeiro <anderson.ribeiro@est.tech>
Tue, 18 May 2021 15:31:28 +0000 (16:31 +0100)
committerMichael Morris <michael.morris@est.tech>
Fri, 28 May 2021 16:00:03 +0000 (16:00 +0000)
Add new vertex type called "model" was added to represent models
Add new edge type called MODEL_ELEMENT was added to connect a tosca type to a model
Add new edge type called MODEL was added to connect a resource/service to the model it is based on

Issue-ID: SDC-3596
Signed-off-by: MichaelMorris <michael.morris@est.tech>
Signed-off-by: aribeiro <anderson.ribeiro@est.tech>
Change-Id: I310e14d0cf5a9ca0eb0bda592efe8a3baf73749c

21 files changed:
catalog-be/pom.xml
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/ModelBusinessLogic.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java [new file with mode: 0644]
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogicTest.java [new file with mode: 0644]
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ModelServletTest.java [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/graph/GraphElementFactory.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/jsongraph/types/EdgeLabelEnum.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/jsongraph/types/VertexTypeEnum.java
catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ModelData.java [new file with mode: 0644]
catalog-dao/src/test/java/org/openecomp/sdc/be/resources/data/ModelDataTest.java [new file with mode: 0644]
catalog-model/pom.xml
catalog-model/src/main/java/org/openecomp/sdc/be/model/Model.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/UniqueIdBuilder.java
catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/ModelCreateRequest.java [new file with mode: 0644]
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/NodeTypeEnum.java
pom.xml

index c156b96..d12e7c1 100644 (file)
                 </exclusion>
             </exclusions>
         </dependency>
+
+        <dependency>
+            <groupId>com.googlecode.jmapper-framework</groupId>
+            <artifactId>jmapper-core</artifactId>
+            <version>${jMapper.version}</version>
+        </dependency>
+
     </dependencies>
 
     <build>
index b49c111..2c6a0c8 100644 (file)
@@ -2464,4 +2464,12 @@ errors:
         code: 500,
         message: "An unexpected error occurred while updating the capability '%1'.",
         messageId: "SVC4143"
-    }
\ No newline at end of file
+    }
+
+    #---------SVC4144------------------------------
+    # %1 - "Model name"
+    MODEL_ALREADY_EXISTS: {
+        code: 409,
+        message: "Error: Model name '%1' already exists.",
+        messageId: "SVC4144"
+    }
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java
new file mode 100644 (file)
index 0000000..1ef4cef
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * ============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;
+
+import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component("modelBusinessLogic")
+public class ModelBusinessLogic {
+
+    private static final Logger log = LoggerFactory.getLogger(ModelBusinessLogic.class);
+    private final ModelOperation modelOperation;
+
+    @Autowired
+    public ModelBusinessLogic(final ModelOperation modelOperation) {
+        this.modelOperation = modelOperation;
+    }
+
+    public Model createModel(final Model model) {
+        log.debug("createModel: creating model {}", model);
+        return modelOperation.createModel(model, false);
+    }
+}
\ No newline at end of file
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java
new file mode 100644 (file)
index 0000000..f4fc883
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * ============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 com.googlecode.jmapper.JMapper;
+import com.jcabi.aspects.Loggable;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+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.tags.Tag;
+import java.util.Arrays;
+import javax.inject.Inject;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+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.components.validation.UserValidations;
+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.Model;
+import org.openecomp.sdc.be.ui.model.ModelCreateRequest;
+import org.openecomp.sdc.be.user.Role;
+import org.openecomp.sdc.be.user.UserBusinessLogic;
+import org.openecomp.sdc.common.api.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * Root resource (exposed at "/" path)
+ */
+@Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
+@Path("/v1/catalog")
+@Tag(name = "SDCE-2 APIs")
+@Server(url = "/sdc2/rest")
+@Controller
+public class ModelServlet extends AbstractValidationsServlet {
+
+    private static final Logger log = LoggerFactory.getLogger(ModelServlet.class);
+    private final ModelBusinessLogic modelBusinessLogic;
+    private final UserValidations userValidations;
+
+    @Inject
+    public ModelServlet(final UserBusinessLogic userBusinessLogic, final ComponentInstanceBusinessLogic componentInstanceBL,
+                        final ComponentsUtils componentsUtils, final ServletUtils servletUtils, final ResourceImportManager resourceImportManager,
+                        final ModelBusinessLogic modelBusinessLogic, final UserValidations userValidations) {
+        super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
+        this.modelBusinessLogic = modelBusinessLogic;
+        this.userValidations = userValidations;
+    }
+
+    @POST
+    @Path("/model")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Operation(description = "Create model", method = "POST", summary = "Returns created model", responses = {
+        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+        @ApiResponse(responseCode = "201", description = "Model created"),
+        @ApiResponse(responseCode = "403", description = "Restricted operation"),
+        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+        @ApiResponse(responseCode = "409", description = "Resource already exists")})
+    @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
+    public Response createModel(@Parameter(description = "model to be created", required = true)
+                                    @Valid @RequestBody @NotNull final ModelCreateRequest modelCreateRequest,
+                                @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
+
+        validateUser(userId);
+        try {
+            final Model modelCreateResponse = modelBusinessLogic
+                .createModel(new JMapper<>(Model.class, ModelCreateRequest.class).getDestination(modelCreateRequest));
+            return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED),
+                RepresentationUtils.toRepresentation(modelCreateResponse));
+        } catch (final BusinessException e) {
+            throw e;
+        } catch (final Exception e) {
+            var errorMsg = String
+                .format("Unexpected error while creating model '%s'", modelCreateRequest.getName());
+            BeEcompErrorManager.getInstance().logBeRestApiGeneralError(errorMsg);
+            log.error(errorMsg, e);
+            return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
+        }
+    }
+
+    private void validateUser(final String userId) {
+        userValidations.validateUserRole(userValidations.validateUserExists(userId), Arrays.asList(Role.DESIGNER, Role.ADMIN));
+    }
+
+}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogicTest.java
new file mode 100644 (file)
index 0000000..6c7bd53
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * ============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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.when;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.exception.BusinessException;
+import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
+
+@TestInstance(Lifecycle.PER_CLASS)
+@TestMethodOrder(OrderAnnotation.class)
+class ModelBusinessLogicTest {
+
+    @InjectMocks
+    private ModelBusinessLogic modelBusinessLogic;
+    @Mock
+    private ModelOperation modelOperation;
+    private Model model;
+
+    @BeforeAll
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        initTestData();
+    }
+
+    private void initTestData() {
+        model = new Model("ETSI-SDC-MODEL-TEST");
+    }
+
+    @Test
+    @Order(1)
+    void createModelTest() {
+        when(modelOperation.createModel(model, false)).thenReturn(model);
+        final Model result = modelBusinessLogic.createModel(model);
+        assertThat(result).isNotNull();
+        assertThat(result.getName()).isEqualTo(model.getName());
+    }
+
+    @Test
+    @Order(2)
+    void createModelFailTest() {
+        when(modelOperation.createModel(model, false))
+            .thenThrow(new OperationException(ActionStatus.MODEL_ALREADY_EXISTS, model.getName()));
+        final BusinessException exception = assertThrows(BusinessException.class, () -> modelBusinessLogic.createModel(model));
+        assertThat(((OperationException) exception).getActionStatus().name()).isEqualTo(ActionStatus.MODEL_ALREADY_EXISTS.name());
+        assertThat(((OperationException) exception).getParams()).contains(model.getName());
+    }
+
+}
\ No newline at end of file
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ModelServletTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ModelServletTest.java
new file mode 100644 (file)
index 0000000..34201d3
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * ============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.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.validation.ConstraintViolationException;
+import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jetty.http.HttpStatus;
+import org.glassfish.hk2.utilities.binding.AbstractBinder;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+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.InjectMocks;
+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.ResourceImportManager;
+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.exception.BusinessException;
+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.ui.model.ModelCreateRequest;
+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 ModelServletTest 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 ModelBusinessLogic modelBusinessLogic;
+    @InjectMocks
+    private ModelServlet modelServlet;
+    @Mock
+    private ResponseFormat responseFormat;
+    @Mock
+    private UserValidations userValidations;
+
+    private Model model;
+    private Response response;
+    private ModelCreateRequest modelCreateRequest;
+
+    @BeforeAll
+    public void initClass() {
+        MockitoAnnotations.openMocks(this);
+        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() {
+        final String modelName = "MY-INTEGRATION-TEST-MODEL";
+        model = new Model(modelName);
+        modelCreateRequest = new ModelCreateRequest();
+        modelCreateRequest.setName(modelName);
+    }
+
+    @Override
+    protected ResourceConfig configure() {
+        forceSet(TestProperties.CONTAINER_PORT, "0");
+        final ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
+        return new ResourceConfig(ModelServlet.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(modelBusinessLogic).to(ModelBusinessLogic.class);
+                }
+            })
+            .property("contextConfig", context);
+    }
+
+    @Test
+    void createModelSuccessTest() {
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.OK_200);
+        when(componentsUtils.getResponseFormat(ActionStatus.CREATED)).thenReturn(responseFormat);
+        when(modelBusinessLogic.createModel(any(Model.class))).thenReturn(model);
+        response = modelServlet.createModel(modelCreateRequest, USER_ID);
+        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK_200);
+    }
+
+    @Test
+    void createModelFailTest() {
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
+        when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(responseFormat);
+        when(modelBusinessLogic.createModel(any(Model.class))).thenReturn(model);
+        response = modelServlet.createModel(modelCreateRequest, USER_ID);
+        assertThat(response.getStatus()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR_500);
+    }
+
+    @Test
+    void createModelFailWithModelNameEmptyTest() {
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
+        when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(responseFormat);
+        modelCreateRequest.setName(StringUtils.EMPTY);
+        final Exception exception = assertThrows(ConstraintViolationException.class, () -> modelServlet.createModel(modelCreateRequest, USER_ID));
+        assertThat(exception.getMessage()).isEqualTo("Model name cannot be empty");
+    }
+
+    @Test
+    void createModelFailWithModelNameNullTest() {
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
+        when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(responseFormat);
+        modelCreateRequest.setName(null);
+        final Exception exception = assertThrows(ConstraintViolationException.class, () -> modelServlet.createModel(modelCreateRequest, USER_ID));
+        assertThat(exception.getMessage()).isEqualTo("Model name cannot be null");
+    }
+
+    @Test
+    void createModelThrowsBusinessExceptionTest() {
+        when(modelBusinessLogic.createModel(model)).thenThrow(new BusinessException() {});
+        assertThrows(BusinessException.class, () -> modelServlet.createModel(modelCreateRequest, USER_ID));
+    }
+
+}
\ No newline at end of file
index 619f882..1ebaeab 100644 (file)
@@ -51,6 +51,8 @@ public enum ActionStatus {
     VENDOR_NAME_EXCEEDS_LIMIT, VENDOR_RELEASE_EXCEEDS_LIMIT, INVALID_VENDOR_NAME, INVALID_VENDOR_RELEASE, MISSING_VENDOR_NAME, MISSING_VENDOR_RELEASE, RESOURCE_VENDOR_MODEL_NUMBER_EXCEEDS_LIMIT, INVALID_RESOURCE_VENDOR_MODEL_NUMBER,
     // 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,
     // Service API URL
     INVALID_SERVICE_API_URL,
     // Property related
index c3c5e9f..1c500e7 100644 (file)
@@ -46,6 +46,7 @@ import org.openecomp.sdc.be.resources.data.HeatParameterValueData;
 import org.openecomp.sdc.be.resources.data.InputValueData;
 import org.openecomp.sdc.be.resources.data.InputsData;
 import org.openecomp.sdc.be.resources.data.InterfaceData;
+import org.openecomp.sdc.be.resources.data.ModelData;
 import org.openecomp.sdc.be.resources.data.OperationData;
 import org.openecomp.sdc.be.resources.data.PolicyTypeData;
 import org.openecomp.sdc.be.resources.data.ProductMetadataData;
@@ -255,6 +256,10 @@ public class GraphElementFactory {
                     break;
                 case AnnotationType:
                     element = clazz.cast(new AnnotationTypeData(properties));
+                    break;
+                case Model:
+                    element = clazz.cast(new ModelData(properties));
+                    break;
                 default:
                     break;
             }
index 33a4391..7fc954e 100644 (file)
@@ -69,7 +69,8 @@ public enum EdgeLabelEnum {
     INST_INTERFACES,
     NODE_FILTER_TEMPLATE,
     SUBSTITUTION_FILTER_TEMPLATE,
-    DATA_TYPES;
+    DATA_TYPES,
+    MODEL_ELEMENT;
     // @formatter:on
 
     /**
index cc8c8bc..e9648a3 100644 (file)
@@ -92,7 +92,8 @@ public enum VertexTypeEnum {
        NODE_FILTER_TEMPLATE            ("NodeTemplateFilter",        CINodeFilterDataDefinition.class),
        SUBSTITUTION_FILTER_TEMPLATE ("substitution_mapping",     SubstitutionFilterDataDefinition.class),
        INST_INTERFACES             ("InstInterfaces",            MapInterfaceDataDefinition.class),
-       DATA_TYPES                                      ("data_types",                          DataTypeDataDefinition.class);
+       DATA_TYPES                                      ("data_types",                          DataTypeDataDefinition.class),
+       MODEL                       ("model",                   null);
     // @formatter:on
 
     private final String name;
diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ModelData.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ModelData.java
new file mode 100644 (file)
index 0000000..026b1d7
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * ============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.resources.data;
+
+import java.util.HashMap;
+import java.util.Map;
+import lombok.Getter;
+import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
+import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
+import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
+
+@Getter
+public class ModelData extends GraphNode {
+
+    private final String name;
+    private final String uniqueId;
+
+    public ModelData(final String name, final String uniqueId) {
+        super(NodeTypeEnum.Model);
+        this.name = name;
+        this.uniqueId = uniqueId;
+    }
+
+    public ModelData(final Map<String, Object> properties) {
+        super(NodeTypeEnum.Model);
+        name = (String) properties.get(GraphPropertiesDictionary.NAME.getProperty());
+        uniqueId = (String) properties.get(GraphPropertiesDictionary.UNIQUE_ID.getProperty());
+    }
+
+    @Override
+    public Map<String, Object> toGraphMap() {
+        final Map<String, Object> map = new HashMap<>();
+        addIfExists(map, GraphPropertiesDictionary.NAME, name);
+        addIfExists(map, GraphPropertiesDictionary.UNIQUE_ID, uniqueId);
+        return map;
+    }
+
+}
\ No newline at end of file
diff --git a/catalog-dao/src/test/java/org/openecomp/sdc/be/resources/data/ModelDataTest.java b/catalog-dao/src/test/java/org/openecomp/sdc/be/resources/data/ModelDataTest.java
new file mode 100644 (file)
index 0000000..1fb34dd
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * ============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.resources.data;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+
+@TestInstance(Lifecycle.PER_CLASS)
+class ModelDataTest {
+
+    private final String modelName = "ETSI-SDC-MODEL-TEST";
+    private final String modelId = UUID.randomUUID().toString();
+    ModelData modelData;
+
+    @BeforeAll
+    void initTestData() {
+        modelData = new ModelData(modelName, modelId);
+    }
+
+    @Test
+    void modelDataTest() {
+        assertThat(modelData).isNotNull();
+        assertThat(modelData.getUniqueId()).isEqualTo(modelId);
+        assertThat(modelData.getName()).isEqualTo(modelName);
+    }
+
+    @Test
+    void modelDataFromPropertiesMapTest() {
+        final Map<String, Object> properties = new HashMap();
+        properties.put("name", modelData.getName());
+        properties.put("uid", modelData.getUniqueId());
+        final ModelData modelDataFromPropertiesMap = new ModelData(properties);
+        assertThat(modelDataFromPropertiesMap).isNotNull();
+        assertThat(modelDataFromPropertiesMap.getUniqueId()).isEqualTo(modelId);
+        assertThat(modelDataFromPropertiesMap.getName()).isEqualTo(modelName);
+    }
+
+    @Test
+    void modelDataToGraphTest() {
+        final var result = modelData.toGraphMap();
+        assertThat(result).isNotNull();
+        assertThat(result).isNotEmpty();
+        assertThat(result.values()).contains(modelId);
+        assertThat(result.values()).contains(modelName);
+    }
+
+}
index ff28ea6..fc55fb7 100644 (file)
       <version>3.1.0</version>
     </dependency>
 
+    <dependency>
+      <groupId>com.googlecode.jmapper-framework</groupId>
+      <artifactId>jmapper-core</artifactId>
+      <version>${jMapper.version}</version>
+    </dependency>
+
   </dependencies>
   <build>
     <plugins>
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Model.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Model.java
new file mode 100644 (file)
index 0000000..99d0f65
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * ============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.model;
+
+import com.googlecode.jmapper.annotations.JGlobalMap;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@JGlobalMap
+public class Model {
+
+    private String name;
+
+}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java
new file mode 100644 (file)
index 0000000..c604df6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * ============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.model.operations.impl;
+
+import fj.data.Either;
+import java.util.Objects;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
+import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
+import org.openecomp.sdc.be.resources.data.ModelData;
+import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
+import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component("model-operation")
+public class ModelOperation extends AbstractOperation {
+
+    private static final Logger log = Logger.getLogger(ModelOperation.class);
+
+    private final JanusGraphGenericDao genericDao;
+
+    @Autowired
+    public ModelOperation(final JanusGraphGenericDao janusGraphGenericDao) {
+        this.genericDao = janusGraphGenericDao;
+    }
+
+    public Model createModel(final Model model, final boolean inTransaction) {
+        Model result = null;
+        final ModelData modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()));
+        try {
+            final Either<ModelData, JanusGraphOperationStatus> createNode = genericDao.createNode(modelData, ModelData.class);
+            if (createNode.isRight()) {
+                final JanusGraphOperationStatus janusGraphOperationStatus = createNode.right().value();
+                log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(), "Problem while creating model, reason {}",
+                    janusGraphOperationStatus);
+                if (janusGraphOperationStatus == JanusGraphOperationStatus.JANUSGRAPH_SCHEMA_VIOLATION) {
+                    throw new OperationException(ActionStatus.MODEL_ALREADY_EXISTS, model.getName());
+                }
+                throw new OperationException(ActionStatus.GENERAL_ERROR,
+                    String.format("Failed to create model %s on JanusGraph with %s error", model, janusGraphOperationStatus));
+            }
+            result = new Model(createNode.left().value().getName());
+            return result;
+        } finally {
+            if (!inTransaction) {
+                if (Objects.nonNull(result)) {
+                    genericDao.commit();
+                } else {
+                    genericDao.rollback();
+                }
+            }
+        }
+    }
+
+}
+
+
index c9225c7..62404aa 100644 (file)
@@ -202,4 +202,8 @@ public class UniqueIdBuilder {
     public static String buildGroupPropertyValueUid(String groupUniqueId, Integer index) {
         return groupUniqueId + DOT + "property" + DOT + index;
     }
+
+    public static String buildModelUid(final String modelName) {
+        return NodeTypeEnum.Model.getName() + DOT + modelName;
+    }
 }
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/ModelCreateRequest.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/ModelCreateRequest.java
new file mode 100644 (file)
index 0000000..0d294b4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ============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.ui.model;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import lombok.Data;
+
+/**
+ * This class is responsible for holding all required fields from the create Model post request.
+ * It also validates the Model 'name' field.
+ */
+@Data
+public class ModelCreateRequest {
+
+    @NotNull(message = "Model name cannot be null")
+    @Size(min = 2, message = "Model name cannot be empty")
+    private String name;
+
+}
diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java
new file mode 100644 (file)
index 0000000..c1c0132
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * ============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.model.operations.impl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import fj.data.Either;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
+import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.ModelTestBase;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
+import org.openecomp.sdc.be.resources.data.ModelData;
+import org.springframework.test.context.ContextConfiguration;
+
+@ContextConfiguration("classpath:application-context-test.xml")
+@TestInstance(Lifecycle.PER_CLASS)
+class ModelOperationTest extends ModelTestBase {
+
+    @InjectMocks
+    private ModelOperation modelOperation;
+    @Mock
+    private JanusGraphGenericDao janusGraphGenericDao;
+
+    private final String modelName = "ETSI-SDC-MODEL-TEST";
+
+    @BeforeAll
+    void setup() {
+        init();
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void createModelSuccessTest() {
+        final ModelData modelData = new ModelData(modelName,  UniqueIdBuilder.buildModelUid(modelName));
+        when(janusGraphGenericDao.createNode(any(),any())).thenReturn(Either.left(modelData));
+        final Model createdModel = modelOperation.createModel(new Model(modelName), false);
+        assertThat(createdModel).isNotNull();
+        assertThat(createdModel.getName()).isEqualTo(modelName);
+    }
+
+    @Test
+    void createModelFailWithModelAlreadyExistTest() {
+        when(janusGraphGenericDao.createNode(any(),any())).thenReturn(Either.right(JanusGraphOperationStatus.JANUSGRAPH_SCHEMA_VIOLATION));
+        assertThrows(OperationException.class, () -> modelOperation.createModel(new Model(modelName), false));
+    }
+
+    @Test
+    void createModelFailTest() {
+        when(janusGraphGenericDao.createNode(any(),any())).thenReturn(Either.right(JanusGraphOperationStatus.GRAPH_IS_NOT_AVAILABLE));
+        assertThrows(OperationException.class, () -> modelOperation.createModel(new Model(modelName), false));
+    }
+
+}
index 4cdf050..185d953 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),
     DATA_TYPES("data_types", GraphPropertyEnum.DATA_TYPES),
 
     ////Inputs
index 75a2177..2a927b8 100644 (file)
@@ -63,7 +63,8 @@ public enum NodeTypeEnum {
     Input("input"),
     GroupInstance("groupInstance"),
     AnnotationType("annotationType"),
-    Component("component");
+    Component("component"),
+    Model("model");
     // @formatter:on
 
     private final String name;
diff --git a/pom.xml b/pom.xml
index 5427d1d..341b29d 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -133,6 +133,7 @@ Modifications copyright (c) 2018-2019 Nokia
         <hamcrest-all.version>1.3</hamcrest-all.version>
         <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
         <maven-jar-plugin.version>2.4</maven-jar-plugin.version>
+        <jMapper.version>1.6.0.1</jMapper.version>
 
         <!-- sonar -->
         <sonar.projectVersion>${project.version}</sonar.projectVersion>
@@ -735,6 +736,8 @@ Modifications copyright (c) 2018-2019 Nokia
                 <skipYamlJsonValidator>true</skipYamlJsonValidator>
                 <checkstyle.skip>true</checkstyle.skip>
                 <jacoco.skip>true</jacoco.skip>
+
+
                 <docker.skip.run>true</docker.skip.run>
             </properties>
             <modules>