From cb03544962c994c0cc9d9117a3c6b9182ce22204 Mon Sep 17 00:00:00 2001 From: Ruslan Kashapov Date: Tue, 24 Nov 2020 11:13:43 +0200 Subject: Schema Set persistence (store) implementation Issue-ID: CPS-92 Change-Id: I11257726e4f847e3337d8bafad824853e6a458e2 Signed-off-by: Ruslan Kashapov --- .../java/org/onap/cps/spi/entities/SchemaSet.java | 71 ++++++++++++++++++ .../org/onap/cps/spi/entities/YangResource.java | 63 ++++++++++++++++ .../cps/spi/impl/ModelPersistenceServiceImpl.java | 83 ++++++++++++++++++---- .../cps/spi/repository/SchemaSetRepository.java | 36 ++++++++++ .../cps/spi/repository/YangResourceRepository.java | 34 +++++++++ cps-ri/src/main/resources/schema.sql | 26 ++++++- 6 files changed, 297 insertions(+), 16 deletions(-) create mode 100644 cps-ri/src/main/java/org/onap/cps/spi/entities/SchemaSet.java create mode 100644 cps-ri/src/main/java/org/onap/cps/spi/entities/YangResource.java create mode 100644 cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java create mode 100644 cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java (limited to 'cps-ri/src/main') diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/SchemaSet.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/SchemaSet.java new file mode 100644 index 000000000..fe67a6089 --- /dev/null +++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/SchemaSet.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Pantheon.tech + * ================================================================================ + * 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.entities; + +import java.io.Serializable; +import java.util.Set; +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.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * Entity to store a Schema Set. + */ +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "schema_set") +public class SchemaSet implements Serializable { + + private static final long serialVersionUID = 6665056955069047269L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @NotNull + @Column + private String name; + + @NotNull + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "dataspace_id", referencedColumnName = "ID") + private Dataspace dataspace; + + @NotNull + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = "schema_set_yang_resources", + joinColumns = @JoinColumn(name = "schema_set_id"), + inverseJoinColumns = @JoinColumn(name = "yang_resource_id")) + private Set yangResources; +} diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/YangResource.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/YangResource.java new file mode 100644 index 000000000..862b7aea6 --- /dev/null +++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/YangResource.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Pantheon.tech + * ================================================================================ + * 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.entities; + +import java.io.Serializable; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * Entity to store a Yang files. + */ +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "yang_resource") +public class YangResource implements Serializable { + + private static final long serialVersionUID = -4496883162142106774L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Column + private String checksum; + + @NotNull + @Column + private String content; + + @ManyToMany(mappedBy = "yangResources") + private Set moduleSets; + +} diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistenceServiceImpl.java index 03679b316..2207f7940 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/ModelPersistenceServiceImpl.java @@ -20,39 +20,92 @@ package org.onap.cps.spi.impl; -import org.onap.cps.exceptions.CpsValidationException; +import static org.onap.cps.exceptions.CpsExceptionBuilder.duplicateSchemaSetException; +import static org.onap.cps.exceptions.CpsExceptionBuilder.invalidDataspaceException; + +import com.google.common.collect.ImmutableSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import javax.transaction.Transactional; import org.onap.cps.spi.ModelPersistenceService; import org.onap.cps.spi.entities.Dataspace; -import org.onap.cps.spi.entities.Module; +import org.onap.cps.spi.entities.SchemaSet; +import org.onap.cps.spi.entities.YangResource; import org.onap.cps.spi.repository.DataspaceRepository; -import org.onap.cps.spi.repository.ModuleRepository; +import org.onap.cps.spi.repository.SchemaSetRepository; +import org.onap.cps.spi.repository.YangResourceRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Component; +import org.springframework.util.DigestUtils; @Component public class ModelPersistenceServiceImpl implements ModelPersistenceService { @Autowired - private ModuleRepository moduleRepository; + private YangResourceRepository yangResourceRepository; + + @Autowired + private SchemaSetRepository schemaSetRepository; @Autowired private DataspaceRepository dataspaceRepository; @Override 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.getByName(dataspaceName).getId()); - final Module module = new Module(namespace, moduleContent, revision, dataspace); + final String dataspaceName) { + // TODO this method should be removed as obsolete. + // Modules to be processed within schema sets only. + } + + @Override + @Transactional + public void storeSchemaSet(final String dataspaceName, final String schemaSetName, + final Set yangResourcesAsStrings) { + + final Dataspace dataspace = dataspaceRepository.findByName(dataspaceName) + .orElseThrow(() -> invalidDataspaceException(dataspaceName)); + + final Set yangResources = synchronizeYangResources(yangResourcesAsStrings); + final SchemaSet schemaSet = new SchemaSet(); + schemaSet.setName(schemaSetName); + schemaSet.setDataspace(dataspace); + schemaSet.setYangResources(yangResources); try { - moduleRepository.save(module); - } catch (final DataIntegrityViolationException ex) { - throw new CpsValidationException("Duplicate Entry", - String.format("Module already exist in dataspace %s.", dataspaceName)); + schemaSetRepository.save(schemaSet); + } catch (final DataIntegrityViolationException e) { + throw duplicateSchemaSetException(dataspaceName, schemaSetName); + } + } + + private Set synchronizeYangResources(final Set yangResourcesAsStrings) { + final Map checksumToContentMap = yangResourcesAsStrings.stream() + .collect(Collectors.toMap( + content -> DigestUtils.md5DigestAsHex(content.getBytes()), + content -> content) + ); + + final List existingYangResources = + yangResourceRepository.findAllByChecksumIn(checksumToContentMap.keySet()); + existingYangResources.forEach(yangFile -> checksumToContentMap.remove(yangFile.getChecksum())); + + final List newYangResources = checksumToContentMap.entrySet().stream() + .map(entry -> { + final YangResource yangResource = new YangResource(); + yangResource.setChecksum(entry.getKey()); + yangResource.setContent(entry.getValue()); + return yangResource; + }).collect(Collectors.toList()); + if (!newYangResources.isEmpty()) { + yangResourceRepository.saveAll(newYangResources); } + + return ImmutableSet.builder() + .addAll(existingYangResources) + .addAll(newYangResources) + .build(); } + } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java new file mode 100644 index 000000000..f9746972f --- /dev/null +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Pantheon.tech + * ================================================================================ + * 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 java.util.List; +import java.util.Optional; +import javax.validation.constraints.NotNull; +import org.onap.cps.spi.entities.Dataspace; +import org.onap.cps.spi.entities.SchemaSet; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SchemaSetRepository extends JpaRepository { + + List findAllByDataspace(@NotNull Dataspace dataspace); + + Optional findByDataspaceAndName(@NotNull Dataspace dataspace, @NotNull String name); +} diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java new file mode 100644 index 000000000..47d3ea32c --- /dev/null +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java @@ -0,0 +1,34 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Pantheon.tech + * ================================================================================ + * 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 java.util.List; +import java.util.Set; +import javax.validation.constraints.NotNull; +import org.onap.cps.spi.entities.YangResource; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface YangResourceRepository extends JpaRepository { + + List findAllByChecksumIn(@NotNull Set checksum); + +} diff --git a/cps-ri/src/main/resources/schema.sql b/cps-ri/src/main/resources/schema.sql index 3fabc6c9f..d47f261ad 100755 --- a/cps-ri/src/main/resources/schema.sql +++ b/cps-ri/src/main/resources/schema.sql @@ -17,6 +17,30 @@ CREATE TABLE IF NOT EXISTS SCHEMA_NODE ID SERIAL PRIMARY KEY ); +CREATE TABLE IF NOT EXISTS SCHEMA_SET +( + ID SERIAL PRIMARY KEY, + NAME TEXT NOT NULL, + DATASPACE_ID BIGINT NOT NULL, + UNIQUE (NAME, DATASPACE_ID), + CONSTRAINT SCHEMA_SET_DATASPACE FOREIGN KEY (DATASPACE_ID) REFERENCES DATASPACE(ID) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS YANG_RESOURCE +( + ID SERIAL PRIMARY KEY, + CHECKSUM TEXT NOT NULL, + CONTENT TEXT NOT NULL, + UNIQUE (CHECKSUM) +); + +CREATE TABLE IF NOT EXISTS SCHEMA_SET_YANG_RESOURCES +( + SCHEMA_SET_ID BIGINT NOT NULL, + YANG_RESOURCE_ID BIGINT NOT NULL REFERENCES YANG_RESOURCE(ID), + CONSTRAINT SCHEMA_SET_RESOURCE FOREIGN KEY (SCHEMA_SET_ID) REFERENCES SCHEMA_SET(ID) ON DELETE CASCADE +); + CREATE TABLE IF NOT EXISTS MODULE ( ID SERIAL PRIMARY KEY, @@ -62,4 +86,4 @@ CREATE INDEX IF NOT EXISTS "FKI_RELATION_TYPE_ID_FK" ON RELATION USING CREATE INDEX IF NOT EXISTS "FKI_RELATIONS_FROM_ID_FK" ON RELATION USING BTREE(FROM_FRAGMENT_ID); CREATE INDEX IF NOT EXISTS "FKI_RELATIONS_TO_ID_FK" ON RELATION USING BTREE(TO_FRAGMENT_ID); CREATE INDEX IF NOT EXISTS "PERF_MODULE_MODULE_CONTENT" ON MODULE USING BTREE(MODULE_CONTENT); -CREATE UNIQUE INDEX IF NOT EXISTS "UQ_FRAGMENT_XPATH"ON FRAGMENT USING btree(xpath COLLATE pg_catalog."default" text_pattern_ops, dataspace_id); \ No newline at end of file +CREATE UNIQUE INDEX IF NOT EXISTS "UQ_FRAGMENT_XPATH"ON FRAGMENT USING btree(xpath COLLATE pg_catalog."default" text_pattern_ops, dataspace_id); -- cgit 1.2.3-korg