From 252b950552a9815f2680c457e7bd0e8af9f610f7 Mon Sep 17 00:00:00 2001 From: "puthuparambil.aditya" Date: Tue, 20 Oct 2020 12:23:34 +0100 Subject: [PATCH] VSE: Upload modules (a model file) to a (new) dataspace 1. Schema.sql modified to include modules and json_data tables which can be removed after the PoC 2. URI changed as per the proposal to '/dataspaces/{dataspace_name}/modules' 3. Dataspace name corresponding to a model is passed as a parameter. 4. In case the dataspace doesnt exist in the dataspace table, a new entry for the passed dataspace is created. 5. The corresponding dataspace_id is also stored as a reference in the modules table. 6. Test case for Rest API will be pushed as another review. JIRA: https://jira.onap.org/browse/CCSDK-2897 Issue-ID: CCSDK-2897 Change-Id: Ic9caa39b5a7afca28c0365cdb4f492848d0ead3e Signed-off-by: puthuparambil.aditya --- cps/README.md | 4 +-- .../onap/cps/rest/controller/RestController.java | 18 ++++++------ .../java/org/onap/cps/spi/entities/Dataspace.java | 12 +++++++- .../org/onap/cps/spi/entities/ModuleEntity.java | 28 ++++++++++++++----- .../cps/spi/impl/ModelPersistencyServiceImpl.java | 20 +++++++++++--- .../cps/spi/repository/DataspaceRepository.java | 32 ++++++++++++++++++++++ .../onap/cps/spi/repository/ModuleRepository.java | 1 - cps/cps-ri/src/main/resources/schema.sql | 17 ++++++++---- cps/cps-service/pom.xml | 8 +----- .../src/main/java/org/onap/cps/api/CpService.java | 4 ++- .../java/org/onap/cps/api/impl/CpServiceImpl.java | 18 ++++++------ .../org/onap/cps/spi/ModelPersistencyService.java | 7 +++-- .../org/onap/cps/api/impl/CpServiceImplSpec.groovy | 6 ++-- cps/pom.xml | 21 ++++++++++++++ 14 files changed, 145 insertions(+), 51 deletions(-) create mode 100644 cps/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java diff --git a/cps/README.md b/cps/README.md index 791015ef1..d1bf49d8c 100644 --- a/cps/README.md +++ b/cps/README.md @@ -1,7 +1,7 @@ -# Configuration & Persistency Service +# Configuration Persistence Service This folder contains all files for -[Configuration & Persistency Service](https://wiki.onap.org/pages/viewpage.action?pageId=81406119). +[Configuration Persistence Service](https://wiki.onap.org/pages/viewpage.action?pageId=81406119). The code here is related to CPS POC, then it must be kept self contained in this cps folder to prevent any impact on current ccsdk components and to be ready to be moved in its own repo once CPS becomes a standalone project. diff --git a/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/RestController.java b/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/RestController.java index 18e24b437..703e77823 100644 --- a/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/RestController.java +++ b/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/RestController.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2020 Bell Canada. 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. @@ -22,8 +23,6 @@ package org.onap.cps.rest.controller; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import java.io.File; -import java.io.IOException; -import java.io.InputStream; import javax.persistence.PersistenceException; import javax.validation.Valid; import javax.ws.rs.Consumes; @@ -36,10 +35,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.SecurityContext; import org.apache.cxf.jaxrs.ext.multipart.Attachment; -import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; +import org.hibernate.exception.ConstraintViolationException; import org.onap.cps.api.CpService; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; @@ -110,19 +108,21 @@ public class RestController implements CpsResourceApi { * Upload a yang model file. * * @param uploadedFile the yang model file. + * @param dataspaceName the dataspace name linked to the model. * @return a http response code. */ @POST - @Path("/upload-yang-model-file") + @Path("/dataspaces/{dataspace_name}/modules") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.MULTIPART_FORM_DATA) - public final Response uploadYangModelFile(@FormDataParam("file") File uploadedFile) throws IOException { + public final Response uploadYangModelFile(@FormDataParam("file") File uploadedFile, + @PathParam("dataspace_name") String dataspaceName) { try { final File fileToParse = renameFileIfNeeded(uploadedFile); final SchemaContext schemaContext = cpService.parseAndValidateModel(fileToParse); - cpService.storeSchemaContext(schemaContext); - return Response.status(Status.OK).entity("Yang File Parsed").build(); - } catch (final YangParserException e) { + cpService.storeSchemaContext(schemaContext, dataspaceName); + return Response.status(Status.CREATED).entity("Resource successfully created").build(); + } catch (final YangParserException | ConstraintViolationException e) { return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); } catch (final Exception e) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); diff --git a/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/Dataspace.java b/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/Dataspace.java index 8f37692b1..627a14467 100644 --- a/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/Dataspace.java +++ b/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/Dataspace.java @@ -31,6 +31,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; + /** * Entity to store a dataspace. */ @@ -49,4 +50,13 @@ public class Dataspace { @NotNull @Column(columnDefinition = "text") private String name; -} + + /** + * Initialize a Dataspace . + * + * @param name the Dataspace name. + */ + public Dataspace(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/ModuleEntity.java b/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/ModuleEntity.java index f786c58f1..d2130aeec 100644 --- a/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/ModuleEntity.java +++ b/cps/cps-ri/src/main/java/org/onap/cps/spi/entities/ModuleEntity.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2020 Bell Canada. 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. @@ -21,10 +22,14 @@ package org.onap.cps.spi.entities; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -39,32 +44,41 @@ import lombok.Setter; @Entity @AllArgsConstructor @NoArgsConstructor -@Table(name = "modules") +@Table(name = "module") public class ModuleEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; - @Column - private String name; - + @NotNull @Column private String moduleContent; + @NotNull @Column private String revision; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "dataspace_id", referencedColumnName = "ID") + private Dataspace dataspace; + + @NotNull + @Column + private String namespace; + /** * Initialize a module entity. * - * @param name the module name. + * @param namespace the module namespace. * @param moduleContent the module content. * @param revision the revision number of the module. + * @param dataspace the dataspace related to the module. */ - public ModuleEntity(String name, String moduleContent, String revision) { - this.name = name; + public ModuleEntity(String namespace, String moduleContent, String revision, Dataspace dataspace) { + this.namespace = namespace; this.moduleContent = moduleContent; this.revision = revision; + this.dataspace = dataspace; } } \ No newline at end of file diff --git a/cps/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistencyServiceImpl.java b/cps/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistencyServiceImpl.java index 14085c7cf..01c7a7b53 100644 --- a/cps/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistencyServiceImpl.java +++ b/cps/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistencyServiceImpl.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2020 Bell Canada. 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. @@ -20,7 +21,9 @@ package org.onap.cps.spi.impl; import org.onap.cps.spi.ModelPersistencyService; +import org.onap.cps.spi.entities.Dataspace; import org.onap.cps.spi.entities.ModuleEntity; +import org.onap.cps.spi.repository.DataspaceRepository; import org.onap.cps.spi.repository.ModuleRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -31,15 +34,24 @@ public class ModelPersistencyServiceImpl implements ModelPersistencyService { private final ModuleRepository moduleRepository; + private final DataspaceRepository dataspaceRepository; + @Autowired - public ModelPersistencyServiceImpl(final ModuleRepository moduleRepository) { + public ModelPersistencyServiceImpl(final ModuleRepository moduleRepository, + final DataspaceRepository dataspaceRepository) { this.moduleRepository = moduleRepository; + this.dataspaceRepository = dataspaceRepository; } @Override - public void storeModule(final String name, final String moduleContent, final String revision) { - final ModuleEntity moduleEntity = new ModuleEntity(name, moduleContent, revision); + public void storeModule(final String namespace, final String moduleContent, final String revision, + final String dataspaceName) { + final Dataspace dataspace = new Dataspace(dataspaceName); + if (Boolean.FALSE.equals(dataspaceRepository.existsByName(dataspaceName))) { + dataspaceRepository.save(dataspace); + } + dataspace.setId(dataspaceRepository.findByName(dataspaceName).getId()); + final ModuleEntity moduleEntity = new ModuleEntity(namespace, moduleContent, revision, dataspace); moduleRepository.save(moduleEntity); - } } diff --git a/cps/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java b/cps/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java new file mode 100644 index 000000000..46a526610 --- /dev/null +++ b/cps/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java @@ -0,0 +1,32 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Bell Canada. 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.spi.repository; + + +import org.onap.cps.spi.entities.Dataspace; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DataspaceRepository extends JpaRepository { + Boolean existsByName(String name); //Checks if there are any records by name() + + Dataspace findByName(String name); +} \ No newline at end of file diff --git a/cps/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleRepository.java b/cps/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleRepository.java index 0fe53b621..f9078d7c1 100644 --- a/cps/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleRepository.java +++ b/cps/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleRepository.java @@ -26,5 +26,4 @@ import org.springframework.stereotype.Repository; @Repository public interface ModuleRepository extends JpaRepository { - } \ No newline at end of file diff --git a/cps/cps-ri/src/main/resources/schema.sql b/cps/cps-ri/src/main/resources/schema.sql index 05d31d92f..6a76fbd19 100644 --- a/cps/cps-ri/src/main/resources/schema.sql +++ b/cps/cps-ri/src/main/resources/schema.sql @@ -17,12 +17,6 @@ CREATE TABLE IF NOT EXISTS SCHEMA_NODE ID SERIAL PRIMARY KEY ); -CREATE TABLE IF NOT EXISTS MODULE_SET -( - MODULE_SET_REFERENCE TEXT NOT NULL, - ID SERIAL PRIMARY KEY -); - CREATE TABLE IF NOT EXISTS FRAGMENT ( ID BIGSERIAL PRIMARY KEY, @@ -45,6 +39,17 @@ CREATE TABLE IF NOT EXISTS RELATION CONSTRAINT RELATION_PKEY PRIMARY KEY (TO_FRAGMENT_ID, FROM_FRAGMENT_ID, RELATION_TYPE_ID) ); +CREATE TABLE IF NOT EXISTS MODULE +( + NAMESPACE TEXT NOT NULL, + REVISION TEXT NOT NULL, + MODULE_CONTENT TEXT NOT NULL, + DATASPACE_ID BIGINT NOT NULL, + ID SERIAL PRIMARY KEY, + UNIQUE (NAMESPACE, REVISION), + CONSTRAINT module_dataspace FOREIGN KEY (DATASPACE_ID) REFERENCES DATASPACE (id) ON UPDATE CASCADE ON DELETE CASCADE +); + CREATE INDEX IF NOT EXISTS "FKI_FRAGMENT_DATASPACE_ID_FK" ON FRAGMENT USING BTREE(DATASPACE_ID) ; CREATE INDEX IF NOT EXISTS "FKI_FRAGMENT_MODULE_SET_ID_FK" ON FRAGMENT USING BTREE(MODULE_SET_ID) ; CREATE INDEX IF NOT EXISTS "FKI_FRAGMENT_PARENT_ID_FK" ON FRAGMENT USING BTREE(PARENT_ID) ; diff --git a/cps/cps-service/pom.xml b/cps/cps-service/pom.xml index 731873420..ea1bdad39 100644 --- a/cps/cps-service/pom.xml +++ b/cps/cps-service/pom.xml @@ -60,25 +60,19 @@ - org.codehaus.groovy groovy - ${groovy.version} - test org.spockframework spock-core - ${spock-core.version} - test cglib cglib-nodep - 3.1 - test + diff --git a/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java b/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java index 177fc043a..2f735abc7 100644 --- a/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java +++ b/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2020 Bell Canada. 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. @@ -49,8 +50,9 @@ public interface CpService { * Store schema context for a yang model. * * @param schemaContext the schema context + * @param dataspaceName the dataspace name */ - void storeSchemaContext(final SchemaContext schemaContext); + void storeSchemaContext(final SchemaContext schemaContext, final String dataspaceName); /** * Store the JSON structure in the database. diff --git a/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java b/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java index 80a685b09..45aad3e44 100644 --- a/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java +++ b/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2020 Bell Canada. 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. @@ -19,20 +20,19 @@ package org.onap.cps.api.impl; - import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.Optional; import org.onap.cps.api.CpService; import org.onap.cps.spi.DataPersistencyService; import org.onap.cps.spi.ModelPersistencyService; import org.onap.cps.utils.YangUtils; +import org.opendaylight.yangtools.yang.common.Revision; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -40,15 +40,12 @@ import org.springframework.stereotype.Component; @Component public class CpServiceImpl implements CpService { - private static final Logger LOGGER = LoggerFactory.getLogger(CpServiceImpl.class); - @Autowired private ModelPersistencyService modelPersistencyService; @Autowired private DataPersistencyService dataPersistencyService; - @Override public final SchemaContext parseAndValidateModel(final String yangModelContent) throws IOException, YangParserException { @@ -76,13 +73,16 @@ public class CpServiceImpl implements CpService { @Override public void deleteJsonById(int jsonObjectId) { - dataPersistencyService.deleteJsonById(jsonObjectId);; + dataPersistencyService.deleteJsonById(jsonObjectId); } @Override - public final void storeSchemaContext(final SchemaContext schemaContext) { + public final void storeSchemaContext(final SchemaContext schemaContext, final String dataspaceName) { for (final Module module : schemaContext.getModules()) { - modelPersistencyService.storeModule(module.getName(), module.toString(), module.getRevision().toString()); + Optional optionalRevision = module.getRevision(); + String revisionValue = optionalRevision.isPresent() ? optionalRevision.get().toString() : null; + modelPersistencyService.storeModule(module.getNamespace().toString(), module.toString(), + revisionValue, dataspaceName); } } } diff --git a/cps/cps-service/src/main/java/org/onap/cps/spi/ModelPersistencyService.java b/cps/cps-service/src/main/java/org/onap/cps/spi/ModelPersistencyService.java index f88c6b241..2afdaa82a 100644 --- a/cps/cps-service/src/main/java/org/onap/cps/spi/ModelPersistencyService.java +++ b/cps/cps-service/src/main/java/org/onap/cps/spi/ModelPersistencyService.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2020 Bell Canada. 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. @@ -27,10 +28,12 @@ public interface ModelPersistencyService { /** * Store the module from a yang model in the database. * - * @param name module name + * @param namespace module namespace * @param moduleContent module content * @param revision module revision + * @param dataspaceName the name of the dataspace the module is associated with */ - void storeModule(final String name, final String moduleContent, final String revision); + void storeModule(final String namespace, final String moduleContent, final String revision, + final String dataspaceName); } diff --git a/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy b/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy index a2f9b3543..5e6fccb7a 100644 --- a/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy +++ b/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020 Nordix Foundation + * Modifications Copyright (C) 2020 Bell Canada. 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. @@ -21,6 +22,7 @@ package org.onap.cps.api.impl import org.onap.cps.TestUtils import org.onap.cps.spi.DataPersistencyService + import org.opendaylight.yangtools.yang.common.Revision import org.opendaylight.yangtools.yang.model.api.SchemaContext import org.opendaylight.yangtools.yang.model.parser.api.YangParserException @@ -32,7 +34,7 @@ class CpServiceImplSpec extends Specification { def objectUnderTest = new CpServiceImpl() def setup() { - objectUnderTest.dataPersistencyService = mockDataPersistencyService; + objectUnderTest.dataPersistencyService = mockDataPersistencyService } def 'Cps Service provides to its client the id assigned by the system when storing a data structure'() { @@ -77,7 +79,7 @@ class CpServiceImplSpec extends Specification { def 'Store a SchemaContext'() { expect: 'No exception to be thrown when a valid model (schema) is stored' - objectUnderTest.storeSchemaContext(Stub(SchemaContext.class)) + objectUnderTest.storeSchemaContext(Stub(SchemaContext.class), "sampleDataspace") } def 'Read a JSON object with a valid identifier'(){ diff --git a/cps/pom.xml b/cps/pom.xml index dd98ca586..892492d2d 100644 --- a/cps/pom.xml +++ b/cps/pom.xml @@ -45,6 +45,27 @@ pom import + + + + org.codehaus.groovy + groovy + ${groovy.version} + test + + + org.spockframework + spock-core + ${spock-core.version} + test + + + cglib + cglib-nodep + 3.1 + test + + -- 2.16.6