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 &mdash; Cassandra hostname or IP address.
+
+- CS_PORT &mdash; Cassandra Thrift client port. If not specified, the default of 9160 will be used.
+
+- CS_AUTHENTICATE &mdash; whether password authentication must be used to connect to Cassandra. A *false* will be
+assumed if this variable is not specified.
+
+- CS_USER &mdash; Cassandra username if CS_AUTHENTICATE is *true*.
+
+- CS_PASSWORD &mdash; 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 &mdash; 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 &mdash; SSL key password if SERVER_SSL_ENABLED is *true*.
+
+- SERVER_SSL_KEYSTORE_PATH &mdash; SSL Keystore path if SERVER_SSL_ENABLED is *true*.
+
+- SERVER_SSL_KEYSTORE_TYPE &mdash; SSL Keystore type if SERVER_SSL_ENABLED is *true*.
+
+- CS_HOSTS &mdash; comma-separated list of Cassandra hostnames or IP addresses.
+
+- CS_PORT &mdash; CQL native client port. If not specified, the default of 9042 will be used.
+
+- CS_AUTHENTICATE &mdash; whether password authentication must be used to connect to Cassandra. A *false* will be
+assumed if this variable is not specified.
+
+- CS_USER &mdash; Cassandra username if CS_AUTHENTICATE is *true*.
+
+- CS_PASSWORD &mdash; Cassandra password if CS_AUTHENTICATE is *true*.
+
+- CS_SSL_ENABLED &mdash; 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 &mdash; Cassandra Truststore path if CS_SSL_ENABLED is *true*.
+
+- CS_TRUST_STORE_PASSWORD &mdash; Cassandra Truststore password if CS_SSL_ENABLED is *true*.
+
+- TRANSLATION_PROTOCOL &mdash; protocol to be used for calling Translation APIs (http or https).
+
+- TRANSLATION_HOST &mdash;  a Translation server.
+
+- TRANSLATION_PORT &mdash;  a Translation server port, usually 8080.
+
+- SDC_PROTOCOL &mdash; protocol to be used for calling SDC APIs (http or https).
+
+- SDC_HOST &mdash;  a SDC backend server.
+
+- SDC_PORT &mdash;  a SDC backend server port, usually 8080.
+
+- SDC_USER &mdash; Onboarding consumer username
+
+- SDC_PASSWORD &mdash; Onboarding consumer password
+
+- JAVA_OPTIONS &mdash; 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 &mdash; root endpoint of the RESTful APIs exposed by a backend server.
+
+- JAVA_OPTIONS &mdash; 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