Add versioning, session and zusammen libs
Issue-ID: SDC-2486
Signed-off-by: talig <talig@amdocs.com>
Change-Id: I848edbcb84f424f949b646df04f04fa66d0f3bd2
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
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..fc2333b
--- /dev/null
+++ b/pom.xml
@@ -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