Implement YAML Validator 86/134886/14
authorvasraz <vasyl.razinkov@est.tech>
Wed, 28 Jun 2023 14:34:47 +0000 (15:34 +0100)
committerVasyl Razinkov <vasyl.razinkov@est.tech>
Thu, 29 Jun 2023 10:31:23 +0000 (10:31 +0000)
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Change-Id: I0365d4160984e4d68906959fb801ec7da5449b77
Issue-ID: SDC-4537

28 files changed:
asdctool/src/main/resources/config/error-configuration.yaml
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/servlets/TypesUploadServlet.java
catalog-be/src/main/resources/config/error-configuration.yaml
catalog-be/src/main/resources/validateYaml/schema.json [new file with mode: 0644]
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/SchemaFiles.java [deleted file]
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/SchemaFilesTest.java [new file with mode: 0644]
catalog-be/src/test/resources/config/catalog-be/error-configuration.yaml
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-001.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-002.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-003.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-004.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-005.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-006.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-007.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-008.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-009.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-010.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-011.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-012.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-013.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-01.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-02.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-03.yaml [new file with mode: 0644]
catalog-be/src/test/resources/yamlValidation/noValid/schema.json [new file with mode: 0644]
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-ui/src/app/utils/service-data-type-reader.ts

index e8f100d..0ac4369 100644 (file)
@@ -2874,7 +2874,15 @@ errors:
   # %1 - componentType
   # %2 - component id
   CANNOT_ARCHIVE_SYSTEM_DEPLOYED_RESOURCES: {
-      code: 409,
-      message: "System deployed %1 cannot be archived. Component: '%2'",
-      messageId: "SVC4018"
-  }
\ No newline at end of file
+    code: 409,
+    message: "System deployed %1 cannot be archived. Component: '%2'",
+    messageId: "SVC4018"
+  }
+
+  #---------SVC4010-----------------------------
+  # %1 - error's list
+  YAML_IS_INVALID: {
+    code: 402,
+    message: "Error: Uploaded YAML file is invalid.\n%1",
+    messageId: "SVC4010"
+  }
index 5dc9423..54d6ce2 100644 (file)
@@ -22,6 +22,7 @@
     </properties>
 
     <dependencies>
+
         <dependency>
             <groupId>org.openecomp.sdc</groupId>
             <artifactId>togglz-rest-services</artifactId>
         </dependency>
 
         <!--JSON and YAML Parsing-->
+        <dependency>
+            <groupId>com.networknt</groupId>
+            <artifactId>json-schema-validator</artifactId>
+            <version>1.0.84</version>
+        </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-core</artifactId>
@@ -57,7 +63,6 @@
                 </exclusion>
             </exclusions>
         </dependency>
-
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
             </exclusions>
         </dependency>
 
-      <dependency>
-          <groupId>io.micrometer</groupId>
-          <artifactId>micrometer-registry-prometheus</artifactId>
-          <version>${micrometer.version}</version>
-      </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+            <version>${micrometer.version}</version>
+        </dependency>
 
         <dependency>
             <groupId>ch.qos.logback</groupId>
                                         <exclude>
                                             src/test/resources/artifacts/pnfSoftwareInformation/**
                                         </exclude>
+                                        <exclude>
+                                            src/test/resources/yamlValidation/noValid/**
+                                        </exclude>
                                     </excludes>
                                 </validationSet>
                                 <validationSet>
index 0cdcd01..006752e 100644 (file)
@@ -2894,4 +2894,12 @@ errors:
         code: 409,
         message: "System deployed %1 cannot be archived. Component: '%2'",
         messageId: "SVC4018"
-    }
\ No newline at end of file
+    }
+
+    #---------SVC4010-----------------------------
+    # %1 - error's list
+    YAML_IS_INVALID: {
+        code: 402,
+        message: "Error: Uploaded YAML file is invalid.\n%1",
+        messageId: "SVC4010"
+    }
index f7ea9bb..309bff2 100644 (file)
  */
 package org.openecomp.sdc.be.servlets;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import com.google.gson.reflect.TypeToken;
 import com.jcabi.aspects.Loggable;
+import com.networknt.schema.JsonSchemaFactory;
+import com.networknt.schema.SpecVersion;
+import com.networknt.schema.ValidationMessage;
 import fj.data.Either;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -30,25 +35,6 @@ 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.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import javax.inject.Inject;
-import javax.servlet.http.HttpServletRequest;
-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.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.glassfish.jersey.media.multipart.FormDataParam;
 import org.jetbrains.annotations.NotNull;
@@ -64,6 +50,7 @@ import org.openecomp.sdc.be.components.impl.RelationshipTypeImportManager;
 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.impl.exceptions.ByActionStatusComponentException;
 import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
@@ -85,6 +72,28 @@ import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.stereotype.Controller;
 
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+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.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
 @Path("/v1/catalog/uploadType")
 @Consumes(MediaType.MULTIPART_FORM_DATA)
@@ -129,67 +138,67 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
     @POST
     @Path("/capability")
     @Operation(description = "Create Capability Type from yaml", method = "POST", summary = "Returns created Capability Type", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "Capability Type created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "Capability Type already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "Capability Type created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "Capability Type already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadCapabilityType(@Parameter(description = "FileInputStream") @FormDataParam("capabilityTypeZip") File file,
                                          @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
                                          @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                          @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         ConsumerFourParam<Wrapper<Response>, String, String, Boolean> createElementsMethod = (responseWrapper, ymlPayload, model, includeToModelImport) ->
-            createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload, modelName,
-                includeToModelDefaultImports));
+                createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload, modelName,
+                        includeToModelDefaultImports));
         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.CapabilityType.name(), modelName,
-            includeToModelDefaultImports);
+                includeToModelDefaultImports);
     }
 
     @POST
     @Path("/relationship")
     @Operation(description = "Create Relationship Type from yaml", method = "POST", summary = "Returns created Relationship Type", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "Relationship Type created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "Relationship Type already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "Relationship Type created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "Relationship Type already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadRelationshipType(@Parameter(description = "FileInputStream") @FormDataParam("relationshipTypeZip") File file,
                                            @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
                                            @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                            @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         return uploadElementTypeServletLogic(this::createRelationshipTypes, file, request, creator, NodeTypeEnum.RelationshipType.getName(),
-            modelName, includeToModelDefaultImports);
+                modelName, includeToModelDefaultImports);
     }
 
     @POST
     @Path("/interfaceLifecycle")
     @Operation(description = "Create Interface Lyfecycle Type from yaml", method = "POST", summary = "Returns created Interface Lifecycle Type", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "Interface Lifecycle Type created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "Interface Lifecycle Type already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "Interface Lifecycle Type created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "Interface Lifecycle Type already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadInterfaceLifecycleType(@Parameter(description = "FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file,
                                                  @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
                                                  @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                                  @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) ->
-            createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload, modelName,
-                includeToModelDefaultImports));
+                createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload, modelName,
+                        includeToModelDefaultImports));
         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "Interface Types");
     }
 
     @POST
     @Path("/artifactTypes")
     @Operation(description = "Create Tosca Artifact types from yaml", method = "POST", summary = "Returns created Tosca artifact types", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "Tosca Artifact types created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "Tosca Artifact Type already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "Tosca Artifact types created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "Tosca Artifact Type already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadArtifactTypes(@Parameter(description = "Zip file containing a yaml with the TOSCA artifact types definition")
                                         @FormDataParam("artifactsZip") File file,
@@ -198,69 +207,69 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
                                         @Parameter(description = "A flag to add types to the default imports")
                                         @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         final ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) ->
-            createElementsType(responseWrapper,
-                () -> artifactTypeImportManager.createArtifactTypes(ymlPayload, modelName, includeToModelDefaultImports));
+                createElementsType(responseWrapper,
+                        () -> artifactTypeImportManager.createArtifactTypes(ymlPayload, modelName, includeToModelDefaultImports));
         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.ArtifactType.getName());
     }
 
     @POST
     @Path("/categories")
     @Operation(description = "Create Categories from yaml", method = "POST", summary = "Returns created categories", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "Categories created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "Category already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "Categories created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "Category already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadCategories(@Parameter(description = "FileInputStream") @FormDataParam("categoriesZip") File file,
                                      @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator) {
         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) ->
-            createElementsType(responseWrapper, () -> categoriesImportManager.createCategories(ymlPayload));
+                createElementsType(responseWrapper, () -> categoriesImportManager.createCategories(ymlPayload));
         return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, "categories");
     }
 
     @POST
     @Path("/datatypes")
     @Operation(description = "Create Data Types from zip", method = "POST", summary = "Returns created data types", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "Data types created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "Data types already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "Data types created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "Data types already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadDataTypes(@Parameter(description = "FileInputStream") @FormDataParam("dataTypesZip") File file,
                                     @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
                                     @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                     @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         return uploadElementTypeServletLogic(this::createDataTypes, file, request, creator, NodeTypeEnum.DataType.getName(), modelName,
-            includeToModelDefaultImports);
+                includeToModelDefaultImports);
     }
 
     @POST
     @Path("/datatypesyaml")
     @Operation(description = "Create Data Types from yaml", method = "POST", summary = "Returns created data types", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "Data types created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "Data types already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "Data types created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "Data types already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadDataTypesYaml(@Parameter(description = "FileInputStream") @FormDataParam("dataTypesYaml") File file,
                                         @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
                                         @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                         @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         return uploadElementTypeServletLogicYaml(this::createDataTypes, file, request, creator, NodeTypeEnum.DataType.getName(), modelName,
-            includeToModelDefaultImports);
+                includeToModelDefaultImports);
     }
 
     @POST
     @Path("/grouptypes")
     @Operation(description = "Create GroupTypes from yaml", method = "POST", summary = "Returns created group types", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "group types created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "group types already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "group types created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "group types already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadGroupTypes(@Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
                                      @Parameter(description = "model name") @FormDataParam("model") String modelName,
@@ -269,17 +278,17 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
                                      @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
         return uploadTypesWithMetaData(this::createGroupTypes, typesMetadata, file, request, creator, NodeTypeEnum.GroupType.getName(), modelName,
-            includeToModelDefaultImports);
+                includeToModelDefaultImports);
     }
 
     @POST
     @Path("/policytypes")
     @Operation(description = "Create PolicyTypes from yaml", method = "POST", summary = "Returns created policy types", responses = {
-        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
-        @ApiResponse(responseCode = "201", description = "policy types created"),
-        @ApiResponse(responseCode = "403", description = "Restricted operation"),
-        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
-        @ApiResponse(responseCode = "409", description = "policy types already exist")})
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+            @ApiResponse(responseCode = "201", description = "policy types created"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation"),
+            @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+            @ApiResponse(responseCode = "409", description = "policy types already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadPolicyTypes(@Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
                                       @Parameter(description = "model name") @FormDataParam("model") String modelName,
@@ -288,7 +297,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
                                       @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         Map<String, ToscaTypeMetadata> typesMetadata = getTypesMetadata(toscaTypesMetaData);
         return uploadTypesWithMetaData(this::createPolicyTypes, typesMetadata, file, request, creator, NodeTypeEnum.PolicyType.getName(), modelName,
-            includeToModelDefaultImports);
+                includeToModelDefaultImports);
     }
 
     private Map<String, ToscaTypeMetadata> getTypesMetadata(String toscaTypesMetaData) {
@@ -346,6 +355,12 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
                                                        final String elementTypeName, final String modelName,
                                                        final boolean includeToModelDefaultImports) {
         init();
+        final Set<ValidationMessage> validationMessages = validateYaml(file);
+        if (!validationMessages.isEmpty()) {
+            throw new ByActionStatusComponentException(ActionStatus.YAML_IS_INVALID, validationMessages.stream().map(validationMessage -> {
+                return validationMessage.getMessage();
+            }).collect(Collectors.joining("\n")));
+        }
         final String userId = initHeaderParam(creator, request, Constants.USER_ID_HEADER);
         try {
             final String url = request.getMethod() + " " + request.getRequestURI();
@@ -365,6 +380,24 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
         }
     }
 
+    private Set<ValidationMessage> validateYaml(final File file) {
+        final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+        final JsonSchemaFactory factory =
+                JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012)).objectMapper(mapper).build();
+
+        final Set<ValidationMessage> validationMessages = new HashSet<>();
+        try (final InputStream yamlFile = new FileInputStream(file);
+             final InputStream schemaFile = Thread.currentThread().getContextClassLoader().getResourceAsStream("validateYaml/schema.json")) {
+            validationMessages.addAll(factory.getSchema(schemaFile).validate(mapper.readTree(yamlFile)));
+        } catch (final IOException e) {
+            ValidationMessage.Builder builder = new ValidationMessage.Builder();
+            builder.customMessage(e.getMessage());
+            validationMessages.add(builder.build());
+        }
+
+        return validationMessages;
+    }
+
     @NotNull
     private String getFileAsString(File file) throws IOException {
         try (final FileInputStream fl = new FileInputStream(file)) {
@@ -423,7 +456,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
         } else {
             try {
                 Response response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED),
-                    RepresentationUtils.toRepresentation(eitherResult.left().value()));
+                        RepresentationUtils.toRepresentation(eitherResult.left().value()));
                 responseWrapper.setInnerElement(response);
             } catch (Exception e) {
                 responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)));
@@ -436,27 +469,27 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
     private void createDataTypes(Wrapper<Response> responseWrapper, String dataTypesYml, final String modelName,
                                  final boolean includeToModelDefaultImports) {
         final Supplier<Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () ->
-            dataTypeImportManager.createDataTypes(dataTypesYml, modelName, includeToModelDefaultImports);
+                dataTypeImportManager.createDataTypes(dataTypesYml, modelName, includeToModelDefaultImports);
         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.DATA_TYPE_ALREADY_EXIST,
-            NodeTypeEnum.DataType.name());
+                NodeTypeEnum.DataType.name());
     }
 
     // group types
     private void createGroupTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData, String modelName,
                                   final boolean includeToModelDefaultImports) {
         final Supplier<Either<List<ImmutablePair<GroupTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () ->
-            groupTypeImportManager.createGroupTypes(toscaTypeImportData, modelName, includeToModelDefaultImports);
+                groupTypeImportManager.createGroupTypes(toscaTypeImportData, modelName, includeToModelDefaultImports);
         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.GROUP_TYPE_ALREADY_EXIST,
-            NodeTypeEnum.GroupType.name());
+                NodeTypeEnum.GroupType.name());
     }
 
     // policy types
     private void createPolicyTypes(Wrapper<Response> responseWrapper, ToscaTypeImportData toscaTypeImportData, String modelName,
                                    final boolean includeToModelDefaultImports) {
         final Supplier<Either<List<ImmutablePair<PolicyTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () ->
-            policyTypeImportManager.createPolicyTypes(toscaTypeImportData, modelName, includeToModelDefaultImports);
+                policyTypeImportManager.createPolicyTypes(toscaTypeImportData, modelName, includeToModelDefaultImports);
         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.POLICY_TYPE_ALREADY_EXIST,
-            NodeTypeEnum.PolicyType.name());
+                NodeTypeEnum.PolicyType.name());
     }
 
     // data types
@@ -475,7 +508,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
                     // Group result by the right value - true or false.
                     // I.e., get the number of data types which are new and which are old.
                     final Map<Boolean, List<ImmutablePair<T, Boolean>>> collect =
-                        list.stream().collect(Collectors.groupingBy(ImmutablePair<T, Boolean>::getRight));
+                            list.stream().collect(Collectors.groupingBy(ImmutablePair<T, Boolean>::getRight));
                     if (collect != null) {
                         Set<Boolean> keySet = collect.keySet();
                         if (keySet.size() == 1) {
@@ -506,8 +539,8 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
                                          final String modelName,
                                          final boolean includeToModelDefaultImports) {
         final Supplier<Either<List<ImmutablePair<RelationshipTypeDefinition, Boolean>>, ResponseFormat>> generateElementTypeFromYml = () -> relationshipTypeImportManager
-            .createRelationshipTypes(relationshipTypesYml, modelName, includeToModelDefaultImports);
+                .createRelationshipTypes(relationshipTypesYml, modelName, includeToModelDefaultImports);
         buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST,
-            NodeTypeEnum.RelationshipType.name());
+                NodeTypeEnum.RelationshipType.name());
     }
 }
index 7589511..d77f98e 100644 (file)
@@ -2886,4 +2886,12 @@ errors:
         code: 409,
         message: "System deployed %1 cannot be archived. Component: '%2'",
         messageId: "SVC4018"
-    }
\ No newline at end of file
+    }
+
+    #---------SVC4010-----------------------------
+    # %1 - error's list
+    YAML_IS_INVALID: {
+        code: 402,
+        message: "Error: Uploaded YAML file is invalid.\n%1",
+        messageId: "SVC4010"
+    }
diff --git a/catalog-be/src/main/resources/validateYaml/schema.json b/catalog-be/src/main/resources/validateYaml/schema.json
new file mode 100644 (file)
index 0000000..df43dc4
--- /dev/null
@@ -0,0 +1,121 @@
+{
+  "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "$id": "http://example.com/example.json",
+  "title": "Root Schema",
+  "type": "object",
+  "default": {},
+  "properties": {
+    "tosca_definitions_version": {
+      "title": "The tosca_definitions_version Schema",
+      "type": "string",
+      "default": ""
+    },
+    "data_types": {
+      "title": "The data_types Schema",
+      "type": "object",
+      "default": {},
+      "required": [],
+      "additionalProperties": {
+        "title": "The additionalProperties Schema",
+        "type": "object",
+        "default": {},
+        "required": [
+          "derived_from",
+          "properties"
+        ],
+        "properties": {
+          "derived_from": {
+            "title": "The derived_from Schema",
+            "type": "string",
+            "default": ""
+          },
+          "properties": {
+            "title": "The properties Schema",
+            "type": "object",
+            "default": {},
+            "required": [],
+            "additionalProperties": {
+              "title": "The additionalProperties Schema",
+              "type": "object",
+              "default": {},
+              "required": [
+                "type"
+              ],
+              "properties": {
+                "type": {
+                  "title": "The type Schema",
+                  "type": "string",
+                  "default": ""
+                },
+                "description": {
+                  "title": "The description Schema",
+                  "type": "string",
+                  "default": ""
+                },
+                "default": {
+                  "title": "The default Schema",
+                  "type": [
+                    "string",
+                    "integer",
+                    "boolean",
+                    "number"
+                  ],
+                  "default": ""
+                },
+                "required": {
+                  "title": "The required Schema",
+                  "type": "boolean",
+                  "default": false
+                },
+                "status": {
+                  "title": "The status Schema",
+                  "type": "string",
+                  "default": ""
+                },
+                "constraints": {
+                  "title": "The constraints Schema",
+                  "type": [
+                    "array"
+                  ],
+                  "default": {}
+                },
+                "entry_schema": {
+                  "title": "The entry_schema Schema",
+                  "type": "object",
+                  "default": {},
+                  "properties": {
+                    "type": {
+                      "title": "The type Schema",
+                      "type": [
+                        "string",
+                        "integer",
+                        "boolean",
+                        "number"
+                      ],
+                      "default": ""
+                    }
+                  }
+                }
+              },
+              "if": {
+                "properties": {
+                  "type": {
+                    "enum": [
+                      "map",
+                      "list"
+                    ]
+                  }
+                }
+              },
+              "then": {
+                "required": [
+                  "entry_schema"
+                ]
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/SchemaFiles.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/SchemaFiles.java
deleted file mode 100644 (file)
index 839095f..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.openecomp.sdc.be.tosca;
-
-import org.junit.Test;
-import org.yaml.snakeyaml.Yaml;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class SchemaFiles {
-
-    @Test
-    public void testValidateYamlNormativeFiles(){
-        String importToscaPath = "src/main/resources/import/tosca";
-        assertTrue(checkValidYamlInFileTree(importToscaPath));
-    }
-
-    @Test
-    public void testRainyYamlNormativeFiles(){
-        String importToscaPathTest = "src/test/resources/yamlValidation";
-        assertFalse(checkValidYamlInFileTree(importToscaPathTest));
-    }
-
-    private boolean checkValidYamlInFileTree(String fileTree)  {
-
-        try {
-            List<Path> fileTreeYamlList = Files.walk(Paths.get(fileTree))
-              .filter(path -> path.getFileName().toString().toLowerCase().endsWith(".yml"))
-              .collect(Collectors.toList());
-
-            for (Path yamlFile : fileTreeYamlList) {
-                try {
-                    FileInputStream inputStream = new FileInputStream(yamlFile.toAbsolutePath().toString());
-                    Yaml yaml = new Yaml();
-                    Object content = yaml.load(inputStream);
-                } catch (Exception e) {
-                    System.out.println("Not valid yaml in file creation : " + yamlFile.toAbsolutePath().toString());
-                    return false;
-                }
-            }
-        } catch (IOException e) {
-            System.out.println("Error in reading file from folder : " + fileTree);
-            return false;
-        }
-        return true;
-    }
-
-
-}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/SchemaFilesTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/SchemaFilesTest.java
new file mode 100644 (file)
index 0000000..ddcf649
--- /dev/null
@@ -0,0 +1,131 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.tosca;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.networknt.schema.JsonSchemaFactory;
+import com.networknt.schema.SpecVersion;
+import com.networknt.schema.ValidationMessage;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.test.util.TestResourcesHandler;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.parser.ParserException;
+import org.yaml.snakeyaml.scanner.ScannerException;
+
+class SchemaFilesTest {
+
+    @Test
+    void testValidateYamlNormativeFiles() {
+        String importToscaPath = "src/main/resources/import/tosca";
+        assertTrue(checkValidYamlInFileTree(importToscaPath));
+    }
+
+    @Test
+    void testRainyYamlNormativeFiles() {
+        String importToscaPathTest = "src/test/resources/yamlValidation";
+        assertFalse(checkValidYamlInFileTree(importToscaPathTest));
+    }
+
+    private boolean checkValidYamlInFileTree(final String fileTree) {
+        AtomicBoolean ret = new AtomicBoolean(true);
+        try (final Stream<Path> pathStream = Files.walk(Paths.get(fileTree))) {
+            pathStream
+                .filter(path -> path.getFileName().toString().toLowerCase().endsWith(".yml"))
+                .forEach(yamlFile -> {
+                    try {
+                        new Yaml().load(new FileInputStream(yamlFile.toAbsolutePath().toString()));
+                    } catch (final Exception e) {
+                        System.out.println("Not valid yaml in file creation : " + yamlFile.toAbsolutePath());
+                        ret.set(false);
+                    }
+                });
+        } catch (final IOException e) {
+            System.out.println("Error in reading file from folder : " + fileTree);
+            return false;
+        }
+        return ret.get();
+    }
+
+    @Test
+    void yamlValidation_test_no_valid() {
+        final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+        final JsonSchemaFactory factory =
+            JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012)).objectMapper(mapper).build();
+
+        try (final Stream<Path> pathStream = Files.walk(Paths.get("src/test/resources/yamlValidation"))) {
+            pathStream
+                .filter(path -> path.getFileName().toString().toLowerCase().startsWith("data_types_no-valid-"))
+                .forEach(path -> {
+                    try (final InputStream schemaFile = TestResourcesHandler.getResourceAsStream("yamlValidation/noValid/" + "schema.json");
+                        final InputStream yamlFile = TestResourcesHandler.getResourceAsStream("yamlValidation/noValid/" + path.getFileName())) {
+                        final Set<ValidationMessage> validationMessages = factory.getSchema(schemaFile).validate(mapper.readTree(yamlFile));
+                        validationMessages.forEach(System.out::println);
+                        assertFalse(validationMessages.isEmpty());
+                    } catch (JsonParseException e) {
+                        assertTrue(e.getCause() instanceof ParserException || e.getCause() instanceof ScannerException);
+                    } catch (IOException e) {
+                        fail(e.getMessage());
+                    }
+                });
+        } catch (final IOException e) {
+            fail(e.getMessage());
+        }
+    }
+    @Test
+    void yamlValidation_test_valid() {
+        final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+        final JsonSchemaFactory factory =
+            JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012)).objectMapper(mapper).build();
+
+        try (final Stream<Path> pathStream = Files.walk(Paths.get("src/test/resources/yamlValidation"))) {
+            pathStream
+                .filter(path -> path.getFileName().toString().toLowerCase().startsWith("data_types_valid-"))
+                .forEach(path -> {
+                    try (final InputStream schemaFile = TestResourcesHandler.getResourceAsStream("yamlValidation/noValid/" + "schema.json");
+                        final InputStream yamlFile = TestResourcesHandler.getResourceAsStream("yamlValidation/noValid/" + path.getFileName())) {
+                        final Set<ValidationMessage> validationMessages = factory.getSchema(schemaFile).validate(mapper.readTree(yamlFile));
+                        validationMessages.forEach(System.out::println);
+                        assertTrue(validationMessages.isEmpty());
+                    } catch (IOException e) {
+                        fail(e.getMessage());
+                    }
+                });
+        } catch (final IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+}
index 6911570..0937c1d 100644 (file)
@@ -2872,4 +2872,12 @@ errors:
         code: 409,
         message: "System deployed %1 cannot be archived. Component: '%2'",
         messageId: "SVC4018"
-    }
\ No newline at end of file
+    }
+
+    #---------SVC4010-----------------------------
+    # %1 - error's list
+    YAML_IS_INVALID: {
+        code: 402,
+        message: "Error: Uploaded YAML file is invalid.\n%1",
+        messageId: "SVC4010"
+    }
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-001.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-001.yaml
new file mode 100644 (file)
index 0000000..ca05128
--- /dev/null
@@ -0,0 +1 @@
+tosca_definitions_version:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-002.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-002.yaml
new file mode 100644 (file)
index 0000000..ca05128
--- /dev/null
@@ -0,0 +1 @@
+tosca_definitions_version:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-003.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-003.yaml
new file mode 100644 (file)
index 0000000..85683a0
--- /dev/null
@@ -0,0 +1,2 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-004.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-004.yaml
new file mode 100644 (file)
index 0000000..ae209d1
--- /dev/null
@@ -0,0 +1,3 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-005.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-005.yaml
new file mode 100644 (file)
index 0000000..00d452c
--- /dev/null
@@ -0,0 +1,4 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-006.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-006.yaml
new file mode 100644 (file)
index 0000000..74e2c8a
--- /dev/null
@@ -0,0 +1,4 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from: tosca.datatypes.Root\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-007.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-007.yaml
new file mode 100644 (file)
index 0000000..6eb68d0
--- /dev/null
@@ -0,0 +1,5 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from: tosca.datatypes.Root\r
+    properties:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-008.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-008.yaml
new file mode 100644 (file)
index 0000000..21b5445
--- /dev/null
@@ -0,0 +1,6 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from: tosca.datatypes.Root\r
+    properties:\r
+      pr_2:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-009.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-009.yaml
new file mode 100644 (file)
index 0000000..00073a3
--- /dev/null
@@ -0,0 +1,7 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from: tosca.datatypes.Root\r
+    properties:\r
+      pr_2:\r
+        type:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-010.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-010.yaml
new file mode 100644 (file)
index 0000000..2ccb8dd
--- /dev/null
@@ -0,0 +1,7 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from: tosca.datatypes.Root\r
+    properties:\r
+      pr_2:\r
+        type: map\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-011.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-011.yaml
new file mode 100644 (file)
index 0000000..d7e2197
--- /dev/null
@@ -0,0 +1,9 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from: tosca.datatypes.Root\r
+    properties:\r
+      pr_2:\r
+        type: map\r
+        entry_schema:\r
+          type:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-012.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-012.yaml
new file mode 100644 (file)
index 0000000..8e9ade8
--- /dev/null
@@ -0,0 +1,14 @@
+tosca_definitions_version: tosca_simple_yaml_1_2\r
+data_types:\r
+  datatype_test:\r
+    derived_from: tosca.datatypes.Root\r
+    properties:\r
+      pr_2:\r
+        type: map\r
+        entry_schema:\r
+          type: boolean\r
+      descriptor_id:\r
+        type: string\r
+        description: Globally unique identifier of the VNFD\r
+        required: true\r
+        constraints:\r
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-013.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_no-valid-013.yaml
new file mode 100644 (file)
index 0000000..bfc5f2a
--- /dev/null
@@ -0,0 +1,20 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+data_types:
+  datatype_test:
+    derived_from: tosca.datatypes.Root
+    properties:
+      pr_1:
+        type: list
+        entry_schema:
+          type: boolean
+        default: [
+      pr_2:
+        type: map
+        entry_schema:
+          type: boolean
+        default: }
+      descriptor_id:
+        type: string
+        description: Globally unique identifier of the VNFD
+        default: 'Missing quote
+        required: true
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-01.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-01.yaml
new file mode 100644 (file)
index 0000000..991477c
--- /dev/null
@@ -0,0 +1,85 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+data_types:
+  datatype_test:
+    derived_from: tosca.datatypes.Root
+    properties:
+      pr_1:
+        type: map
+        entry_schema:
+          type: boolean
+      pr_2:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - equal: fgh
+      pr_3:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - greater_than: a
+      pr_4:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - greater_or_equal: b
+      pr_5:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - less_than: z
+      pr_6:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - less_or_equal: y
+      pr_7:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - in_range:
+              - bb
+              - yy
+      pr_8:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - valid_values:
+              - dd
+              - rr
+      pr_9:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - length: 3
+      pr_10:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - min_length: 3
+      pr_11:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - min_length: 3
+      pr_12:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - max_length: 3
+      pr_13:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - pattern: '[a-z]'
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-02.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-02.yaml
new file mode 100644 (file)
index 0000000..d4ba271
--- /dev/null
@@ -0,0 +1,84 @@
+data_types:
+  datatype_test:
+    derived_from: tosca.datatypes.Root
+    properties:
+      pr_1:
+        type: map
+        entry_schema:
+          type: boolean
+      pr_2:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - equal: fgh
+      pr_3:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - greater_than: a
+      pr_4:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - greater_or_equal: b
+      pr_5:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - less_than: z
+      pr_6:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - less_or_equal: y
+      pr_7:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - in_range:
+              - bb
+              - yy
+      pr_8:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - valid_values:
+              - dd
+              - rr
+      pr_9:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - length: 3
+      pr_10:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - min_length: 3
+      pr_11:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - min_length: 3
+      pr_12:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - max_length: 3
+      pr_13:
+        type: string
+        description: Globally unique identifier of the VNFD
+        required: true
+        constraints:
+          - pattern: '[a-z]'
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-03.yaml b/catalog-be/src/test/resources/yamlValidation/noValid/data_types_valid-03.yaml
new file mode 100644 (file)
index 0000000..a15f368
--- /dev/null
@@ -0,0 +1,83 @@
+datatype_test:
+  derived_from: tosca.datatypes.Root
+  properties:
+    pr_1:
+      type: map
+      entry_schema:
+        type: boolean
+    pr_2:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - equal: fgh
+    pr_3:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - greater_than: a
+    pr_4:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - greater_or_equal: b
+    pr_5:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - less_than: z
+    pr_6:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - less_or_equal: y
+    pr_7:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - in_range:
+            - bb
+            - yy
+    pr_8:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - valid_values:
+            - dd
+            - rr
+    pr_9:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - length: 3
+    pr_10:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - min_length: 3
+    pr_11:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - min_length: 3
+    pr_12:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - max_length: 3
+    pr_13:
+      type: string
+      description: Globally unique identifier of the VNFD
+      required: true
+      constraints:
+        - pattern: '[a-z]'
diff --git a/catalog-be/src/test/resources/yamlValidation/noValid/schema.json b/catalog-be/src/test/resources/yamlValidation/noValid/schema.json
new file mode 100644 (file)
index 0000000..df43dc4
--- /dev/null
@@ -0,0 +1,121 @@
+{
+  "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "$id": "http://example.com/example.json",
+  "title": "Root Schema",
+  "type": "object",
+  "default": {},
+  "properties": {
+    "tosca_definitions_version": {
+      "title": "The tosca_definitions_version Schema",
+      "type": "string",
+      "default": ""
+    },
+    "data_types": {
+      "title": "The data_types Schema",
+      "type": "object",
+      "default": {},
+      "required": [],
+      "additionalProperties": {
+        "title": "The additionalProperties Schema",
+        "type": "object",
+        "default": {},
+        "required": [
+          "derived_from",
+          "properties"
+        ],
+        "properties": {
+          "derived_from": {
+            "title": "The derived_from Schema",
+            "type": "string",
+            "default": ""
+          },
+          "properties": {
+            "title": "The properties Schema",
+            "type": "object",
+            "default": {},
+            "required": [],
+            "additionalProperties": {
+              "title": "The additionalProperties Schema",
+              "type": "object",
+              "default": {},
+              "required": [
+                "type"
+              ],
+              "properties": {
+                "type": {
+                  "title": "The type Schema",
+                  "type": "string",
+                  "default": ""
+                },
+                "description": {
+                  "title": "The description Schema",
+                  "type": "string",
+                  "default": ""
+                },
+                "default": {
+                  "title": "The default Schema",
+                  "type": [
+                    "string",
+                    "integer",
+                    "boolean",
+                    "number"
+                  ],
+                  "default": ""
+                },
+                "required": {
+                  "title": "The required Schema",
+                  "type": "boolean",
+                  "default": false
+                },
+                "status": {
+                  "title": "The status Schema",
+                  "type": "string",
+                  "default": ""
+                },
+                "constraints": {
+                  "title": "The constraints Schema",
+                  "type": [
+                    "array"
+                  ],
+                  "default": {}
+                },
+                "entry_schema": {
+                  "title": "The entry_schema Schema",
+                  "type": "object",
+                  "default": {},
+                  "properties": {
+                    "type": {
+                      "title": "The type Schema",
+                      "type": [
+                        "string",
+                        "integer",
+                        "boolean",
+                        "number"
+                      ],
+                      "default": ""
+                    }
+                  }
+                }
+              },
+              "if": {
+                "properties": {
+                  "type": {
+                    "enum": [
+                      "map",
+                      "list"
+                    ]
+                  }
+                }
+              },
+              "then": {
+                "required": [
+                  "entry_schema"
+                ]
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
index 352f09e..5434f1f 100644 (file)
@@ -75,7 +75,7 @@ public enum ActionStatus {
     EMPTY_OCCURRENCES_LIST, INVALID_OCCURRENCES, NOT_TOPOLOGY_TOSCA_TEMPLATE, INVALID_NODE_TEMPLATE,
     // Data type related
     DATA_TYPE_ALREADY_EXIST, DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM, DATA_TYPE_PROPERTIES_CANNOT_BE_EMPTY, DATA_TYPE_DERIVED_IS_MISSING, DATA_TYPE_PROPERTY_ALREADY_DEFINED_IN_ANCESTOR, DATA_TYPE_DUPLICATE_PROPERTY, DATA_TYPE_PROEPRTY_CANNOT_HAVE_SAME_TYPE_OF_DATA_TYPE, DATA_TYPE_CANNOT_HAVE_PROPERTIES, DATA_TYPE_CANNOT_BE_EMPTY, DATA_TYPE_CANNOT_BE_UPDATED_BAD_REQUEST,
-    DATA_TYPES_NOT_LOADED, DATA_TYPE_NOT_FOUND, DATA_TYPE_PROPERTIES_NOT_FOUND,
+    DATA_TYPES_NOT_LOADED, DATA_TYPE_NOT_FOUND, DATA_TYPE_PROPERTIES_NOT_FOUND, YAML_IS_INVALID,
     // Policy Type related
     TARGETS_EMPTY, TARGETS_NON_VALID, POLICY_TYPE_ALREADY_EXIST,
     // Group Type related
index 9686f3d..dbb5508 100644 (file)
@@ -35,10 +35,11 @@ export class ServiceDataTypeReader {
                     const result = <String>reader.result;
                     const loadedContent = load(result);
                     console.log("Readed content: " + loadedContent);
-                    this.readName(this.getDataType(loadedContent));
-                    this.readDerivedFrom(this.getDataType(loadedContent));
-                    this.readDescription(this.getDataType(loadedContent));
-                    this.readProperties(this.getDataType(loadedContent));
+                    const dataType = this.getDataType(loadedContent);
+                    this.readName(dataType);
+                    this.readDerivedFrom(dataType);
+                    this.readDescription(dataType);
+                    this.readProperties(dataType);
                     resolve(this.serviceDataType);
                 } catch (error) {
                     reject(error);
@@ -201,4 +202,4 @@ export class ServiceDataTypeReader {
             value:constraintValue
         }
     }
-}
\ No newline at end of file
+}