diff options
author | 2019-08-05 16:53:44 +0300 | |
---|---|---|
committer | 2019-08-05 16:53:44 +0300 | |
commit | 2c78e55c6918b090d0ca47f931ac7f24a7c64abc (patch) | |
tree | be9518d695a44f1d45e07f15c568bfa393199e2d | |
parent | 3a818f7755e4d958b8d9cc593553e2353b56a227 (diff) |
Add versioning, session and zusammen libs
Issue-ID: SDC-2486
Signed-off-by: talig <talig@amdocs.com>
Change-Id: I848edbcb84f424f949b646df04f04fa66d0f3bd2
51 files changed, 3853 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..64189eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.idea/ +*.iml +.classpath +.project +.settings/ +.checkstyle +target/ +logs/ +debug-logs/ +*.log +.idea/ +*.iml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 European Support Limited + ~ + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <groupId>org.onap.sdc.common</groupId> + <artifactId>sdc-be-common</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>pom</packaging> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <mockito.version>2.23.4</mockito.version> + <junit.version>4.12</junit.version> + <snapshots.path>snapshots</snapshots.path> + <releases.path>releases</releases.path> + <sitePath>/content/sites/site/org/onap/sdc/sdc-be-common/${project.version}</sitePath> + <docker.username>docker</docker.username> + <docker.password>docker</docker.password> + </properties> + + <modules> + <module>session-lib</module> + <module>zusammen-lib</module> + <module>versioning-lib</module> + </modules> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.8</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <!--<version>2.1.5.RELEASE</version>--> + <version>2.0.3.RELEASE</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>${mockito.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.5.1</version> + <executions> + <execution> + <id>compile</id> + <phase>compile</phase> + <goals> + <goal>compile</goal> + </goals> + </execution> + <execution> + <id>testCompile</id> + <phase>test-compile</phase> + <goals> + <goal>testCompile</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <repositories> + <repository> + <id>central</id> + <name>Official Maven repository</name> + <url>http://repo2.maven.org/maven2/</url> + </repository> + <repository> + <id>onap-releases</id> + <name>Release Repository</name> + <url>${nexus.proxy}/content/repositories/releases/</url> + </repository> + <repository> + <id>onap-snapshots</id> + <name>Snapshots Repository</name> + <url>${nexus.proxy}/content/repositories/snapshots/</url> + </repository> + </repositories> + + <distributionManagement> + <repository> + <id>onap-releases</id> + <name>Release Repository</name> + <url>${nexus.proxy}/content/repositories/${releases.path}/</url> + </repository> + <snapshotRepository> + <id>onap-snapshots</id> + <name>Snapshot Repository</name> + <url>${nexus.proxy}/content/repositories/${snapshots.path}/</url> + </snapshotRepository> + <site> + <id>onap-site</id> + <url>dav:${nexus.proxy}${sitePath}</url> + </site> + </distributionManagement> + +</project> + diff --git a/session-lib/lombok.config b/session-lib/lombok.config new file mode 100644 index 0000000..8f7e8aa --- /dev/null +++ b/session-lib/lombok.config @@ -0,0 +1 @@ +lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file diff --git a/session-lib/pom.xml b/session-lib/pom.xml new file mode 100644 index 0000000..de3e23a --- /dev/null +++ b/session-lib/pom.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 European Support Limited + ~ + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <artifactId>session-lib</artifactId> + <parent> + <groupId>org.onap.sdc.common</groupId> + <artifactId>sdc-be-common</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + + <dependencies> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + </dependencies> + +</project> + diff --git a/session-lib/src/main/java/org/onap/sdc/common/session/SessionContext.java b/session-lib/src/main/java/org/onap/sdc/common/session/SessionContext.java new file mode 100644 index 0000000..c4807f8 --- /dev/null +++ b/session-lib/src/main/java/org/onap/sdc/common/session/SessionContext.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.session; + +public interface SessionContext { + + String getUserId(); + + String getTenant(); +} diff --git a/session-lib/src/main/java/org/onap/sdc/common/session/SessionContextProvider.java b/session-lib/src/main/java/org/onap/sdc/common/session/SessionContextProvider.java new file mode 100644 index 0000000..6ada627 --- /dev/null +++ b/session-lib/src/main/java/org/onap/sdc/common/session/SessionContextProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.session; + +public interface SessionContextProvider { + + void create(String user, String tenant); + + SessionContext get(); + + void close(); +} diff --git a/session-lib/src/main/java/org/onap/sdc/common/session/impl/SdcSessionContextProvider.java b/session-lib/src/main/java/org/onap/sdc/common/session/impl/SdcSessionContextProvider.java new file mode 100644 index 0000000..4a7bc96 --- /dev/null +++ b/session-lib/src/main/java/org/onap/sdc/common/session/impl/SdcSessionContextProvider.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * 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. + */ + + +package org.onap.sdc.common.session.impl; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.onap.sdc.common.session.SessionContext; +import org.onap.sdc.common.session.SessionContextProvider; +import org.springframework.stereotype.Service; + +@Service +public class SdcSessionContextProvider implements SessionContextProvider { + + private static final InheritableThreadLocal<String> threadUserId = new InheritableThreadLocal<>(); + private static final InheritableThreadLocal<String> threadTenant = new InheritableThreadLocal<>(); + + @Override + public void create(String userId, String tenant) { + threadUserId.set(userId); + threadTenant.set(tenant); + } + + @Override + public SessionContext get() { + if (threadUserId.get() == null) { + throw new SessionException("UserId was not set for this thread"); + } + + if (threadTenant.get() == null) { + throw new SessionException("Tenant was not set for this thread"); + } + + return new SdcSessionContext(threadUserId.get(), threadTenant.get()); + } + + @Override + public void close() { + threadUserId.remove(); + threadTenant.remove(); + } + + @Getter + @AllArgsConstructor + private static class SdcSessionContext implements SessionContext { + + private final String userId; + private final String tenant; + } +} diff --git a/session-lib/src/main/java/org/onap/sdc/common/session/impl/SessionException.java b/session-lib/src/main/java/org/onap/sdc/common/session/impl/SessionException.java new file mode 100644 index 0000000..54b2fd3 --- /dev/null +++ b/session-lib/src/main/java/org/onap/sdc/common/session/impl/SessionException.java @@ -0,0 +1,8 @@ +package org.onap.sdc.common.session.impl; + +public class SessionException extends RuntimeException { + + public SessionException(String message) { + super(message); + } +} diff --git a/version.properties b/version.properties new file mode 100644 index 0000000..7f212d4 --- /dev/null +++ b/version.properties @@ -0,0 +1,14 @@ +########################################################### +# Versioning variables +# Note that these variables cannot be structured (e.g. : version.release or version.snapshot etc... ) +# because they are used in Jenkins, whose plug-in doesn't support +# change: +# +major=1 +minor=0 +patch=0 + +base_version=${major}.${minor}.${patch} + +release_version=${base_version} +snapshot_version=${base_version}-SNAPSHOT diff --git a/versioning-lib/lombok.config b/versioning-lib/lombok.config new file mode 100644 index 0000000..8f7e8aa --- /dev/null +++ b/versioning-lib/lombok.config @@ -0,0 +1 @@ +lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file diff --git a/versioning-lib/pom.xml b/versioning-lib/pom.xml new file mode 100644 index 0000000..91a69de --- /dev/null +++ b/versioning-lib/pom.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 European Support Limited + ~ + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <artifactId>versioning-lib</artifactId> + <parent> + <groupId>org.onap.sdc.common</groupId> + <artifactId>sdc-be-common</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + <dependencies> + <dependency> + <groupId>org.onap.sdc.common</groupId> + <artifactId>session-lib</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.sdc.common</groupId> + <artifactId>zusammen-lib</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + </dependencies> + +</project> + diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/ItemDao.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/ItemDao.java new file mode 100644 index 0000000..a47ce00 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/ItemDao.java @@ -0,0 +1,17 @@ +package org.onap.sdc.common.versioning.persistence; + +import java.util.Collection; +import org.onap.sdc.common.versioning.persistence.types.InternalItem; + +public interface ItemDao { + + Collection<InternalItem> list(); + + InternalItem get(String itemId); + + InternalItem create(InternalItem item); + + void update(InternalItem item); + + void delete(String itemId); +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/VersionDao.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/VersionDao.java new file mode 100644 index 0000000..17354e8 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/VersionDao.java @@ -0,0 +1,31 @@ +package org.onap.sdc.common.versioning.persistence; + +import java.util.List; +import java.util.Optional; +import org.onap.sdc.common.versioning.persistence.types.InternalVersion; +import org.onap.sdc.common.versioning.services.types.Revision; + +public interface VersionDao { + + List<InternalVersion> list(String itemId); + + InternalVersion create(String itemId, InternalVersion version); + + void update(String itemId, InternalVersion version); + + Optional<InternalVersion> get(String itemId, String versionId); + + void delete(String itemId, String versionId); + + void publish(String itemId, String versionId, String message); + + void sync(String itemId, String versionId); + + void forceSync(String itemId, String versionId); + + void clean(String itemId, String versionId); + + void revert(String itemId, String versionId, String revisionId); + + List<Revision> listRevisions(String itemId, String versionId); +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/types/InternalItem.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/types/InternalItem.java new file mode 100644 index 0000000..3d6610b --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/types/InternalItem.java @@ -0,0 +1,77 @@ +/* + * + * Copyright © 2017-2018 European Support Limited + * + * 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. + * + */ + +package org.onap.sdc.common.versioning.persistence.types; + +import java.util.Date; +import java.util.EnumMap; +import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import org.onap.sdc.common.versioning.services.types.Item; +import org.onap.sdc.common.versioning.services.types.ItemStatus; +import org.onap.sdc.common.versioning.services.types.VersionStatus; + + +@Setter +@Getter +public class InternalItem extends Item { + + private Map<VersionStatus, Integer> versionStatusCounters = new EnumMap<>(VersionStatus.class); + + public void setId(String id) { + this.id = id; + } + + public void setCreationTime(Date creationTime) { + this.creationTime = creationTime; + } + + public void setModificationTime(Date modificationTime) { + this.modificationTime = modificationTime; + } + + public void setStatus(ItemStatus status) { + this.status = status; + } + + public void addVersionStatus(VersionStatus versionStatus) { + Integer counter = versionStatusCounters.get(versionStatus); + versionStatusCounters.put(versionStatus, counter == null ? 1 : counter + 1); + } + + public void removeVersionStatus(VersionStatus versionStatus) { + Integer counter = versionStatusCounters.get(versionStatus); + if (counter == null) { + return; + } + if (counter == 1) { + versionStatusCounters.remove(versionStatus); + } else { + versionStatusCounters.put(versionStatus, counter - 1); + } + } + + public void populateExternalFields(Item item) { + setType(item.getType()); + setName(item.getName()); + setOwner(item.getOwner()); + setDescription(item.getDescription()); + item.getProperties().forEach(this::addProperty); + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/types/InternalVersion.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/types/InternalVersion.java new file mode 100644 index 0000000..d48400b --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/types/InternalVersion.java @@ -0,0 +1,42 @@ +package org.onap.sdc.common.versioning.persistence.types; + +import java.util.Date; +import org.onap.sdc.common.versioning.services.types.Version; +import org.onap.sdc.common.versioning.services.types.VersionState; +import org.onap.sdc.common.versioning.services.types.VersionStatus; + +public class InternalVersion extends Version { + + public void setId(String id) { + this.id = id; + } + + public void setBaseId(String baseId) { + this.baseId = baseId; + } + + public void setName(String name) { + this.name = name; + } + + public void setStatus(VersionStatus status) { + this.status = status; + } + + public void setState(VersionState state) { + this.state = state; + } + + public void setCreationTime(Date creationTime) { + this.creationTime = creationTime; + } + + public void setModificationTime(Date modificationTime) { + this.modificationTime = modificationTime; + } + + public void populateExternalFields(Version version) { + setDescription(version.getDescription()); + version.getProperties().forEach(this::addProperty); + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/ItemZusammenDao.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/ItemZusammenDao.java new file mode 100644 index 0000000..8530697 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/ItemZusammenDao.java @@ -0,0 +1,126 @@ +package org.onap.sdc.common.versioning.persistence.zusammen; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.Item; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; +import org.onap.sdc.common.versioning.persistence.ItemDao; +import org.onap.sdc.common.versioning.persistence.types.InternalItem; +import org.onap.sdc.common.versioning.services.types.ItemStatus; +import org.onap.sdc.common.versioning.services.types.VersionStatus; +import org.onap.sdc.common.zusammen.services.ZusammenAdaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class ItemZusammenDao implements ItemDao { + + private final ZusammenSessionContextCreator contextCreator; + private final ZusammenAdaptor zusammenAdaptor; + + @Autowired + public ItemZusammenDao(ZusammenSessionContextCreator contextCreator, ZusammenAdaptor zusammenAdaptor) { + this.contextCreator = contextCreator; + this.zusammenAdaptor = zusammenAdaptor; + } + + @Override + public Collection<InternalItem> list() { + return zusammenAdaptor.listItems(contextCreator.create()).stream().map(this::mapFromZusammenItem) + .collect(Collectors.toList()); + } + + @Override + public InternalItem get(String itemId) { + return mapFromZusammenItem(zusammenAdaptor.getItem(contextCreator.create(), new Id(itemId))); + } + + @Override + public InternalItem create(InternalItem item) { + Id itemId = zusammenAdaptor.createItem(contextCreator.create(), mapToZusammenItemInfo(item)); + item.setId(itemId.getValue()); + return item; + } + + @Override + public void delete(String itemId) { + zusammenAdaptor.deleteItem(contextCreator.create(), new Id(itemId)); + } + + @Override + public void update(InternalItem item) { + zusammenAdaptor.updateItem(contextCreator.create(), new Id(item.getId()), mapToZusammenItemInfo(item)); + } + + private InternalItem mapFromZusammenItem(Item zusammenItem) { + if (zusammenItem == null) { + return null; + } + InternalItem item = new InternalItem(); + item.setId(zusammenItem.getId().getValue()); + item.setName(zusammenItem.getInfo().getName()); + item.setDescription(zusammenItem.getInfo().getDescription()); + + zusammenItem.getInfo().getProperties().forEach((key, value) -> addPropertyToItem(key, value, item)); + + item.setCreationTime(zusammenItem.getCreationTime()); + item.setModificationTime(zusammenItem.getModificationTime()); + + if (item.getStatus() == null) { + item.setStatus(ItemStatus.ACTIVE); + update(item); + } + + return item; + } + + private void addPropertyToItem(String propertyKey, Object propertyValue, InternalItem item) { + switch (propertyKey) { + case InfoPropertyName.ITEM_TYPE: + item.setType((String) propertyValue); + break; + case InfoPropertyName.ITEM_OWNER: + item.setOwner((String) propertyValue); + break; + case InfoPropertyName.ITEM_STATUS: + item.setStatus(ItemStatus.valueOf((String) propertyValue)); + break; + case InfoPropertyName.ITEM_VERSIONS_STATUSES: + for (Map.Entry<String, Number> statusCounter : ((Map<String, Number>) propertyValue).entrySet()) { + item.getVersionStatusCounters() + .put(VersionStatus.valueOf(statusCounter.getKey()), statusCounter.getValue().intValue()); + } + break; + default: + item.addProperty(propertyKey, propertyValue); + } + } + + private Info mapToZusammenItemInfo(InternalItem item) { + Info info = new Info(); + info.setName(item.getName()); + info.setDescription(item.getDescription()); + info.addProperty(InfoPropertyName.ITEM_TYPE, item.getType()); + info.addProperty(InfoPropertyName.ITEM_OWNER, item.getOwner()); + if (item.getStatus() != null) { + info.addProperty(InfoPropertyName.ITEM_STATUS, item.getStatus()); + } + info.addProperty(InfoPropertyName.ITEM_VERSIONS_STATUSES, item.getVersionStatusCounters()); + item.getProperties().forEach(info::addProperty); + return info; + } + + private static final class InfoPropertyName { + + private static final String ITEM_TYPE = "item_type"; + private static final String ITEM_VERSIONS_STATUSES = "item_versions_statuses"; + private static final String ITEM_OWNER = "Owner"; + private static final String ITEM_STATUS = "status"; + + private InfoPropertyName() { + throw new IllegalStateException("Constants class"); + } + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/VersionZusammenDao.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/VersionZusammenDao.java new file mode 100644 index 0000000..cb062c7 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/VersionZusammenDao.java @@ -0,0 +1,202 @@ +package org.onap.sdc.common.versioning.persistence.zusammen; + + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import com.amdocs.zusammen.datatypes.item.ItemVersionStatus; +import com.amdocs.zusammen.datatypes.item.SynchronizationStatus; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.onap.sdc.common.versioning.persistence.VersionDao; +import org.onap.sdc.common.versioning.persistence.types.InternalVersion; +import org.onap.sdc.common.versioning.services.exceptions.VersioningException; +import org.onap.sdc.common.versioning.services.types.Revision; +import org.onap.sdc.common.versioning.services.types.SynchronizationState; +import org.onap.sdc.common.versioning.services.types.VersionState; +import org.onap.sdc.common.versioning.services.types.VersionStatus; +import org.onap.sdc.common.zusammen.services.ZusammenAdaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class VersionZusammenDao implements VersionDao { + + private static final String STATUS_PROPERTY = "status"; + + private final ZusammenSessionContextCreator contextCreator; + private final ZusammenAdaptor zusammenAdaptor; + + @Autowired + public VersionZusammenDao(ZusammenSessionContextCreator contextCreator, ZusammenAdaptor zusammenAdaptor) { + this.contextCreator = contextCreator; + this.zusammenAdaptor = zusammenAdaptor; + } + + @Override + public List<InternalVersion> list(String itemId) { + return zusammenAdaptor.listPublicVersions(contextCreator.create(), new Id(itemId)).stream() + .map(VersionZusammenDao::convertFromZusammen).collect(Collectors.toList()); + } + + @Override + public InternalVersion create(String itemId, InternalVersion version) { + Id versionId = zusammenAdaptor.createVersion(contextCreator.create(), new Id(itemId), + version.getBaseId() == null ? null : new Id(version.getBaseId()), mapToZusammenVersion(version)); + + version.setId(versionId.getValue()); + return version; + } + + @Override + public void update(String itemId, InternalVersion version) { + zusammenAdaptor.updateVersion(contextCreator.create(), new Id(itemId), new Id(version.getId()), + mapToZusammenVersion(version)); + } + + @Override + public Optional<InternalVersion> get(String itemId, String versionId) { + SessionContext context = contextCreator.create(); + Id itemIdObj = new Id(itemId); + Id versionIdObj = new Id(versionId); + ItemVersion itemVersion = zusammenAdaptor.getVersion(context, itemIdObj, versionIdObj); + + if (itemVersion == null) { + return Optional.empty(); + } + + VersionState versionState = convertState(zusammenAdaptor.getVersionStatus(context, itemIdObj, versionIdObj)); + updateVersionStatus(context, itemIdObj, versionIdObj, versionState, itemVersion); + + InternalVersion result = convertFromZusammen(itemVersion); + result.setState(versionState); + return Optional.of(result); + } + + @Override + public void delete(String itemId, String versionId) { + throw new UnsupportedOperationException("Delete version operation is not yet supported."); + } + + @Override + public void publish(String itemId, String versionId, String message) { + zusammenAdaptor.publishVersion(contextCreator.create(), new Id(itemId), new Id(versionId), message); + } + + @Override + public void sync(String itemId, String versionId) { + zusammenAdaptor.syncVersion(contextCreator.create(), new Id(itemId), new Id(versionId)); + } + + @Override + public void forceSync(String itemId, String versionId) { + zusammenAdaptor.forceSyncVersion(contextCreator.create(), new Id(itemId), new Id(versionId)); + } + + @Override + public void clean(String itemId, String versionId) { + zusammenAdaptor.cleanVersion(contextCreator.create(), new Id(itemId), new Id(versionId)); + } + + @Override + public void revert(String itemId, String versionId, String revisionId) { + zusammenAdaptor.revert(contextCreator.create(), new Id(itemId), new Id(versionId), new Id(revisionId)); + } + + @Override + public List<Revision> listRevisions(String itemId, String versionId) { + ItemVersionRevisions itemVersionRevisions = + zusammenAdaptor.listRevisions(contextCreator.create(), new Id(itemId), new Id(versionId)); + + return itemVersionRevisions == null || itemVersionRevisions.getItemVersionRevisions() == null + || itemVersionRevisions.getItemVersionRevisions().isEmpty() ? new ArrayList<>() : + itemVersionRevisions.getItemVersionRevisions().stream().map(this::convertRevision) + .sorted(this::compareRevisionsTime).collect(Collectors.toList()); + } + + private void updateVersionStatus(SessionContext context, Id itemId, Id versionId, VersionState versionState, + ItemVersion itemVersion) { + if (versionState.getSynchronizationState() != SynchronizationState.UpToDate) { + String versionStatus = zusammenAdaptor.getPublicVersion(context, itemId, versionId).getData().getInfo() + .getProperty(STATUS_PROPERTY); + itemVersion.getData().getInfo().addProperty(STATUS_PROPERTY, versionStatus); + } + } + + private ItemVersionData mapToZusammenVersion(InternalVersion version) { + Info info = new Info(); + info.addProperty(STATUS_PROPERTY, version.getStatus().name()); + info.setName(version.getName()); + info.setDescription(version.getDescription()); + version.getProperties().forEach(info::addProperty); + ItemVersionData itemVersionData = new ItemVersionData(); + itemVersionData.setInfo(info); + return itemVersionData; + } + + private VersionState convertState(ItemVersionStatus versionStatus) { + VersionState state = new VersionState(); + state.setSynchronizationState(getSyncState(versionStatus.getSynchronizationStatus())); + state.setDirty(versionStatus.isDirty()); + return state; + } + + private SynchronizationState getSyncState(SynchronizationStatus synchronizationStatus) { + switch (synchronizationStatus) { + case UP_TO_DATE: + return SynchronizationState.UpToDate; + case OUT_OF_SYNC: + return SynchronizationState.OutOfSync; + case MERGING: + return SynchronizationState.Merging; + default: + throw new VersioningException("Version state is unknown"); + } + } + + private Revision convertRevision(com.amdocs.zusammen.datatypes.itemversion.Revision zusammenRevision) { + Revision revision = new Revision(); + revision.setId(zusammenRevision.getRevisionId().getValue()); + revision.setTime(zusammenRevision.getTime()); + revision.setUser(zusammenRevision.getUser()); + revision.setMessage(zusammenRevision.getMessage()); + return revision; + } + + private int compareRevisionsTime(Revision revision1, Revision revision2) { + return revision1.getTime().before(revision2.getTime()) ? 1 : -1; + } + + private static InternalVersion convertFromZusammen(ItemVersion itemVersion) { + if (itemVersion == null) { + return null; + } + InternalVersion version = new InternalVersion(); + version.setId(itemVersion.getId().getValue()); + if (itemVersion.getBaseId() != null) { + version.setBaseId(itemVersion.getBaseId().getValue()); + } + version.setName(itemVersion.getData().getInfo().getName()); + version.setDescription(itemVersion.getData().getInfo().getDescription()); + version.setCreationTime(itemVersion.getCreationTime()); + version.setModificationTime(itemVersion.getModificationTime()); + + itemVersion.getData().getInfo().getProperties() + .forEach((key, value) -> addPropertyToVersion(key, value, version)); + + return version; + } + + private static void addPropertyToVersion(String propertyKey, Object propertyValue, InternalVersion version) { + if (STATUS_PROPERTY.equals(propertyKey)) { + version.setStatus(VersionStatus.valueOf((String) propertyValue)); + } else { + version.addProperty(propertyKey, propertyValue); + } + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/ZusammenSessionContextCreator.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/ZusammenSessionContextCreator.java new file mode 100644 index 0000000..f8a677a --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/persistence/zusammen/ZusammenSessionContextCreator.java @@ -0,0 +1,28 @@ +package org.onap.sdc.common.versioning.persistence.zusammen; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.UserInfo; +import org.onap.sdc.common.session.SessionContextProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ZusammenSessionContextCreator { + + private final SessionContextProvider sessionContextProvider; + + @Autowired + public ZusammenSessionContextCreator(SessionContextProvider sessionContextProvider) { + this.sessionContextProvider = sessionContextProvider; + } + + + public SessionContext create() { + org.onap.sdc.common.session.SessionContext sdcSessionContext = sessionContextProvider.get(); + + SessionContext sessionContext = new SessionContext(); + sessionContext.setUser(new UserInfo(sdcSessionContext.getUserId())); + sessionContext.setTenant(sdcSessionContext.getTenant()); + return sessionContext; + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/ItemManager.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/ItemManager.java new file mode 100644 index 0000000..de91f2e --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/ItemManager.java @@ -0,0 +1,37 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.versioning.services; + +import java.util.Collection; +import java.util.function.Predicate; +import org.onap.sdc.common.versioning.services.types.Item; +import org.onap.sdc.common.versioning.services.types.ItemStatus; + +public interface ItemManager { + + Collection<Item> list(Predicate<Item> predicate); + + Item get(String itemId); + + Item create(Item item); + + Item update(String itemId, Item item); + + void delete(String itemId); + + void updateStatus(String itemId, ItemStatus status); +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/VersioningManager.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/VersioningManager.java new file mode 100644 index 0000000..f522077 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/VersioningManager.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.versioning.services; + +import java.util.List; +import org.onap.sdc.common.versioning.services.types.Revision; +import org.onap.sdc.common.versioning.services.types.Version; +import org.onap.sdc.common.versioning.services.types.VersionCreationMethod; +import org.onap.sdc.common.versioning.services.types.VersionStatus; + +public interface VersioningManager { + + List<Version> list(String itemId); // TODO: 5/24/2017 filter (by status for example) + + Version get(String itemId, String versionId); + + Version create(String itemId, String baseVersionId, Version version, VersionCreationMethod creationMethod); + + Version update(String itemId, String versionId, Version version); + + void updateStatus(String itemId, String versionId, VersionStatus status, String message); + + void publish(String itemId, String versionId, String message); + + void sync(String itemId, String versionId); + + void forceSync(String itemId, String versionId); + + void revert(String itemId, String versionId, String revisionId); + + List<Revision> listRevisions(String itemId, String versionId); + + void clean(String itemId, String versionId); +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/convertors/ItemConvertor.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/convertors/ItemConvertor.java new file mode 100644 index 0000000..88405e5 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/convertors/ItemConvertor.java @@ -0,0 +1,17 @@ +package org.onap.sdc.common.versioning.services.convertors; + +import org.onap.sdc.common.versioning.services.types.Item; + +public interface ItemConvertor<T> { + + String getItemType(); + + //Item toItem(T model); + + void toItem(T source, Item target); + + // void fromItem(Item source, T target); + + T fromItem(Item item); + +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/convertors/VersionConvertor.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/convertors/VersionConvertor.java new file mode 100644 index 0000000..beab1d9 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/convertors/VersionConvertor.java @@ -0,0 +1,16 @@ +package org.onap.sdc.common.versioning.services.convertors; + +import org.onap.sdc.common.versioning.services.types.Version; + +public interface VersionConvertor<T> { + + String getItemType(); + + //Version toVersion(T model); + + void toVersion(T source, Version target); + + //void fromVersion(Version source, T target); + + T fromVersion(Version version); +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/exceptions/VersioningException.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/exceptions/VersioningException.java new file mode 100644 index 0000000..6440ccc --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/exceptions/VersioningException.java @@ -0,0 +1,8 @@ +package org.onap.sdc.common.versioning.services.exceptions; + +public class VersioningException extends RuntimeException { + + public VersioningException(String message) { + super(message); + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/ItemManagerImpl.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/ItemManagerImpl.java new file mode 100644 index 0000000..47acabc --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/ItemManagerImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.versioning.services.impl; + +import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.onap.sdc.common.versioning.persistence.ItemDao; +import org.onap.sdc.common.versioning.persistence.types.InternalItem; +import org.onap.sdc.common.versioning.services.ItemManager; +import org.onap.sdc.common.versioning.services.exceptions.VersioningException; +import org.onap.sdc.common.versioning.services.types.Item; +import org.onap.sdc.common.versioning.services.types.ItemStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ItemManagerImpl implements ItemManager { + + private final ItemDao itemDao; + + @Autowired + public ItemManagerImpl(ItemDao itemDao) { + this.itemDao = itemDao; + + } + + @Override + public Collection<Item> list(Predicate<Item> predicate) { + return itemDao.list().stream().filter(predicate).collect(Collectors.toList()); + } + + @Override + public Item get(String itemId) { + return itemDao.get(itemId); + } + + @Override + public Item create(Item item) { + InternalItem internalItem = new InternalItem(); + internalItem.populateExternalFields(item); + return itemDao.create(internalItem); + } + + @Override + public Item update(String itemId, Item item) { + InternalItem internalItem = getItem(itemId); + internalItem.populateExternalFields(item); + itemDao.update(internalItem); + return internalItem; + } + + @Override + public void delete(String itemId) { + itemDao.delete(itemId); + } + + @Override + public void updateStatus(String itemId, ItemStatus status) { + InternalItem item = getItem(itemId); + if (item.getStatus() == status) { + throw new VersioningException( + String.format("Update status of item %s failed, it is already in status %s", item.getId(), status)); + } + + item.setStatus(status); + itemDao.update(item); + } + + private InternalItem getItem(String itemId) { + InternalItem item = itemDao.get(itemId); + if (item == null) { + throw new VersioningException(String.format("Item with Id %s does not exist", itemId)); + } + return item; + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/MajorVersionCalculatorImpl.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/MajorVersionCalculatorImpl.java new file mode 100644 index 0000000..a98fa58 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/MajorVersionCalculatorImpl.java @@ -0,0 +1,46 @@ +package org.onap.sdc.common.versioning.services.impl; + +import java.util.HashSet; +import java.util.Set; +import org.onap.sdc.common.versioning.services.types.Version; +import org.onap.sdc.common.versioning.services.types.VersionCreationMethod; +import org.onap.sdc.common.versioning.services.types.VersionStatus; +import org.springframework.stereotype.Service; + +@Service +public class MajorVersionCalculatorImpl implements VersionCalculator { + + private static final String INITIAL_VERSION = "1.0"; + private static final String VERSION_STRING_VIOLATION_MSG = + "Version string must be in the format of: {integer}.{integer}"; + + @Override + public String calculate(String baseVersion, VersionCreationMethod creationMethod) { + + if (baseVersion == null) { + return INITIAL_VERSION; + } + + String[] versionLevels = baseVersion.split("\\."); + if (versionLevels.length != 2) { + throw new IllegalArgumentException(VERSION_STRING_VIOLATION_MSG); + } + + int index = Integer.parseInt(versionLevels[0]); + index++; + + return index + ".0"; + } + + @Override + public void injectAdditionalInfo(Version version, Set<String> existingVersions) { + Set<VersionCreationMethod> optionalCreationMethods = new HashSet<>(); + if (version.getStatus().equals(VersionStatus.Certified)) { + String nextVersion = calculate(version.getName(), VersionCreationMethod.major); + if (!existingVersions.contains(nextVersion)) { + optionalCreationMethods.add(VersionCreationMethod.major); + } + } + version.addProperty("OptionalCreationMethods", optionalCreationMethods); + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/VersionCalculator.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/VersionCalculator.java new file mode 100644 index 0000000..203dfbb --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/VersionCalculator.java @@ -0,0 +1,12 @@ +package org.onap.sdc.common.versioning.services.impl; + +import java.util.Set; +import org.onap.sdc.common.versioning.services.types.Version; +import org.onap.sdc.common.versioning.services.types.VersionCreationMethod; + +public interface VersionCalculator { + + String calculate(String baseVersion, VersionCreationMethod creationMethod); + + void injectAdditionalInfo(Version version, Set<String> existingVersions); +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/VersioningManagerImpl.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/VersioningManagerImpl.java new file mode 100644 index 0000000..601f517 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/impl/VersioningManagerImpl.java @@ -0,0 +1,202 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.versioning.services.impl; + + +import static org.onap.sdc.common.versioning.services.types.VersionStatus.Certified; +import static org.onap.sdc.common.versioning.services.types.VersionStatus.Draft; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.onap.sdc.common.versioning.persistence.ItemDao; +import org.onap.sdc.common.versioning.persistence.VersionDao; +import org.onap.sdc.common.versioning.persistence.types.InternalItem; +import org.onap.sdc.common.versioning.persistence.types.InternalVersion; +import org.onap.sdc.common.versioning.services.VersioningManager; +import org.onap.sdc.common.versioning.services.exceptions.VersioningException; +import org.onap.sdc.common.versioning.services.types.Revision; +import org.onap.sdc.common.versioning.services.types.SynchronizationState; +import org.onap.sdc.common.versioning.services.types.Version; +import org.onap.sdc.common.versioning.services.types.VersionCreationMethod; +import org.onap.sdc.common.versioning.services.types.VersionStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class VersioningManagerImpl implements VersioningManager { + + //private static final Logger LOGGER = LoggerFactory.getLogger(VersioningManagerImpl.class); + + private final ItemDao itemDao; + private final VersionDao versionDao; + private final VersionCalculator versionCalculator; + + @Autowired + public VersioningManagerImpl(VersionDao versionDao, VersionCalculator versionCalculator, ItemDao itemDao) { + this.itemDao = itemDao; + this.versionDao = versionDao; + this.versionCalculator = versionCalculator; + } + + + @Override + public List<Version> list(String itemId) { + List<InternalVersion> versions = versionDao.list(itemId); + Set<String> versionsNames = versions.stream().map(Version::getName).collect(Collectors.toSet()); + versions.forEach(version -> versionCalculator.injectAdditionalInfo(version, versionsNames)); + return versions.stream().map(version -> (Version) version).collect(Collectors.toList()); + } + + @Override + public Version get(String itemId, String versionId) { + return getVersion(itemId, versionId); + } + + @Override + public Version create(String itemId, String baseVersionId, Version version, VersionCreationMethod creationMethod) { + InternalVersion internalVersion = new InternalVersion(); + internalVersion.setBaseId(baseVersionId); + internalVersion.populateExternalFields(version); + + String baseVersionName = null; + if (baseVersionId != null) { + Version baseVersion = getVersion(itemId, baseVersionId); + validateBaseVersion(itemId, baseVersion); + baseVersionName = baseVersion.getName(); + } + String versionName = versionCalculator.calculate(baseVersionName, creationMethod); + validateVersionName(itemId, versionName); + internalVersion.setName(versionName); + + InternalVersion createdVersion = versionDao.create(itemId, internalVersion); + + updateStatusOnItem(itemId, Draft, null); + + publish(itemId, createdVersion.getId(), String.format("Create version: %s", versionName)); + return createdVersion; + } + + @Override + public Version update(String itemId, String versionId, Version version) { + InternalVersion internalVersion = getVersion(itemId, versionId); + internalVersion.populateExternalFields(version); + versionDao.update(itemId, internalVersion); + return internalVersion; + } + + @Override + public void updateStatus(String itemId, String versionId, VersionStatus status, String message) { + InternalVersion version = getVersion(itemId, versionId); + + VersionStatus prevStatus = version.getStatus(); + if (prevStatus == status) { + throw new VersioningException( + String.format("Item %s: update version status failed, version %s is already in status %s", itemId, + version.getId(), status)); + } + + version.setStatus(status); + versionDao.update(itemId, version); + + publish(itemId, versionId, message); + + updateStatusOnItem(itemId, status, prevStatus); + } + + @Override + public void publish(String itemId, String versionId, String message) { + versionDao.publish(itemId, versionId, message); + } + + @Override + public void sync(String itemId, String versionId) { + versionDao.sync(itemId, versionId); + } + + @Override + public void forceSync(String itemId, String versionId) { + versionDao.forceSync(itemId, versionId); + } + + @Override + public void revert(String itemId, String versionId, String revisionId) { + versionDao.revert(itemId, versionId, revisionId); + } + + @Override + public List<Revision> listRevisions(String itemId, String versionId) { + return versionDao.listRevisions(itemId, versionId); + } + + @Override + public void clean(String itemId, String versionId) { + versionDao.clean(itemId, versionId); + } + + private InternalVersion getVersion(String itemId, String versionId) { + return versionDao.get(itemId, versionId) + .map(retrievedVersion -> getUpdateRetrievedVersion(itemId, retrievedVersion)) + .orElseGet(() -> getSyncedVersion(itemId, versionId)); + } + + private InternalVersion getUpdateRetrievedVersion(String itemId, InternalVersion version) { + if (version.getStatus() == Certified + && version.getState().getSynchronizationState() == SynchronizationState.OutOfSync) { + forceSync(itemId, version.getId()); + //LOGGER.info("Item Id {}, version Id {}: Force sync is done", itemId, version.getId()); + version = versionDao.get(itemId, version.getId()).orElseThrow(() -> new IllegalStateException( + "Get version after a successful force sync must return the version")); + } + return version; + } + + private InternalVersion getSyncedVersion(String itemId, String versionId) { + sync(itemId, versionId); + //LOGGER.info("Item Id {}, version Id {}: First time sync is done", itemId, version.getId()); + return versionDao.get(itemId, versionId).orElseThrow( + () -> new IllegalStateException("Get version after a successful sync must return the version")); + } + + private void validateBaseVersion(String itemId, Version baseVersion) { + if (Certified != baseVersion.getStatus()) { + throw new VersioningException( + String.format("Item %s: base version %s must be Certified", itemId, baseVersion.getId())); + } + } + + private void validateVersionName(String itemId, String versionName) { + if (versionDao.list(itemId).stream().anyMatch(version -> versionName.equals(version.getName()))) { + throw new VersioningException( + String.format("Item %s: create version failed, a version with the name %s already exist", itemId, + versionName)); + } + } + + private void updateStatusOnItem(String itemId, VersionStatus addedVersionStatus, + VersionStatus removedVersionStatus) { + InternalItem item = itemDao.get(itemId); + if (item == null) { + throw new VersioningException(String.format("Item with Id %s does not exist", itemId)); + } + item.addVersionStatus(addedVersionStatus); + if (removedVersionStatus != null) { + item.removeVersionStatus(removedVersionStatus); + } + itemDao.update(item); + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Item.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Item.java new file mode 100644 index 0000000..796fc1a --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Item.java @@ -0,0 +1,55 @@ +/* + * + * Copyright © 2017-2018 European Support Limited + * + * 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. + * + */ + +package org.onap.sdc.common.versioning.services.types; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import lombok.Getter; +import lombok.Setter; + +@Getter +public class Item { + + protected String id; + protected Date creationTime; + protected Date modificationTime; + protected ItemStatus status; + @Setter + private String type; + @Setter + private String name; + @Setter + private String owner; + @Setter + private String description; + private Map<String, Object> properties = new HashMap<>(); + + public boolean isNew() { + return id == null; + } + + public void addProperty(String key, Object value) { + properties.put(key, value); + } + + public <T> T getProperty(String key) { + return (T) properties.get(key); + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/ItemStatus.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/ItemStatus.java new file mode 100644 index 0000000..57b5f23 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/ItemStatus.java @@ -0,0 +1,5 @@ +package org.onap.sdc.common.versioning.services.types; + +public enum ItemStatus { + ACTIVE, ARCHIVED +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Revision.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Revision.java new file mode 100644 index 0000000..10cadb5 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Revision.java @@ -0,0 +1,15 @@ +package org.onap.sdc.common.versioning.services.types; + +import java.util.Date; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Revision { + + private String id; + private String message; + private Date time; + private String user; +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/SynchronizationState.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/SynchronizationState.java new file mode 100644 index 0000000..dd2efcc --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/SynchronizationState.java @@ -0,0 +1,17 @@ +package org.onap.sdc.common.versioning.services.types; + +public enum SynchronizationState { + UpToDate("Up to date"), + OutOfSync("Out of sync"), + Merging("Merging"); + + private final String displayName; + + SynchronizationState(String displayName) { + this.displayName = displayName; + } + + public String toString() { + return this.displayName; + } +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Version.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Version.java new file mode 100644 index 0000000..5cb0b69 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/Version.java @@ -0,0 +1,56 @@ +/*- + * ============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.onap.sdc.common.versioning.services.types; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@NoArgsConstructor +public class Version { + + protected String id; + protected String baseId; + protected String name; + protected VersionStatus status = VersionStatus.Draft; + protected VersionState state; + protected Date creationTime; + protected Date modificationTime; + @Setter + private String description; + private Map<String, Object> properties = new HashMap<>(); + + public boolean isNew() { + return id == null; + } + + public void addProperty(String key, Object value) { + properties.put(key, value); + } + + public <T> T getProperty(String key) { + return (T) properties.get(key); + } +}
\ No newline at end of file diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionCreationMethod.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionCreationMethod.java new file mode 100644 index 0000000..3e18c28 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionCreationMethod.java @@ -0,0 +1,5 @@ +package org.onap.sdc.common.versioning.services.types; + +public enum VersionCreationMethod { + major, minor +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionState.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionState.java new file mode 100644 index 0000000..755c671 --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionState.java @@ -0,0 +1,11 @@ +package org.onap.sdc.common.versioning.services.types; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class VersionState { + private SynchronizationState synchronizationState; + private boolean dirty; +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionStatus.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionStatus.java new file mode 100644 index 0000000..53c2e8f --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionStatus.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.versioning.services.types; + +public enum VersionStatus { + Draft, Certified, Deprecated, Deleted +} diff --git a/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionType.java b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionType.java new file mode 100644 index 0000000..771959b --- /dev/null +++ b/versioning-lib/src/main/java/org/onap/sdc/common/versioning/services/types/VersionType.java @@ -0,0 +1,25 @@ +/*- + * ============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.onap.sdc.common.versioning.services.types; + +public enum VersionType { + Draft, Finalized +} diff --git a/versioning-lib/src/test/java/org/onap/sdc/common/versioning/persistence/zusammen/ItemZusammenDaoTest.java b/versioning-lib/src/test/java/org/onap/sdc/common/versioning/persistence/zusammen/ItemZusammenDaoTest.java new file mode 100644 index 0000000..fac3e0c --- /dev/null +++ b/versioning-lib/src/test/java/org/onap/sdc/common/versioning/persistence/zusammen/ItemZusammenDaoTest.java @@ -0,0 +1,229 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + + +package org.onap.sdc.common.versioning.persistence.zusammen; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.UserInfo; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.Item; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.sdc.common.versioning.persistence.types.InternalItem; +import org.onap.sdc.common.versioning.services.types.ItemStatus; +import org.onap.sdc.common.versioning.services.types.VersionStatus; +import org.onap.sdc.common.zusammen.services.ZusammenAdaptor; + +@RunWith(MockitoJUnitRunner.class) +public class ItemZusammenDaoTest { + + private static final String ITEM_TYPE = "item_type"; + private static final String ITEM_VERSIONS_STATUSES = "item_versions_statuses"; + private static final String APP_PROP_1 = "app_prop1"; + private static final String APP_PROP_2 = "app_prop2"; + private static final SessionContext SESSION_CONTEXT = new SessionContext(); + + static { + SESSION_CONTEXT.setUser(new UserInfo("user")); + SESSION_CONTEXT.setTenant("tenant"); + } + + @Mock + private ZusammenSessionContextCreator contextCreatorMock; + @Mock + private ZusammenAdaptor zusammenAdaptorMock; + @InjectMocks + private ItemZusammenDao itemDao; + + @Before + public void mockSessionContext() { + doReturn(SESSION_CONTEXT).when(contextCreatorMock).create(); + } + + + @Test + public void testListWhenNone() { + doReturn(new ArrayList<>()).when(zusammenAdaptorMock).listItems(eq(SESSION_CONTEXT)); + + Collection<InternalItem> items = itemDao.list(); + + Assert.assertTrue(items.isEmpty()); + } + + @Test + public void testList() { + Map<String, Number> vlm1versionStatuses = new HashMap<>(); + vlm1versionStatuses.put(VersionStatus.Draft.name(), 1); + + Map<String, Number> vsp2versionStatuses = new HashMap<>(); + vsp2versionStatuses.put(VersionStatus.Draft.name(), 3); + vsp2versionStatuses.put(VersionStatus.Certified.name(), 2); + + + List<Item> returnedItems = + Stream.of(createItem("1", "vsp1", "vsp 1", "vsp", new Date(), new Date(), new HashMap<>()), + createItem("2", "vlm1", "vlm 1", "vlm", new Date(), new Date(), vlm1versionStatuses), + createItem("3", "vsp2", "vsp 2", "vsp", new Date(), new Date(), vsp2versionStatuses)) + .collect(Collectors.toList()); + doReturn(returnedItems).when(zusammenAdaptorMock).listItems(eq(SESSION_CONTEXT)); + + Collection<InternalItem> items = itemDao.list(); + assertEquals(items.size(), 3); + + Iterator<InternalItem> itemIterator = items.iterator(); + assertItemEquals(itemIterator.next(), returnedItems.get(0)); + assertItemEquals(itemIterator.next(), returnedItems.get(1)); + assertItemEquals(itemIterator.next(), returnedItems.get(2)); + } + + @Test + public void testGetNonExisting() { + InternalItem item = itemDao.get("nonExisting"); + + Assert.assertNull(item); + } + + @Test + public void testGet() { + String itemId = "1"; + + Map<String, Number> versionStatuses = new HashMap<>(); + versionStatuses.put(VersionStatus.Draft.name(), 3); + versionStatuses.put(VersionStatus.Certified.name(), 2); + + Item toBeReturned = + createItem("1", "vsp1", "vsp 1", "vsp", new Date(System.currentTimeMillis() - 100), new Date(), + versionStatuses); + doReturn(toBeReturned).when(zusammenAdaptorMock).getItem(eq(SESSION_CONTEXT), eq(new Id(itemId))); + + InternalItem item = itemDao.get(itemId); + + Assert.assertNotNull(item); + assertItemEquals(item, toBeReturned); + assertEquals(item.getStatus(), ItemStatus.ACTIVE); + + } + + @Test + public void testCreate() { + InternalItem inputItem = new InternalItem(); + inputItem.setName("vsp1"); + inputItem.setDescription("VSP 1"); + inputItem.setType("vsp"); + + ArgumentCaptor<Info> capturedZusammenInfo = ArgumentCaptor.forClass(Info.class); + + String itemId = "1"; + doReturn(new Id(itemId)).when(zusammenAdaptorMock) + .createItem(eq(SESSION_CONTEXT), capturedZusammenInfo.capture()); + + InternalItem item = itemDao.create(inputItem); + + Info capturedInfo = capturedZusammenInfo.getValue(); + assertEquals(capturedInfo.getName(), inputItem.getName()); + assertEquals(capturedInfo.getDescription(), inputItem.getDescription()); + assertEquals(capturedInfo.getProperty(ITEM_TYPE), inputItem.getType()); + assertEquals(capturedInfo.getProperty(ITEM_VERSIONS_STATUSES), inputItem.getVersionStatusCounters()); + + assertEquals(item.getId(), itemId); + assertEquals(item.getName(), inputItem.getName()); + assertEquals(item.getDescription(), inputItem.getDescription()); + assertEquals(item.getType(), inputItem.getType()); + assertEquals(item.getVersionStatusCounters(), inputItem.getVersionStatusCounters()); + } + + @Test + public void testUpdate() { + InternalItem item = new InternalItem(); + item.setId("1"); + item.setName("vsp1"); + item.setDescription("VSP 1"); + item.setType("vsp"); + item.addVersionStatus(VersionStatus.Draft); + item.addVersionStatus(VersionStatus.Draft); + item.addVersionStatus(VersionStatus.Certified); + + ArgumentCaptor<Info> capturedZusammenInfo = ArgumentCaptor.forClass(Info.class); + + itemDao.update(item); + + verify(zusammenAdaptorMock) + .updateItem(eq(SESSION_CONTEXT), eq(new Id(item.getId())), capturedZusammenInfo.capture()); + + Info capturedInfo = capturedZusammenInfo.getValue(); + assertEquals(capturedInfo.getName(), item.getName()); + assertEquals(capturedInfo.getDescription(), item.getDescription()); + assertEquals(capturedInfo.getProperty(ITEM_TYPE), item.getType()); + assertEquals(capturedInfo.getProperty(ITEM_VERSIONS_STATUSES), item.getVersionStatusCounters()); + } + + private Item createItem(String id, String name, String description, String type, Date creationTime, + Date modificationTime, Map<String, Number> versionStatusCounters) { + Item item = new Item(); + item.setId(new Id(id)); + Info info = new Info(); + info.setName(name); + info.setDescription(description); + info.addProperty(ITEM_TYPE, type); + info.addProperty(ITEM_VERSIONS_STATUSES, versionStatusCounters); + info.addProperty(APP_PROP_1, "app_prop1_value"); + info.addProperty(APP_PROP_2, 8); + item.setInfo(info); + item.setCreationTime(creationTime); + item.setModificationTime(modificationTime); + return item; + } + + private void assertItemEquals(InternalItem item, Item zusammenItem) { + assertEquals(item.getId(), zusammenItem.getId().getValue()); + assertEquals(item.getName(), zusammenItem.getInfo().getName()); + assertEquals(item.getDescription(), zusammenItem.getInfo().getDescription()); + assertEquals(item.getType(), zusammenItem.getInfo().getProperty(ITEM_TYPE)); + assertEquals(item.getProperties().get(APP_PROP_1), zusammenItem.getInfo().getProperty(APP_PROP_1)); + assertEquals(item.getProperties().get(APP_PROP_2), zusammenItem.getInfo().getProperty(APP_PROP_2)); + + Map<String, Number> zusammenStatusesMap = zusammenItem.getInfo().getProperty(ITEM_VERSIONS_STATUSES); + Map<VersionStatus, Integer> statusesMap = item.getVersionStatusCounters(); + + zusammenStatusesMap.forEach((key, value) -> assertEquals(statusesMap.get(VersionStatus.valueOf(key)), value)); + + assertEquals(item.getCreationTime(), zusammenItem.getCreationTime()); + assertEquals(item.getModificationTime(), zusammenItem.getModificationTime()); + } + +} diff --git a/versioning-lib/src/test/java/org/onap/sdc/common/versioning/persistence/zusammen/VersionZusammenDaoTest.java b/versioning-lib/src/test/java/org/onap/sdc/common/versioning/persistence/zusammen/VersionZusammenDaoTest.java new file mode 100644 index 0000000..1db761b --- /dev/null +++ b/versioning-lib/src/test/java/org/onap/sdc/common/versioning/persistence/zusammen/VersionZusammenDaoTest.java @@ -0,0 +1,410 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, InternalVersion 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. + */ + + +package org.onap.sdc.common.versioning.persistence.zusammen; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.UserInfo; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import com.amdocs.zusammen.datatypes.item.ItemVersionStatus; +import com.amdocs.zusammen.datatypes.item.SynchronizationStatus; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.sdc.common.versioning.persistence.types.InternalVersion; +import org.onap.sdc.common.versioning.services.types.Revision; +import org.onap.sdc.common.versioning.services.types.VersionStatus; +import org.onap.sdc.common.zusammen.services.ZusammenAdaptor; + +@RunWith(MockitoJUnitRunner.class) +public class VersionZusammenDaoTest { + + private static final String STATUS_PROPERTY = "status"; + private static final SessionContext SESSION_CONTEXT = new SessionContext(); + + static { + SESSION_CONTEXT.setUser(new UserInfo("user")); + SESSION_CONTEXT.setTenant("tenant"); + } + + @Mock + private ZusammenSessionContextCreator contextCreatorMock; + @Mock + private ZusammenAdaptor zusammenAdaptorMock; + @InjectMocks + private VersionZusammenDao versionDao; + + @Before + public void mockSessionContext() { + doReturn(SESSION_CONTEXT).when(contextCreatorMock).create(); + } + + @Test + public void testListWhenNone() { + String itemId = "itemId"; + + doReturn(new ArrayList<>()).when(zusammenAdaptorMock) + .listPublicVersions(eq(SESSION_CONTEXT), eq(new Id(itemId))); + + List<InternalVersion> versions = versionDao.list(itemId); + + Assert.assertTrue(versions.isEmpty()); + } + + @Test + public void testList() { + String itemId = "itemId"; + Id versionId1 = new Id("v1_id"); + Id versionId2 = new Id("v2_id"); + Id versionId3 = new Id("v3_id"); + + List<ItemVersion> zusammenVersions = + Stream.of(createZusammenVersion(versionId1, null, "version desc", "1.0", VersionStatus.Certified), + createZusammenVersion(versionId2, versionId1, "version desc", "2.0", VersionStatus.Certified), + createZusammenVersion(versionId3, versionId2, "version desc", "3.0", VersionStatus.Draft)) + .collect(Collectors.toList()); + doReturn(zusammenVersions).when(zusammenAdaptorMock) + .listPublicVersions(eq(SESSION_CONTEXT), eq(new Id(itemId))); + + List<InternalVersion> versions = versionDao.list(itemId); + Assert.assertEquals(versions.size(), 3); + + int zusammenVersionIndex; + for (InternalVersion version : versions) { + zusammenVersionIndex = versionId1.getValue().equals(version.getId()) ? 0 : + versionId2.getValue().equals(version.getId()) ? 1 : 2; + assetVersionEquals(version, zusammenVersions.get(zusammenVersionIndex), null); + } + } + + @Test + public void testCreate() { + testCreate(null, null); + } + + @Test + public void testCreateBasedOn() { + Map<String, Object> properties = new HashMap<>(); + properties.put("key", "value"); + testCreate("baseId", properties); + } + + private void testCreate(String baseId, Map<String, Object> properties) { + String itemId = "itemId"; + InternalVersion version = new InternalVersion(); + version.setBaseId(baseId); + version.setName("1.0"); + version.setDescription("version description"); + version.setStatus(VersionStatus.Draft); + if (properties != null) { + properties.forEach(version::addProperty); + } + ArgumentCaptor<ItemVersionData> capturedZusammenVersion = ArgumentCaptor.forClass(ItemVersionData.class); + + String versionId = "versionId"; + doReturn(new Id(versionId)).when(zusammenAdaptorMock) + .createVersion(eq(SESSION_CONTEXT), eq(new Id(itemId)), baseId == null ? isNull() : eq(new Id(baseId)), + capturedZusammenVersion.capture()); + + + versionDao.create(itemId, version); + + Assert.assertEquals(version.getId(), versionId); + + Info capturedInfo = capturedZusammenVersion.getValue().getInfo(); + Assert.assertEquals(capturedInfo.getName(), version.getName()); + Assert.assertEquals(capturedInfo.getDescription(), version.getDescription()); + Assert.assertEquals(VersionStatus.valueOf(capturedInfo.getProperty(STATUS_PROPERTY)), version.getStatus()); + String capturedInfoProperty = capturedInfo.getProperty("key"); + Assert.assertEquals(capturedInfoProperty, version.getProperty("key")); + } + + @Test + public void testUpdate() { + String itemId = "itemId"; + InternalVersion version = new InternalVersion(); + version.setId("versionId"); + version.setBaseId("baseId"); + version.setName("1.0"); + version.setDescription("version description"); + version.setStatus(VersionStatus.Certified); + + ArgumentCaptor<ItemVersionData> capturedZusammenVersion = ArgumentCaptor.forClass(ItemVersionData.class); + + versionDao.update(itemId, version); + + verify(zusammenAdaptorMock).updateVersion(eq(SESSION_CONTEXT), eq(new Id(itemId)), eq(new Id(version.getId())), + capturedZusammenVersion.capture()); + + Info capturedInfo = capturedZusammenVersion.getValue().getInfo(); + Assert.assertEquals(capturedInfo.getName(), version.getName()); + Assert.assertEquals(capturedInfo.getDescription(), version.getDescription()); + Assert.assertEquals(VersionStatus.valueOf(capturedInfo.getProperty(STATUS_PROPERTY)), version.getStatus()); + } + + @Test + public void testGetNonExisting() { + Optional<InternalVersion> version = versionDao.get("itemId", "versionId"); + + Assert.assertEquals(version, Optional.empty()); + } + + @Test + public void testGetSynced() { + String itemId = "itemId"; + String versionId = "versionId"; + + SessionContext zusammenContext = SESSION_CONTEXT; + Id itemIdObj = new Id(itemId); + Id versionIdObj = new Id(versionId); + + ItemVersion zusammenPrivateVersion = + createZusammenVersion(versionIdObj, new Id("baseId"), "version desc updated", "2.0", + VersionStatus.Draft); + doReturn(zusammenPrivateVersion).when(zusammenAdaptorMock) + .getVersion(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + ItemVersionStatus zusammenVersionStatus = new ItemVersionStatus(SynchronizationStatus.UP_TO_DATE, true); + doReturn(zusammenVersionStatus).when(zusammenAdaptorMock) + .getVersionStatus(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + Optional<InternalVersion> version = versionDao.get(itemId, versionId); + + Assert.assertTrue(version.isPresent()); + assetVersionEquals(version.get(), zusammenPrivateVersion, zusammenVersionStatus); + } + + @Test + public void testGetOutOfSync() { + String itemId = "itemId"; + String versionId = "versionId"; + + SessionContext zusammenContext = SESSION_CONTEXT; + Id itemIdObj = new Id(itemId); + Id versionIdObj = new Id(versionId); + + ItemVersion zusammenPrivateVersion = + createZusammenVersion(versionIdObj, new Id("baseId"), "version desc updated", "2.0", + VersionStatus.Draft); + doReturn(zusammenPrivateVersion).when(zusammenAdaptorMock) + .getVersion(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + ItemVersionStatus zusammenVersionStatus = new ItemVersionStatus(SynchronizationStatus.OUT_OF_SYNC, true); + doReturn(zusammenVersionStatus).when(zusammenAdaptorMock) + .getVersionStatus(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + VersionStatus statusOnPublic = VersionStatus.Certified; + ItemVersion zusammenPublicVersion = + createZusammenVersion(versionIdObj, new Id("baseId"), "version desc", "2.0", statusOnPublic); + doReturn(zusammenPublicVersion).when(zusammenAdaptorMock) + .getPublicVersion(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + Optional<InternalVersion> version = versionDao.get(itemId, versionId); + + Assert.assertTrue(version.isPresent()); + zusammenPrivateVersion.getData().getInfo().addProperty(STATUS_PROPERTY, statusOnPublic.name()); + assetVersionEquals(version.get(), zusammenPrivateVersion, zusammenVersionStatus); + } + + @Test + public void testGetMerging() { + String itemId = "itemId"; + String versionId = "versionId"; + + SessionContext zusammenContext = SESSION_CONTEXT; + Id itemIdObj = new Id(itemId); + Id versionIdObj = new Id(versionId); + + ItemVersion zusammenPrivateVersion = + createZusammenVersion(versionIdObj, new Id("baseId"), "version desc", "2.0", VersionStatus.Draft); + doReturn(zusammenPrivateVersion).when(zusammenAdaptorMock) + .getVersion(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + ItemVersionStatus zusammenVersionStatus = new ItemVersionStatus(SynchronizationStatus.MERGING, true); + doReturn(zusammenVersionStatus).when(zusammenAdaptorMock) + .getVersionStatus(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + ItemVersion zusammenPublicVersion = + createZusammenVersion(versionIdObj, new Id("baseId"), "version desc", "2.0", VersionStatus.Draft); + doReturn(zusammenPublicVersion).when(zusammenAdaptorMock) + .getPublicVersion(eq(zusammenContext), eq(itemIdObj), eq(versionIdObj)); + + Optional<InternalVersion> version = versionDao.get(itemId, versionId); + + Assert.assertTrue(version.isPresent()); + assetVersionEquals(version.get(), zusammenPrivateVersion, zusammenVersionStatus); + } + + @Test + public void testPublish() { + String itemId = "itemId"; + String versionId = "versionId"; + String message = "publish message"; + + versionDao.publish(itemId, versionId, message); + + verify(zusammenAdaptorMock) + .publishVersion(eq(SESSION_CONTEXT), eq(new Id(itemId)), eq(new Id(versionId)), eq(message)); + } + + @Test + public void testSync() { + String itemId = "itemId"; + String versionId = "versionId"; + + versionDao.sync(itemId, versionId); + + verify(zusammenAdaptorMock).syncVersion(eq(SESSION_CONTEXT), eq(new Id(itemId)), eq(new Id(versionId))); + } + + @Test + public void testForceSync() { + String itemId = "itemId"; + String versionId = "versionId"; + + versionDao.forceSync(itemId, versionId); + + verify(zusammenAdaptorMock).forceSyncVersion(eq(SESSION_CONTEXT), eq(new Id(itemId)), eq(new Id(versionId))); + } + + @Test + public void testRevert() { + String itemId = "itemId"; + String versionId = "versionId"; + String revisionId = "revisionId"; + + versionDao.revert(itemId, versionId, revisionId); + + verify(zusammenAdaptorMock) + .revert(eq(SESSION_CONTEXT), eq(new Id(itemId)), eq(new Id(versionId)), eq(new Id(revisionId))); + } + + @Test + public void testListRevisionsWhenNone() { + String itemId = "itemId"; + String versionId = "versionId"; + + List<Revision> revisions = versionDao.listRevisions(itemId, versionId); + + Assert.assertTrue(revisions.isEmpty()); + } + + @Test + public void testListRevisions() { + String itemId = "itemId"; + String versionId = "versionId"; + + long currentTime = System.currentTimeMillis(); + Date rev4time = new Date(currentTime); // latest + Date rev3time = new Date(currentTime - 1); + Date rev2time = new Date(currentTime - 2); + Date rev1time = new Date(currentTime - 3); // oldest + List<com.amdocs.zusammen.datatypes.itemversion.Revision> zusammenRevisions = + Stream.of(createZusammenRevision("rev4", "forth rev", "user1", rev4time), + createZusammenRevision("rev1", "first rev", "user2", rev1time), + createZusammenRevision("rev3", "third rev", "user2", rev3time), + createZusammenRevision("rev2", "second rev", "user1", rev2time)).collect(Collectors.toList()); + ItemVersionRevisions toBeReturned = new ItemVersionRevisions(); + toBeReturned.setItemVersionRevisions(zusammenRevisions); + doReturn(toBeReturned).when(zusammenAdaptorMock) + .listRevisions(eq(SESSION_CONTEXT), eq(new Id(itemId)), eq(new Id(versionId))); + + List<Revision> revisions = versionDao.listRevisions(itemId, versionId); + + Assert.assertEquals(revisions.size(), 4); + assertRevisionEquals(revisions.get(0), zusammenRevisions.get(0)); // rev4 - latest + assertRevisionEquals(revisions.get(1), zusammenRevisions.get(2)); // rev3 + assertRevisionEquals(revisions.get(2), zusammenRevisions.get(3)); // rev2 + assertRevisionEquals(revisions.get(3), zusammenRevisions.get(1)); // rev1 - oldest + } + + private ItemVersion createZusammenVersion(Id id, Id baseId, String description, String name, VersionStatus status) { + ItemVersion version = new ItemVersion(); + version.setId(id); + version.setBaseId(baseId); + Info info = new Info(); + info.setName(name); + info.setDescription(description); + info.addProperty(STATUS_PROPERTY, status.name()); + ItemVersionData data = new ItemVersionData(); + data.setInfo(info); + version.setData(data); + version.setCreationTime(new Date()); + version.setModificationTime(new Date()); + return version; + } + + private void assetVersionEquals(InternalVersion version, ItemVersion zusammenVersion, + ItemVersionStatus zusammenVersionStatus) { + Assert.assertEquals(version.getId(), zusammenVersion.getId().getValue()); + Assert.assertEquals(version.getBaseId(), + zusammenVersion.getBaseId() == null ? null : zusammenVersion.getBaseId().getValue()); + Info info = zusammenVersion.getData().getInfo(); + Assert.assertEquals(version.getName(), info.getName()); + Assert.assertEquals(version.getDescription(), info.getDescription()); + Assert.assertEquals(version.getStatus(), VersionStatus.valueOf(info.getProperty(STATUS_PROPERTY))); + Assert.assertEquals(version.getCreationTime(), zusammenVersion.getCreationTime()); + Assert.assertEquals(version.getModificationTime(), zusammenVersion.getModificationTime()); + + if (zusammenVersionStatus != null) { + Assert.assertEquals(version.getState().isDirty(), zusammenVersionStatus.isDirty()); + Assert.assertEquals(version.getState().getSynchronizationState().toString(), + zusammenVersionStatus.getSynchronizationStatus().toString()); + } + } + + private com.amdocs.zusammen.datatypes.itemversion.Revision createZusammenRevision(String id, String message, + String user, Date time) { + com.amdocs.zusammen.datatypes.itemversion.Revision revision = + new com.amdocs.zusammen.datatypes.itemversion.Revision(); + revision.setRevisionId(new Id(id)); + revision.setMessage(message); + revision.setUser(user); + revision.setTime(time); + return revision; + } + + private void assertRevisionEquals(Revision revision, + com.amdocs.zusammen.datatypes.itemversion.Revision zusammenRevision) { + Assert.assertEquals(revision.getId(), zusammenRevision.getRevisionId().getValue()); + Assert.assertEquals(revision.getMessage(), zusammenRevision.getMessage()); + Assert.assertEquals(revision.getUser(), zusammenRevision.getUser()); + Assert.assertEquals(revision.getTime(), zusammenRevision.getTime()); + } +} diff --git a/zusammen-lib/README.md b/zusammen-lib/README.md new file mode 100644 index 0000000..e5c2040 --- /dev/null +++ b/zusammen-lib/README.md @@ -0,0 +1,272 @@ +Introduction +============ + +This zusammen library is a library which encapsulate access to Zusammen collaborative database based on cassandra. + +Components +========== + +The onboarding is comprised of the following deployment units: + +- Designer backend is the core component. It exposes RESTful APIs for managing vsp. The backend +currently supports VNFD packages of ETSI SOL001 standard only. + +- Designer frontend serves static content of a Web application for creating and managing vsps, and forwards API +requests to the backend. The static content includes JavaScript, images, CSS, etc. + +- Translator from Tosca SOL001 standard to Onboarding internal model is used by the designer backend. + +- Cassandra database is used by the designer backend as the main storage for onboarding data. A dedicated instance of +Cassandra can be deployed, or an existing cluster may be used. + +- Database initialization scripts run once per deployment to create the necessary Cassandra keyspaces and tables, +pre-populate data, etc. + +Execute Backend from IntelliJ +============================= +Create a copy of `application.properties` (located in `vnf-onboarding-backend\src\main\resources`) and name it `application-dev.properties`. + +In this file, populate the required properties with your Cassandra, Translation and SDC Catalog info. + +Run `org.onap.sdc.onboarding.SpringBootWebApplication` with the VM options: `-Dspring.profiles.active=dev`. + +Deployment on Docker +==================== + +The procedure below describes manual deployment on plain Docker for development or a demo. + +## 1. Database + +Create a dedicated instance of Cassandra. This step is optional if you already have a Cassandra cluster. +The designer is not expected to have problems working with Cassandra 3.x, but has been tested with 2.1.x because this +is the version used by SDC. + +An easy way to spin up a Cassandra instance is using a Cassandra Docker image as described in the +[official documentation](https://hub.docker.com/_/cassandra/). + +### Example + +`docker run -d --name onboard-cassandra cassandra:2.1` + +## 2. Database Initialization + +**WARNING**: *This step must be executed only once.* + +the designer requires two Cassandra namespaces: + +- ONBOARDING +- ZUSAMMEN_ONBOARDING + +By default, these keyspaces are configured to use a simple replication strategy (`'class' : 'SimpleStrategy'`) +and the replication factor of one (`'replication_factor' : 1`). In order to override this configuration, override +the *create_keyspaces.cql* file at the root of the initialization container using +[Docker volume mapping](https://docs.docker.com/storage/volumes/). Include `IF NOT EXISTS` clause in the keyspace +creation statements to prevent accidental data loss. + +`docker run -ti -e CS_HOST=<cassandra-host> -e CS_PORT=<cassandra-port> -e CS_AUTHENTICATE=true/false +-e CS_USER=<cassandra-user> -e CS_PASSWORD=<cassandra-password> nexus3.onap.org:10001/NPO/vnf-onboard-init:latest` + +### Environment Variables + +- CS_HOST — Cassandra hostname or IP address. + +- CS_PORT — Cassandra Thrift client port. If not specified, the default of 9160 will be used. + +- CS_AUTHENTICATE — whether password authentication must be used to connect to Cassandra. A *false* will be +assumed if this variable is not specified. + +- CS_USER — Cassandra username if CS_AUTHENTICATE is *true*. + +- CS_PASSWORD — Cassandra password if CS_AUTHENTICATE is *true*. + +### Example + +Assuming you have created a dedicated Cassandra container as described in Database section, and the access to it is not +protected with a password, the following command will initialize the database: + +`docker run -d --name vnf-onboard-init +-e CS_HOST=$(docker inspect vnf-onboard-cassandra --format={{.NetworkSettings.IPAddress}}) +nexus3.onap.org:10001/onap/vnf-onboard-init:latest` + +### Troubleshooting + +In order to see if the the designer was successfully initialized, make sure the console does not contain error +messages. You can also see the logs of the initialization container using `docker logs vnf-onboard-init` command. +## 3. Translation + +`docker run -d --name vnfd-sol001-translation -p 8080:8080 npo/vnfd-sol001-translation:latest` + +## 4. Backend + +`docker run -d --name vnf-onboard-backend +-e SERVER_SSL_ENABLED=true/false +-e SERVER_SSL_KEY_PASSWORD=<ssl_key_password> +-e SERVER_SSL_KEYSTORE_PATH=<ssl_keystore_path> +-e SERVER_SSL_KEYSTORE_TYPE=<ssl_keystore_type> +-e SDC_PROTOCL=http/https +-e CS_HOSTS=<cassandra-hosts> +-e CS_PORT=<cassandra-port> +-e CS_AUTHENTICATE=true/false +-e CS_USER=<cassandra user> +-e CS_PASSWORD=<cassandra password> +-e CS_SSL_ENABLED=true/false +--volume <cassandra-truststore-path_container>:<cassandra-truststore-path_local> +-e CS_TRUST_STORE_PATH=<cassandra-truststore-path_container> +-e CS_TRUST_STORE_PASSWORD=<cassandra-truststore-password> +-e TRANSLATION_HOST=<translation ip> +-e TRANSLATION_PORT=<translation port> +-e SDC_HOST=<sdc catalog ip> +-e SDC_PORT=<sdc catalog port> +-e SDC_USER=<sdc consumer user> +-e SDC_PASSWORD=<secret> +-e JAVA_OPTIONS="-Xmx1536m -Xms1536m" +-p 8443:8443 +npo/vnf-onboard-backend:latest` + +### Environment Variables + +- SERVER_SSL_ENABLED — whether ssl authentication must be used to connect to application. A *false* will be +assumed if this variable is not specified. + +- SERVER_SSL_KEY_PASSWORD — SSL key password if SERVER_SSL_ENABLED is *true*. + +- SERVER_SSL_KEYSTORE_PATH — SSL Keystore path if SERVER_SSL_ENABLED is *true*. + +- SERVER_SSL_KEYSTORE_TYPE — SSL Keystore type if SERVER_SSL_ENABLED is *true*. + +- CS_HOSTS — comma-separated list of Cassandra hostnames or IP addresses. + +- CS_PORT — CQL native client port. If not specified, the default of 9042 will be used. + +- CS_AUTHENTICATE — whether password authentication must be used to connect to Cassandra. A *false* will be +assumed if this variable is not specified. + +- CS_USER — Cassandra username if CS_AUTHENTICATE is *true*. + +- CS_PASSWORD — Cassandra password if CS_AUTHENTICATE is *true*. + +- CS_SSL_ENABLED — whether ssl authentication must be used to connect to Cassandra. A *false* will be +assumed if this variable is not specified. + +- CS_TRUST_STORE_PATH — Cassandra Truststore path if CS_SSL_ENABLED is *true*. + +- CS_TRUST_STORE_PASSWORD — Cassandra Truststore password if CS_SSL_ENABLED is *true*. + +- TRANSLATION_PROTOCOL — protocol to be used for calling Translation APIs (http or https). + +- TRANSLATION_HOST — a Translation server. + +- TRANSLATION_PORT — a Translation server port, usually 8080. + +- SDC_PROTOCOL — protocol to be used for calling SDC APIs (http or https). + +- SDC_HOST — a SDC backend server. + +- SDC_PORT — a SDC backend server port, usually 8080. + +- SDC_USER — Onboarding consumer username + +- SDC_PASSWORD — Onboarding consumer password + +- JAVA_OPTIONS — optionally, JVM (Java Virtual Machine) arguments. + +### Example + +Assuming you have a dedicated Cassandra container as described in Database section, and the access to it is not +protected with a password. The following command will start a backend container without SSL support: + +`docker run -d --name vnf-onboard-backend +-e CS_HOSTS=$(docker inspect vnf-onboard-cassandra --format={{.NetworkSettings.IPAddress}}) +-e TRANSLATION_HOST=<translation ip> +-e TRANSLATION_PORT=<translation port> +-e SDC_HOST=<sdc catalog ip> +-e SDC_PORT=<sdc catalog port> +-e SDC_USER=<sdc consumer user> +-e SDC_PASSWORD=<secret> +-e JAVA_OPTIONS="-Xmx1536m -Xms1536m" +-p 8443:8443 +npo/vnf-onboard-backend:latest` + +### Troubleshooting + +In order to verify that the backend has started successfully, check the logs of the +backend container. For example, by running `docker logs vnf-onboard-backend`. The logs must not contain any +error messages. + +Application logs are located in the */var/log/... directory of a backend +container. For example, you can view the audit log by running +`docker exec -ti vnf-onboard-backend less /var/log/npo/vnf-onboard-backend/backend/audit.log`. + +## 5. Frontend + +`docker run -d -e BACKEND=http://<backend-host>:<backend-port> -e JAVA_OPTIONS=<jvm-options> +nexus3.onap.org:10001/npo/vnf-onboard-frontend:latest` + +- BACKEND — root endpoint of the RESTful APIs exposed by a backend server. + +- JAVA_OPTIONS — optionally, JVM (Java Virtual Machine) arguments. + +### Example + +`docker run -d --name vnf-onboard-frontend +-e BACKEND=http://$(docker inspect vnf-onboard-backend --format={{.NetworkSettings.IPAddress}}):8080 +-e JAVA_OPTIONS="-Xmx64m -Xms64m -Xss1m" -p 9088:8080 nexus3.onap.org:10001/npo/vnf-onboard-frontend:latest` + +Notice that port 8080 of the frontend container has been +[mapped]( https://docs.docker.com/config/containers/container-networking/#published-ports) to port 9088 of the host +machine. This makes the Designer Web application accessible from the outside world via the host machine's +IP address/hostname. + +### Troubleshooting + +In order to check if the Designer frontend has successfully started, look at the logs of the +frontend container. For example, by running `docker logs vnf-onboard-frontend`. The logs should not contain +error messages. + +Frontend does not have backend logic, therefore there are no application logs. + + +SDC Plugin Configuration +======================== + +In order to run as an SDC pluggable designer, the designer must be added to SDC configuration as described in +[Generic plugin support](https://wiki.onap.org/display/DW/Generic+Designer+Support). + +If you are deploying SDC using a standard procedure (OOM or the +[SDC shell script](https://wiki.onap.org/display/DW/Deploying+SDC+on+a+Linux+VM+for+Development)), +the easiest way to configure the Onboarding plugin is to edit the *plugins-configuration.yaml*. + +### Plugin Source + +The main endpoint to load the designer Web application is defined by `"pluginSourceUrl": "http://<host>:<port>"`. + +Keep in mind that the URL **must be accessible from a user's browser**. In most cases, `<host>` will be the hostname or +IP address of the machine that runs Docker engine, and `<port>` will be a host port to which you have published port +8080 of the Onboarding frontend container. + +### Plugin Discovery + +In order to check the availability of a plugin, SDC uses `"pluginDiscoveryUrl"`. For Onboarding the value is +`http://<host>:<port>/ping`. + +### Example + +Let's assume that hostname of the machine that runs Docker containers with the Onboarding application is +*onboard.example.com*, and port 8080 of the Onboarding frontend is mapped to 9088 on the host. In this case the +corresponding section of *plugins-configuration.yaml* will look like below: + +``` + +- pluginId: ONBOARD + pluginDiscoveryUrl: "http://onboard.example.com:9088/ping" + pluginSourceUrl: "http://onboard.example.com:9088" + pluginStateUrl: "onboarding" + pluginDisplayOptions: + tab: + displayName: "ONBOARD" + displayRoles: ["DESIGNER", "TESTER"] + +``` + +In a development or demo environment, the designer will run on the same host as SDC, so that its IP address will +be the one of the Docker host.
\ No newline at end of file diff --git a/zusammen-lib/pom.xml b/zusammen-lib/pom.xml new file mode 100644 index 0000000..f76b377 --- /dev/null +++ b/zusammen-lib/pom.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 European Support Limited + ~ + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <artifactId>zusammen-lib</artifactId> + <parent> + <groupId>org.onap.sdc.common</groupId> + <artifactId>sdc-be-common</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + <properties> + <zusammen.version>1.0.1</zusammen.version> + <zusammen-state-store.version>1.0.1</zusammen-state-store.version> + <zusammen-collaboration-store.version>1.0.1</zusammen-collaboration-store.version> + <zusammen-index-store.version>1.0.0</zusammen-index-store.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-cassandra</artifactId> + </dependency> + <dependency> + <groupId>com.amdocs.zusammen</groupId> + <artifactId>zusammen-datatypes</artifactId> + <version>${zusammen.version}</version> + </dependency> + <dependency> + <groupId>com.amdocs.zusammen</groupId> + <artifactId>zusammen-adaptor-inbound-api</artifactId> + <version>${zusammen.version}</version> + </dependency> + <dependency> + <groupId>com.amdocs.zusammen</groupId> + <artifactId>zusammen-adaptor-inbound-impl</artifactId> + <version>${zusammen.version}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>com.amdocs.zusammen.plugin</groupId> + <artifactId>zusammen-collaboration-cassandra-plugin</artifactId> + <version>${zusammen-collaboration-store.version}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>com.amdocs.zusammen.plugin</groupId> + <artifactId>zusammen-search-index-empty-plugin</artifactId> + <version>${zusammen-index-store.version}</version> + <scope>runtime</scope> + </dependency> + </dependencies> +</project> + diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/config/ZusammenConfig.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/config/ZusammenConfig.java new file mode 100644 index 0000000..920b07a --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/config/ZusammenConfig.java @@ -0,0 +1,88 @@ +/* + * Copyright © 2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.zusammen.config; + +import com.datastax.driver.core.RemoteEndpointAwareJdkSSLOptions; +import com.datastax.driver.core.SSLOptions; +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.SecureRandom; +import javax.annotation.PostConstruct; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.cassandra.ClusterBuilderCustomizer; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZusammenConfig { + + private static final String[] CIPHER_SUITES = {"TLS_RSA_WITH_AES_128_CBC_SHA"}; + private static final String KEYSTORE_TYPE = "JKS"; + private static final String SECURE_SOCKET_PROTOCOL = "SSL"; + private static final String KEYSPACE = "zusammen"; + + private final ZusammenConfigProvider provider; + + + @Autowired + public ZusammenConfig(ZusammenConfigProvider provider) { + this.provider = provider; + } + + @PostConstruct + public void init() { + System.setProperty("cassandra.nodes", provider.getCassandraAddresses()); + System.setProperty("cassandra.ssl.port", provider.getCassandraPort()); + System.setProperty("cassandra.keyspace", KEYSPACE); + + System.setProperty("cassandra.authenticate", Boolean.toString(Boolean.valueOf(provider.getCassandraAuth()))); + System.setProperty("cassandra.user", provider.getCassandraUser()); + System.setProperty("cassandra.password", provider.getCassandraPassword()); + + System.setProperty("cassandra.ssl", Boolean.toString(Boolean.valueOf(provider.getCassandraSSL()))); + System.setProperty("cassandra.truststore", provider.getCassandraTrustStorePath()); + System.setProperty("cassandra.truststore.password", provider.getCassandraTrustStorePassword()); + } + + @Bean + @ConditionalOnProperty("cassandra.ssl") + ClusterBuilderCustomizer clusterBuilderCustomizer() { + SSLOptions sslOptions = RemoteEndpointAwareJdkSSLOptions + .builder() + .withSSLContext(getSslContext()) + .withCipherSuites(CIPHER_SUITES).build(); + return builder -> builder.withSSL(sslOptions); + } + + private SSLContext getSslContext() { + try (FileInputStream tsf = new FileInputStream(provider.getCassandraTrustStorePath())) { + SSLContext ctx = SSLContext.getInstance(SECURE_SOCKET_PROTOCOL); + KeyStore ts = KeyStore.getInstance(KEYSTORE_TYPE); + ts.load(tsf, provider.getCassandraTrustStorePassword().toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ts); + ctx.init(null, tmf.getTrustManagers(), new SecureRandom()); + return ctx; + } catch (Exception ex) { + throw new BeanCreationException(ex.getMessage(), ex); + } + } +}
\ No newline at end of file diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/config/ZusammenConfigProvider.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/config/ZusammenConfigProvider.java new file mode 100644 index 0000000..4cbe1f2 --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/config/ZusammenConfigProvider.java @@ -0,0 +1,20 @@ +package org.onap.sdc.common.zusammen.config; + +public interface ZusammenConfigProvider { + + String getCassandraAddresses(); + + String getCassandraPort(); + + String getCassandraAuth(); + + String getCassandraUser(); + + String getCassandraPassword(); + + String getCassandraSSL(); + + String getCassandraTrustStorePath(); + + String getCassandraTrustStorePassword(); +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/ZusammenConnector.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/ZusammenConnector.java new file mode 100644 index 0000000..98640e2 --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/ZusammenConnector.java @@ -0,0 +1,98 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.zusammen.persistence; + +import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementConflict; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ItemVersionConflict; +import com.amdocs.zusammen.commons.health.data.HealthInfo; +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.Item; +import com.amdocs.zusammen.datatypes.item.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import com.amdocs.zusammen.datatypes.item.ItemVersionStatus; +import com.amdocs.zusammen.datatypes.item.Resolution; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import com.amdocs.zusammen.datatypes.itemversion.Tag; +import java.util.Collection; + +public interface ZusammenConnector { + + Collection<HealthInfo> checkHealth(SessionContext sessionContext); + + String getReleaseVersion(SessionContext sessionContext); + + Collection<Item> listItems(SessionContext context); + + Item getItem(SessionContext context, Id itemId); + + Id createItem(SessionContext context, Info info); + + void deleteItem(SessionContext context, Id itemId); + + void updateItem(SessionContext context, Id itemId, Info info); + + + Collection<ItemVersion> listPublicVersions(SessionContext context, Id itemId); + + ItemVersion getPublicVersion(SessionContext context, Id itemId, Id versionId); + + Id createVersion(SessionContext context, Id itemId, Id baseVersionId, ItemVersionData itemVersionData); + + void updateVersion(SessionContext context, Id itemId, Id versionId, ItemVersionData itemVersionData); + + ItemVersion getVersion(SessionContext context, Id itemId, Id versionId); + + ItemVersionStatus getVersionStatus(SessionContext context, Id itemId, Id versionId); + + void tagVersion(SessionContext context, Id itemId, Id versionId, Tag tag); + + void resetVersionRevision(SessionContext context, Id itemId, Id versionId, Id revisionId); + + void revertVersionRevision(SessionContext context, Id itemId, Id versionId, Id revisionId); + + ItemVersionRevisions listVersionRevisions(SessionContext context, Id itemId, Id versionId); + + void publishVersion(SessionContext context, Id itemId, Id versionId, String message); + + void syncVersion(SessionContext context, Id itemId, Id versionId); + + void forceSyncVersion(SessionContext context, Id itemId, Id versionId); + + void cleanVersion(SessionContext context, Id itemId, Id versionId); + + ItemVersionConflict getVersionConflict(SessionContext context, Id itemId, Id versionId); + + + Collection<ElementInfo> listElements(SessionContext context, ElementContext elementContext, Id parentElementId); + + ElementInfo getElementInfo(SessionContext context, ElementContext elementContext, Id elementId); + + Element getElement(SessionContext context, ElementContext elementContext, Id elementId); + + ElementConflict getElementConflict(SessionContext context, ElementContext elementContext, Id elementId); + + Element saveElement(SessionContext context, ElementContext elementContext, Element element, String message); + + void resolveElementConflict(SessionContext context, ElementContext elementContext, Element element, + Resolution resolution); + +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/impl/ZusammenAdaptorsConfig.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/impl/ZusammenAdaptorsConfig.java new file mode 100644 index 0000000..18d34bc --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/impl/ZusammenAdaptorsConfig.java @@ -0,0 +1,32 @@ +package org.onap.sdc.common.zusammen.persistence.impl; + +import com.amdocs.zusammen.adaptor.inbound.api.health.HealthAdaptorFactory; +import com.amdocs.zusammen.adaptor.inbound.api.item.ElementAdaptorFactory; +import com.amdocs.zusammen.adaptor.inbound.api.item.ItemAdaptorFactory; +import com.amdocs.zusammen.adaptor.inbound.api.item.ItemVersionAdaptorFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZusammenAdaptorsConfig { + + @Bean + public ItemAdaptorFactory itemAdaptorFactory() { + return ItemAdaptorFactory.getInstance(); + } + + @Bean + public ItemVersionAdaptorFactory itemVersionAdaptorFactory() { + return ItemVersionAdaptorFactory.getInstance(); + } + + @Bean + public ElementAdaptorFactory elementAdaptorFactory() { + return ElementAdaptorFactory.getInstance(); + } + + @Bean + public HealthAdaptorFactory healthAdaptorFactory() { + return HealthAdaptorFactory.getInstance(); + } +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/impl/ZusammenConnectorImpl.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/impl/ZusammenConnectorImpl.java new file mode 100644 index 0000000..5d9c749 --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/persistence/impl/ZusammenConnectorImpl.java @@ -0,0 +1,281 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.zusammen.persistence.impl; + +import com.amdocs.zusammen.adaptor.inbound.api.health.HealthAdaptorFactory; +import com.amdocs.zusammen.adaptor.inbound.api.item.ElementAdaptorFactory; +import com.amdocs.zusammen.adaptor.inbound.api.item.ItemAdaptorFactory; +import com.amdocs.zusammen.adaptor.inbound.api.item.ItemVersionAdaptorFactory; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementConflict; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ItemVersionConflict; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.MergeResult; +import com.amdocs.zusammen.commons.health.data.HealthInfo; +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.Space; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.Item; +import com.amdocs.zusammen.datatypes.item.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import com.amdocs.zusammen.datatypes.item.ItemVersionStatus; +import com.amdocs.zusammen.datatypes.item.Resolution; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import com.amdocs.zusammen.datatypes.itemversion.Tag; +import com.amdocs.zusammen.datatypes.response.Response; +import java.util.Collection; +import org.onap.sdc.common.zusammen.persistence.ZusammenConnector; +import org.onap.sdc.common.zusammen.services.exceptions.ZusammenException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class ZusammenConnectorImpl implements ZusammenConnector { + + private static final String GET_ELEMENT_ERR_MSG = + "Failed to get element. Item Id: %s, version Id: %s, element Id: %s message: %s"; + private static final String GET_ELEMENT_IN_REV_ERR_MSG = + "Failed to get element. Item Id: %s, version Id: %s, revision Id: %s, element Id: %s message: %s"; + private final ItemAdaptorFactory itemAdaptorFactory; + private final ItemVersionAdaptorFactory versionAdaptorFactory; + private final ElementAdaptorFactory elementAdaptorFactory; + private final HealthAdaptorFactory healthAdaptorFactory; + + @Autowired + public ZusammenConnectorImpl(ItemAdaptorFactory itemAdaptorFactory, ItemVersionAdaptorFactory versionAdaptorFactory, + ElementAdaptorFactory elementAdaptorFactory, HealthAdaptorFactory healthAdaptorFactory) { + this.itemAdaptorFactory = itemAdaptorFactory; + this.versionAdaptorFactory = versionAdaptorFactory; + this.elementAdaptorFactory = elementAdaptorFactory; + this.healthAdaptorFactory = healthAdaptorFactory; + } + + @Override + public Collection<HealthInfo> checkHealth(SessionContext sessionContext) { + return healthAdaptorFactory.createInterface(sessionContext).getHealthStatus(sessionContext); + } + + @Override + public String getReleaseVersion(SessionContext sessionContext) { + return healthAdaptorFactory.createInterface(sessionContext).getVersion(); + } + + @Override + public Collection<Item> listItems(SessionContext context) { + Response<Collection<Item>> response = itemAdaptorFactory.createInterface(context).list(context); + return getResponseValue(response, "list items"); + } + + @Override + public Item getItem(SessionContext context, Id itemId) { + Response<Item> response = itemAdaptorFactory.createInterface(context).get(context, itemId); + return getResponseValue(response, String.format("get item %s", itemId)); + } + + + @Override + public Id createItem(SessionContext context, Info info) { + Response<Id> response = itemAdaptorFactory.createInterface(context).create(context, info); + return getResponseValue(response, "create item"); + } + + @Override + public void deleteItem(SessionContext context, Id itemId) { + Response<Void> response = itemAdaptorFactory.createInterface(context).delete(context, itemId); + getResponseValue(response, String.format("get item %s", itemId)); + } + + @Override + public void updateItem(SessionContext context, Id itemId, Info info) { + Response<Void> response = itemAdaptorFactory.createInterface(context).update(context, itemId, info); + getResponseValue(response, String.format("update item %s", itemId)); + } + + @Override + public Collection<ItemVersion> listPublicVersions(SessionContext context, Id itemId) { + Response<Collection<ItemVersion>> response = + versionAdaptorFactory.createInterface(context).list(context, Space.PUBLIC, itemId); + return getResponseValue(response, String.format("list public versions of item %s", itemId)); + } + + @Override + public ItemVersion getPublicVersion(SessionContext context, Id itemId, Id versionId) { + Response<ItemVersion> response = + versionAdaptorFactory.createInterface(context).get(context, Space.PUBLIC, itemId, versionId); + return getResponseValue(response, String.format("get public version %s of item %s", versionId, itemId)); + } + + @Override + public Id createVersion(SessionContext context, Id itemId, Id baseVersionId, ItemVersionData itemVersionData) { + Response<Id> response = + versionAdaptorFactory.createInterface(context).create(context, itemId, baseVersionId, itemVersionData); + return getResponseValue(response, + String.format("create version for item %s based on version %s", itemId, baseVersionId)); + } + + @Override + public void updateVersion(SessionContext context, Id itemId, Id versionId, ItemVersionData itemVersionData) { + Response<Void> response = + versionAdaptorFactory.createInterface(context).update(context, itemId, versionId, itemVersionData); + getResponseValue(response, String.format("update version %s of item %s", versionId, itemId)); + } + + @Override + public ItemVersion getVersion(SessionContext context, Id itemId, Id versionId) { + Response<ItemVersion> response = + versionAdaptorFactory.createInterface(context).get(context, Space.PRIVATE, itemId, versionId); + return getResponseValue(response, String.format("get version %s of item %s", versionId, itemId)); + } + + @Override + public ItemVersionStatus getVersionStatus(SessionContext context, Id itemId, Id versionId) { + Response<ItemVersionStatus> response = + versionAdaptorFactory.createInterface(context).getStatus(context, itemId, versionId); + return getResponseValue(response, String.format("get status of version %s of item %s", versionId, itemId)); + } + + @Override + public void tagVersion(SessionContext context, Id itemId, Id versionId, Tag tag) { + Response<Void> response = + versionAdaptorFactory.createInterface(context).tag(context, itemId, versionId, null, tag); + getResponseValue(response, + String.format("tag version %s of item %s with tag %s", versionId, itemId, tag.getName())); + } + + @Override + public void resetVersionRevision(SessionContext context, Id itemId, Id versionId, Id revisionId) { + Response<Void> response = + versionAdaptorFactory.createInterface(context).resetRevision(context, itemId, versionId, revisionId); + getResponseValue(response, + String.format("reset version %s of item %s to revision %s", versionId, itemId, revisionId)); + } + + @Override + public void revertVersionRevision(SessionContext context, Id itemId, Id versionId, Id revisionId) { + Response<Void> response = + versionAdaptorFactory.createInterface(context).revertRevision(context, itemId, versionId, revisionId); + getResponseValue(response, + String.format("revert version %s of item %s to revision %s", versionId, itemId, revisionId)); + } + + @Override + public ItemVersionRevisions listVersionRevisions(SessionContext context, Id itemId, Id versionId) { + Response<ItemVersionRevisions> response = + versionAdaptorFactory.createInterface(context).listRevisions(context, itemId, versionId); + return getResponseValue(response, String.format("list revisions of version %s of item %s", versionId, itemId)); + } + + + @Override + public void publishVersion(SessionContext context, Id itemId, Id versionId, String message) { + Response<Void> response = + versionAdaptorFactory.createInterface(context).publish(context, itemId, versionId, message); + getResponseValue(response, String.format("publish version %s of item %s", versionId, itemId)); + } + + @Override + public void syncVersion(SessionContext context, Id itemId, Id versionId) { + Response<MergeResult> response = + versionAdaptorFactory.createInterface(context).sync(context, itemId, versionId); + getResponseValue(response, String.format("sync version %s of item %s", versionId, itemId)); + } + + @Override + public void forceSyncVersion(SessionContext context, Id itemId, Id versionId) { + Response<MergeResult> response = + versionAdaptorFactory.createInterface(context).forceSync(context, itemId, versionId); + getResponseValue(response, String.format("force sync version %s of item %s", versionId, itemId)); + } + + @Override + public void cleanVersion(SessionContext context, Id itemId, Id versionId) { + Response<Void> response = versionAdaptorFactory.createInterface(context).delete(context, itemId, versionId); + getResponseValue(response, String.format("clean version %s of item %s", versionId, itemId)); + } + + @Override + public ItemVersionConflict getVersionConflict(SessionContext context, Id itemId, Id versionId) { + Response<ItemVersionConflict> response = + versionAdaptorFactory.createInterface(context).getConflict(context, itemId, versionId); + return getResponseValue(response, String.format("get conflict of version %s of item %s", versionId, itemId)); + } + + @Override + public Collection<ElementInfo> listElements(SessionContext context, ElementContext elementContext, + Id parentElementId) { + Response<Collection<ElementInfo>> response = + elementAdaptorFactory.createInterface(context).list(context, elementContext, parentElementId); + return getResponseValue(response, + String.format("list elements of version %s of item %s", elementContext.getVersionId(), + elementContext.getItemId())); + } + + + @Override + public ElementInfo getElementInfo(SessionContext context, ElementContext elementContext, Id elementId) { + Response<ElementInfo> response = + elementAdaptorFactory.createInterface(context).getInfo(context, elementContext, elementId); + return getResponseValue(response, String.format("get info of element %s of version %s of item %s", elementId, + elementContext.getVersionId(), elementContext.getItemId())); + } + + @Override + public Element getElement(SessionContext context, ElementContext elementContext, Id elementId) { + Response<Element> response = + elementAdaptorFactory.createInterface(context).get(context, elementContext, elementId); + return getResponseValue(response, + String.format("get element %s of version %s of item %s", elementId, elementContext.getVersionId(), + elementContext.getItemId())); + } + + @Override + public ElementConflict getElementConflict(SessionContext context, ElementContext elementContext, Id elementId) { + Response<ElementConflict> response = + elementAdaptorFactory.createInterface(context).getConflict(context, elementContext, elementId); + return getResponseValue(response, + String.format("get conflict of element %s of version %s of item %s", elementId, + elementContext.getVersionId(), elementContext.getItemId())); + } + + @Override + public Element saveElement(SessionContext context, ElementContext elementContext, Element element, String message) { + Response<Element> response = + elementAdaptorFactory.createInterface(context).save(context, elementContext, element, message); + return getResponseValue(response, + String.format("save element %s of version %s of item %s", element.getElementId(), + elementContext.getVersionId(), elementContext.getItemId())); + } + + @Override + public void resolveElementConflict(SessionContext context, ElementContext elementContext, Element element, + Resolution resolution) { + Response<Void> response = elementAdaptorFactory.createInterface(context) + .resolveConflict(context, elementContext, element, resolution); + getResponseValue(response, + String.format("resolve conflict of element %s of version %s of item %s", element.getElementId(), + elementContext.getVersionId(), elementContext.getItemId())); + } + + private <T> T getResponseValue(Response<T> response, String action) { + if (!response.isSuccessful()) { + throw new ZusammenException(String.format("Failed to %s: %s", action, response.getReturnCode().toString())); + } + return response.getValue(); + } +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ElementConvertor.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ElementConvertor.java new file mode 100644 index 0000000..5a678ce --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ElementConvertor.java @@ -0,0 +1,15 @@ +package org.onap.sdc.common.zusammen.services; + + +import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement; + +public interface ElementConvertor<T> { + + void toElement(T source, ZusammenElement target); + + T fromElement(Element element); + + T fromElementInfo(ElementInfo element); +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ZusammenAdaptor.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ZusammenAdaptor.java new file mode 100644 index 0000000..6397726 --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ZusammenAdaptor.java @@ -0,0 +1,110 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.zusammen.services; + +import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementConflict; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ItemVersionConflict; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement; +import com.amdocs.zusammen.commons.health.data.HealthInfo; +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.Item; +import com.amdocs.zusammen.datatypes.item.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import com.amdocs.zusammen.datatypes.item.ItemVersionStatus; +import com.amdocs.zusammen.datatypes.item.Resolution; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import com.amdocs.zusammen.datatypes.itemversion.Tag; +import java.util.Collection; +import java.util.Optional; + +public interface ZusammenAdaptor { + + Collection<Item> listItems(SessionContext context); + + Item getItem(SessionContext context, Id itemId); + + void deleteItem(SessionContext context, Id itemId); + + Id createItem(SessionContext context, Info info); + + void updateItem(SessionContext context, Id itemId, Info info); + + Collection<ItemVersion> listPublicVersions(SessionContext context, Id itemId); + + ItemVersion getPublicVersion(SessionContext context, Id itemId, Id versionId); + + Id createVersion(SessionContext context, Id itemId, Id baseVersionId, ItemVersionData itemVersionData); + + void updateVersion(SessionContext context, Id itemId, Id versionId, ItemVersionData itemVersionData); + + ItemVersion getVersion(SessionContext context, Id itemId, Id versionId); + + ItemVersionStatus getVersionStatus(SessionContext context, Id itemId, Id versionId); + + ItemVersionConflict getVersionConflict(SessionContext context, Id itemId, Id versionId); + + void tagVersion(SessionContext context, Id itemId, Id versionId, Tag tag); + + void publishVersion(SessionContext context, Id itemId, Id versionId, String message); + + void syncVersion(SessionContext context, Id itemId, Id versionId); + + void forceSyncVersion(SessionContext context, Id itemId, Id versionId); + + void cleanVersion(SessionContext context, Id itemId, Id versionId); + + Optional<ElementInfo> getElementInfo(SessionContext context, ElementContext elementContext, Id elementId); + + Optional<Element> getElement(SessionContext context, ElementContext elementContext, Id elementId); + + Optional<Element> getElementByName(SessionContext context, ElementContext elementContext, Id parentElementId, + String elementName); + + Collection<ElementInfo> listElements(SessionContext context, ElementContext elementContext, Id parentElementId); + + Collection<Element> listElementData(SessionContext context, ElementContext elementContext, Id parentElementId); + + /** + * Lists the sub elements of the element named elementName which is a sub element of + * parentElementId + */ + Collection<ElementInfo> listElementsByName(SessionContext context, ElementContext elementContext, + Id parentElementId, String elementName); + + Optional<ElementInfo> getElementInfoByName(SessionContext context, ElementContext elementContext, + Id parentElementId, String elementName); + + Optional<ElementConflict> getElementConflict(SessionContext context, ElementContext elementContext, Id elementId); + + Element saveElement(SessionContext context, ElementContext elementContext, ZusammenElement element, String message); + + void resolveElementConflict(SessionContext context, ElementContext elementContext, ZusammenElement element, + Resolution resolution); + + void revert(SessionContext context, Id itemId, Id versionId, Id revisionId); + + ItemVersionRevisions listRevisions(SessionContext context, Id itemId, Id versionId); + + Collection<HealthInfo> checkHealth(SessionContext context); + + String getReleaseVersion(SessionContext context); +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ZusammenElementUtil.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ZusammenElementUtil.java new file mode 100644 index 0000000..c083ea4 --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/ZusammenElementUtil.java @@ -0,0 +1,27 @@ +package org.onap.sdc.common.zusammen.services; + +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement; +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.item.Action; +import com.amdocs.zusammen.datatypes.item.Info; + +public class ZusammenElementUtil { + + public static final String ELEMENT_TYPE_PROPERTY = "elementType"; + + public static ZusammenElement buildStructuralElement(String elementType, Action action) { + ZusammenElement element = buildElement(null, action); + Info info = new Info(); + info.setName(elementType); + info.addProperty(ELEMENT_TYPE_PROPERTY, elementType); + element.setInfo(info); + return element; + } + + public static ZusammenElement buildElement(Id elementId, Action action) { + ZusammenElement element = new ZusammenElement(); + element.setElementId(elementId); + element.setAction(action); + return element; + } +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/exceptions/ZusammenException.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/exceptions/ZusammenException.java new file mode 100644 index 0000000..4e7f06f --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/exceptions/ZusammenException.java @@ -0,0 +1,8 @@ +package org.onap.sdc.common.zusammen.services.exceptions; + +public class ZusammenException extends RuntimeException { + + public ZusammenException(String message) { + super(message); + } +} diff --git a/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/impl/ZusammenAdaptorImpl.java b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/impl/ZusammenAdaptorImpl.java new file mode 100644 index 0000000..1624e49 --- /dev/null +++ b/zusammen-lib/src/main/java/org/onap/sdc/common/zusammen/services/impl/ZusammenAdaptorImpl.java @@ -0,0 +1,277 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.zusammen.services.impl; + +import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementConflict; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ItemVersionConflict; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement; +import com.amdocs.zusammen.commons.health.data.HealthInfo; +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Action; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.Item; +import com.amdocs.zusammen.datatypes.item.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import com.amdocs.zusammen.datatypes.item.ItemVersionStatus; +import com.amdocs.zusammen.datatypes.item.Resolution; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import com.amdocs.zusammen.datatypes.itemversion.Tag; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.onap.sdc.common.zusammen.persistence.ZusammenConnector; +import org.onap.sdc.common.zusammen.services.ZusammenAdaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ZusammenAdaptorImpl implements ZusammenAdaptor { + + private final ZusammenConnector connector; + + @Autowired + public ZusammenAdaptorImpl(ZusammenConnector connector) { + this.connector = connector; + } + + @Override + public Optional<ElementInfo> getElementInfo(SessionContext context, ElementContext elementContext, Id elementId) { + return Optional.ofNullable(connector.getElementInfo(context, elementContext, elementId)); + } + + @Override + public Optional<Element> getElement(SessionContext context, ElementContext elementContext, Id elementId) { + return Optional.ofNullable(connector.getElement(context, elementContext, elementId)); + } + + @Override + public Optional<Element> getElementByName(SessionContext context, ElementContext elementContext, Id parentElementId, + String elementName) { + Collection<ElementInfo> elementInfos = connector.listElements(context, elementContext, parentElementId); + Predicate<ElementInfo> elementInfoPredicate = + elementInfo -> elementInfo.getInfo() != null && elementName.equals(elementInfo.getInfo().getName()); + return getFirstElementInfo(elementInfos, elementInfoPredicate) + .flatMap(elementInfo -> getElement(context, elementContext, elementInfo.getId())); + } + + @Override + public Collection<ElementInfo> listElements(SessionContext context, ElementContext elementContext, + Id parentElementId) { + return connector.listElements(context, elementContext, parentElementId); + } + + @Override + public Collection<Element> listElementData(SessionContext context, ElementContext elementContext, + Id parentElementId) { + Collection<ElementInfo> elementInfoList = connector.listElements(context, elementContext, parentElementId); + + return elementInfoList == null ? new ArrayList<>() : elementInfoList.stream().map(elementInfo -> connector + .getElement( + context, + elementContext, + elementInfo + .getId())) + .collect(Collectors.toList()); + } + + + @Override + public Collection<ElementInfo> listElementsByName(SessionContext context, ElementContext elementContext, + Id parentElementId, String elementName) { + Optional<ElementInfo> elementInfoByName = + getElementInfoByName(context, elementContext, parentElementId, elementName); + + return elementInfoByName.isPresent() ? + connector.listElements(context, elementContext, elementInfoByName.get().getId()) : + new ArrayList<>(); + } + + @Override + public Optional<ElementInfo> getElementInfoByName(SessionContext context, ElementContext elementContext, + Id parentElementId, String elementName) { + Collection<ElementInfo> elementInfos = connector.listElements(context, elementContext, parentElementId); + return getFirstElementInfo(elementInfos, + elementInfo -> elementInfo.getInfo() != null && elementName.equals(elementInfo.getInfo().getName())); + } + + @Override + public Optional<ElementConflict> getElementConflict(SessionContext context, ElementContext elementContext, + Id elementId) { + return Optional.ofNullable(connector.getElementConflict(context, elementContext, elementId)); + } + + @Override + public Element saveElement(SessionContext context, ElementContext elementContext, ZusammenElement element, + String message) { + enrichElementHierarchyRec(context, elementContext, null, element); + return connector.saveElement(context, elementContext, element, message); + } + + @Override + public void resolveElementConflict(SessionContext context, ElementContext elementContext, ZusammenElement element, + Resolution resolution) { + connector.resolveElementConflict(context, elementContext, element, resolution); + } + + private void enrichElementHierarchyRec(SessionContext context, ElementContext elementContext, Id parentElementId, + ZusammenElement element) { + if (element.getAction() == Action.CREATE) { + return; + } + locateElementAndUpdateAction(context, elementContext, parentElementId, element); + element.getSubElements().forEach( + subElement -> enrichElementHierarchyRec(context, elementContext, element.getElementId(), + (ZusammenElement) subElement)); + } + + // should be applied only for structural elements + private void locateElementAndUpdateAction(SessionContext context, ElementContext elementContext, Id parentElementId, + ZusammenElement element) { + if (element.getElementId() != null) { + return; + } + if (element.getInfo() == null || element.getInfo().getName() == null) { + throw new IllegalArgumentException("When saving element to zusammen - its Id or name must be supplied"); + } + Optional<ElementInfo> elementInfo = + getElementInfoByName(context, elementContext, parentElementId, element.getInfo().getName()); + if (elementInfo.isPresent()) { + element.setElementId(elementInfo.get().getId()); + if (element.getAction() == null) { + element.setAction(Action.IGNORE); + } + } else { + element.setAction(Action.CREATE); + } + } + + private Optional<ElementInfo> getFirstElementInfo(Collection<ElementInfo> elementInfos, + Predicate<ElementInfo> elementInfoPredicate) { + return elementInfos.stream().filter(elementInfoPredicate).findFirst(); + } + + @Override + public Collection<Item> listItems(SessionContext context) { + return connector.listItems(context); + } + + @Override + public Item getItem(SessionContext context, Id itemId) { + return connector.getItem(context, itemId); + } + + @Override + public Id createItem(SessionContext context, Info info) { + return connector.createItem(context, info); + } + + @Override + public void deleteItem(SessionContext context, Id itemId) { + connector.deleteItem(context, itemId); + } + + @Override + public void updateItem(SessionContext context, Id itemId, Info info) { + connector.updateItem(context, itemId, info); + } + + @Override + public Collection<ItemVersion> listPublicVersions(SessionContext context, Id itemId) { + return connector.listPublicVersions(context, itemId); + } + + @Override + public ItemVersion getPublicVersion(SessionContext context, Id itemId, Id versionId) { + return connector.getPublicVersion(context, itemId, versionId); + } + + @Override + public ItemVersion getVersion(SessionContext context, Id itemId, Id versionId) { + return connector.getVersion(context, itemId, versionId); + } + + @Override + public ItemVersionStatus getVersionStatus(SessionContext context, Id itemId, Id versionId) { + return connector.getVersionStatus(context, itemId, versionId); + } + + @Override + public ItemVersionConflict getVersionConflict(SessionContext context, Id itemId, Id versionId) { + return connector.getVersionConflict(context, itemId, versionId); + } + + @Override + public Id createVersion(SessionContext context, Id itemId, Id baseVersionId, ItemVersionData itemVersionData) { + return connector.createVersion(context, itemId, baseVersionId, itemVersionData); + } + + @Override + public void updateVersion(SessionContext context, Id itemId, Id versionId, ItemVersionData itemVersionData) { + connector.updateVersion(context, itemId, versionId, itemVersionData); + } + + @Override + public void tagVersion(SessionContext context, Id itemId, Id versionId, Tag tag) { + connector.tagVersion(context, itemId, versionId, tag); + } + + @Override + public void publishVersion(SessionContext context, Id itemId, Id versionId, String message) { + connector.publishVersion(context, itemId, versionId, message); + } + + @Override + public void syncVersion(SessionContext context, Id itemId, Id versionId) { + connector.syncVersion(context, itemId, versionId); + } + + @Override + public void forceSyncVersion(SessionContext context, Id itemId, Id versionId) { + connector.forceSyncVersion(context, itemId, versionId); + } + + @Override + public void cleanVersion(SessionContext context, Id itemId, Id versionId) { + connector.cleanVersion(context, itemId, versionId); + } + + @Override + public void revert(SessionContext context, Id itemId, Id versionId, Id revisionId) { + connector.revertVersionRevision(context, itemId, versionId, revisionId); + } + + @Override + public ItemVersionRevisions listRevisions(SessionContext context, Id itemId, Id versionId) { + return connector.listVersionRevisions(context, itemId, versionId); + } + + @Override + public Collection<HealthInfo> checkHealth(SessionContext context) { + return connector.checkHealth(context); + } + + @Override + public String getReleaseVersion(SessionContext context) { + return connector.getReleaseVersion(context); + } +} diff --git a/zusammen-lib/src/test/java/org/onap/sdc/common/zusammen/services/impl/ZusammenAdaptorImplTest.java b/zusammen-lib/src/test/java/org/onap/sdc/common/zusammen/services/impl/ZusammenAdaptorImplTest.java new file mode 100644 index 0000000..a6ddbc5 --- /dev/null +++ b/zusammen-lib/src/test/java/org/onap/sdc/common/zusammen/services/impl/ZusammenAdaptorImplTest.java @@ -0,0 +1,315 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.onap.sdc.common.zusammen.services.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo; +import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement; +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Action; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.Info; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.sdc.common.zusammen.persistence.ZusammenConnector; + +public class ZusammenAdaptorImplTest { + + private static final SessionContext CONTEXT = new SessionContext(); + private static final ElementContext ELEMENT_CONTEXT = new ElementContext(); + private static final Id ELEMENT_ID = new Id("elementId 0"); + private static final List<ElementInfo> ELEMENTS = + Arrays.asList(createElementInfo("elementId1", "element1"), createElementInfo("elementId2", "element2"), + createElementInfo("elementId3", "element3")); + + @Mock + private ZusammenConnector connector; + @InjectMocks + private ZusammenAdaptorImpl zusammenAdaptor; + @Captor + private ArgumentCaptor<Element> savedElementArg; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void getEmptyWhenElementNameNotExist() { + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + Optional<Element> element = + zusammenAdaptor.getElementByName(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID, "nonExistingName"); + + assertFalse(element.isPresent()); + } + + @Test + public void getEmptyInfoWhenElementNameNotExist() { + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + Optional<ElementInfo> elementInfo = + zusammenAdaptor.getElementInfoByName(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID, "nonExistingName"); + + assertFalse(elementInfo.isPresent()); + } + + @Test + public void getElementWhenItsNameExist() { + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + ZusammenElement returnedElement = new ZusammenElement(); + doReturn(returnedElement).when(connector).getElement(CONTEXT, ELEMENT_CONTEXT, ELEMENTS.get(1).getId()); + + Optional<Element> element = zusammenAdaptor.getElementByName(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID, "element2"); + + assertTrue(element.isPresent()); + assertEquals(returnedElement, element.get()); + } + + @Test + public void getElementInfoWhenItsNameExist() { + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + Optional<ElementInfo> elementInfo = + zusammenAdaptor.getElementInfoByName(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID, "element2"); + + assertTrue(elementInfo.isPresent()); + assertEquals(ELEMENTS.get(1), elementInfo.get()); + + } + + @Test + public void listElementsWhenTheirParentIdExist() { + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + List<ZusammenElement> returnedElements = + Arrays.asList(new ZusammenElement(), new ZusammenElement(), new ZusammenElement()); + doReturn(returnedElements.get(0)).when(connector).getElement(CONTEXT, ELEMENT_CONTEXT, ELEMENTS.get(0).getId()); + doReturn(returnedElements.get(1)).when(connector).getElement(CONTEXT, ELEMENT_CONTEXT, ELEMENTS.get(1).getId()); + doReturn(returnedElements.get(2)).when(connector).getElement(CONTEXT, ELEMENT_CONTEXT, ELEMENTS.get(2).getId()); + + Collection<Element> elements = zusammenAdaptor.listElementData(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + assertEquals(returnedElements, elements); + } + + @Test + public void getEmptyListWhenParentElementNameNotExist() { + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + Collection<ElementInfo> elements = + zusammenAdaptor.listElementsByName(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID, "nonExistingName"); + + assertTrue(elements.isEmpty()); + } + + @Test + public void listElementsInfoWhenTheirParentElementNameExist() { + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + List<ElementInfo> returnedElements = Arrays.asList(new ElementInfo(), new ElementInfo()); + doReturn(returnedElements).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENTS.get(1).getId()); + + Collection<ElementInfo> elements = + zusammenAdaptor.listElementsByName(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID, "element2"); + + assertEquals(returnedElements, elements); + } + + @Test(expected = IllegalArgumentException.class) + public void failWhenSavingElementWithoutIdNameOrAction() { + zusammenAdaptor.saveElement(CONTEXT, ELEMENT_CONTEXT, new ZusammenElement(), "Illegal element save"); + } + + @Test + public void saveElementAsRootWhenParentIdNotSupplied() { + String message = "Create new element tree"; + ZusammenElement element = new ZusammenElement(); + element.setAction(Action.CREATE); + + ZusammenElement subElement = new ZusammenElement(); + subElement.setAction(Action.CREATE); + element.addSubElement(subElement); + + testSaveElement(message, element); + + verify(connector).saveElement(CONTEXT, ELEMENT_CONTEXT, element, message); + } + + @Test + public void saveElementAsSubWhenParentIdSupplied() { + String message = "Create sub element"; + ZusammenElement element = new ZusammenElement(); + element.setAction(Action.IGNORE); + element.setElementId(ELEMENT_ID); + + ZusammenElement subElement = new ZusammenElement(); + subElement.setAction(Action.CREATE); + element.addSubElement(subElement); + + testSaveElement(message, element); + + verify(connector).saveElement(CONTEXT, ELEMENT_CONTEXT, element, message); + } + + @Test + public void saveElementWhenItsIdSupplied() { + String message = "Update element"; + ZusammenElement element = new ZusammenElement(); + element.setAction(Action.UPDATE); + element.setElementId(new Id("id")); + + testSaveElement(message, element); + + verify(connector).saveElement(CONTEXT, ELEMENT_CONTEXT, element, message); + } + + @Test + public void saveRootElementWhenItsNameSupplied() { + String message = "Update element"; + ZusammenElement element = new ZusammenElement(); + element.setAction(Action.UPDATE); + element.setInfo(ELEMENTS.get(1).getInfo()); + + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, null); + + testSaveElement(message, element); + + verify(connector).saveElement(eq(CONTEXT), eq(ELEMENT_CONTEXT), savedElementArg.capture(), eq(message)); + + Element savedElement = savedElementArg.getValue(); + assertEquals(element, savedElement); + assertNotNull(savedElement.getElementId()); + } + + @Test + public void saveElementWhenItsNameAndParentIdSupplied() { + String message = "Update existing element"; + ZusammenElement element = new ZusammenElement(); + element.setAction(Action.IGNORE); + element.setElementId(ELEMENT_ID); + + ZusammenElement existingSub = new ZusammenElement(); + existingSub.setAction(Action.UPDATE); + existingSub.setInfo(ELEMENTS.get(2).getInfo()); + element.addSubElement(existingSub); + + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + testSaveElement(message, element); + + verify(connector).saveElement(eq(CONTEXT), eq(ELEMENT_CONTEXT), savedElementArg.capture(), eq(message)); + + Element savedElement = savedElementArg.getValue(); + assertEquals(element, savedElement); + + Element updated = savedElement.getSubElements().iterator().next(); + assertNotNull(updated.getElementId()); + assertEquals(Action.UPDATE, updated.getAction()); + } + + @Test + public void saveElementWithCreateActionInsteadOfUpdateWhenItDoesNotExist() { + String message = "Create new element"; + ZusammenElement element = new ZusammenElement(); + element.setAction(Action.IGNORE); + element.setElementId(ELEMENT_ID); + + ZusammenElement nonExistingSub = new ZusammenElement(); + nonExistingSub.setAction(Action.UPDATE); + Info info = new Info(); + info.setName("nonExistingName"); + nonExistingSub.setInfo(info); + + element.addSubElement(nonExistingSub); + + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + testSaveElement(message, element); + + verify(connector).saveElement(eq(CONTEXT), eq(ELEMENT_CONTEXT), savedElementArg.capture(), eq(message)); + + Element savedElement = savedElementArg.getValue(); + assertEquals(element, savedElement); + + Element created = savedElement.getSubElements().iterator().next(); + assertNull(created.getElementId()); + assertEquals(Action.CREATE, created.getAction()); + } + + @Test + public void saveElementWithIgnoreActionWhenItExistAndActionNotSupplied() { + String message = "save existing element"; + ZusammenElement element = new ZusammenElement(); + element.setAction(Action.IGNORE); + element.setElementId(ELEMENT_ID); + + ZusammenElement existingSub = new ZusammenElement(); + existingSub.setInfo(ELEMENTS.get(2).getInfo()); + element.addSubElement(existingSub); + + doReturn(ELEMENTS).when(connector).listElements(CONTEXT, ELEMENT_CONTEXT, ELEMENT_ID); + + testSaveElement(message, element); + + verify(connector).saveElement(eq(CONTEXT), eq(ELEMENT_CONTEXT), savedElementArg.capture(), eq(message)); + + Element savedElement = savedElementArg.getValue(); + assertEquals(element, savedElement); + + Element ignored = savedElement.getSubElements().iterator().next(); + assertNotNull(ignored.getElementId()); + assertEquals(Action.IGNORE, ignored.getAction()); + } + + private void testSaveElement(String message, ZusammenElement element) { + ZusammenElement returnedElement = new ZusammenElement(); + doReturn(returnedElement).when(connector).saveElement(CONTEXT, ELEMENT_CONTEXT, element, message); + + Element saved = zusammenAdaptor.saveElement(CONTEXT, ELEMENT_CONTEXT, element, message); + + assertEquals(returnedElement, saved); + } + + private static ElementInfo createElementInfo(String id, String name) { + ElementInfo elementInfo = new ElementInfo(); + elementInfo.setId(new Id(id)); + Info info = new Info(); + info.setName(name); + elementInfo.setInfo(info); + return elementInfo; + } +}
\ No newline at end of file |