diff options
Diffstat (limited to 'openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin')
62 files changed, 5414 insertions, 683 deletions
diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml index fba7d568e3..f8cfcfdc9b 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml @@ -33,5 +33,32 @@ <artifactId>zusammen-state-store-cassandra-plugin</artifactId> <version>${zusammen-state-store.version}</version> </dependency> + <dependency> + <groupId>org.testng</groupId> + <artifactId>testng</artifactId> + <version>${testng.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <version>${mockito.all.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.amdocs.zusammen</groupId> + <artifactId>zusammen-commons-utils</artifactId> + <version>${zusammen.version}</version> + </dependency> + <dependency> + <groupId>org.openecomp.sdc.core</groupId> + <artifactId>openecomp-facade-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.openecomp.sdc.core</groupId> + <artifactId>openecomp-session-lib</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> </project> diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/ZusammenPluginUtil.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/ZusammenPluginUtil.java index 59afa70e9a..a973590eb5 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/ZusammenPluginUtil.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/ZusammenPluginUtil.java @@ -19,13 +19,30 @@ package org.openecomp.core.zusammen.plugin; import com.amdocs.zusammen.datatypes.Id; import com.amdocs.zusammen.datatypes.SessionContext; import com.amdocs.zusammen.datatypes.Space; -import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import com.amdocs.zusammen.datatypes.item.Action; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionChange; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import com.amdocs.zusammen.datatypes.item.ItemVersionDataConflict; import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElement; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElementChange; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElementConflict; +import com.amdocs.zusammen.sdk.state.types.StateElement; +import com.amdocs.zusammen.sdk.types.ElementDescriptor; import com.amdocs.zusammen.utils.fileutils.FileUtils; +import com.amdocs.zusammen.utils.fileutils.json.JsonUtil; import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Date; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID; public class ZusammenPluginUtil { @@ -34,7 +51,7 @@ public class ZusammenPluginUtil { case PUBLIC: return ZusammenPluginConstants.PUBLIC_SPACE; case PRIVATE: - return ZusammenPluginUtil.getPrivateSpaceName(context); + return getPrivateSpaceName(context); default: throw new IllegalArgumentException(String.format("Space %s is not supported.", space)); } @@ -44,14 +61,54 @@ public class ZusammenPluginUtil { return context.getUser().getUserName(); } - public static ElementEntity getElementEntity(CollaborationElement element) { + public static ElementContext getPrivateElementContext(ElementContext elementContext) { + return new ElementContext(elementContext.getItemId(),elementContext.getVersionId(),Id.ZERO); + } + + + public static VersionEntity convertToVersionEntity(Id versionId, Id baseVersionId, + Date creationTime, + Date modificationTime) { + + return convertToVersionEntity(versionId, null, baseVersionId, + creationTime, modificationTime); + } + + public static VersionEntity convertToVersionEntity(Id versionId, Id revisionId, Id baseVersionId, + Date creationTime, + Date modificationTime) { + VersionEntity version = new VersionEntity(versionId); + version.setBaseId(baseVersionId); + version.setCreationTime(creationTime); + version.setModificationTime(modificationTime); + return version; + } + + public static ItemVersion convertToItemVersion(VersionEntity versionEntity, + ItemVersionData itemVersionData) { + ItemVersion itemVersion = new ItemVersion(); + itemVersion.setId(versionEntity.getId()); + + itemVersion.setBaseId(versionEntity.getBaseId()); + itemVersion.setCreationTime(versionEntity.getCreationTime()); + itemVersion.setModificationTime(versionEntity.getModificationTime()); + itemVersion.setData(itemVersionData); + return itemVersion; + } + + public static ElementEntity convertToElementEntity(CollaborationElement element) { + ElementEntity elementEntity = new ElementEntity(element.getId()); elementEntity.setNamespace(element.getNamespace()); elementEntity.setParentId(element.getParentId() == null - ? ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID + ? ROOT_ELEMENTS_PARENT_ID : element.getParentId()); + + elementEntity.setInfo(element.getInfo()); + elementEntity.setRelations(element.getRelations()); + if (element.getData() != null) { elementEntity.setData(ByteBuffer.wrap(FileUtils.toByteArray(element.getData()))); } @@ -63,21 +120,29 @@ public class ZusammenPluginUtil { elementEntity.setVisualization( ByteBuffer.wrap(FileUtils.toByteArray(element.getVisualization()))); } + elementEntity.setElementHash(new Id(calculateElementHash(elementEntity))); + return elementEntity; } - public static CollaborationElement getCollaborationElement( - ElementEntityContext elementEntityContext, ElementEntity elementEntity) { - Id parentId = - ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID.equals(elementEntity.getParentId()) - ? null - : elementEntity.getParentId(); - CollaborationElement element = new CollaborationElement(elementEntityContext.getItemId(), - elementEntityContext.getVersionId(), elementEntity.getNamespace(), elementEntity.getId()); + public static ElementDescriptor convertToElementDescriptor( + ElementContext elementContext, ElementEntity elementEntity) { + if (elementEntity == null) { + return null; + } + ElementDescriptor element = new ElementDescriptor(elementContext.getItemId(), + elementContext.getVersionId(), elementEntity.getNamespace(), elementEntity.getId()); - element.setParentId(parentId); - element.setInfo(elementEntity.getInfo()); - element.setRelations(elementEntity.getRelations()); + mapElementEntityToDescriptor(elementEntity, element); + return element; + } + + public static CollaborationElement convertToCollaborationElement( + ElementContext elementContext, ElementEntity elementEntity) { + CollaborationElement element = new CollaborationElement(elementContext.getItemId(), + elementContext.getVersionId(), elementEntity.getNamespace(), elementEntity.getId()); + + mapElementEntityToDescriptor(elementEntity, element); if (elementEntity.getData() != null) { element.setData(new ByteArrayInputStream(elementEntity.getData().array())); @@ -89,7 +154,134 @@ public class ZusammenPluginUtil { if (elementEntity.getVisualization() != null) { element.setVisualization(new ByteArrayInputStream(elementEntity.getVisualization().array())); } + return element; + } + + public static CollaborationElementChange convertToElementChange( + ElementContext changedElementContext, ElementEntity changedElement, Action action) { + CollaborationElementChange elementChange = new CollaborationElementChange(); + elementChange.setElement(convertToCollaborationElement(changedElementContext, changedElement)); + elementChange.setAction(action); + return elementChange; + } + + public static ItemVersionChange convertToVersionChange(ElementContext elementContext, + ElementEntity versionDataElement, + Action action) { + ItemVersionChange versionChange = new ItemVersionChange(); + + ItemVersion itemVersion = new ItemVersion(); + itemVersion.setId(elementContext.getVersionId()); + + itemVersion.setData(convertToVersionData(versionDataElement)); + + versionChange.setItemVersion(itemVersion); + versionChange.setAction(action); + return versionChange; + } + + public static ItemVersionDataConflict getVersionConflict(ElementEntity localVesionData, + ElementEntity remoteVersionData) { + ItemVersionDataConflict versionConflict = new ItemVersionDataConflict(); + versionConflict.setLocalData(convertToVersionData(localVesionData)); + versionConflict.setRemoteData(convertToVersionData(remoteVersionData)); + return versionConflict; + } + + public static CollaborationElementConflict getElementConflict(ElementContext elementContext, + ElementEntity localElement, + ElementEntity remoteElement) { + CollaborationElementConflict elementConflict = new CollaborationElementConflict(); + elementConflict + .setLocalElement(convertToCollaborationElement(elementContext, localElement)); + elementConflict.setRemoteElement( + convertToCollaborationElement(elementContext, remoteElement)); + return elementConflict; + } + + public static ItemVersionData convertToVersionData(ElementEntity versionDataElement) { + ItemVersionData versionData = new ItemVersionData(); + versionData.setInfo(versionDataElement.getInfo()); + versionData.setRelations(versionDataElement.getRelations()); + return versionData; + } + + private static void mapElementEntityToDescriptor(ElementEntity elementEntity, + ElementDescriptor elementDescriptor) { + Id parentId = ROOT_ELEMENTS_PARENT_ID.equals(elementEntity.getParentId()) + ? null + : elementEntity.getParentId(); + + elementDescriptor.setParentId(parentId); + elementDescriptor.setInfo(elementEntity.getInfo()); + elementDescriptor.setRelations(elementEntity.getRelations()); + elementDescriptor.setSubElements(elementEntity.getSubElementIds()); + } + + public static String calculateElementHash(ElementEntity elementEntity) { + StringBuffer elementHash = new StringBuffer(); + if (elementEntity.getData() != null) { + elementHash.append(calculateSHA1(elementEntity.getData().array())); + } else { + elementHash.append("0"); + } + elementHash.append("_"); + if (elementEntity.getVisualization() != null) { + elementHash.append(calculateSHA1(elementEntity.getVisualization().array())); + } else { + elementHash.append("0"); + } + elementHash.append("_"); + + if (elementEntity.getSearchableData() != null) { + elementHash.append(calculateSHA1(elementEntity.getSearchableData().array())); + } else { + elementHash.append("0"); + } + elementHash.append("_"); + + if (elementEntity.getInfo() != null) { + elementHash.append(calculateSHA1(JsonUtil.object2Json(elementEntity.getInfo()).getBytes())); + } else { + elementHash.append("0"); + } + elementHash.append("_"); + + if (elementEntity.getRelations() != null) { + elementHash + .append(calculateSHA1(JsonUtil.object2Json(elementEntity.getRelations()).getBytes())); + } else { + elementHash.append("0"); + } + + return elementHash.toString(); + } + + private static String calculateSHA1(byte[] content2Convert) { + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + return Base64.getEncoder().encodeToString(md.digest(content2Convert)); + } + + + public static StateElement getStateElement(ElementContext elementContext, ElementEntity + elementEntity) { + Id parentId = ROOT_ELEMENTS_PARENT_ID.equals(elementEntity.getParentId()) + ? null + : elementEntity.getParentId(); + StateElement element = new StateElement(elementContext.getItemId(), + elementContext.getVersionId(), elementEntity.getNamespace(), elementEntity.getId()); + + element.setParentId(parentId); + element.setInfo(elementEntity.getInfo()); + element.setRelations(elementEntity.getRelations()); element.setSubElements(elementEntity.getSubElementIds()); return element; } + + } diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/CommitStagingService.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/CommitStagingService.java new file mode 100644 index 0000000000..45d5769e9c --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/CommitStagingService.java @@ -0,0 +1,100 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Collection; +import java.util.Optional; + +public class CommitStagingService { + + private VersionPrivateStore versionPrivateStore; + private VersionStageStore versionStageStore; + private ElementPrivateStore elementPrivateStore; + private ElementStageStore elementStageStore; + + public CommitStagingService(VersionPrivateStore versionPrivateStore, + VersionStageStore versionStageStore, + ElementPrivateStore elementPrivateStore, + ElementStageStore elementStageStore) { + this.versionPrivateStore = versionPrivateStore; + this.versionStageStore = versionStageStore; + this.elementPrivateStore = elementPrivateStore; + this.elementStageStore = elementStageStore; + } + + public void commitStaging(SessionContext context, Id itemId, Id versionId) { + Optional<StageEntity<VersionEntity>> versionStage = + versionStageStore.get(context, itemId, new VersionEntity(versionId)); + + final ElementContext elementContext = new ElementContext(itemId, versionId, Id.ZERO); + Collection<ElementEntity> stagedElementIds = elementStageStore.listIds(context, elementContext); + + if ((!versionStage.isPresent() && stagedElementIds.isEmpty()) || + elementStageStore.hasConflicts(context, elementContext)) { + return; + } + + versionStage.ifPresent(verStage -> commitVersionStage(context, itemId, verStage)); + commitElementsStage(context, elementContext, stagedElementIds); + } + + private void commitVersionStage(SessionContext context, Id itemId, + StageEntity<VersionEntity> versionStage) { + switch (versionStage.getAction()) { + case CREATE: + versionPrivateStore.commitStagedCreate(context, itemId, versionStage.getEntity(), + versionStage.getPublishTime()); + break; + case UPDATE: + versionPrivateStore.commitStagedUpdate(context, itemId, versionStage.getEntity(), + versionStage.getPublishTime()); + break; + case IGNORE: + versionPrivateStore.commitStagedIgnore(context, itemId, versionStage.getEntity(), + versionStage.getPublishTime()); + break; + default: + throw new UnsupportedOperationException( + "Version change other then Create/Update/Ignore is not supported"); + } + + versionStageStore.delete(context, itemId, versionStage.getEntity()); + } + + private void commitElementsStage(SessionContext context, ElementContext elementContext, + Collection<ElementEntity> stagedElementIds) { + for (ElementEntity stagedElementId : stagedElementIds) { + StageEntity<ElementEntity> stagedElement = + elementStageStore.get(context, elementContext, stagedElementId) + .orElseThrow( + () -> new IllegalStateException("Element id returned by list must exist")); + switch (stagedElement.getAction()) { + case CREATE: + elementPrivateStore.commitStagedCreate(context, elementContext, stagedElement.getEntity(), + stagedElement.getPublishTime()); + break; + case UPDATE: + elementPrivateStore.commitStagedUpdate(context, elementContext, stagedElement.getEntity(), + stagedElement.getPublishTime()); + break; + case DELETE: + elementPrivateStore + .commitStagedDelete(context, elementContext, stagedElement.getEntity()); + break; + case IGNORE: + elementPrivateStore.commitStagedIgnore(context, elementContext, stagedElement.getEntity(), + stagedElement.getPublishTime()); + break; + default: + throw new UnsupportedOperationException( + "Element change other then Create/Update/Delete/Ignore is not supported"); + } + elementStageStore.delete(context, elementContext, stagedElement.getEntity()); + } + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementCollaborationStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementCollaborationStore.java deleted file mode 100644 index ac103c0fbf..0000000000 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementCollaborationStore.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.openecomp.core.zusammen.plugin.collaboration; - -import com.amdocs.zusammen.datatypes.Id; -import com.amdocs.zusammen.datatypes.SessionContext; -import com.amdocs.zusammen.datatypes.item.ElementContext; -import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; -import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElement; -import org.openecomp.core.zusammen.plugin.ZusammenPluginConstants; -import org.openecomp.core.zusammen.plugin.ZusammenPluginUtil; -import org.openecomp.core.zusammen.plugin.dao.ElementRepository; -import org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory; -import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Optional; - -import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getCollaborationElement; -import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getSpaceName; - - -public class ElementCollaborationStore { - - private static final String SUB_ELEMENT_NOT_EXIST_ERROR_MSG = - "List sub elements error: item %s, version %s - " + - "element %s, which appears as sub element of element %s, does not exist"; - - public Collection<CollaborationElement> listElements(SessionContext context, - ElementContext elementContext, - Id elementId) { - ElementEntityContext elementEntityContext = - new ElementEntityContext(ZusammenPluginUtil.getPrivateSpaceName(context), elementContext); - - if (elementId == null) { - elementId = ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID; - } - - ElementRepository elementRepository = getElementRepository(context); - String elementIdValue = elementId.getValue(); - String versionIdValue = elementContext.getChangeRef() == null - ? elementContext.getVersionId().getValue() - : elementContext.getChangeRef(); - Collection<CollaborationElement> subElements = new ArrayList<>(); - - Optional<ElementEntity> element = - elementRepository.get(context, elementEntityContext, new ElementEntity(elementId)); - if (element.isPresent() && element.get().getSubElementIds() != null) { - for (Id subElementId : element.get().getSubElementIds()) { - ElementEntity subElement = - elementRepository.get(context, elementEntityContext, new ElementEntity(subElementId)) - .orElseThrow( - () -> new IllegalStateException(String.format(SUB_ELEMENT_NOT_EXIST_ERROR_MSG, - elementContext.getItemId().getValue(), versionIdValue, - subElementId.getValue(), elementIdValue))); - subElements.add(getCollaborationElement(elementEntityContext, subElement)); - } - } - return subElements; - } - - public CollaborationElement getElement(SessionContext context, ElementContext elementContext, - Id elementId) { - ElementEntityContext elementEntityContext = - new ElementEntityContext(ZusammenPluginUtil.getPrivateSpaceName(context), elementContext); - return getElementRepository(context) - .get(context, elementEntityContext, new ElementEntity(elementId)) - .map(elementEntity -> getCollaborationElement(elementEntityContext, elementEntity)) - .orElse(null); - } - - public void createElement(SessionContext context, CollaborationElement element) { - getElementRepository(context) - .create(context, - new ElementEntityContext(getSpaceName(context, element.getSpace()), - element.getItemId(), element.getVersionId()), - ZusammenPluginUtil.getElementEntity(element)); - } - - public void updateElement(SessionContext context, CollaborationElement element) { - getElementRepository(context) - .update(context, - new ElementEntityContext(getSpaceName(context, element.getSpace()), - element.getItemId(), element.getVersionId()), - ZusammenPluginUtil.getElementEntity(element)); - } - - public void deleteElement(SessionContext context, CollaborationElement element) { - deleteElementHierarchy(getElementRepository(context), - context, - new ElementEntityContext(getSpaceName(context, element.getSpace()), - element.getItemId(), element.getVersionId()), - ZusammenPluginUtil.getElementEntity(element)); - } - - public boolean checkHealth(SessionContext sessionContext) { - return getElementRepository(sessionContext).checkHealth(sessionContext); - } - - private void deleteElementHierarchy(ElementRepository elementRepository, SessionContext context, - ElementEntityContext elementEntityContext, - ElementEntity elementEntity) { - Optional<ElementEntity> retrieved = - elementRepository.get(context, elementEntityContext, elementEntity); - if (!retrieved.isPresent()) { - return; - } - retrieved.get().getSubElementIds().stream() - .map(ElementEntity::new) - .forEach(subElementEntity -> deleteElementHierarchy( - elementRepository, context, elementEntityContext, subElementEntity)); - - // only for the first one the parentId will populated (so it'll be removed from its parent) - elementRepository.delete(context, elementEntityContext, elementEntity); - } - - protected ElementRepository getElementRepository(SessionContext context) { - return ElementRepositoryFactory.getInstance().createInterface(context); - } -} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementPrivateStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementPrivateStore.java new file mode 100644 index 0000000000..045def2561 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementPrivateStore.java @@ -0,0 +1,48 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.Optional; + +public interface ElementPrivateStore extends ElementStore { + + Map<Id, Id> listIds(SessionContext context, ElementContext elementContext); + + Collection<ElementEntity> listSubs(SessionContext context, ElementContext elementContext, + Id elementId); + + Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context, + ElementContext elementContext, + Id elementId); + + void create(SessionContext context, ElementContext elementContext, ElementEntity element); + + boolean update(SessionContext context, ElementContext elementContext, ElementEntity element); + + void delete(SessionContext context, ElementContext elementContext, ElementEntity element); + + void markAsPublished(SessionContext context, ElementContext elementContext, Id elementId, + Date publishTime); + + void markDeletionAsPublished(SessionContext context, ElementContext elementContext, Id elementId, + Date publishTime); + + void commitStagedCreate(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime); + + void commitStagedUpdate(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime); + + void commitStagedDelete(SessionContext context, ElementContext elementContext, + ElementEntity element); + + void commitStagedIgnore(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementPublicStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementPublicStore.java new file mode 100644 index 0000000000..0f1790a1bf --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementPublicStore.java @@ -0,0 +1,23 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; + +import java.util.Date; +import java.util.Map; + +public interface ElementPublicStore extends ElementStore { + + void create(SessionContext context, ElementContext elementContext, ElementEntity element, + Date publishTime); + + void update(SessionContext context, ElementContext elementContext, ElementEntity element, + Date publishTime); + + void delete(SessionContext context, ElementContext elementContext, ElementEntity element, + Date publishTime); + + Map<Id,Id> listIds(SessionContext context, ElementContext elementContext); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementStageStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementStageStore.java new file mode 100644 index 0000000000..a9236247f9 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementStageStore.java @@ -0,0 +1,35 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.Resolution; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; + +import java.util.Collection; +import java.util.Optional; + +public interface ElementStageStore { + + Collection<ElementEntity> listIds(SessionContext context, ElementContext elementContext); + + boolean hasConflicts(SessionContext context, ElementContext elementContext); + + Collection<StageEntity<ElementEntity>> listConflictedDescriptors(SessionContext context, + ElementContext elementContext); + + Optional<StageEntity<ElementEntity>> get(SessionContext context, ElementContext elementContext, + ElementEntity element); + + Optional<StageEntity<ElementEntity>> getConflicted(SessionContext context, + ElementContext elementContext, + ElementEntity element); + + void create(SessionContext context, ElementContext elementContext, + StageEntity<ElementEntity> elementStage); + + void delete(SessionContext context, ElementContext elementContext, ElementEntity element); + + void resolveConflict(SessionContext context, ElementContext elementContext, ElementEntity element, + Resolution resolution); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementStore.java new file mode 100644 index 0000000000..1c26a817ae --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ElementStore.java @@ -0,0 +1,20 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.Collection; +import java.util.Optional; + +public interface ElementStore { + Optional<ElementEntity> get(SessionContext context, ElementContext elementContext, Id elementId); + + Optional<ElementEntity> getDescriptor(SessionContext context, ElementContext elementContext, + Id elementId); + + Collection<SynchronizationStateEntity> listSynchronizationStates(SessionContext context, + ElementContext elementContext); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ErrorCode.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ErrorCode.java new file mode 100644 index 0000000000..3d0910072c --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/ErrorCode.java @@ -0,0 +1,5 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +public class ErrorCode { + public static final int NO_CHANGES_TO_PUBLISH = 60000; +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/Message.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/Message.java new file mode 100644 index 0000000000..2816974307 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/Message.java @@ -0,0 +1,6 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +public class Message { + public static final String NO_CHANGES_TO_PUBLISH = + "Item Id %s, version Id %s: There are no changes to publish."; +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/PublishService.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/PublishService.java new file mode 100644 index 0000000000..7b043c830f --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/PublishService.java @@ -0,0 +1,201 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +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.response.ReturnCode; +import com.amdocs.zusammen.datatypes.response.ZusammenException; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationMergeChange; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationPublishResult; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import static com.amdocs.zusammen.datatypes.response.Module.ZCSP; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToElementChange; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToVersionChange; +import static org.openecomp.core.zusammen.plugin.collaboration.ErrorCode.NO_CHANGES_TO_PUBLISH; + +public class PublishService { + // TODO: 6/29/2017 throw ZusammenException with ReturnCode when needed. + private static final String PUSH_NON_EXISTING_VERSION = + "Item Id %s, version Id %s: Non existing version cannot be pushed."; + + private VersionPublicStore versionPublicStore; + private VersionPrivateStore versionPrivateStore; + private ElementPublicStore elementPublicStore; + private ElementPrivateStore elementPrivateStore; + + public PublishService(VersionPublicStore versionPublicStore, + VersionPrivateStore versionPrivateStore, + ElementPublicStore elementPublicStore, + ElementPrivateStore elementPrivateStore) { + this.versionPublicStore = versionPublicStore; + this.versionPrivateStore = versionPrivateStore; + this.elementPublicStore = elementPublicStore; + this.elementPrivateStore = elementPrivateStore; + } + + public CollaborationPublishResult publish(SessionContext context, Id itemId, Id versionId, + String message) { + CollaborationPublishResult result = new CollaborationPublishResult(); + result.setChange(new CollaborationMergeChange()); + + Date publishTime = new Date(); + Id revisionId = new Id(UUID.randomUUID().toString()); + boolean versionFirstPublication = publishVersion(context, itemId, versionId, revisionId, + publishTime,message); + if (versionFirstPublication) { + publishAllElements(context, new ElementContext(itemId, versionId, revisionId), publishTime, + result); + } else { + publishDirtyElements(context, new ElementContext(itemId, versionId, revisionId), publishTime, + result); + } + return result; + } + + private boolean publishVersion(SessionContext context, Id itemId, Id versionId, Id revisionId, + Date publishTime, String message) { + SynchronizationStateEntity privateVersionSyncState = + versionPrivateStore.getSynchronizationState(context, itemId, versionId) + .orElseThrow(() -> new IllegalArgumentException( + String.format(PUSH_NON_EXISTING_VERSION, itemId.toString(), versionId.toString()))); + + if (!privateVersionSyncState.isDirty()) { + throw new ZusammenException(new ReturnCode(NO_CHANGES_TO_PUBLISH, ZCSP, + String.format(Message.NO_CHANGES_TO_PUBLISH, itemId, versionId), null)); + } + + Optional<SynchronizationStateEntity> publicVersionSyncState = + versionPublicStore.getSynchronizationState(context, itemId, versionId); + + // private must be synced with public (if public exists) + if (publicVersionSyncState.isPresent() && + !privateVersionSyncState.getPublishTime() + .equals(publicVersionSyncState.get().getPublishTime())) { + // should not happen as it is validated in zusammen-core + throw new UnsupportedOperationException("Out of sync item version can not be publish"); + } + + boolean versionFirstPublication; + Map<Id, Id> versionElementIds = + elementPublicStore.listIds(context, new ElementContext(itemId, + versionId)); + if (publicVersionSyncState.isPresent()) { + versionPublicStore.update(context, itemId, new VersionEntity(versionId), revisionId, + versionElementIds,publishTime,message); + versionFirstPublication = false; + } else { + VersionEntity privateVersion = versionPrivateStore.get(context, itemId, versionId) + .orElseThrow(() -> new IllegalArgumentException( + String.format(PUSH_NON_EXISTING_VERSION, itemId.toString(), versionId.toString()))); + versionPublicStore.create(context, itemId, privateVersion, revisionId,versionElementIds, + publishTime,message); + versionFirstPublication = true; + } + versionPrivateStore.markAsPublished(context, itemId, versionId, publishTime); + return versionFirstPublication; + } + + private void publishAllElements(SessionContext context, ElementContext elementContext, + Date publishTime, CollaborationPublishResult result) { + Collection<SynchronizationStateEntity> privateElementSyncStates = + elementPrivateStore.listSynchronizationStates(context, elementContext); + + for (SynchronizationStateEntity privateElementSyncState : privateElementSyncStates) { + Optional<ElementEntity> privateElement = + elementPrivateStore.get(context, elementContext, privateElementSyncState.getId()); + + if (!privateElement.isPresent()) { + continue; + } + ElementEntity elementToPublish = privateElement.get(); + + elementPublicStore.create(context, elementContext, elementToPublish, + privateElementSyncState.isDirty() ? publishTime + : privateElementSyncState.getPublishTime()); + + if (privateElementSyncState.isDirty()) { + elementPrivateStore + .markAsPublished(context, elementContext, privateElementSyncState.getId(), publishTime); + } + updateResult(elementContext, elementToPublish, Action.CREATE, + ROOT_ELEMENTS_PARENT_ID.equals(privateElementSyncState.getId()), result); + } + } + + private void publishDirtyElements(SessionContext context, ElementContext elementContext, + Date publishTime, CollaborationPublishResult result) { + + Id revisionId = elementContext.getRevisionId(); + elementContext.setRevisionId(revisionId); + ElementContext privateElementContext = new ElementContext(elementContext.getItemId(), + elementContext.getVersionId(),Id.ZERO); + Collection<SynchronizationStateEntity> privateElementSyncStates = + elementPrivateStore.listSynchronizationStates(context, elementContext); + + Collection<SynchronizationStateEntity> publicElementSyncStates = + elementPublicStore.listSynchronizationStates(context, elementContext); + + for (SynchronizationStateEntity privateElementSyncState : privateElementSyncStates) { + if (!privateElementSyncState.isDirty()) { + continue; + } + + Optional<ElementEntity> privateElement = + elementPrivateStore.get(context, privateElementContext, privateElementSyncState.getId()); + + ElementEntity elementToPublish; + Action actionOnPublic; + if (privateElement.isPresent()) { + elementToPublish = privateElement.get(); + + if (publicElementSyncStates.contains(privateElementSyncState)) { + + elementPublicStore.update(context, elementContext, elementToPublish, publishTime); + actionOnPublic = Action.UPDATE; + } else { + elementPublicStore.create(context, elementContext, elementToPublish, publishTime); + actionOnPublic = Action.CREATE; + } + + elementPrivateStore + .markAsPublished(context, privateElementContext, privateElementSyncState.getId(), publishTime); + } else { + elementToPublish = + elementPublicStore.get(context, elementContext, privateElementSyncState.getId()) + .orElseThrow(() -> new IllegalStateException( + "Element that should be deleted from public must exist there")); + elementPublicStore.delete(context, elementContext, elementToPublish, publishTime); + actionOnPublic = Action.DELETE; + + elementPrivateStore + .markDeletionAsPublished(context, privateElementContext, privateElementSyncState.getId(), + publishTime); + } + + updateResult(elementContext, elementToPublish, actionOnPublic, + ROOT_ELEMENTS_PARENT_ID.equals(privateElementSyncState.getId()), result); + } + } + + private void updateResult(ElementContext elementContext, ElementEntity element, + Action action, boolean versionDataElement, + CollaborationPublishResult result) { + if (versionDataElement) { + result.getChange().setChangedVersion(convertToVersionChange(elementContext, element, action)); + } else { + result.getChange().getChangedElements() + .add(convertToElementChange(elementContext, element, action)); + } + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/RevertService.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/RevertService.java new file mode 100644 index 0000000000..0d2ea2c0d8 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/RevertService.java @@ -0,0 +1,161 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class RevertService { + + private ElementPublicStore elementPublicStore; + private ElementPrivateStore elementPrivateStore; + + public RevertService(ElementPublicStore elementPublicStore, + ElementPrivateStore elementPrivateStore) { + this.elementPublicStore = elementPublicStore; + this.elementPrivateStore = elementPrivateStore; + } + + public void revert(SessionContext context, Id itemId, Id versionId, Id revisionId) { + ElementContext targetContext = new ElementContext(itemId, versionId); + ElementContext sourceContext = new ElementContext(itemId, versionId, revisionId); + copyElementsFromPublic(context, sourceContext, targetContext); + } + + private void copyElementsFromPublic(SessionContext context, ElementContext sourceContext, + ElementContext targetContext) { + Collection<RevertElementAction> revertElementActions = + evaluateRevertElementActions(context, sourceContext, targetContext); + + revertElementActions.forEach(revertElementAction -> revertElementAction.run(context)); + } + + private Collection<RevertElementAction> evaluateRevertElementActions(SessionContext context, + ElementContext sourceContext, + ElementContext targetContext) { + + Map<Id, Id> sourceElements = elementPublicStore.listIds(context, sourceContext); + Map<Id, Id> targetPublicElements = elementPublicStore.listIds(context, targetContext); + Collection<SynchronizationStateEntity> synchronizationStateEntities = + elementPrivateStore.listSynchronizationStates(context, targetContext); + + Map<Id, Id> targetElements = + evaluateTargetElements(targetPublicElements, synchronizationStateEntities); + + + Collection<RevertElementAction> revertElementActions = new ArrayList<>(); + + sourceElements.entrySet().forEach(entry -> { + Id sourceElementId = entry.getKey(); + Id sourceElementRevisionId = entry.getValue(); + + if (!targetElements.containsKey(sourceElementId)) { + revertElementActions + .add(new RevertElementAction(sourceContext, sourceElementId, commands[CREATE])); + } else if (!targetElements.get(sourceElementId).equals(sourceElementRevisionId)) { + revertElementActions + .add(new RevertElementAction(sourceContext, sourceElementId, commands[UPDATE])); + } + }); + + targetElements.entrySet().forEach(entry -> { + Id targetElementId = entry.getKey(); + if (!sourceElements.containsKey(targetElementId)) { + revertElementActions + .add(new RevertElementAction(targetContext, targetElementId, commands[DELETE])); + } + }); + + return revertElementActions; + } + + private Map<Id, Id> evaluateTargetElements(Map<Id, Id> targetPublicElements, + Collection<SynchronizationStateEntity> syncStates) { + Map<Id, Id> targetElements = new HashMap<>(targetPublicElements); + syncStates.stream() + .filter(SynchronizationStateEntity::isDirty) + .forEach(syncState -> targetElements.put(syncState.getId(), Id.ZERO)); + return targetElements; + } + + private static class RevertElementAction { + private ElementContext elementContext; + private Id elementId; + private ActionCommand command; + + private RevertElementAction(ElementContext elementContext, Id elementId, + ActionCommand command) { + this.elementContext = elementContext; + this.elementId = elementId; + this.command = command; + } + + public ElementContext getElementContext() { + return elementContext; + } + + public Id getElementId() { + return elementId; + } + + public void run(SessionContext context) { + command.run(context, elementContext, elementId); + } + } + + private interface ActionCommand { + void run(SessionContext context, ElementContext elementContext, Id elementId); + } + + private static int CREATE = 0; + private static int UPDATE = 1; + private static int DELETE = 2; + + private ActionCommand[] commands = {new ActionCommand() { + @Override + public void run(SessionContext context, ElementContext elementContext, Id elementId) { + //create + Optional<ElementEntity> element = elementPublicStore.get(context, elementContext, elementId); + if (!element.isPresent()) { + throw getMissingElementException(elementContext, elementId); + } + elementPrivateStore.create(context, elementContext, element.get()); + } + }, new ActionCommand() { + @Override + public void run(SessionContext context, ElementContext elementContext, Id elementId) { + //update + Optional<ElementEntity> element = elementPublicStore.get(context, elementContext, elementId); + if (!element.isPresent()) { + throw getMissingElementException(elementContext, elementId); + } + elementPrivateStore.update(context, elementContext, element.get()); + } + }, new ActionCommand() { + @Override + public void run(SessionContext context, ElementContext elementContext, Id elementId) { + //delete + Optional<ElementEntity> element = elementPrivateStore.get(context, elementContext, elementId); + if (!element.isPresent()) { + return; // deleted by parent when hierarchy was deleted + } + elementPrivateStore.delete(context, elementContext, element.get()); + } + }}; + + private RuntimeException getMissingElementException(ElementContext elementContext, + Id elementId) { + return new IllegalStateException( + String.format("Item Id %s, version Id %s, revision Id %s: Missing element with Id %s", + elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue(), elementId.getValue()) + ); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/SyncService.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/SyncService.java new file mode 100644 index 0000000000..04a7e9ffb1 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/SyncService.java @@ -0,0 +1,384 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +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.sdk.collaboration.types.CollaborationMergeChange; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationMergeConflict; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationMergeResult; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID; + +public class SyncService { + private static final String PULL_NON_EXISTING_VERSION = + "Item Id %s, version Id %s: Non existing version cannot be synced."; + private static final String PUBLIC_SYNC_STATE_EXISTS_WITHOUT_ELEMENT = + "Item Id %s, version Id %s: Sync state of element with Id %s " + + "exists in public space while the element does not"; + private static final String PRIVATE_UNPUBLISHED_SYNC_STATE_EXISTS_WITHOUT_ELEMENT = + "Item Id %s, version Id %s: Sync state of unpublished element with Id %s " + + "exists in private space while the element does not"; + + private VersionPublicStore versionPublicStore; + private VersionPrivateStore versionPrivateStore; + private VersionStageStore versionStageStore; + private ElementPublicStore elementPublicStore; + private ElementPrivateStore elementPrivateStore; + private ElementStageStore elementStageStore; + + public SyncService(VersionPublicStore versionPublicStore, + VersionPrivateStore versionPrivateStore, + VersionStageStore versionStageStore, + ElementPublicStore elementPublicStore, + ElementPrivateStore elementPrivateStore, + ElementStageStore elementStageStore) { + this.versionPublicStore = versionPublicStore; + this.versionPrivateStore = versionPrivateStore; + this.versionStageStore = versionStageStore; + this.elementPublicStore = elementPublicStore; + this.elementPrivateStore = elementPrivateStore; + this.elementStageStore = elementStageStore; + } + + public CollaborationMergeResult sync(SessionContext context, Id itemId, Id versionId, + boolean force) { + SynchronizationStateEntity publicVersionSyncState = + versionPublicStore.getSynchronizationState(context, itemId, versionId) + .orElseThrow(() -> new IllegalStateException( + String.format(PULL_NON_EXISTING_VERSION, itemId.toString(), versionId.toString()))); + + Date publishTime = publicVersionSyncState.getPublishTime(); + + Optional<SynchronizationStateEntity> privateVersionSyncState = + versionPrivateStore.getSynchronizationState(context, itemId, versionId); + + if (force || !privateVersionSyncState.isPresent() || + !publishTime.equals(privateVersionSyncState.get().getPublishTime())) { + ElementContext elementContext = + new ElementContext(itemId, versionId, publicVersionSyncState.getRevisionId()); + + Collection<SynchronizationStateEntity> publicSyncStates = + elementPublicStore.listSynchronizationStates(context, elementContext); + Collection<SynchronizationStateEntity> privateSyncStates = + elementPrivateStore.listSynchronizationStates(context, elementContext); + Map<Id, SynchronizationStateEntity> publicSyncStateById = toMapById(publicSyncStates); + + Set<Id> syncedElements = new HashSet<>(); + if (force) { + List<SynchronizationStateEntity> dirtyPrivateSyncStates = privateSyncStates.stream() + .filter(SynchronizationStateEntity::isDirty) + .collect(Collectors.toList()); + + forceSyncDirtyElements(context, elementContext, dirtyPrivateSyncStates, publicSyncStateById, + syncedElements); + } + + if (!privateVersionSyncState.isPresent() || + !publishTime.equals(privateVersionSyncState.get().getPublishTime())) { + syncVersion(context, itemId, versionId, publishTime, privateVersionSyncState.isPresent()); + syncElements(context, elementContext, + privateVersionSyncState.map(SynchronizationStateEntity::getPublishTime).orElse(null), + publicSyncStates, privateSyncStates, publicSyncStateById, syncedElements); + } + } + + return createResult(); + } + + private CollaborationMergeResult createResult() { + CollaborationMergeResult result = new CollaborationMergeResult(); + result.setChange(new CollaborationMergeChange()); + result.setConflict(new CollaborationMergeConflict()); + return result; + } + + private void syncVersion(SessionContext context, Id itemId, Id versionId, Date publishTime, + boolean versionExistOnPrivate) { + if (versionExistOnPrivate) { + stageVersion(context, itemId, new VersionEntity(versionId), Action.UPDATE, publishTime); + } else { + stageVersion(context, itemId, versionPublicStore.get(context, itemId, versionId) + .orElseThrow(() -> new IllegalArgumentException(String + .format(PULL_NON_EXISTING_VERSION, itemId.toString(), versionId.toString()))), + Action.CREATE, publishTime); + } + } + + private void syncElements(SessionContext context, ElementContext elementContext, + Date previousSyncedPublishTime, + Collection<SynchronizationStateEntity> publicSyncStates, + Collection<SynchronizationStateEntity> privateSyncStates, + Map<Id, SynchronizationStateEntity> publicSyncStateById, + Set<Id> syncedElements) { + Map<Id, SynchronizationStateEntity> privateSyncStateById = toMapById(privateSyncStates); + + Collection<SynchronizationStateEntity> updatedPublicSyncStates = + previousSyncedPublishTime == null + ? publicSyncStates + : publicSyncStates.stream() + .filter(syncState -> syncState.getPublishTime().after(previousSyncedPublishTime)) + .collect(Collectors.toList()); + + syncPublicUpdatedElements(context, elementContext, updatedPublicSyncStates, + publicSyncStateById, privateSyncStateById, syncedElements); + + List<SynchronizationStateEntity> onlyOnPrivatePublishedSyncStates = + privateSyncStates.stream() + .filter(syncState -> !publicSyncStateById.containsKey(syncState.getId()) && + syncState.getPublishTime() != null) + .collect(Collectors.toList()); + + syncPublicDeletedElements(context, elementContext, onlyOnPrivatePublishedSyncStates, + publicSyncStateById, privateSyncStateById, syncedElements); + } + + private void syncPublicUpdatedElements(SessionContext context, ElementContext elementContext, + Collection<SynchronizationStateEntity> updatedPublicSyncStates, + Map<Id, SynchronizationStateEntity> publicSyncStateById, + Map<Id, SynchronizationStateEntity> privateSyncStateById, + Set<Id> syncedElements) { + for (SynchronizationStateEntity publicSyncState : updatedPublicSyncStates) { + if (syncedElements.contains(publicSyncState.getId())) { + continue; + } + + ElementEntity publicElement = + elementPublicStore.get(context, elementContext, publicSyncState.getId()).orElseThrow( + () -> new IllegalStateException(String + .format(PUBLIC_SYNC_STATE_EXISTS_WITHOUT_ELEMENT, + elementContext.getItemId().getValue(), + elementContext.getVersionId().getValue(), + publicSyncState.getId().getValue()))); + + SynchronizationStateEntity privateSyncState = + privateSyncStateById.get(publicSyncState.getId()); + + if (privateSyncState != null) { + if (!privateSyncState.isDirty()) { + // not changed on private + stageElement(context, elementContext, publicElement, + publicSyncState.getPublishTime(), + Action.UPDATE, false, null); + syncedElements.add(publicSyncState.getId()); + } else { + Optional<ElementEntity> privateElement = + elementPrivateStore.get(context, elementContext, publicSyncState.getId()); + + if (privateElement.isPresent()) { + // updated on private - conflict if it has different hash + stageElement(context, elementContext, publicElement, + publicSyncState.getPublishTime(), Action.UPDATE, + !publicElement.getElementHash().equals(privateElement.get().getElementHash()), + null); + + syncedElements.add(publicSyncState.getId()); + } else { + // deleted on private - conflict tree + Set<Id> changeTreeElementIds = + stagePublicElementTree(context, elementContext, publicElement, publicSyncStateById, + (treeElementIds) -> true); + syncedElements.addAll(changeTreeElementIds); + } + } + } else { + // not existing on private - new creation on public + Set<Id> changeTreeElementIds = + stagePublicElementTree(context, elementContext, publicElement, publicSyncStateById, + (treeElementIds) -> containsDirty(treeElementIds, privateSyncStateById)); + syncedElements.addAll(changeTreeElementIds); + } + } + } + + private void syncPublicDeletedElements( + SessionContext context, ElementContext elementContext, + Collection<SynchronizationStateEntity> onlyOnPrivatePublishedSyncStates, + Map<Id, SynchronizationStateEntity> publicSyncStateById, + Map<Id, SynchronizationStateEntity> privateSyncStateById, + Set<Id> syncedElements) { + for (SynchronizationStateEntity privateSyncState : onlyOnPrivatePublishedSyncStates) { + if (syncedElements.contains(privateSyncState.getId())) { + continue; + } + + Optional<ElementEntity> privateElement = + elementPrivateStore.get(context, elementContext, privateSyncState.getId()); + + if (!privateElement.isPresent()) { + // deleted on private as well + stageElement(context, elementContext, new ElementEntity(privateSyncState.getId()), + null, Action.DELETE, false, null); + syncedElements.add(privateSyncState.getId()); + } else { + Set<Id> changeTreeElementIds = + stageElementTree(context, elementContext, privateElement.get(), + elementPrivateStore, publicSyncStateById::containsKey, + (treeElementIds) -> containsDirty(treeElementIds, privateSyncStateById), + (elementId) -> null, Action.DELETE); + syncedElements.addAll(changeTreeElementIds); + } + } + } + + private void forceSyncDirtyElements(SessionContext context, ElementContext elementContext, + List<SynchronizationStateEntity> dirtyPrivateSyncStates, + Map<Id, SynchronizationStateEntity> publicSyncStateById, + Set<Id> syncedElements) { + for (SynchronizationStateEntity privateSyncState : dirtyPrivateSyncStates) { + Optional<ElementEntity> privateElement = + elementPrivateStore.get(context, elementContext, privateSyncState.getId()); + if (privateSyncState.getPublishTime() == null) { + stageElement(context, elementContext, + privateElement.orElseThrow(() -> new IllegalStateException( + String.format(PRIVATE_UNPUBLISHED_SYNC_STATE_EXISTS_WITHOUT_ELEMENT, + elementContext.getItemId().getValue(), + elementContext.getVersionId().getValue(), + privateSyncState.getId().getValue()))), + null, Action.DELETE, false, null); + } else { + SynchronizationStateEntity publicSyncState = + publicSyncStateById.get(privateSyncState.getId()); + if (publicSyncState != null) { + ElementEntity publicElement = + elementPublicStore.get(context, elementContext, privateSyncState.getId()).orElseThrow( + () -> new IllegalStateException(String + .format(PUBLIC_SYNC_STATE_EXISTS_WITHOUT_ELEMENT, + elementContext.getItemId().getValue(), + elementContext.getVersionId().getValue(), + privateSyncState.getId().getValue()))); + + stageElement(context, elementContext, publicElement, publicSyncState.getPublishTime(), + privateElement.isPresent() ? Action.UPDATE : Action.CREATE, false, null); + } else { + stageElement(context, elementContext, privateElement.isPresent() + ? privateElement.get() + : new ElementEntity(privateSyncState.getId()), + null, Action.DELETE, false, null); + } + } + syncedElements.add(privateSyncState.getId()); + } + } + + private Set<Id> stagePublicElementTree(SessionContext context, + ElementContext elementContext, + ElementEntity publicElement, + Map<Id, SynchronizationStateEntity> publicSyncStateById, + Predicate<Set<Id>> isElementTreeConflicted) { + + + return stageElementTree(context, elementContext, publicElement, + elementPublicStore, + (elementId) -> elementPrivateStore.getDescriptor(context, elementContext, elementId) + .isPresent(), + isElementTreeConflicted, + (elementId) -> publicSyncStateById.get(elementId).getPublishTime(), + Action.CREATE); + } + + private Set<Id> stageElementTree(SessionContext context, ElementContext elementContext, + ElementEntity element, + ElementStore elementStore, + Predicate<Id> isElementExist, + Predicate<Set<Id>> isElementTreeConflicted, + Function<Id, Date> stagePublishTimeGetter, + Action stageAction) { + ElementEntity elementTreeRoot = findRootElementOfChange(context, elementContext, + elementStore, isElementExist, element); + + Set<Id> elementTreeIds = new HashSet<>(); + elementTreeIds.add(elementTreeRoot.getId()); + + Set<Id> subElementIds = stageElementSubs(context, elementContext, elementStore, elementTreeRoot, + stagePublishTimeGetter, stageAction); + elementTreeIds.addAll(subElementIds); + + boolean conflicted = isElementTreeConflicted.test(elementTreeIds); + stageElement(context, elementContext, elementTreeRoot, + stagePublishTimeGetter.apply(elementTreeRoot.getId()), stageAction, conflicted, + conflicted ? subElementIds : null); + return elementTreeIds; + } + + private ElementEntity findRootElementOfChange(SessionContext context, + ElementContext elementContext, + ElementStore elementStore, + Predicate<Id> isElementExistOnOppositeStore, + ElementEntity element) { + return element.getId().equals(ROOT_ELEMENTS_PARENT_ID) || + isElementExistOnOppositeStore.test(element.getParentId()) + ? element + : findRootElementOfChange(context, elementContext, elementStore, + isElementExistOnOppositeStore, + elementStore.get(context, elementContext, element.getParentId()) + .orElseThrow(() -> new IllegalStateException( + String.format("Element %s exists while its parent element %s does not", + element.getId(), element.getParentId())))); + } + + private boolean containsDirty(Set<Id> elementIds, + Map<Id, SynchronizationStateEntity> syncStateById) { + return elementIds.stream().anyMatch(elementId -> { + SynchronizationStateEntity privateSyncState = syncStateById.get(elementId); + return privateSyncState != null && privateSyncState.isDirty(); + }); + } + + private Set<Id> stageElementSubs(SessionContext context, ElementContext elementContext, + ElementStore elementStore, ElementEntity parentElement, + Function<Id, Date> stagePublishTimeGetter, Action stageAction) { + Set<Id> elementTreeIds = new HashSet<>(); + for (Id elementId : parentElement.getSubElementIds()) { + ElementEntity element = elementStore.get(context, elementContext, elementId).get(); + + stageElement(context, elementContext, element, stagePublishTimeGetter.apply(elementId), + stageAction, false, null); + + elementTreeIds.add(elementId); + elementTreeIds.addAll( + stageElementSubs(context, elementContext, elementStore, element, stagePublishTimeGetter, + stageAction)); + } + return elementTreeIds; + } + + private void stageElement(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime, Action action, + boolean conflicted, Set<Id> conflictDependents) { + StageEntity<ElementEntity> elementStage = + new StageEntity<>(element, publishTime, action, conflicted); + if (conflictDependents != null) { + elementStage.setConflictDependents( + conflictDependents.stream().map(ElementEntity::new).collect(Collectors.toSet())); + } + elementStageStore.create(context, elementContext, elementStage); + } + + private void stageVersion(SessionContext context, Id itemId, VersionEntity stageVersion, + Action stageAction, Date publishTime) { + versionStageStore + .create(context, itemId, new StageEntity<>(stageVersion, publishTime, stageAction, false)); + } + + private Map<Id, SynchronizationStateEntity> toMapById( + Collection<SynchronizationStateEntity> syncStates) { + return syncStates.stream() + .collect(Collectors.toMap(SynchronizationStateEntity::getId, Function.identity())); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionCollaborationStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionCollaborationStore.java deleted file mode 100644 index db3066c313..0000000000 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionCollaborationStore.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.openecomp.core.zusammen.plugin.collaboration; - -import com.amdocs.zusammen.datatypes.Id; -import com.amdocs.zusammen.datatypes.SessionContext; -import com.amdocs.zusammen.datatypes.Space; -import com.amdocs.zusammen.datatypes.item.Action; -import com.amdocs.zusammen.datatypes.itemversion.Tag; -import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; -import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElementChange; -import com.amdocs.zusammen.sdk.collaboration.types.CollaborationMergeChange; -import org.openecomp.core.zusammen.plugin.ZusammenPluginUtil; -import org.openecomp.core.zusammen.plugin.dao.ElementRepository; -import org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory; -import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -import static org.openecomp.core.zusammen.plugin.ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID; -import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getSpaceName; - -public class VersionCollaborationStore { - - public void tagItemVersion(SessionContext context, Id itemId, Id versionId, Id changeId, - Tag tag) { - if (changeId != null) { - throw new UnsupportedOperationException( - "In this plugin implementation tag is supported only on versionId"); - } - String space = getSpaceName(context, Space.PRIVATE); - ElementEntityContext targetContext = new ElementEntityContext(space, itemId, versionId); - targetContext.setChangeRef(tag.getName()); - copyElements(context, new ElementEntityContext(space, itemId, versionId), targetContext, - getElementRepository(context)); - } - - public CollaborationMergeChange resetItemVersionHistory(SessionContext context, Id itemId, - Id versionId, String changeRef) { - ElementRepository elementRepository = getElementRepository(context); - - String spaceName = getSpaceName(context, Space.PRIVATE); - ElementEntityContext versionContext = new ElementEntityContext(spaceName, itemId, versionId); - - Collection<ElementEntity> deletedElements = - deleteElements(context, versionContext, elementRepository); - - ElementEntityContext changeRefContext = new ElementEntityContext(spaceName, itemId, versionId); - changeRefContext.setChangeRef(changeRef); - - Collection<ElementEntity> createdElements = - copyElements(context, changeRefContext, versionContext, elementRepository); - - // TODO: 4/19/2017 version change... - return createCollaborationMergeChange(versionContext, deletedElements, createdElements); - } - - private Collection<ElementEntity> deleteElements(SessionContext context, - ElementEntityContext elementContext, - ElementRepository elementRepository) { - Collection<ElementEntity> elements = elementRepository.list(context, elementContext); - elements.forEach(element -> elementRepository - .delete(context, elementContext, new ElementEntity(element.getId()))); - elementRepository.delete(context, elementContext, new ElementEntity(ROOT_ELEMENTS_PARENT_ID)); - return elements; - } - - private Collection<ElementEntity> copyElements(SessionContext context, - ElementEntityContext sourceElementContext, - ElementEntityContext targetElementContext, - ElementRepository elementRepository) { - Collection<ElementEntity> elements = elementRepository.list(context, sourceElementContext); - elements.forEach(elementEntity -> - elementRepository.create(context, targetElementContext, elementEntity)); - return elements; - } - - private CollaborationMergeChange createCollaborationMergeChange( - ElementEntityContext versionContext, - Collection<ElementEntity> deletedElements, - Collection<ElementEntity> createdElements) { - CollaborationMergeChange mergeChange = new CollaborationMergeChange(); - mergeChange.getChangedElements().addAll( - convertToCollaborationElementChanges(versionContext, deletedElements, Action.DELETE)); - mergeChange.getChangedElements().addAll( - convertToCollaborationElementChanges(versionContext, createdElements, Action.CREATE)); - return mergeChange; - } - - private List<CollaborationElementChange> convertToCollaborationElementChanges( - ElementEntityContext elementContext, Collection<ElementEntity> changedElements, - Action action) { - return changedElements.stream() - .map(element -> convertToCollaborationElementChange(element, elementContext, action)) - .collect(Collectors.toList()); - } - - private CollaborationElementChange convertToCollaborationElementChange( - ElementEntity elementEntity, ElementEntityContext elementContext, Action action) { - CollaborationElementChange elementChange = new CollaborationElementChange(); - elementChange - .setElement(ZusammenPluginUtil.getCollaborationElement(elementContext, elementEntity)); - elementChange.setAction(action); - return elementChange; - } - - protected ElementRepository getElementRepository(SessionContext context) { - return ElementRepositoryFactory.getInstance().createInterface(context); - } -} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionPrivateStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionPrivateStore.java new file mode 100644 index 0000000000..a024327548 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionPrivateStore.java @@ -0,0 +1,38 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Date; +import java.util.Optional; + +public interface VersionPrivateStore { + Optional<VersionEntity> get(SessionContext context, Id itemId, Id versionId); + + Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context, Id itemId, + Id versionId); + + void create(SessionContext context, Id itemId, VersionEntity version); + + void update(SessionContext context, Id itemId, VersionEntity version); + + void update(SessionContext context, Id itemId, VersionEntity version, Date publishTime, + boolean dirty); + + void delete(SessionContext context, Id itemId, VersionEntity version); + + void markAsPublished(SessionContext context, Id itemId, Id versionId, Date publishTime); + + void commitStagedCreate(SessionContext context, Id itemId, VersionEntity version, + Date publishTime); + + void commitStagedUpdate(SessionContext context, Id itemId, VersionEntity version, + Date publishTime); + + void commitStagedIgnore(SessionContext context, Id itemId, VersionEntity version, + Date publishTime); + + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionPublicStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionPublicStore.java new file mode 100644 index 0000000000..c86db0ec43 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionPublicStore.java @@ -0,0 +1,29 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Date; +import java.util.Map; +import java.util.Optional; + +public interface VersionPublicStore { + + Optional<VersionEntity> get(SessionContext context, Id itemId, Id versionId); + + Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context, + Id itemId, Id versionId); + + void create(SessionContext context, Id itemId, VersionEntity version, Id revisionId, + Map<Id, Id> versionElementIds, Date publishTime, String message); + + void update(SessionContext context, Id itemId, VersionEntity version, Id revisionId, + Map<Id, Id> versionElementIds, Date publishTime, String message); + + boolean checkHealth(SessionContext context); + + ItemVersionRevisions listItemVersionRevisions(SessionContext context, Id itemId, Id versionId); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionStageStore.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionStageStore.java new file mode 100644 index 0000000000..5058a262cc --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/VersionStageStore.java @@ -0,0 +1,18 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Optional; + +public interface VersionStageStore { + + Optional<StageEntity<VersionEntity>> get(SessionContext context, Id itemId, + VersionEntity versionEntity); + + void create(SessionContext context, Id itemId, StageEntity<VersionEntity> versionStage); + + void delete(SessionContext context, Id itemId, VersionEntity version); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementPrivateStoreImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementPrivateStoreImpl.java new file mode 100644 index 0000000000..9f54ee3ae2 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementPrivateStoreImpl.java @@ -0,0 +1,269 @@ +package org.openecomp.core.zusammen.plugin.collaboration.impl; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import org.openecomp.core.zusammen.plugin.ZusammenPluginConstants; +import org.openecomp.core.zusammen.plugin.collaboration.ElementPrivateStore; +import org.openecomp.core.zusammen.plugin.dao.ElementRepository; +import org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateElementContext; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateSpaceName; + +public class ElementPrivateStoreImpl implements ElementPrivateStore { + private static final Id REVISION_ID = Id.ZERO; // the private revision id is Id.ZERO 0000000... + + @Override + public Map<Id, Id> listIds(SessionContext context, ElementContext elementContext) { + return getElementRepository(context) + .listIds(context, new ElementEntityContext(getPrivateSpaceName(context), elementContext)); + } + + @Override + public Collection<ElementEntity> listSubs(SessionContext context, ElementContext elementContext, + Id elementId) { + if (elementId == null) { + elementId = ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID; + } + + ElementRepository elementRepository = getElementRepository(context); + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateContext.setRevisionId(REVISION_ID); + return elementRepository.get(context, privateContext, new ElementEntity(elementId)) + .map(ElementEntity::getSubElementIds).orElse(new HashSet<>()).stream() + .map(subElementId -> elementRepository + .get(context, privateContext, new ElementEntity(subElementId)).get()) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + @Override + public Optional<ElementEntity> get(SessionContext context, ElementContext elementContext, + Id elementId) { + ElementEntityContext privateElementContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateElementContext.setRevisionId(REVISION_ID); + return getElementRepository(context) + .get(context, privateElementContext, + new ElementEntity(elementId)); + } + + @Override + public Optional<ElementEntity> getDescriptor(SessionContext context, + ElementContext elementContext, Id elementId) { + return getElementRepository(context) + .getDescriptor(context, + new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext + (elementContext)), + new ElementEntity(elementId)); + } + + @Override + public Collection<SynchronizationStateEntity> listSynchronizationStates(SessionContext context, + ElementContext elementContext) { + ElementEntityContext privateElementContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + return getElementSyncStateRepository(context) + .list(context, privateElementContext); + } + + @Override + public Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context, + ElementContext elementContext, + Id elementId) { + + ElementEntityContext privateElementContext = + new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext + (elementContext)); + return getElementSyncStateRepository(context) + .get(context, privateElementContext, + new SynchronizationStateEntity(elementId, REVISION_ID)); + } + + @Override + public void create(SessionContext context, ElementContext elementContext, ElementEntity element) { + create(context, elementContext, element, true, null); + } + + @Override + public boolean update(SessionContext context, ElementContext elementContext, + ElementEntity element) { + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateContext.setRevisionId(REVISION_ID); + + if (!isElementChanged(context, privateContext, element)) { + return false; + } + + getElementRepository(context).update(context, privateContext, element); + getElementSyncStateRepository(context).markAsDirty(context, privateContext, + new SynchronizationStateEntity(element.getId(), REVISION_ID)); + return true; + } + + @Override + public void delete(SessionContext context, ElementContext elementContext, ElementEntity element) { + + ElementEntityContext privateElementContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateElementContext.setRevisionId(REVISION_ID); + deleteElementHierarchy(context, getElementRepository(context), + getElementSyncStateRepository(context), + privateElementContext, element); + } + + @Override + public void markAsPublished(SessionContext context, ElementContext elementContext, Id elementId, + Date publishTime) { + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateContext.setRevisionId(REVISION_ID); + getElementSyncStateRepository(context).update(context, + privateContext, + new SynchronizationStateEntity(elementId, REVISION_ID, publishTime, false)); + } + + @Override + public void markDeletionAsPublished(SessionContext context, ElementContext elementContext, + Id elementId, Date publishTime) { + + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateContext.setRevisionId(REVISION_ID); + getElementSyncStateRepository(context).delete(context, + privateContext, + new SynchronizationStateEntity(elementId, REVISION_ID)); + } + + @Override + public void commitStagedCreate(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime) { + create(context, elementContext, element, false, publishTime); + } + + @Override + public void commitStagedUpdate(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime) { + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateContext.setRevisionId(REVISION_ID); + + getElementRepository(context).update(context, privateContext, element); + // Currently Resolution='Other' is not supported so this is invoked after conflict was + // resolved with Resolution='Theirs' so dirty flag should be turned off. + // (if there was no conflict it's off anyway) + getElementSyncStateRepository(context).update(context, privateContext, + new SynchronizationStateEntity(element.getId(), REVISION_ID, publishTime, false)); + } + + @Override + public void commitStagedDelete(SessionContext context, ElementContext elementContext, + ElementEntity element) { + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateContext.setRevisionId(REVISION_ID); + getElementRepository(context).delete(context, privateContext, element); + getElementSyncStateRepository(context) + .delete(context, privateContext, + new SynchronizationStateEntity(element.getId(), REVISION_ID)); + } + + @Override + public void commitStagedIgnore(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime) { + // publish time - updated to mark that this element was already synced with this publish time + // (even though the local data was preferred) and to prevent this conflict again. + // dirty - turned on because the local data which is different than the public one was + // preferred. It will enable future publication of this data. + getElementSyncStateRepository(context).update(context, + new ElementEntityContext(getPrivateSpaceName(context), elementContext), + new SynchronizationStateEntity(element.getId(), REVISION_ID, publishTime, true)); + } + + private void create(SessionContext context, ElementContext elementContext, + ElementEntity element, boolean dirty, Date publishTime) { + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), elementContext); + privateContext.setRevisionId(REVISION_ID); + getElementRepository(context).create(context, privateContext, element); + getElementSyncStateRepository(context).create(context, privateContext, + new SynchronizationStateEntity(element.getId(), REVISION_ID, publishTime, dirty)); + } + + + private void deleteElementHierarchy( + SessionContext context, ElementRepository elementRepository, + ElementSynchronizationStateRepository elementSyncStateRepository, + ElementEntityContext elementContext, ElementEntity element) { + + Optional<ElementEntity> retrieved = elementRepository.get(context, elementContext, element); + if (!retrieved.isPresent()) { + return; + } + retrieved.get().getSubElementIds().stream() + .map(ElementEntity::new) + .forEach(subElementEntity -> deleteElementHierarchy( + context, elementRepository, elementSyncStateRepository, elementContext, + subElementEntity)); + + // only for the first one the parentId will populated (so it'll be removed from its parent) + elementRepository.delete(context, elementContext, element); + handleDeletedElementSyncState(context, elementSyncStateRepository, elementContext, element); + } + + private void handleDeletedElementSyncState(SessionContext context, + ElementSynchronizationStateRepository elementSyncStateRepository, + ElementEntityContext elementContext, + ElementEntity element) { + SynchronizationStateEntity elementSyncState = new SynchronizationStateEntity(element.getId(), + REVISION_ID); + if (elementSyncStateRepository.get(context, elementContext, elementSyncState). + orElseThrow( + () -> new IllegalStateException("Synchronization state must exist for an element")) + .getPublishTime() == null) { + elementSyncStateRepository.delete(context, elementContext, elementSyncState); + } else { + elementSyncStateRepository.markAsDirty(context, elementContext, elementSyncState); + } + } + + private boolean isElementChanged(SessionContext context, + ElementEntityContext elementContext, + ElementEntity newElement) { + return getElementHash(context, elementContext, new ElementEntity(newElement.getId())) + .map(existingHash -> !newElement.getElementHash().equals(existingHash)) + .orElse(true); + } + + private Optional<Id> getElementHash(SessionContext context, + ElementEntityContext elementEntityContext, + ElementEntity element) { + return getElementRepository(context).getHash(context, elementEntityContext, element); + } + + protected ElementRepository getElementRepository(SessionContext context) { + return ElementRepositoryFactory.getInstance().createInterface(context); + } + + protected ElementSynchronizationStateRepository getElementSyncStateRepository( + SessionContext context) { + return ElementSynchronizationStateRepositoryFactory.getInstance().createInterface(context); + } + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementPublicStoreImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementPublicStoreImpl.java new file mode 100644 index 0000000000..d946a529ce --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementPublicStoreImpl.java @@ -0,0 +1,189 @@ +package org.openecomp.core.zusammen.plugin.collaboration.impl; + +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.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import org.openecomp.core.zusammen.plugin.collaboration.ElementPublicStore; +import org.openecomp.core.zusammen.plugin.dao.ElementRepository; +import org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getSpaceName; + +public class ElementPublicStoreImpl implements ElementPublicStore { + + @Override + public Optional<ElementEntity> get(SessionContext context, + ElementContext elementContext, Id elementId) { + return getElementRepository(context) + .get(context, new ElementEntityContext(getSpaceName(context, Space.PUBLIC), elementContext), + new ElementEntity(elementId)); + } + + @Override + public Optional<ElementEntity> getDescriptor(SessionContext context, + ElementContext elementContext, Id elementId) { + return getElementRepository(context).getDescriptor(context, + new ElementEntityContext(getSpaceName(context, Space.PUBLIC), elementContext), + new ElementEntity(elementId)); + } + + @Override + public Collection<SynchronizationStateEntity> listSynchronizationStates( + SessionContext context, ElementContext elementContext) { + ElementEntityContext entityContext = new ElementEntityContext(getSpaceName + (context, Space.PUBLIC), elementContext); + + ElementSynchronizationStateRepository elementSyncStateRepository = + getElementSyncStateRepository(context); + Map<Id, Id> ids = getElementRepository(context).listIds(context, entityContext); + + Collection<SynchronizationStateEntity> synchronizationStateEntities = new HashSet<>(); + for (Map.Entry<Id, Id> elementEntry : ids.entrySet()) { + Optional<SynchronizationStateEntity> synchronizationStateEntity = elementSyncStateRepository. + get(context, entityContext, new SynchronizationStateEntity(elementEntry.getKey(), + elementEntry.getValue())); + if (synchronizationStateEntity.isPresent()) { + synchronizationStateEntities.add(synchronizationStateEntity.get()); + } else { + /*throw new IllegalStateException(String.format( + "list Synchronization States error: " + "element %s revision %s, which appears as an " + + "element of " + + "item" + + " %s version %s, does not exist", + elementEntry.getKey(), elementEntry.getValue(), elementContext.getItemId().getValue(), + elementContext.getVersionId().getValue()));*/ + } + } + + return synchronizationStateEntities; + } + + @Override + public void create(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime) { + ElementEntityContext publicContext = + new ElementEntityContext(getSpaceName(context, Space.PUBLIC), elementContext); + + + if (element.getParentId() != null) { + createParentElement(context, elementContext, element.getParentId(), publishTime); + } + getElementRepository(context).create(context, publicContext, element); + getElementSyncStateRepository(context).create(context, publicContext, + new SynchronizationStateEntity(element.getId(), elementContext.getRevisionId(), + publishTime, false)); + } + + @Override + public void update(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime) { + //todo - update in public should be create new entry with new revision_id in public - this is a + // new revision + ElementEntityContext publicContext = + new ElementEntityContext(getSpaceName(context, Space.PUBLIC), elementContext); + + Optional<ElementEntity> publicElement = getElementRepository(context).get(context, + publicContext, new ElementEntity(element.getId())); + if (publicElement.isPresent()) { + getElementRepository(context).update(context, publicContext, element); + } else { + publicElement = get(context,new ElementContext(publicContext.getItemId(),publicContext + .getVersionId()),element.getId()); + element.setSubElementIds(publicElement.get().getSubElementIds()); + getElementRepository(context).create(context, publicContext, element); + } + getElementSyncStateRepository(context).update(context, publicContext, + new SynchronizationStateEntity(element.getId(), elementContext.getRevisionId(), publishTime, + false)); + } + + @Override + public void delete(SessionContext context, ElementContext elementContext, + ElementEntity element, Date publishTime) { + ElementEntityContext publicContext = + new ElementEntityContext(getSpaceName(context, Space.PUBLIC), elementContext); + + if (element.getParentId() != null) { + Optional<ElementEntity> parentElement = get(context, elementContext, element.getParentId()); + if (parentElement.isPresent()) { + createParentElement(context, elementContext, element.getParentId(), publishTime); + } + } + + getElementRepository(context).delete(context, publicContext, element); + getElementSyncStateRepository(context) + .delete(context, publicContext, new SynchronizationStateEntity(element.getId(), + elementContext.getRevisionId())); + } + + @Override + public Map<Id, Id> listIds(SessionContext context, ElementContext elementContext) { + + return getElementRepository(context) + .listIds(context, + new ElementEntityContext(getSpaceName(context, Space.PUBLIC), elementContext)); + + } + + private void createParentElement(SessionContext context, ElementContext elementContext, + Id parentElementId, Date publishTime + ) { + ElementEntityContext publicContext = + new ElementEntityContext(getSpaceName(context, Space.PUBLIC), elementContext); + + Optional<ElementEntity> parentElement = + getElementRepository(context).get(context, new ElementEntityContext + (publicContext.getSpace(), publicContext.getItemId(), publicContext.getVersionId(), + elementContext.getRevisionId()), + new ElementEntity(parentElementId)); + if(parentElement.isPresent()) { + update(context, elementContext, parentElement.get(), publishTime); + } + + + /* Id elementRevisionId = getElementRevision(context, publicContext, elementContext.getRevisionId() + , parentElementId); + + if (elementRevisionId != null && !elementRevisionId.equals(elementContext.getRevisionId())) { + Optional<ElementEntity> parentElement = + getElementRepository(context).get(context, new ElementEntityContext + (publicContext.getSpace(), publicContext.getItemId(), publicContext.getVersionId(), + elementContext.getRevisionId()), + new ElementEntity(parentElementId)); + elementRevisionId = getElementRevision(context, publicContext, elementContext.getRevisionId() + , parentElement.get().getId()); + if (elementRevisionId != null) { + update(context, elementContext, parentElement.get(), publishTime); + } else { + create(context, elementContext, parentElement.get(), publishTime); + } + + }*/ + } + + + + + protected ElementRepository getElementRepository(SessionContext context) { + return ElementRepositoryFactory.getInstance().createInterface(context); + } + + protected ElementSynchronizationStateRepository getElementSyncStateRepository( + SessionContext context) { + return ElementSynchronizationStateRepositoryFactory.getInstance().createInterface(context); + } + + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementStageStoreImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementStageStoreImpl.java new file mode 100644 index 0000000000..f6c29432df --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementStageStoreImpl.java @@ -0,0 +1,133 @@ +package org.openecomp.core.zusammen.plugin.collaboration.impl; + +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.Resolution; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import org.openecomp.core.zusammen.plugin.collaboration.ElementStageStore; +import org.openecomp.core.zusammen.plugin.dao.ElementStageRepository; +import org.openecomp.core.zusammen.plugin.dao.ElementStageRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; + +import java.util.Collection; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateElementContext; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateSpaceName; + +public class ElementStageStoreImpl implements ElementStageStore { + + @Override + public Collection<ElementEntity> listIds(SessionContext context, ElementContext elementContext) { + return getElementStageRepository(context) + .listIds(context, new ElementEntityContext(getPrivateSpaceName(context), + getPrivateElementContext(elementContext))); + } + + @Override + public Optional<StageEntity<ElementEntity>> get(SessionContext context, + ElementContext elementContext, + ElementEntity element) { + return getElementStageRepository(context).get(context, + new ElementEntityContext(getPrivateSpaceName(context), + getPrivateElementContext(elementContext)), + element); + } + + @Override + public Optional<StageEntity<ElementEntity>> getConflicted(SessionContext context, + ElementContext elementContext, + ElementEntity element) { + return get(context, elementContext, element).filter(StageEntity::isConflicted); + } + + @Override + public boolean hasConflicts(SessionContext context, ElementContext elementContext) { + return !getElementStageRepository(context).listConflictedIds(context, + new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext(elementContext))).isEmpty(); + } + + @Override + public Collection<StageEntity<ElementEntity>> listConflictedDescriptors(SessionContext context, + ElementContext elementContext) { + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext + (elementContext)); + ElementStageRepository elementStageRepository = getElementStageRepository(context); + + return elementStageRepository.listConflictedIds(context, privateContext).stream() + .map(conflictedElement -> elementStageRepository + .getDescriptor(context, privateContext, conflictedElement).get()) + .collect(Collectors.toList()); + } + + @Override + public void create(SessionContext context, ElementContext elementContext, + StageEntity<ElementEntity> elementStage) { + getElementStageRepository(context) + .create(context, + new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext(elementContext)), + elementStage); + } + + @Override + public void delete(SessionContext context, ElementContext elementContext, ElementEntity element) { + getElementStageRepository(context) + .delete(context, + new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext(elementContext)), + element); + } + + + @Override + public void resolveConflict(SessionContext context, ElementContext elementContext, + ElementEntity element, Resolution resolution) { + Optional<StageEntity<ElementEntity>> stagedElement = + getConflicted(context, elementContext, element); + if (!stagedElement.isPresent()) { + return; + } + + ElementEntityContext privateContext = + new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext + (elementContext)); + + switch (resolution) { + case YOURS: + resolveConflictByYours(context, privateContext, stagedElement.get()); + break; + case THEIRS: + resolveConflictByTheirs(context, privateContext, stagedElement.get()); + break; + case OTHER: // other = data updates only? no data deletions? if so, then: + // conflicted = false + // element = the input of resolve + // action = update + throw new UnsupportedOperationException("'Other' conflict resolution is not yet supported"); + default: + break; + } + } + + private void resolveConflictByYours(SessionContext context, ElementEntityContext privateContext, + StageEntity<ElementEntity> stagedElement) { + getElementStageRepository(context) + .markAsNotConflicted(context, privateContext, stagedElement.getEntity(), Action.IGNORE); + stagedElement.getConflictDependents().forEach(conflictDependant -> + getElementStageRepository(context) + .markAsNotConflicted(context, privateContext, conflictDependant, Action.IGNORE)); + } + + private void resolveConflictByTheirs(SessionContext context, ElementEntityContext privateContext, + StageEntity<ElementEntity> stagedElement) { + getElementStageRepository(context) + .markAsNotConflicted(context, privateContext, stagedElement.getEntity()); + } + + protected ElementStageRepository getElementStageRepository(SessionContext context) { + return ElementStageRepositoryFactory.getInstance().createInterface(context); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionPrivateStoreImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionPrivateStoreImpl.java new file mode 100644 index 0000000000..11e61ab5a9 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionPrivateStoreImpl.java @@ -0,0 +1,117 @@ +package org.openecomp.core.zusammen.plugin.collaboration.impl; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.collaboration.VersionPrivateStore; +import org.openecomp.core.zusammen.plugin.dao.VersionDao; +import org.openecomp.core.zusammen.plugin.dao.VersionDaoFactory; +import org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Date; +import java.util.Optional; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateSpaceName; + +public class VersionPrivateStoreImpl implements VersionPrivateStore { + + Id revisionId = Id.ZERO; + + @Override + public Optional<VersionEntity> get(SessionContext context, Id itemId, Id versionId) { + return getVersionDao(context).get(context, getPrivateSpaceName(context), itemId, versionId); + } + + @Override + public Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context, + Id itemId, Id versionId) { + + return getVersionSyncStateRepository(context) + .get(context, new VersionContext(getPrivateSpaceName(context), itemId), + new SynchronizationStateEntity(versionId, revisionId)); + } + + @Override + public void create(SessionContext context, Id itemId, VersionEntity version) { + String privateSpace = getPrivateSpaceName(context); + + + getVersionDao(context).create(context, privateSpace, itemId, version); + getVersionSyncStateRepository(context).create(context, new VersionContext(privateSpace, + itemId), + new SynchronizationStateEntity(version.getId(), revisionId, null, true)); + } + + @Override + public void update(SessionContext context, Id itemId, VersionEntity version) { + + getVersionDao(context) + .updateModificationTime(context, getPrivateSpaceName(context), itemId, version.getId(), + version.getModificationTime()); + } + + @Override + public void update(SessionContext context, Id itemId, VersionEntity version, Date publishTime, + boolean dirty) { + getVersionSyncStateRepository(context).updatePublishTime(context, + new VersionContext(getPrivateSpaceName(context), itemId), + new SynchronizationStateEntity(version.getId(), revisionId, publishTime, dirty)); + } + + @Override + public void delete(SessionContext context, Id itemId, VersionEntity version) { + String privateSpace = getPrivateSpaceName(context); + + getVersionDao(context).delete(context, privateSpace, itemId, version.getId()); + getVersionSyncStateRepository(context).delete(context, new VersionContext(privateSpace, + itemId), + new SynchronizationStateEntity(version.getId(), revisionId)); + } + + @Override + public void markAsPublished(SessionContext context, Id itemId, Id versionId, Date publishTime) { + getVersionSyncStateRepository(context) + .updatePublishTime(context, new VersionContext(getPrivateSpaceName(context), itemId), + new SynchronizationStateEntity(versionId, revisionId, publishTime, false)); + } + + @Override + public void commitStagedCreate(SessionContext context, Id itemId, VersionEntity version, + Date publishTime) { + String privateSpace = getPrivateSpaceName(context); + + getVersionDao(context).create(context, privateSpace, itemId, version); + getVersionSyncStateRepository(context).create(context, new VersionContext(privateSpace, + itemId), + new SynchronizationStateEntity(version.getId(), revisionId, publishTime, false)); + } + + @Override + public void commitStagedUpdate(SessionContext context, Id itemId, VersionEntity version, + Date publishTime) { + update(context, itemId, version, publishTime, false); + } + + @Override + public void commitStagedIgnore(SessionContext context, Id itemId, VersionEntity version, + Date publishTime) { + getVersionSyncStateRepository(context).updatePublishTime(context, + new VersionContext(getPrivateSpaceName(context), itemId), + new SynchronizationStateEntity(version.getId(), revisionId, publishTime, false)); + } + + + + + protected VersionDao getVersionDao(SessionContext context) { + return VersionDaoFactory.getInstance().createInterface(context); + } + + protected VersionSynchronizationStateRepository getVersionSyncStateRepository( + SessionContext context) { + return VersionSynchronizationStateRepositoryFactory.getInstance().createInterface(context); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionPublicStoreImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionPublicStoreImpl.java new file mode 100644 index 0000000000..aa628eb706 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionPublicStoreImpl.java @@ -0,0 +1,135 @@ +package org.openecomp.core.zusammen.plugin.collaboration.impl; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.Space; +import com.amdocs.zusammen.datatypes.itemversion.ItemVersionRevisions; +import com.amdocs.zusammen.datatypes.itemversion.Revision; +import org.openecomp.core.zusammen.plugin.collaboration.VersionPublicStore; +import org.openecomp.core.zusammen.plugin.dao.VersionDao; +import org.openecomp.core.zusammen.plugin.dao.VersionDaoFactory; +import org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getSpaceName; + +public class VersionPublicStoreImpl implements VersionPublicStore { + @Override + public Optional<VersionEntity> get(SessionContext context, Id itemId, Id versionId) { + return getVersionDao(context) + .get(context, getSpaceName(context, Space.PUBLIC), itemId, versionId); + } + + @Override + public Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context, + Id itemId, Id versionId) { + Id revisionId = getLastItemVersionRevision(context, itemId, + versionId); + if (revisionId == null) { + return Optional.empty(); + } + + return getVersionSyncStateRepository(context) + .get(context, new VersionContext(getSpaceName(context, Space.PUBLIC), itemId), + new SynchronizationStateEntity(versionId, revisionId)); + } + + + @Override + public void create(SessionContext context, Id itemId, VersionEntity version, Id revisionId, + Map<Id, Id> versionElementIds, Date + publishTime, String message) { + String publicSpace = getSpaceName(context, Space.PUBLIC); + + getVersionDao(context).create(context, publicSpace, itemId, version); + + getVersionDao(context).createVersionElements(context, publicSpace, itemId, version.getId(), + revisionId, versionElementIds, publishTime,message); + + getVersionSyncStateRepository(context).create(context, new VersionContext(publicSpace, + itemId), + new SynchronizationStateEntity(version.getId(), revisionId, publishTime, false)); + } + + @Override + public void update(SessionContext context, Id itemId, VersionEntity version, + Id revisionId, Map<Id, Id> versionElementIds, Date publishTime, String message) { + String publicSpace = getSpaceName(context, Space.PUBLIC); + + getVersionDao(context). + createVersionElements(context, publicSpace, itemId, version.getId(), + revisionId, versionElementIds, publishTime,message); + + getVersionSyncStateRepository(context). + updatePublishTime(context, new VersionContext(publicSpace, itemId), + new SynchronizationStateEntity(version.getId(), revisionId, publishTime, false)); + } + + @Override + public boolean checkHealth(SessionContext context) { + return getVersionDao(context).checkHealth(context); + } + + @Override + public ItemVersionRevisions listItemVersionRevisions(SessionContext context, Id itemId, + Id versionId) { + VersionContext entityContext = new VersionContext(getSpaceName(context, Space.PUBLIC), itemId); + List<SynchronizationStateEntity> versionRevisions = getVersionSyncStateRepository(context) + .list(context, entityContext, new VersionEntity(versionId)); + + if (versionRevisions == null || versionRevisions.size() == 0) { + return null; + } + + versionRevisions.sort(new Comparator<SynchronizationStateEntity>() { + @Override + public int compare(SynchronizationStateEntity o1, SynchronizationStateEntity o2) { + if (o1.getPublishTime().after(o2.getPublishTime())) { + return -1; + } else { + return 1; + } + } + }); + ItemVersionRevisions itemVersionRevisions = new ItemVersionRevisions(); + versionRevisions.forEach(synchronizationStateEntity -> itemVersionRevisions.addChange + (convertSyncState2Revision(synchronizationStateEntity))); + return itemVersionRevisions; + } + + private Revision convertSyncState2Revision( + SynchronizationStateEntity synchronizationStateEntity) { + Revision revision = new Revision(); + revision.setRevisionId(synchronizationStateEntity.getRevisionId()); + revision.setTime(synchronizationStateEntity.getPublishTime()); + revision.setMessage(synchronizationStateEntity.getMessage()); + revision.setUser(synchronizationStateEntity.getUser()); + return revision; + } + + + private Id getLastItemVersionRevision(SessionContext context, Id itemId, Id versionId) { + + ItemVersionRevisions versionRevisions = listItemVersionRevisions(context, itemId, versionId); + if(versionRevisions ==null ) return null; + return versionRevisions.getItemVersionRevisions().get(0).getRevisionId(); + } + + protected VersionDao getVersionDao(SessionContext context) { + return VersionDaoFactory.getInstance().createInterface(context); + } + + protected VersionSynchronizationStateRepository getVersionSyncStateRepository( + SessionContext context) { + return VersionSynchronizationStateRepositoryFactory.getInstance().createInterface(context); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionStageStoreImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionStageStoreImpl.java new file mode 100644 index 0000000000..dac9d257ea --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/collaboration/impl/VersionStageStoreImpl.java @@ -0,0 +1,39 @@ +package org.openecomp.core.zusammen.plugin.collaboration.impl; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.collaboration.VersionStageStore; +import org.openecomp.core.zusammen.plugin.dao.VersionStageRepository; +import org.openecomp.core.zusammen.plugin.dao.VersionStageRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Optional; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateSpaceName; + +public class VersionStageStoreImpl implements VersionStageStore { + @Override + public Optional<StageEntity<VersionEntity>> get(SessionContext context, Id itemId, + VersionEntity versionEntity) { + return getVersionStageRepository(context) + .get(context, new VersionContext(getPrivateSpaceName(context), itemId), versionEntity); + } + + @Override + public void create(SessionContext context, Id itemId, StageEntity<VersionEntity> versionStage) { + getVersionStageRepository(context) + .create(context, new VersionContext(getPrivateSpaceName(context), itemId), versionStage); + } + + @Override + public void delete(SessionContext context, Id itemId, VersionEntity version) { + getVersionStageRepository(context) + .delete(context, new VersionContext(getPrivateSpaceName(context), itemId), version); + } + + protected VersionStageRepository getVersionStageRepository(SessionContext context) { + return VersionStageRepositoryFactory.getInstance().createInterface(context); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementRepository.java index 967814c4d8..7681327e40 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementRepository.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementRepository.java @@ -1,15 +1,18 @@ package org.openecomp.core.zusammen.plugin.dao; +import com.amdocs.zusammen.datatypes.Id; import com.amdocs.zusammen.datatypes.SessionContext; import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; -import java.util.Collection; +import java.util.Map; import java.util.Optional; public interface ElementRepository { - Collection<ElementEntity> list(SessionContext context, ElementEntityContext elementContext); + Map<Id,Id> listIds(SessionContext context, ElementEntityContext elementContext); + +/* void createVersionData(SessionContext context, ElementEntityContext elementContext, VersionDataElement element);*/ void create(SessionContext context, ElementEntityContext elementContext, ElementEntity element); @@ -20,8 +23,28 @@ public interface ElementRepository { Optional<ElementEntity> get(SessionContext context, ElementEntityContext elementContext, ElementEntity element); + Optional<ElementEntity> getDescriptor(SessionContext context, ElementEntityContext elementContext, + ElementEntity element); + void createNamespace(SessionContext context, ElementEntityContext elementContext, ElementEntity element); - boolean checkHealth(SessionContext context); + Optional<Id> getHash(SessionContext context, ElementEntityContext elementEntityContext, + ElementEntity element); + + + + +/* Collection<SynchronizationStateEntity> listSynchronizationStates(SessionContext context, + ElementEntityContext elementContext); + + void updateSynchronizationState(SessionContext context, ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState); + + void markAsDirty(SessionContext context, ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState); + + Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context, + ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState);*/ } diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementStageRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementStageRepository.java new file mode 100644 index 0000000000..ac3dc4e4bf --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementStageRepository.java @@ -0,0 +1,34 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Action; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; + +import java.util.Collection; +import java.util.Optional; + +public interface ElementStageRepository + extends StageRepository<ElementEntityContext, ElementEntity> { + + Optional<StageEntity<ElementEntity>> getDescriptor(SessionContext context, + ElementEntityContext elementContext, + ElementEntity element); + + Collection<ElementEntity> listIds(SessionContext context, + ElementEntityContext elementContext); + + Collection<ElementEntity> listConflictedIds(SessionContext context, + ElementEntityContext elementContext); + + void markAsNotConflicted(SessionContext context, ElementEntityContext entityContext, + ElementEntity entity, Action action); + + void markAsNotConflicted(SessionContext context, ElementEntityContext entityContext, + ElementEntity entity); + + void update(SessionContext context, ElementEntityContext entityContext, ElementEntity entity, + Action action, boolean conflicted); + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementStageRepositoryFactory.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementStageRepositoryFactory.java new file mode 100644 index 0000000000..1e41308ff2 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementStageRepositoryFactory.java @@ -0,0 +1,14 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.utils.facade.api.AbstractComponentFactory; +import com.amdocs.zusammen.utils.facade.api.AbstractFactory; + +public abstract class ElementStageRepositoryFactory + extends AbstractComponentFactory<ElementStageRepository> { + public static ElementStageRepositoryFactory getInstance() { + return AbstractFactory.getInstance(ElementStageRepositoryFactory.class); + } + + public abstract ElementStageRepository createInterface(SessionContext context); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementSynchronizationStateRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementSynchronizationStateRepository.java new file mode 100644 index 0000000000..53c029bb6f --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementSynchronizationStateRepository.java @@ -0,0 +1,21 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.Collection; + +public interface ElementSynchronizationStateRepository + extends SynchronizationStateRepository<ElementEntityContext> { + + Collection<SynchronizationStateEntity> list(SessionContext context, + ElementEntityContext elementContext); + + void update(SessionContext context, ElementEntityContext entityContext, + SynchronizationStateEntity syncStateEntity); + + void markAsDirty(SessionContext context, ElementEntityContext entityContext, + SynchronizationStateEntity syncStateEntity); + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementSynchronizationStateRepositoryFactory.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementSynchronizationStateRepositoryFactory.java new file mode 100644 index 0000000000..26f3bb4f56 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/ElementSynchronizationStateRepositoryFactory.java @@ -0,0 +1,14 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.utils.facade.api.AbstractComponentFactory; +import com.amdocs.zusammen.utils.facade.api.AbstractFactory; + +public abstract class ElementSynchronizationStateRepositoryFactory + extends AbstractComponentFactory<ElementSynchronizationStateRepository> { + public static ElementSynchronizationStateRepositoryFactory getInstance() { + return AbstractFactory.getInstance(ElementSynchronizationStateRepositoryFactory.class); + } + + public abstract ElementSynchronizationStateRepository createInterface(SessionContext context); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/StageRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/StageRepository.java new file mode 100644 index 0000000000..98b0d8242c --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/StageRepository.java @@ -0,0 +1,15 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; + +import java.util.Optional; + +public interface StageRepository<C, E> { + + Optional<StageEntity<E>> get(SessionContext context, C entityContext, E entity); + + void create(SessionContext context, C entityContext, StageEntity<E> stageEntity); + + void delete(SessionContext context, C entityContext, E entity); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/SynchronizationStateRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/SynchronizationStateRepository.java new file mode 100644 index 0000000000..f227b0c925 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/SynchronizationStateRepository.java @@ -0,0 +1,16 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.Optional; + +public interface SynchronizationStateRepository<C> { + + void create(SessionContext context, C entityContext, SynchronizationStateEntity syncStateEntity); + + void delete(SessionContext context, C entityContext, SynchronizationStateEntity syncStateEntity); + + Optional<SynchronizationStateEntity> get(SessionContext context, C entityContext, + SynchronizationStateEntity syncStateEntity); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionDao.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionDao.java new file mode 100644 index 0000000000..f8ad0405b2 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionDao.java @@ -0,0 +1,29 @@ +package org.openecomp.core.zusammen.plugin.dao; + + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.Optional; + +public interface VersionDao { + Collection<VersionEntity> list(SessionContext context, String space, Id itemId); + + Optional<VersionEntity> get(SessionContext context, String space, Id itemId, Id versionId); + + void create(SessionContext context, String space, Id itemId, VersionEntity version); + + void updateModificationTime(SessionContext context, String space, Id itemId, Id versionId, Date modificationTime); + + void delete(SessionContext context, String space, Id itemId, Id versionId); + + boolean checkHealth(SessionContext context); + + void createVersionElements(SessionContext context, String publicSpace, Id itemId, Id versionId, + Id revisionId, Map<Id, Id> versionElementIds, Date publishTime, + String message); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionDaoFactory.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionDaoFactory.java new file mode 100644 index 0000000000..2847959f8f --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionDaoFactory.java @@ -0,0 +1,13 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.utils.facade.api.AbstractComponentFactory; +import com.amdocs.zusammen.utils.facade.api.AbstractFactory; + +public abstract class VersionDaoFactory extends AbstractComponentFactory<VersionDao> { + public static VersionDaoFactory getInstance() { + return AbstractFactory.getInstance(VersionDaoFactory.class); + } + + public abstract VersionDao createInterface(SessionContext context); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionStageRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionStageRepository.java new file mode 100644 index 0000000000..568e0c9d2b --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionStageRepository.java @@ -0,0 +1,9 @@ +package org.openecomp.core.zusammen.plugin.dao; + + +import org.openecomp.core.zusammen.plugin.dao.types.VersionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +public interface VersionStageRepository extends StageRepository<VersionContext, VersionEntity> { + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionStageRepositoryFactory.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionStageRepositoryFactory.java new file mode 100644 index 0000000000..fc9e7725eb --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionStageRepositoryFactory.java @@ -0,0 +1,13 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.utils.facade.api.AbstractComponentFactory; +import com.amdocs.zusammen.utils.facade.api.AbstractFactory; + +public abstract class VersionStageRepositoryFactory extends AbstractComponentFactory<VersionStageRepository> { + public static VersionStageRepositoryFactory getInstance() { + return AbstractFactory.getInstance(VersionStageRepositoryFactory.class); + } + + public abstract VersionStageRepository createInterface(SessionContext context); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionSynchronizationStateRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionSynchronizationStateRepository.java new file mode 100644 index 0000000000..9134392d3b --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionSynchronizationStateRepository.java @@ -0,0 +1,18 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.List; + +public interface VersionSynchronizationStateRepository + extends SynchronizationStateRepository<VersionContext> { + + void updatePublishTime(SessionContext context, VersionContext entityContext, + SynchronizationStateEntity syncStateEntity); + + List<SynchronizationStateEntity> list(SessionContext context, VersionContext entityContext, + VersionEntity versionEntity); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionSynchronizationStateRepositoryFactory.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionSynchronizationStateRepositoryFactory.java new file mode 100644 index 0000000000..dfedb5897b --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/VersionSynchronizationStateRepositoryFactory.java @@ -0,0 +1,14 @@ +package org.openecomp.core.zusammen.plugin.dao; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.utils.facade.api.AbstractComponentFactory; +import com.amdocs.zusammen.utils.facade.api.AbstractFactory; + +public abstract class VersionSynchronizationStateRepositoryFactory + extends AbstractComponentFactory<VersionSynchronizationStateRepository> { + public static VersionSynchronizationStateRepositoryFactory getInstance() { + return AbstractFactory.getInstance(VersionSynchronizationStateRepositoryFactory.class); + } + + public abstract VersionSynchronizationStateRepository createInterface(SessionContext context); +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/CassandraElementRepository.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/CassandraElementRepository.java deleted file mode 100644 index 6cc1350444..0000000000 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/CassandraElementRepository.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * 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.openecomp.core.zusammen.plugin.dao.impl; - -import com.amdocs.zusammen.datatypes.Id; -import com.amdocs.zusammen.datatypes.Namespace; -import com.amdocs.zusammen.datatypes.SessionContext; -import com.amdocs.zusammen.datatypes.item.Info; -import com.amdocs.zusammen.datatypes.item.Relation; -import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; -import com.amdocs.zusammen.utils.fileutils.json.JsonUtil; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.mapping.annotations.Accessor; -import com.datastax.driver.mapping.annotations.Param; -import com.datastax.driver.mapping.annotations.Query; -import com.google.gson.reflect.TypeToken; -import org.openecomp.core.zusammen.plugin.dao.ElementRepository; -import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; - -import java.lang.reflect.Type; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -public class CassandraElementRepository implements ElementRepository { - - private static final String VERSION_ELEMENT_NOT_EXIST_ERROR_MSG = - "List version elements error: " + - "element %s, which appears as an element of item %s version %s, does not exist"; - - @Override - public Collection<ElementEntity> list(SessionContext context, - ElementEntityContext elementContext) { - Set<String> elementIds = getVersionElementIds(context, elementContext); - - Collection<ElementEntity> elements = new ArrayList<>(); - for (String elementId : elementIds) { - elements.add(get(context, elementContext, new ElementEntity(new Id(elementId))) - .orElseThrow( - () -> new IllegalStateException(String.format(VERSION_ELEMENT_NOT_EXIST_ERROR_MSG, - elementId, elementContext.getItemId().getValue(), - getVersionId(elementContext))))); - } - return elements; - } - - @Override - public void create(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - createElement(context, elementContext, element); - addElementToParent(context, elementContext, element); - } - - @Override - public void update(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - updateElement(context, elementContext, element); - } - - @Override - public void delete(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - removeElementFromParent(context, elementContext, element); - deleteElement(context, elementContext, element); - } - - @Override - public Optional<ElementEntity> get(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - Row row = getElementAccessor(context).get( - elementContext.getSpace(), - elementContext.getItemId().toString(), - getVersionId(elementContext), - element.getId().toString()).one(); - - return row == null ? Optional.empty() : Optional.of(getElementEntity(element, row)); - } - - @Override - public void createNamespace(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - getElementNamespaceAccessor(context).create( - elementContext.getSpace(), - elementContext.getItemId().toString(), - element.getId().toString(), - element.getNamespace().toString()); - } - - @Override - public boolean checkHealth(SessionContext context) { - ResultSet resultSet = getVersionElementsAccessor(context).checkHealth(); - return resultSet.getColumnDefinitions().contains("element_ids"); - } - - private String getVersionId(ElementEntityContext elementContext) { - return elementContext.getChangeRef() == null - ? elementContext.getVersionId().toString() - : elementContext.getChangeRef(); - } - - private ElementNamespaceAccessor getElementNamespaceAccessor(SessionContext context) { - return CassandraDaoUtils.getAccessor(context, ElementNamespaceAccessor.class); - } - - private ElementAccessor getElementAccessor(SessionContext context) { - return CassandraDaoUtils.getAccessor(context, ElementAccessor.class); - } - - private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) { - return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class); - } - - private void createElement(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - Set<String> subElementIds = - element.getSubElementIds().stream().map(Id::toString).collect(Collectors.toSet()); - String versionId = getVersionId(elementContext); - - getElementAccessor(context).create( - elementContext.getSpace(), - elementContext.getItemId().toString(), - versionId, - element.getId().toString(), - element.getParentId().toString(), - element.getNamespace().toString(), - JsonUtil.object2Json(element.getInfo()), - JsonUtil.object2Json(element.getRelations()), - element.getData(), - element.getSearchableData(), - element.getVisualization(), - subElementIds); - - getVersionElementsAccessor(context).addElements( - Collections.singleton(element.getId().toString()), - elementContext.getSpace(), - elementContext.getItemId().toString(), - versionId); - } - - private void updateElement(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - getElementAccessor(context).update( - JsonUtil.object2Json(element.getInfo()), - JsonUtil.object2Json(element.getRelations()), - element.getData(), - element.getSearchableData(), - element.getVisualization(), - elementContext.getSpace(), - elementContext.getItemId().toString(), - elementContext.getVersionId().toString(), - element.getId().toString()); - } - - private void deleteElement(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - String versionId = getVersionId(elementContext); - - getElementAccessor(context).delete( - elementContext.getSpace(), - elementContext.getItemId().toString(), - versionId, - element.getId().toString()); - - getVersionElementsAccessor(context).removeElements( - Collections.singleton(element.getId().toString()), - elementContext.getSpace(), - elementContext.getItemId().toString(), - versionId); - } - - private void addElementToParent(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - getElementAccessor(context).addSubElements( - Collections.singleton(element.getId().toString()), - elementContext.getSpace(), - elementContext.getItemId().toString(), - getVersionId(elementContext), - element.getParentId().toString()); - } - - private void removeElementFromParent(SessionContext context, ElementEntityContext elementContext, - ElementEntity element) { - if (element.getParentId() == null) { - return; - } - getElementAccessor(context).removeSubElements( - Collections.singleton(element.getId().toString()), - elementContext.getSpace(), - elementContext.getItemId().toString(), - getVersionId(elementContext), - element.getParentId().toString()); - } - - private ElementEntity getElementEntity(ElementEntity element, Row row) { - element.setNamespace(getNamespace(row.getString(ElementField.NAMESPACE))); - element.setParentId(new Id(row.getString(ElementField.PARENT_ID))); - element.setInfo(json2Object(row.getString(ElementField.INFO), Info.class)); - element.setRelations( - json2Object(row.getString(ElementField.RELATIONS), new TypeToken<ArrayList<Relation>>() { - }.getType())); - element.setData(row.getBytes(ElementField.DATA)); - element.setSearchableData(row.getBytes(ElementField.SEARCHABLE_DATA)); - element.setVisualization(row.getBytes(ElementField.VISUALIZATION)); - element.setSubElementIds(row.getSet(ElementField.SUB_ELEMENT_IDS, String.class) - .stream().map(Id::new).collect(Collectors.toSet())); - return element; - } - - private Namespace getNamespace(String namespaceStr) { - Namespace namespace = new Namespace(); - if (namespaceStr != null) { - namespace.setValue(namespaceStr); - } - return namespace; - } - - private static <T> T json2Object(String json, Type typeOfT) { - return json == null ? null : JsonUtil.json2Object(json, typeOfT); - } - - private Set<String> getVersionElementIds(SessionContext context, - ElementEntityContext elementContext) { - Row row = getVersionElementsAccessor(context).get( - elementContext.getSpace(), - elementContext.getItemId().toString(), - getVersionId(elementContext)).one(); - return row == null - ? new HashSet<>() - : row.getSet(CassandraElementRepository.VersionElementsField.ELEMENT_IDS, String.class); - } - - /* -CREATE TABLE IF NOT EXISTS element_namespace ( - space text, - item_id text, - element_id text, - namespace text, - PRIMARY KEY (( space, item_id, element_id )) -); - */ - @Accessor - interface ElementNamespaceAccessor { - @Query( - "UPDATE element_namespace SET namespace=:ns " + - "WHERE space=:space AND item_id=:item AND element_id=:id ") - void create(@Param("space") String space, - @Param("item") String itemId, - @Param("id") String elementId, - @Param("ns") String namespace); - } - - /* -CREATE TABLE IF NOT EXISTS element ( - space text, - item_id text, - version_id text, - element_id text, - parent_id text, - namespace text, - info text, - relations text, - data blob, - searchable_data blob, - visualization blob, - sub_element_ids set<text>, - PRIMARY KEY (( space, item_id, version_id, element_id )) -); - */ - @Accessor - interface ElementAccessor { - @Query( - "UPDATE element SET parent_id=:parentId, namespace=:ns, info=:info, relations=:rels, " + - "data=:data, searchable_data=:searchableData, visualization=:visualization, " + - "sub_element_ids=sub_element_ids+:subs " + - "WHERE space=:space AND item_id=:item AND version_id=:ver AND element_id=:id ") - void create(@Param("space") String space, - @Param("item") String itemId, - @Param("ver") String versionId, - @Param("id") String elementId, - @Param("parentId") String parentElementId, - @Param("ns") String namespace, - @Param("info") String info, - @Param("rels") String relations, - @Param("data") ByteBuffer data, - @Param("searchableData") ByteBuffer searchableData, - @Param("visualization") ByteBuffer visualization, - @Param("subs") Set<String> subElementIds); - - @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=?" + - " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") - void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData, - ByteBuffer visualization, String space, String itemId, String versionId, - String elementId); - - @Query("DELETE FROM element WHERE space=? AND item_id=? AND version_id=? AND element_id=?") - void delete(String space, String itemId, String versionId, String elementId); - - @Query("SELECT parent_id, namespace, info, relations, data, searchable_data, visualization, " + - "sub_element_ids FROM element " + - "WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") - ResultSet get(String space, String itemId, String versionId, String elementId); - - @Query("UPDATE element SET sub_element_ids=sub_element_ids+? " + - " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") - void addSubElements(Set<String> subElementIds, String space, String itemId, String versionId, - String elementId); - - @Query("UPDATE element SET sub_element_ids=sub_element_ids-? " + - " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") - void removeSubElements(Set<String> subElementIds, String space, String itemId, String versionId, - String elementId); - } - - private static final class ElementField { - private static final String NAMESPACE = "namespace"; - private static final String PARENT_ID = "parent_id"; - private static final String INFO = "info"; - private static final String RELATIONS = "relations"; - private static final String DATA = "data"; - private static final String SEARCHABLE_DATA = "searchable_data"; - private static final String VISUALIZATION = "visualization"; - private static final String SUB_ELEMENT_IDS = "sub_element_ids"; - } - - /* - CREATE TABLE IF NOT EXISTS version_elements ( - space text, - item_id text, - version_id text, - element_ids set<text>, - PRIMARY KEY (( space, item_id, version_id )) - ); - */ - @Accessor - interface VersionElementsAccessor { - - @Query("UPDATE version_elements SET element_ids=element_ids+? " + - "WHERE space=? AND item_id=? AND version_id=?") - void addElements(Set<String> elementIds, String space, String itemId, String versionId); - - @Query("UPDATE version_elements SET element_ids=element_ids-? " + - "WHERE space=? AND item_id=? AND version_id=?") - void removeElements(Set<String> elementIds, String space, String itemId, String versionId); - - @Query("SELECT element_ids FROM version_elements WHERE space=? AND item_id=? AND version_id=?") - ResultSet get(String space, String itemId, String versionId); - - @Query("SELECT element_ids FROM version_elements LIMIT 1") - ResultSet checkHealth(); - } - - private static final class VersionElementsField { - private static final String ELEMENT_IDS = "element_ids"; - } -} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/CassandraDaoUtils.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/CassandraDaoUtils.java index 20a1e1803f..b6cb9e4070 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/CassandraDaoUtils.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/CassandraDaoUtils.java @@ -1,9 +1,9 @@ -package org.openecomp.core.zusammen.plugin.dao.impl; +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; -import com.datastax.driver.core.Session; import com.amdocs.zusammen.commons.db.api.cassandra.CassandraConnectorFactory; import com.amdocs.zusammen.commons.db.api.cassandra.types.CassandraContext; import com.amdocs.zusammen.datatypes.SessionContext; +import com.datastax.driver.core.Session; class CassandraDaoUtils { diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/CassandraElementRepositoryFactory.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementRepositoryFactoryImpl.java index f3072a6502..8540816f00 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/CassandraElementRepositoryFactory.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementRepositoryFactoryImpl.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package org.openecomp.core.zusammen.plugin.dao.impl; +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; import com.amdocs.zusammen.datatypes.SessionContext; import org.openecomp.core.zusammen.plugin.dao.ElementRepository; import org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory; -public class CassandraElementRepositoryFactory extends ElementRepositoryFactory { +public class ElementRepositoryFactoryImpl extends ElementRepositoryFactory { - private static final ElementRepository INSTANCE = new CassandraElementRepository(); + private static final ElementRepository INSTANCE = new ElementRepositoryImpl(); @Override public ElementRepository createInterface(SessionContext context) { diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementRepositoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementRepositoryImpl.java new file mode 100644 index 0000000000..bb3b1cfa7c --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementRepositoryImpl.java @@ -0,0 +1,565 @@ +/* + * 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.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.Namespace; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Info; +import com.amdocs.zusammen.datatypes.item.Relation; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import com.amdocs.zusammen.utils.fileutils.json.JsonUtil; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.mapping.annotations.Accessor; +import com.datastax.driver.mapping.annotations.Param; +import com.datastax.driver.mapping.annotations.Query; +import com.google.gson.reflect.TypeToken; +import org.openecomp.core.zusammen.plugin.ZusammenPluginConstants; +import org.openecomp.core.zusammen.plugin.dao.ElementRepository; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; + +import java.lang.reflect.Type; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +public class ElementRepositoryImpl implements ElementRepository { + + @Override + public Map<Id, Id> listIds(SessionContext context, ElementEntityContext elementContext) { + + if (elementContext.getRevisionId() == null) { + String revisionId = calculateLastRevisionId(context, elementContext); + if (revisionId == null) { + return new HashMap<>(); + } + + elementContext.setRevisionId(new Id(revisionId)); + } + return getVersionElementIds(context, elementContext).entrySet().stream().collect(Collectors + .toMap(entry -> new Id(entry.getKey()), entry -> new Id(entry.getValue()))); + + /* return getVersionElementIds(context, elementContext).stream() + .map(Id::new) + .collect(Collectors.toList());*/ + + } + + @Override + public void create(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + createElement(context, elementContext, element); + addElementToParent(context, elementContext, element); + } + + @Override + public void update(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + + Id elementRevisionId = getElementRevision(context, elementContext, element.getId()); + if (elementRevisionId.equals(elementContext.getRevisionId())) { + updateElement(context, elementContext, element); + } else { + createElement(context, elementContext, element); + } + } + + @Override + public void delete(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + removeElementFromParent(context, elementContext, element); + deleteElement(context, elementContext, element); + } + + @Override + public Optional<ElementEntity> get(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + String revisionId = calculateElementRevisionId(context, elementContext, element); + if (revisionId == null) { + return Optional.empty(); + } + + Row row = getElementAccessor(context).get( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().toString(), + revisionId).one(); + + return row == null ? Optional.empty() : Optional.of(getElementEntity(element, row)); + } + + @Override + public Optional<ElementEntity> getDescriptor(SessionContext context, + ElementEntityContext elementContext, + ElementEntity element) { + String revisionId = calculateElementRevisionId(context, elementContext, element); + if (revisionId == null) { + return Optional.empty(); + } + + Row row = getElementAccessor(context).getDescriptor( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().toString(), + revisionId).one(); + + return row == null ? Optional.empty() : Optional.of(getElementEntityDescriptor(element, row)); + } + + @Override + public void createNamespace(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + getElementNamespaceAccessor(context).create(elementContext.getItemId().toString(), + element.getId().toString(), + element.getNamespace().toString()); + } + + @Override + public Optional<Id> getHash(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + String revisionId = calculateElementRevisionId(context, elementContext, element); + if (revisionId == null) { + return Optional.empty(); + } + + Row row = getElementAccessor(context).getHash( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getId().toString(), + revisionId).one(); + + return row == null ? Optional.empty() : Optional.of(getElementHash(row)); + } + + private String calculateElementRevisionId(SessionContext context, + ElementEntityContext elementContext, + ElementEntity element) { + + if (elementContext.getSpace().equals(ZusammenPluginConstants.PUBLIC_SPACE)) { + + String versionRevision; + if (elementContext.getRevisionId() == null) { + versionRevision = calculateLastRevisionId(context, elementContext); + } else { + versionRevision = elementContext.getRevisionId().getValue(); + } + + elementContext.setRevisionId(new Id(versionRevision)); + Map<String, String> elementIds = getVersionElementIds(context, elementContext); + if (elementIds.containsKey(element.getId().getValue())) { + return elementIds.get(element.getId().getValue()); + } else { + return null; + } + + } else { + return Id.ZERO.getValue(); + } + } + + private String calculateLastRevisionId(SessionContext context, ElementEntityContext + elementContext) { + List<Row> rows = getVersionElementsAccessor(context).listRevisions(elementContext.getSpace(), + elementContext + .getItemId().toString(), elementContext.getVersionId().toString()).all(); + if (rows == null || rows.size() == 0) { + return null; + } + rows.sort((o1, o2) -> o1.getDate(VersionElementsField.PUBLISH_TIME) + .after(o2.getDate(VersionElementsField.PUBLISH_TIME)) ? -1 : 1); + return rows.get(0).getString(VersionElementsField.REVISION_ID); + } + + /*private static String getVersionId(ElementEntityContext elementContext) { + return elementContext.getRevisionId() == null + ? elementContext.getVersionId().toString() + : elementContext.getRevisionId().getValue(); + }*/ + + private ElementNamespaceAccessor getElementNamespaceAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, ElementNamespaceAccessor.class); + } + + private ElementAccessor getElementAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, ElementAccessor.class); + } + + private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class); + } + + private void createElement(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + createElementRow(context, elementContext, element); + + Map<String, String> elementIds = new TreeMap<>(); + elementIds.put(element.getId().toString(), elementContext.getRevisionId().getValue()); + getVersionElementsAccessor(context).addElements( + elementIds, + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + } + + private void createElementRow(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + Set<String> subElementIds = + element.getSubElementIds().stream().map(Id::toString).collect(Collectors.toSet()); + + getElementAccessor(context).create( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getId().toString(), + elementContext.getRevisionId().getValue(), + element.getParentId() == null ? null : element.getParentId().toString(), + element.getNamespace() == null ? null : element.getNamespace().toString(), + JsonUtil.object2Json(element.getInfo()), + JsonUtil.object2Json(element.getRelations()), + element.getData(), + element.getSearchableData(), + element.getVisualization(), + subElementIds, + element.getElementHash().getValue()); + } + + private void updateElement(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + + + if (element.getParentId() == null) { + getElementAccessor(context).update( + JsonUtil.object2Json(element.getInfo()), + JsonUtil.object2Json(element.getRelations()), + element.getData(), + element.getSearchableData(), + element.getVisualization(), + element.getElementHash().getValue(), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().toString(), + elementContext.getRevisionId().getValue()); + } else { + getElementAccessor(context).update( + JsonUtil.object2Json(element.getInfo()), + JsonUtil.object2Json(element.getRelations()), + element.getData(), + element.getSearchableData(), + element.getVisualization(), + element.getElementHash().getValue(), + element.getParentId().getValue(), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().getValue(), + elementContext.getRevisionId().getValue()); + } + + Map<String, String> elementIds = new TreeMap<>(); + elementIds.put(element.getId().getValue(), elementContext.getRevisionId().getValue()); + getVersionElementsAccessor(context).addElements( + elementIds, + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + } + + private void deleteElement(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + + + getElementAccessor(context).delete( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().toString(), + elementContext.getRevisionId().getValue()); + + getVersionElementsAccessor(context).removeElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementContext.getRevisionId().getValue()); + } + + private void addElementToParent(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + if (element.getParentId() == null) { + return; + } + + + getElementAccessor(context).addSubElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getParentId().toString(), + elementContext.getRevisionId().getValue()); + + Map<String, String> elementIds = new TreeMap<>(); + elementIds.put(element.getParentId().toString(), elementContext.getRevisionId().getValue()); + getVersionElementsAccessor(context).addElements(elementIds, elementContext.getSpace(), + elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + } + + private void removeElementFromParent(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + + if (element.getParentId() == null) { + return; + } + + Optional<ElementEntity> parentElement = + get(context, elementContext, new ElementEntity(element.getParentId())); + if (!parentElement.isPresent()) { + return; + } + getElementAccessor(context).removeSubElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getParentId().toString(), + elementContext.getRevisionId().getValue()); + + getVersionElementsAccessor(context) + .removeElements(Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + + Map<String, String> elementIds = new TreeMap<>(); + elementIds.put(element.getParentId().toString(), elementContext.getRevisionId().getValue()); + getVersionElementsAccessor(context).addElements(elementIds, elementContext.getSpace(), + elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + } + + static ElementEntity getElementEntityDescriptor(ElementEntity element, Row row) { + element.setNamespace(getNamespace(row.getString(ElementField.NAMESPACE))); + element.setParentId(getParentId(row.getString(ElementField.PARENT_ID))); + element.setInfo(json2Object(row.getString(ElementField.INFO), Info.class)); + element.setRelations( + json2Object(row.getString(ElementField.RELATIONS), new TypeToken<ArrayList<Relation>>() { + }.getType())); + + element.setSubElementIds(row.getSet(ElementField.SUB_ELEMENT_IDS, String.class) + .stream().map(Id::new).collect(Collectors.toSet())); + return element; + } + + static ElementEntity getElementEntity(ElementEntity element, Row row) { + getElementEntityDescriptor(element, row); + + element.setData(row.getBytes(ElementField.DATA)); + element.setSearchableData(row.getBytes(ElementField.SEARCHABLE_DATA)); + element.setVisualization(row.getBytes(ElementField.VISUALIZATION)); + element.setElementHash(new Id(row.getString(ElementField.ELEMENT_HASH))); + return element; + } + + private Id getElementHash(Row row) { + return new Id(row.getString(ElementField.ELEMENT_HASH)); + } + + private static Id getParentId(String parentIdStr) { + return parentIdStr == null ? null : new Id(parentIdStr); + } + + private static Namespace getNamespace(String namespaceStr) { + Namespace namespace = new Namespace(); + if (namespaceStr != null) { + namespace.setValue(namespaceStr); + } + return namespace; + } + + private static <T> T json2Object(String json, Type typeOfT) { + return json == null ? null : JsonUtil.json2Object(json, typeOfT); + } + + private Map<String, String> getVersionElementIds(SessionContext context, + ElementEntityContext elementContext) { + Row row = getVersionElementsAccessor(context).get( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()).one(); + return row == null + ? new HashMap<>() + : row.getMap(ElementRepositoryImpl.VersionElementsField.ELEMENT_IDS, String.class, String + .class); + } + + private Id getElementRevision(SessionContext context, ElementEntityContext elementContext + , Id elementId) { + Map<Id, Id> versionElementIds = + listIds(context, new ElementEntityContext + (elementContext.getSpace(), elementContext.getItemId(), elementContext.getVersionId(), + elementContext.getRevisionId())); + return versionElementIds.get(elementId); + + } + + + /* +CREATE TABLE IF NOT EXISTS element_namespace ( + item_id text, + element_id text, + namespace text, + PRIMARY KEY (( item_id, element_id )) +); + */ + @Accessor + interface ElementNamespaceAccessor { + @Query("UPDATE element_namespace SET namespace=:ns " + + "WHERE item_id=:item AND element_id=:id ") + void create(@Param("item") String itemId, + @Param("id") String elementId, + @Param("ns") String namespace); + } + + @Accessor + interface ElementAccessor { + @Query( + "UPDATE element SET parent_id=:parentId, namespace=:ns, info=:info, relations=:rels, " + + "data=:data, searchable_data=:searchableData, visualization=:visualization, " + + "sub_element_ids=sub_element_ids+:subs , element_hash=:elementHash " + + " WHERE space=:space AND item_id=:item AND version_id=:ver AND element_id=:id AND " + + "revision_id=:rev ") + void create(@Param("space") String space, + @Param("item") String itemId, + @Param("ver") String versionId, + @Param("id") String elementId, + @Param("rev") String revisionId, + @Param("parentId") String parentElementId, + @Param("ns") String namespace, + @Param("info") String info, + @Param("rels") String relations, + @Param("data") ByteBuffer data, + @Param("searchableData") ByteBuffer searchableData, + @Param("visualization") ByteBuffer visualization, + @Param("subs") Set<String> subElementIds, + @Param("elementHash") String elementHash); + + + @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=? ," + + "element_hash=? , parent_id=? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData, + ByteBuffer visualization, String elementHash, String parentId, String space, String + itemId, String + versionId, String elementId, String revisionId); + + @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=? ," + + "element_hash=? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData, + ByteBuffer visualization, String elementHash, String space, String + itemId, String + versionId, String elementId, String revisionId); + + @Query( + "DELETE FROM element WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + void delete(String space, String itemId, String versionId, String elementId, String revisionId); + + @Query("SELECT parent_id, namespace, info, relations, data, searchable_data, visualization, " + + "sub_element_ids,element_hash FROM element " + + "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + ResultSet get(String space, String itemId, String versionId, String elementId, String + revisionId); + + @Query("SELECT parent_id, namespace, info, relations, sub_element_ids FROM element " + + "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + ResultSet getDescriptor(String space, String itemId, String versionId, String elementId, + String revisionId); + + @Query("UPDATE element SET sub_element_ids=sub_element_ids+? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + void addSubElements(Set<String> subElementIds, String space, String itemId, String versionId, + String elementId, String revisionId); + + @Query("UPDATE element SET sub_element_ids=sub_element_ids-? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + void removeSubElements(Set<String> subElementIds, String space, String itemId, String versionId, + String elementId, String revisionId); + + @Query("SELECT element_hash FROM element " + + "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ") + ResultSet getHash(String space, String itemId, String versionId, String elementId, String + revisionId); + } + + private static final class ElementField { + private static final String NAMESPACE = "namespace"; + private static final String PARENT_ID = "parent_id"; + private static final String INFO = "info"; + private static final String RELATIONS = "relations"; + private static final String DATA = "data"; + private static final String SEARCHABLE_DATA = "searchable_data"; + private static final String VISUALIZATION = "visualization"; + private static final String SUB_ELEMENT_IDS = "sub_element_ids"; + private static final String ELEMENT_HASH = "element_hash"; + } + + @Accessor + interface VersionElementsAccessor { + + @Query("UPDATE version_elements SET element_ids=element_ids+ ? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + void addElements(Map<String, String> elementIds, String space, String itemId, String versionId, + String versionRevisionId); + + @Query("UPDATE version_elements SET element_ids=element_ids-? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=?") + void removeElements(Set<String> elementIds, String space, String itemId, String versionId, + String revisionId); + + @Query( + "SELECT element_ids FROM version_elements WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + ResultSet get(String space, String itemId, String versionId, String revisionId); + + @Query( + "SELECT revision_id,publish_time FROM version_elements WHERE space=? AND item_id=? AND " + + "version_id=? ") + ResultSet listRevisions(String space, String itemId, String versionId); + + } + + private static final class VersionElementsField { + private static final String ELEMENT_IDS = "element_ids"; + private static final String REVISION_ID = "revision_id"; + private static final String PUBLISH_TIME = "publish_time"; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementStageRepositoryFactoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementStageRepositoryFactoryImpl.java new file mode 100644 index 0000000000..02bec12302 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementStageRepositoryFactoryImpl.java @@ -0,0 +1,31 @@ +/* + * 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.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.ElementStageRepository; +import org.openecomp.core.zusammen.plugin.dao.ElementStageRepositoryFactory; + +public class ElementStageRepositoryFactoryImpl extends ElementStageRepositoryFactory { + + private static final ElementStageRepository INSTANCE = new ElementStageRepositoryImpl(); + + @Override + public ElementStageRepository createInterface(SessionContext context) { + return INSTANCE; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementStageRepositoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementStageRepositoryImpl.java new file mode 100644 index 0000000000..c215f825a6 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementStageRepositoryImpl.java @@ -0,0 +1,423 @@ +/* + * 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.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Action; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import com.amdocs.zusammen.utils.fileutils.json.JsonUtil; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.mapping.annotations.Accessor; +import com.datastax.driver.mapping.annotations.Param; +import com.datastax.driver.mapping.annotations.Query; +import org.openecomp.core.zusammen.plugin.dao.ElementStageRepository; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; + +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class ElementStageRepositoryImpl implements ElementStageRepository { + + @Override + public Collection<ElementEntity> listIds(SessionContext context, + ElementEntityContext elementContext) { + return getElements(getStageElementIds(context, elementContext)); + } + + @Override + public Collection<ElementEntity> listConflictedIds(SessionContext context, + ElementEntityContext elementContext) { + return getElements(getConflictedElementIds(context, elementContext)); + } + + @Override + public void create(SessionContext context, ElementEntityContext elementContext, + StageEntity<ElementEntity> elementStage) { + createElement(context, elementContext, elementStage); + addElementToParent(context, elementContext, elementStage.getEntity()); + } + + @Override + public void markAsNotConflicted(SessionContext context, ElementEntityContext elementContext, + ElementEntity element, Action action) { + getElementStageAccessor(context).updateState(action, false, + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().toString()); + + getStageElementsAccessor(context).removeConflictElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementContext.getRevisionId().getValue()); + } + + @Override + public void markAsNotConflicted(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + getElementStageAccessor(context).markAsNotConflicted( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().toString()); + + getStageElementsAccessor(context).removeConflictElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementContext.getRevisionId().getValue()); + } + + @Override + public void update(SessionContext context, ElementEntityContext elementContext, + ElementEntity element, Action action, boolean conflicted) { + getElementStageAccessor(context).update( + JsonUtil.object2Json(element.getInfo()), + JsonUtil.object2Json(element.getRelations()), + element.getData(), + element.getSearchableData(), + element.getVisualization(), + element.getElementHash().getValue(), + action, + conflicted, + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + element.getId().toString()); + + if (!conflicted) { + getStageElementsAccessor(context).removeConflictElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementContext.getRevisionId().getValue()); + } + } + + @Override + public void delete(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + removeElementFromParent(context, elementContext, element); + deleteElement(context, elementContext, element); + } + + @Override + public Optional<StageEntity<ElementEntity>> get(SessionContext context, + ElementEntityContext elementContext, + ElementEntity element) { + Row row = getElementStageAccessor(context).get( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getId().toString()).one(); + + return row == null ? Optional.empty() : Optional.of(getStageElement(row)); + } + + @Override + public Optional<StageEntity<ElementEntity>> getDescriptor(SessionContext context, + ElementEntityContext elementContext, + ElementEntity element) { + Row row = getElementStageAccessor(context).getDescriptor( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getId().toString()).one(); + + return row == null ? Optional.empty() : Optional.of(getStageElementDescriptor(row)); + } + + + + private Collection<ElementEntity> getElements(Set<String> elementIds) { + return elementIds.stream() + .map(id -> new ElementEntity(new Id(id))) + .collect(Collectors.toList()); + } + + private void createElement(SessionContext context, ElementEntityContext elementContext, + StageEntity<ElementEntity> elementStage) { + + + ElementEntity element = elementStage.getEntity(); + Set<String> subElementIds = + element.getSubElementIds().stream().map(Id::toString).collect(Collectors.toSet()); + Set<String> conflictDependents = elementStage.getConflictDependents().stream() + .map(conflictDependent -> conflictDependent.getId().getValue()) + .collect(Collectors.toSet()); + + getElementStageAccessor(context).create( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getId().toString(), + element.getParentId() == null ? null : element.getParentId().toString(), + element.getNamespace() == null ? null : element.getNamespace().toString(), + JsonUtil.object2Json(element.getInfo()), + JsonUtil.object2Json(element.getRelations()), + element.getData(), + element.getSearchableData(), + element.getVisualization(), + subElementIds, + element.getElementHash() == null ? null : element.getElementHash().getValue(), + elementStage.getPublishTime(), + elementStage.getAction(), + elementStage.isConflicted(), + conflictDependents); + + getStageElementsAccessor(context).add( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + + if (elementStage.isConflicted()) { + getStageElementsAccessor(context).addConflictElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + } + } + + private void deleteElement(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + + + getElementStageAccessor(context).delete( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getId().toString()); + + getStageElementsAccessor(context).remove( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()); + } + + private void addElementToParent(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + if (element.getParentId() == null) { + return; + } + getElementStageAccessor(context).addSubElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getParentId().toString()); + } + + private void removeElementFromParent(SessionContext context, ElementEntityContext elementContext, + ElementEntity element) { + if (element.getParentId() == null) { + return; + } + getElementStageAccessor(context).removeSubElements( + Collections.singleton(element.getId().toString()), + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + element.getParentId().toString()); + } + + private StageEntity<ElementEntity> getStageElementDescriptor(Row row) { + return buildStageElement(ElementRepositoryImpl.getElementEntityDescriptor( + new ElementEntity(new Id(row.getString(ElementStageField.ID))), row), row); + } + + private StageEntity<ElementEntity> getStageElement(Row row) { + return buildStageElement(ElementRepositoryImpl.getElementEntity( + new ElementEntity(new Id(row.getString(ElementStageField.ID))), row), row); + } + + + private StageEntity<ElementEntity> buildStageElement(ElementEntity element, Row row) { + StageEntity<ElementEntity> elementStage = + new StageEntity<>(element, row.getDate(ElementStageField.PUBLISH_TIME)); + elementStage.setAction(Action.valueOf(row.getString(ElementStageField.ACTION))); + elementStage.setConflicted(row.getBool(ElementStageField.CONFLICTED)); + elementStage.setConflictDependents( + row.getSet(ElementStageField.CONFLICT_DEPENDENTS, String.class).stream() + .map(conflictDependentId -> new ElementEntity(new Id(conflictDependentId))) + .collect(Collectors.toSet())); + return elementStage; + } + + private Set<String> getStageElementIds(SessionContext context, + ElementEntityContext elementContext) { + Row row = getStageElementsAccessor(context).get( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()).one(); + return row == null ? new HashSet<>() + : row.getSet(StageElementsField.STAGE_ELEMENT_IDS, String.class); + } + + private Set<String> getConflictedElementIds(SessionContext context, + ElementEntityContext elementContext) { + Row row = getStageElementsAccessor(context).getConflicted( + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().getValue(), + elementContext.getRevisionId().getValue()).one(); + return row == null ? new HashSet<>() + : row.getSet(StageElementsField.CONFLICT_ELEMENT_IDS, String.class); + } + + private ElementStageAccessor getElementStageAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, ElementStageAccessor.class); + } + + private StageElementsAccessor getStageElementsAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, StageElementsAccessor.class); + } + + @Accessor + interface ElementStageAccessor { + @Query( + "UPDATE element_stage SET parent_id=:parentId, namespace=:ns, info=:info, relations=:rels, " + + "data=:data, searchable_data=:searchableData, visualization=:visualization, " + + "publish_time=:publishTime, action=:action, " + + "conflicted=:conflicted, conflict_dependent_ids=:conflictDependents, " + + "sub_element_ids=sub_element_ids+:subs, element_hash=:elementHash " + + "WHERE space=:space AND item_id=:item AND version_id=:ver AND element_id=:id ") + void create(@Param("space") String space, + @Param("item") String itemId, + @Param("ver") String versionId, + @Param("id") String elementId, + @Param("parentId") String parentElementId, + @Param("ns") String namespace, + @Param("info") String info, + @Param("rels") String relations, + @Param("data") ByteBuffer data, + @Param("searchableData") ByteBuffer searchableData, + @Param("visualization") ByteBuffer visualization, + @Param("subs") Set<String> subElementIds, + @Param("elementHash") String elementHash, + @Param("publishTime") Date publishTime, + @Param("action") Action action, + @Param("conflicted") boolean conflicted, + @Param("conflictDependents") Set<String> conflictDependents); + + @Query("UPDATE element_stage SET info=?, relations=?, data=?, searchable_data=?, " + + "visualization=?,element_hash=?, action=?, conflicted=? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") + void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData, + ByteBuffer visualization, String elementHash, Action action, boolean conflicted, + String space, + String itemId, String versionId, String elementId); + + @Query("UPDATE element_stage SET action=?, conflicted=? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") + void updateState(Action action, boolean conflicted, String space, String itemId, + String versionId, String elementId); + + @Query("UPDATE element_stage SET conflicted=false " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") + void markAsNotConflicted(String space, String itemId, String versionId, String elementId); + + @Query( + "DELETE FROM element_stage WHERE space=? AND item_id=? AND version_id=? AND element_id=?") + void delete(String space, String itemId, String versionId, String elementId); + + @Query("SELECT element_id, parent_id, namespace, info, relations, data, searchable_data, " + + "visualization, sub_element_ids,element_hash, publish_time, action, " + + "conflicted, conflict_dependent_ids FROM element_stage " + + "WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") + ResultSet get(String space, String itemId, String versionId, String elementId); + + @Query("SELECT element_id, parent_id, namespace, info, relations, " + + "sub_element_ids, publish_time, action, conflicted, conflict_dependent_ids " + + "FROM element_stage WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") + ResultSet getDescriptor(String space, String itemId, String versionId, String elementId); + + @Query("UPDATE element_stage SET sub_element_ids=sub_element_ids+? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") + void addSubElements(Set<String> subElementIds, String space, String itemId, String versionId, + String elementId); + + @Query("UPDATE element_stage SET sub_element_ids=sub_element_ids-? " + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ") + void removeSubElements(Set<String> subElementIds, String space, String itemId, String versionId, + String elementId); + } + + private static final class ElementStageField { + private static final String ID = "element_id"; + private static final String PUBLISH_TIME = "publish_time"; + private static final String ACTION = "action"; + private static final String CONFLICTED = "conflicted"; + private static final String CONFLICT_DEPENDENTS = "conflict_dependent_ids"; + } + + @Accessor + interface StageElementsAccessor { + + @Query("UPDATE version_elements SET stage_element_ids=stage_element_ids+? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + void add(Set<String> elementIds, String space, String itemId, String versionId, String + revisionId); + + @Query("UPDATE version_elements SET stage_element_ids=stage_element_ids-? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + void remove(Set<String> elementIds, String space, String itemId, String versionId, String + revisionId); + + @Query("SELECT stage_element_ids FROM version_elements " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=?") + ResultSet get(String space, String itemId, String versionId, String revisionId); + + @Query("UPDATE version_elements SET conflict_element_ids=conflict_element_ids+? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + void addConflictElements(Set<String> elementIds, String space, String itemId, String + versionId, String revisionId); + + @Query("UPDATE version_elements SET conflict_element_ids=conflict_element_ids-? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + void removeConflictElements(Set<String> elementIds, String space, String itemId, + String versionId, String revisionId); + + @Query("SELECT conflict_element_ids FROM version_elements " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + ResultSet getConflicted(String space, String itemId, String versionId, String revisionId); + } + + private static final class StageElementsField { + private static final String STAGE_ELEMENT_IDS = "stage_element_ids"; + private static final String CONFLICT_ELEMENT_IDS = "conflict_element_ids"; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementSynchronizationStateRepositoryFactoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementSynchronizationStateRepositoryFactoryImpl.java new file mode 100644 index 0000000000..ec7e1c30ae --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementSynchronizationStateRepositoryFactoryImpl.java @@ -0,0 +1,33 @@ +/* + * 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.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepositoryFactory; + +public class ElementSynchronizationStateRepositoryFactoryImpl + extends ElementSynchronizationStateRepositoryFactory { + + private static final ElementSynchronizationStateRepository INSTANCE = + new ElementSynchronizationStateRepositoryImpl(); + + @Override + public ElementSynchronizationStateRepository createInterface(SessionContext context) { + return INSTANCE; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementSynchronizationStateRepositoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementSynchronizationStateRepositoryImpl.java new file mode 100644 index 0000000000..d41d3d73b1 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/ElementSynchronizationStateRepositoryImpl.java @@ -0,0 +1,209 @@ +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.mapping.annotations.Accessor; +import com.datastax.driver.mapping.annotations.Query; +import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; + +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class ElementSynchronizationStateRepositoryImpl + implements ElementSynchronizationStateRepository { + + @Override + public Collection<SynchronizationStateEntity> list(SessionContext context, + ElementEntityContext elementContext) { + List<Row> rows = getAccessor(context) + .list(elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString()).all(); + return rows == null ? new HashSet<>() + : rows.stream().map(this::getSynchronizationStateEntity).collect(Collectors.toSet()); + + } + + @Override + public void create(SessionContext context, ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState) { + update(context, elementContext.getSpace(), + elementContext.getItemId(), + elementContext.getVersionId(), + elementContext.getRevisionId(), + elementSyncState.getRevisionId(), + elementSyncState.getId(), + elementSyncState.getPublishTime(), + elementSyncState.isDirty() + + ); + } + + @Override + public void update(SessionContext context, ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState) { + update(context, elementContext.getSpace(), + elementContext.getItemId(), + elementContext.getVersionId(), + elementContext.getRevisionId(), + elementSyncState.getRevisionId(), + elementSyncState.getId(), + elementSyncState.getPublishTime(), + elementSyncState.isDirty() + + ); + } + + @Override + public void markAsDirty(SessionContext context, ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState) { + + + getAccessor(context).updateDirty(true, + elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementSyncState.getId().toString(), + elementContext.getRevisionId().getValue()); + + getVersionElementsAccessor(context).addDirtyElements( + Collections.singleton(elementSyncState.getId().toString()), elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementContext.getRevisionId().getValue()); + } + + @Override + public void delete(SessionContext context, ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState) { + getAccessor(context).delete(elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementSyncState.getId().toString(), + elementContext.getRevisionId().getValue()); + + getVersionElementsAccessor(context).removeDirtyElements( + Collections.singleton(elementSyncState.getId().toString()), elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementContext.getRevisionId().getValue()); + } + + @Override + public Optional<SynchronizationStateEntity> get(SessionContext context, + ElementEntityContext elementContext, + SynchronizationStateEntity elementSyncState) { + + Row row = getAccessor(context) + .get(elementContext.getSpace(), + elementContext.getItemId().toString(), + elementContext.getVersionId().toString(), + elementSyncState.getId().toString(), + elementSyncState.getRevisionId().getValue()).one(); + + return row == null ? Optional.empty() : Optional.of(getSynchronizationStateEntity(row)); + } + + private void update(SessionContext context, String space, Id itemId, Id versionId, Id + versionRevisionId,Id elementRevisionId,Id elementId, Date publishTime, boolean isDirty) { + getAccessor(context).update(publishTime, + isDirty, + space, + itemId.toString(), + versionId.toString(), + elementId.toString(), + elementRevisionId.getValue()); + + if (isDirty) { + getVersionElementsAccessor(context).addDirtyElements( + Collections.singleton(elementId.toString()), space, + itemId.toString(), + versionId.toString(), + versionRevisionId.getValue()); + } else { + getVersionElementsAccessor(context).removeDirtyElements( + Collections.singleton(elementId.toString()), space, + itemId.toString(), + versionId.toString(), + versionRevisionId.getValue()); + } + } + + + private SynchronizationStateEntity getSynchronizationStateEntity(Row row) { + SynchronizationStateEntity entity = + new SynchronizationStateEntity(new Id(row.getString(SynchronizationStateField.ID)), + new Id(row.getString(SynchronizationStateField.REVISION_ID)), + row.getDate(SynchronizationStateField.PUBLISH_TIME), + row.getBool(SynchronizationStateField.DIRTY)); + entity.setRevisionId(new Id(row.getString(SynchronizationStateField.REVISION_ID))); + + return entity; + + } + + private ElementSynchronizationStateAccessor getAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, ElementSynchronizationStateAccessor.class); + } + + private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class); + } + + @Accessor + interface ElementSynchronizationStateAccessor { + @Query("UPDATE element_synchronization_state SET publish_time=?, dirty=? " + + "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id = ? ") + void update(Date publishTime, boolean dirty, String space, String itemId, String versionId, + String elementId, String revisionId); + + @Query("UPDATE element_synchronization_state SET dirty=? " + + "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id = ? ") + void updateDirty(boolean dirty, String space, String itemId, String versionId, + String elementId, String revisionId); + + @Query("DELETE FROM element_synchronization_state " + + "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id = ? ") + void delete(String space, String itemId, String versionId, String elementId, String revisionId); + + @Query("SELECT element_id,revision_id, publish_time, dirty FROM element_synchronization_state" + + " WHERE space=? AND item_id=? AND version_id=?") + ResultSet list(String space, String itemId, String versionId); + + @Query("SELECT element_id,revision_id, publish_time, dirty FROM element_synchronization_state" + + " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id = ? ") + ResultSet get(String space, String itemId, String versionId, String elementId, String + revisionId); + } + + private static final class SynchronizationStateField { + private static final String ID = "element_id"; + private static final String PUBLISH_TIME = "publish_time"; + private static final String DIRTY = "dirty"; + private static final String REVISION_ID = "revision_id"; + } + + @Accessor + interface VersionElementsAccessor { + + @Query("UPDATE version_elements SET dirty_element_ids=dirty_element_ids+? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=?") + void addDirtyElements(Set<String> elementIds, String space, String itemId, String versionId, + String revisionId); + + @Query("UPDATE version_elements SET dirty_element_ids=dirty_element_ids-? " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + void removeDirtyElements(Set<String> elementIds, String space, String itemId, String + versionId, String revisionId); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionDaoFactoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionDaoFactoryImpl.java new file mode 100644 index 0000000000..60dc9d1765 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionDaoFactoryImpl.java @@ -0,0 +1,15 @@ +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.VersionDao; +import org.openecomp.core.zusammen.plugin.dao.VersionDaoFactory; + +public class VersionDaoFactoryImpl extends VersionDaoFactory { + + private static final VersionDao INSTANCE = new VersionDaoImpl(); + + @Override + public VersionDao createInterface(SessionContext context) { + return INSTANCE; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionDaoImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionDaoImpl.java new file mode 100644 index 0000000000..bba2ddf267 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionDaoImpl.java @@ -0,0 +1,185 @@ +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.mapping.annotations.Accessor; +import com.datastax.driver.mapping.annotations.Query; +import org.openecomp.core.zusammen.plugin.dao.VersionDao; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toMap; + +public class VersionDaoImpl implements VersionDao { + + @Override + public void create(SessionContext context, String space, Id itemId, VersionEntity version) { + String baseVersion = version.getBaseId() != null ? version.getBaseId().toString() : null; + + getAccessor(context) + .create(space, itemId.toString(), version.getId().toString(), + baseVersion, + version.getCreationTime(), version.getModificationTime()); + + } + + @Override + public void delete(SessionContext context, String space, Id itemId, Id versionId) { + + getAccessor(context).delete(space, itemId.toString(), versionId.toString()); + } + + @Override + public void updateModificationTime(SessionContext context, String space, Id itemId, + Id versionId, Date modificationTime) { + getAccessor(context) + .updateModificationTime(modificationTime, space, itemId.toString(), versionId.toString()); + } + + + @Override + public Collection<VersionEntity> list(SessionContext context, String space, Id itemId) { + List<Row> rows = getAccessor(context).list(space, itemId.toString()).all(); + return rows == null ? new ArrayList<>() : + rows.stream().map(VersionDaoImpl::convertToVersionEntity).collect(Collectors.toList()); + } + + + @Override + public Optional<VersionEntity> get(SessionContext context, String space, Id itemId, + Id versionId) { + Row row; + + row = getAccessor(context).get(space, itemId.toString(), versionId.toString()).one(); + + + return row == null ? Optional.empty() : Optional.of(convertToVersionEntity(row)); + } + + @Override + public boolean checkHealth(SessionContext context) { + return getAccessor(context).checkHealth().getColumnDefinitions() + .contains(VersionField.VERSION_ID); + } + + @Override + public void createVersionElements(SessionContext context, String space, Id itemId, + Id versionId, Id revisionId, Map<Id, Id> versionElementIds, + Date publishTime, String message) { + Map<String, String> elementIds = versionElementIds==null?null:versionElementIds. + entrySet(). + stream(). + collect(toMap((Map.Entry<Id, Id>entry)->entry.getKey().getValue(), + (Map.Entry<Id, Id>entry)->entry.getValue().getValue())); + + getVersionElementsAccessor(context).create(space,itemId.toString(),versionId.toString(), + revisionId.getValue(),elementIds,publishTime,message,context.getUser().getUserName()); + } + + + private static VersionEntity convertToVersionEntity(Row row) { + + /*Id revisionId = row.getColumnDefinitions().contains("revision_id")?new Id(row.getString + (VersionField.REVISION_ID)):null;*/ + + VersionEntity version = new VersionEntity(new Id(row.getString(VersionField.VERSION_ID))); + return enrichVersionEntity(version, row); + } + + static VersionEntity enrichVersionEntity(VersionEntity version, Row row) { + version.setBaseId(new Id(row.getString(VersionField.BASE_VERSION_ID))); + version.setCreationTime(row.getDate(VersionField.CREATION_TIME)); + version.setModificationTime(row.getDate(VersionField.MODIFICATION_TIME)); + return version; + } + + private VersionAccessor getAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, VersionAccessor.class); + } + + private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class); + } + + @Accessor + interface VersionAccessor { + + @Query( + "INSERT INTO version (space, item_id, version_id, base_version_id, " + + "creation_time, " + + "modification_time) " + + "VALUES (?, ?, ?, ?, ?, ?)") + void create(String space, String itemId, String versionId, String baseVersionId, + Date creationTime, Date modificationTime); + + @Query("UPDATE version SET modification_time=? WHERE space=? AND item_id=? AND version_id=? ") + void updateModificationTime(Date modificationTime, String space, String itemId, + String versionId); + + @Query("DELETE FROM version WHERE space=? AND item_id=? AND version_id=? ") + void delete(String space, String itemId, String versionId); + + @Query("SELECT version_id, base_version_id, creation_time, modification_time " + + "FROM version WHERE space=? AND item_id=? AND version_id=? ") + ResultSet get(String space, String itemId, String versionId); + + /*@Query("SELECT version_id, base_version_id, creation_time, modification_time " + + "FROM version WHERE space=? AND item_id=? AND version_id=? ") + ResultSet get(String space, String itemId, String versionId);*/ + + + @Query("SELECT version_id, base_version_id, creation_time, modification_time " + + "FROM version WHERE space=? AND item_id=?") + ResultSet list(String space, String itemId); + + @Query("SELECT version_id FROM version LIMIT 1") + ResultSet checkHealth(); + } + + private static final class VersionField { + private static final String VERSION_ID = "version_id"; + private static final String BASE_VERSION_ID = "base_version_id"; + private static final String CREATION_TIME = "creation_time"; + private static final String MODIFICATION_TIME = "modification_time"; + //private static final String REVISION_ID = "revision_id"; + } + + @Accessor + interface VersionElementsAccessor { + + @Query("INSERT INTO version_elements (space,item_id,version_id,revision_id,element_ids," + + "publish_time,message,user) " + + "VALUES (?,?,?,?,?,?,?,?)") + void create(String space, + String itemId, + String versionId, + String versionRevisionId, + Map<String,String> elementIds, + Date publishTime, + String message, + String user); + + + + } + + /* public static final class VersionElementsField { + private static final String SPACE = "space"; + private static final String ITEM_ID = "item_id"; + private static final String VERSION_ID = "version_id"; + private static final String ELEMENT_IDS = "element_ids"; + private static final String REVISION_ID = "revision_id"; + + }*/ + + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionStageRepositoryFactoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionStageRepositoryFactoryImpl.java new file mode 100644 index 0000000000..547bf6a06c --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionStageRepositoryFactoryImpl.java @@ -0,0 +1,15 @@ +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.VersionStageRepository; +import org.openecomp.core.zusammen.plugin.dao.VersionStageRepositoryFactory; + +public class VersionStageRepositoryFactoryImpl extends VersionStageRepositoryFactory { + + private static final VersionStageRepository INSTANCE = new VersionStageRepositoryImpl(); + + @Override + public VersionStageRepository createInterface(SessionContext context) { + return INSTANCE; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionStageRepositoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionStageRepositoryImpl.java new file mode 100644 index 0000000000..353f37b91b --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionStageRepositoryImpl.java @@ -0,0 +1,82 @@ +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Action; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.mapping.annotations.Accessor; +import com.datastax.driver.mapping.annotations.Query; +import org.openecomp.core.zusammen.plugin.dao.VersionStageRepository; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.Date; +import java.util.Optional; + +public class VersionStageRepositoryImpl implements VersionStageRepository { + + @Override + public Optional<StageEntity<VersionEntity>> get(SessionContext context, + VersionContext entityContext, + VersionEntity entity) { + Row row = getAccessor(context) + .get(entityContext.getSpace(), entityContext.getItemId().toString(), + entity.getId().toString()).one(); + return row == null ? Optional.empty() : Optional.of(convertToVersionStage(entity, row)); + } + + @Override + public void create(SessionContext context, VersionContext entityContext, + StageEntity<VersionEntity> stageEntity) { + VersionEntity entity = stageEntity.getEntity(); + getAccessor(context).create(entityContext.getSpace(), + entityContext.getItemId().toString(), + entity.getId().toString(), + entity.getBaseId() == null ? null : entity.getBaseId().toString(), + entity.getCreationTime() == null ? null : entity.getCreationTime(), + entity.getModificationTime() == null ? null : entity.getModificationTime(), + stageEntity.getPublishTime(), + stageEntity.getAction()); + } + + @Override + public void delete(SessionContext context, VersionContext entityContext, VersionEntity entity) { + getAccessor(context).delete(entityContext.getSpace(), entityContext.getItemId().toString(), + entity.getId().toString()); + } + + private StageEntity<VersionEntity> convertToVersionStage(VersionEntity version, Row row) { + StageEntity<VersionEntity> versionStage = + new StageEntity<>(VersionDaoImpl.enrichVersionEntity(version, row), + row.getDate(VersionStageField.PUBLISH_TIME)); + versionStage.setAction(Action.valueOf(row.getString(VersionStageField.ACTION))); + return versionStage; + } + + private VersionStageAccessor getAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, VersionStageAccessor.class); + } + + @Accessor + interface VersionStageAccessor { + + @Query("INSERT INTO version_stage (space, item_id, version_id, base_version_id, " + + "creation_time, modification_time, publish_time, action) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)") + void create(String space, String itemId, String versionId, String baseVersionId, + Date creationTime, Date modificationTime, Date publishTime, Action action); + + @Query("DELETE FROM version_stage WHERE space=? AND item_id=? AND version_id=?") + void delete(String space, String itemId, String versionId); + + @Query("SELECT base_version_id, creation_time, modification_time, publish_time, action " + + "FROM version_stage WHERE space=? AND item_id=? AND version_id=?") + ResultSet get(String space, String itemId, String versionId); + } + + private static final class VersionStageField { + private static final String PUBLISH_TIME = "publish_time"; + private static final String ACTION = "action"; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionSynchronizationStateRepositoryFactoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionSynchronizationStateRepositoryFactoryImpl.java new file mode 100644 index 0000000000..95c3ec2730 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionSynchronizationStateRepositoryFactoryImpl.java @@ -0,0 +1,33 @@ +/* + * 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.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.SessionContext; +import org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepositoryFactory; + +public class VersionSynchronizationStateRepositoryFactoryImpl + extends VersionSynchronizationStateRepositoryFactory { + + private static final VersionSynchronizationStateRepository INSTANCE = + new VersionSynchronizationStateRepositoryImpl(); + + @Override + public VersionSynchronizationStateRepository createInterface(SessionContext context) { + return INSTANCE; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionSynchronizationStateRepositoryImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionSynchronizationStateRepositoryImpl.java new file mode 100644 index 0000000000..5fb9779bc2 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/impl/cassandra/VersionSynchronizationStateRepositoryImpl.java @@ -0,0 +1,137 @@ +package org.openecomp.core.zusammen.plugin.dao.impl.cassandra; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.mapping.annotations.Accessor; +import com.datastax.driver.mapping.annotations.Query; +import org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepository; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionContext; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class VersionSynchronizationStateRepositoryImpl + implements VersionSynchronizationStateRepository { + + @Override + public void create(SessionContext context, VersionContext entityContext, + SynchronizationStateEntity syncStateEntity) { + updatePublishTime(context, entityContext, syncStateEntity); + } + + @Override + public void updatePublishTime(SessionContext context, VersionContext entityContext, + SynchronizationStateEntity syncStateEntity) { + getAccessor(context) + .updatePublishTime(syncStateEntity.getPublishTime(), entityContext.getSpace(), + entityContext.getItemId().toString(), syncStateEntity.getId().toString(), + syncStateEntity.getRevisionId().getValue()); + } + + @Override + public List<SynchronizationStateEntity> list(SessionContext context, VersionContext + entityContext, VersionEntity versionEntity) { + + List<Row> rows = getAccessor(context).list(entityContext.getSpace(), entityContext.getItemId().toString + (),versionEntity.getId().toString()).all(); + return rows == null ? new ArrayList<>(): + rows.stream().map(VersionSynchronizationStateRepositoryImpl::getSynchronizationStateEntity).collect(Collectors.toList()); + } + + + + /*@Override + public List<SynchronizationStateEntity> listRevisions(SessionContext context, + VersionContext entityContext, + SynchronizationStateEntity syncStateEntity) { + List<Row> rows = getAccessor(context).list(entityContext.getSpace(), entityContext.getItemId() + .toString(), syncStateEntity.getId().toString()).all(); + return rows == null ? new ArrayList<>() :rows.stream() + .map(VersionSynchronizationStateRepositoryImpl::getSynchronizationStateEntity) + .collect(Collectors.toList()); + + + + + //forEach(row -> getSynchronizationStateEntity(syncStateEntity.getId(), row)); + + + }*/ + + + @Override + public void delete(SessionContext context, VersionContext entityContext, + SynchronizationStateEntity syncStateEntity) { + // done by version dao + } + + @Override + public Optional<SynchronizationStateEntity> get(SessionContext context, + VersionContext entityContext, + SynchronizationStateEntity syncStateEntity) { + Row row = + getAccessor(context).get(entityContext.getSpace(), entityContext.getItemId().toString(), + syncStateEntity.getId().toString(), syncStateEntity.getRevisionId().getValue()).one(); + + return row == null ? Optional.empty() + : Optional.of(getSynchronizationStateEntity(syncStateEntity.getId(), row)); + } + + private SynchronizationStateEntity getSynchronizationStateEntity(Id entityId, Row row) { + SynchronizationStateEntity syncStateEntity = new SynchronizationStateEntity(entityId, + new Id(row.getString(REVISION_ID_FIELD))); + syncStateEntity.setPublishTime(row.getDate(PUBLISH_TIME_FIELD)); + syncStateEntity.setDirty(!row.getSet(DIRTY_ELEMENT_FIELD, String.class).isEmpty()); + return syncStateEntity; + } + + private static SynchronizationStateEntity getSynchronizationStateEntity(Row row) { + Id entityId = new Id(row.getColumnDefinitions().contains("version_id") ? row.getString + ("version_id") : row.getString("element_id")); + SynchronizationStateEntity syncStateEntity = new SynchronizationStateEntity(entityId, + new Id(row.getString(REVISION_ID_FIELD))); + syncStateEntity.setPublishTime(row.getDate(PUBLISH_TIME_FIELD)); + syncStateEntity.setDirty(!row.getSet(DIRTY_ELEMENT_FIELD, String.class).isEmpty()); + syncStateEntity.setRevisionId(new Id(row.getString(REVISION_ID_FIELD))); + syncStateEntity.setUser(row.getString(USER)); + syncStateEntity.setMessage(row.getString(MESSAGE)); + return syncStateEntity; + } + + private VersionSyncStateAccessor getAccessor(SessionContext context) { + return CassandraDaoUtils.getAccessor(context, VersionSyncStateAccessor.class); + } + + @Accessor + interface VersionSyncStateAccessor { + @Query( + "UPDATE version_elements SET publish_time=? WHERE space=? AND item_id=? AND version_id=? " + + "AND revision_id=? ") + void updatePublishTime(Date publishTime, String space, String itemId, String versionId, String + revisionId); + + @Query("SELECT version_id,revision_id,publish_time, dirty_element_ids FROM version_elements " + + "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ") + ResultSet get(String space, String itemId, String versionId, String revisionId); + + @Query("SELECT version_id,revision_id,publish_time,user,message, dirty_element_ids FROM " + + "version_elements " + + "WHERE space=? AND item_id=? AND version_id=? ") + ResultSet list(String space, String itemId, String versionId); + + } + + + private static final String PUBLISH_TIME_FIELD = "publish_time"; + private static final String DIRTY_ELEMENT_FIELD = "dirty_element_ids"; + private static final String REVISION_ID_FIELD = "revision_id"; + private static final String USER = "user"; + private static final String MESSAGE = "message"; +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/ElementEntity.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/ElementEntity.java index 1663d83427..1cd15102f2 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/ElementEntity.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/ElementEntity.java @@ -30,6 +30,7 @@ public class ElementEntity { private Id id; private Id parentId; private Namespace namespace; + private Id elementHash; private Info info; private Collection<Relation> relations = Collections.emptyList(); private ByteBuffer data; @@ -41,6 +42,10 @@ public class ElementEntity { this.id = id; } + public Id getId() { + return id; + } + public Id getParentId() { return parentId; } @@ -49,14 +54,6 @@ public class ElementEntity { this.parentId = parentId; } - public Id getId() { - return id; - } - - public void setId(Id id) { - this.id = id; - } - public Namespace getNamespace() { return namespace; } @@ -127,8 +124,17 @@ public class ElementEntity { return id.equals(that.id); } + public Id getElementHash() { + return elementHash; + } + + public void setElementHash(Id elementHash) { + this.elementHash = elementHash; + } + @Override public int hashCode() { return id.hashCode(); } + } diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/StageEntity.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/StageEntity.java new file mode 100644 index 0000000000..58ac0a918a --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/StageEntity.java @@ -0,0 +1,60 @@ +package org.openecomp.core.zusammen.plugin.dao.types; + +import com.amdocs.zusammen.datatypes.item.Action; + +import java.util.Collections; +import java.util.Date; +import java.util.Set; + +public class StageEntity<E> { + private E entity; + private Date publishTime; + private Action action = Action.IGNORE; + private boolean conflicted; + private Set<E> conflictDependents = Collections.emptySet(); + + // used by sync on stage creation + public StageEntity(E entity, Date publishTime) { + this.entity = entity; + this.publishTime = publishTime; + } + + public StageEntity(E entity, Date publishTime, Action action, boolean conflicted) { + this.entity = entity; + this.publishTime = publishTime; + this.action = action; + this.conflicted = conflicted; + } + + public E getEntity() { + return entity; + } + + public Date getPublishTime() { + return publishTime; + } + + public Action getAction() { + return action; + } + + public void setAction(Action action) { + this.action = action; + } + + public boolean isConflicted() { + return conflicted; + } + + public void setConflicted(boolean conflicted) { + this.conflicted = conflicted; + } + + public Set<E> getConflictDependents() { + return conflictDependents; + } + + public void setConflictDependents(Set<E> conflictDependents) { + this.conflictDependents = conflictDependents; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/SynchronizationStateEntity.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/SynchronizationStateEntity.java new file mode 100644 index 0000000000..510cef820b --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/SynchronizationStateEntity.java @@ -0,0 +1,116 @@ +/* + * 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.openecomp.core.zusammen.plugin.dao.types; + +import com.amdocs.zusammen.datatypes.Id; + +import java.util.Date; + +/** + * Synchronization state of an entity: + * <ul> + * <li>On private entity edit (create/update/delete): marked as dirty</li> + * <li>On entity publication: + * <ul> + * <li>if the private entity exists - updated with the publish time, marked as not dirty</li> + * <li>Otherwise - deleted</li> + * </ul> + * </li> + * </ul> + */ +public class SynchronizationStateEntity { + private Id id; + private Id revisionId; + private Date publishTime; + private boolean dirty; + private String user; + private String message; + + public SynchronizationStateEntity(Id id,Id revisionId) { + this.id = id; + this.revisionId = revisionId; + } + + public SynchronizationStateEntity(Id id,Id revisionId, Date publishTime, boolean dirty) { + this(id,revisionId); + this.publishTime = publishTime; + this.dirty = dirty; + } + + public Id getId() { + return id; + } + + public Date getPublishTime() { + return publishTime; + } + + public void setPublishTime(Date publishTime) { + this.publishTime = publishTime; + } + + public boolean isDirty() { + return dirty; + } + + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + public Id getRevisionId() { + return revisionId; + } + + public void setRevisionId(Id revisionId) { + this.revisionId = revisionId; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + SynchronizationStateEntity that = (SynchronizationStateEntity) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionContext.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionContext.java new file mode 100644 index 0000000000..41a3e66e0e --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionContext.java @@ -0,0 +1,23 @@ +package org.openecomp.core.zusammen.plugin.dao.types; + +import com.amdocs.zusammen.datatypes.Id; + +public class VersionContext { + private String space; + private Id itemId; + + + public VersionContext(String space, Id itemId) { + this.space = space; + this.itemId = itemId; + } + + public String getSpace() { + return space; + } + + public Id getItemId() { + return itemId; + } + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionDataElement.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionDataElement.java new file mode 100644 index 0000000000..48a52c0d85 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionDataElement.java @@ -0,0 +1,21 @@ +package org.openecomp.core.zusammen.plugin.dao.types; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; +import org.openecomp.core.zusammen.plugin.ZusammenPluginConstants; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.calculateElementHash; + +public class VersionDataElement extends ElementEntity { + + public VersionDataElement() { + super(ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID); + } + + public VersionDataElement(ItemVersionData itemVersionData) { + this(); + setInfo(itemVersionData.getInfo()); + setRelations(itemVersionData.getRelations()); + setElementHash(new Id(calculateElementHash(this))); + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionEntity.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionEntity.java new file mode 100644 index 0000000000..aeed998d96 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/dao/types/VersionEntity.java @@ -0,0 +1,45 @@ +package org.openecomp.core.zusammen.plugin.dao.types; + +import com.amdocs.zusammen.datatypes.Id; + +import java.util.Date; + +public class VersionEntity { + private Id id; + private Id baseId; + private Date creationTime; + private Date modificationTime; + + public VersionEntity(Id id) { + this.id = id; + } + + public Id getId() { + return id; + } + + public Id getBaseId() { + return baseId; + } + + public void setBaseId(Id baseId) { + this.baseId = baseId; + } + + public Date getCreationTime() { + return creationTime; + } + + public void setCreationTime(Date creationTime) { + this.creationTime = creationTime; + } + + public Date getModificationTime() { + return modificationTime; + } + + public void setModificationTime(Date modificationTime) { + this.modificationTime = modificationTime; + } + +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraCollaborationStorePluginImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraCollaborationStorePluginImpl.java index 90fd3366fe..f9b65224e0 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraCollaborationStorePluginImpl.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraCollaborationStorePluginImpl.java @@ -21,97 +21,302 @@ import com.amdocs.zusammen.commons.health.data.HealthStatus; import com.amdocs.zusammen.datatypes.Id; import com.amdocs.zusammen.datatypes.Namespace; import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.Space; +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.ItemVersion; import com.amdocs.zusammen.datatypes.item.ItemVersionData; -import com.amdocs.zusammen.datatypes.itemversion.ItemVersionHistory; +import com.amdocs.zusammen.datatypes.item.ItemVersionDataConflict; +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.Revision; import com.amdocs.zusammen.datatypes.itemversion.Tag; +import com.amdocs.zusammen.datatypes.response.ErrorCode; +import com.amdocs.zusammen.datatypes.response.Module; import com.amdocs.zusammen.datatypes.response.Response; +import com.amdocs.zusammen.datatypes.response.ReturnCode; import com.amdocs.zusammen.datatypes.response.ZusammenException; import com.amdocs.zusammen.sdk.collaboration.CollaborationStore; import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElement; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElementChange; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationElementConflict; +import com.amdocs.zusammen.sdk.collaboration.types.CollaborationItemVersionConflict; import com.amdocs.zusammen.sdk.collaboration.types.CollaborationMergeChange; import com.amdocs.zusammen.sdk.collaboration.types.CollaborationMergeResult; import com.amdocs.zusammen.sdk.collaboration.types.CollaborationPublishResult; -import org.openecomp.core.zusammen.plugin.collaboration.ElementCollaborationStore; -import org.openecomp.core.zusammen.plugin.collaboration.VersionCollaborationStore; +import com.amdocs.zusammen.sdk.types.ElementConflictDescriptor; +import com.amdocs.zusammen.sdk.types.ElementDescriptor; +import org.openecomp.core.zusammen.plugin.ZusammenPluginUtil; +import org.openecomp.core.zusammen.plugin.collaboration.CommitStagingService; +import org.openecomp.core.zusammen.plugin.collaboration.ElementPrivateStore; +import org.openecomp.core.zusammen.plugin.collaboration.ElementPublicStore; +import org.openecomp.core.zusammen.plugin.collaboration.ElementStageStore; +import org.openecomp.core.zusammen.plugin.collaboration.PublishService; +import org.openecomp.core.zusammen.plugin.collaboration.RevertService; +import org.openecomp.core.zusammen.plugin.collaboration.SyncService; +import org.openecomp.core.zusammen.plugin.collaboration.VersionPrivateStore; +import org.openecomp.core.zusammen.plugin.collaboration.VersionPublicStore; +import org.openecomp.core.zusammen.plugin.collaboration.VersionStageStore; +import org.openecomp.core.zusammen.plugin.collaboration.impl.ElementPrivateStoreImpl; +import org.openecomp.core.zusammen.plugin.collaboration.impl.ElementPublicStoreImpl; +import org.openecomp.core.zusammen.plugin.collaboration.impl.ElementStageStoreImpl; +import org.openecomp.core.zusammen.plugin.collaboration.impl.VersionPrivateStoreImpl; +import org.openecomp.core.zusammen.plugin.collaboration.impl.VersionPublicStoreImpl; +import org.openecomp.core.zusammen.plugin.collaboration.impl.VersionStageStoreImpl; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; +import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionDataElement; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.amdocs.zusammen.datatypes.item.SynchronizationStatus.MERGING; +import static com.amdocs.zusammen.datatypes.item.SynchronizationStatus.OUT_OF_SYNC; +import static com.amdocs.zusammen.datatypes.item.SynchronizationStatus.UP_TO_DATE; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToCollaborationElement; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToElementChange; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToElementDescriptor; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToElementEntity; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToItemVersion; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToVersionData; +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToVersionEntity; public class CassandraCollaborationStorePluginImpl implements CollaborationStore { + // TODO: 8/15/2017 inject + + private VersionPrivateStore versionPrivateStore = new VersionPrivateStoreImpl(); + private VersionPublicStore versionPublicStore = new VersionPublicStoreImpl(); + private VersionStageStore versionStageStore = new VersionStageStoreImpl(); + + private ElementPrivateStore elementPrivateStore = new ElementPrivateStoreImpl(); + private ElementPublicStore elementPublicStore = new ElementPublicStoreImpl(); + private ElementStageStore elementStageStore = new ElementStageStoreImpl(); - private VersionCollaborationStore versionCollaborationStore = new VersionCollaborationStore(); - private ElementCollaborationStore elementCollaborationStore = new ElementCollaborationStore(); + // TODO: 9/4/2017 + private CommitStagingService commitStagingService = + new CommitStagingService(versionPrivateStore, versionStageStore, elementPrivateStore, + elementStageStore); + private PublishService publishService = + new PublishService(versionPublicStore, versionPrivateStore, elementPublicStore, + elementPrivateStore); + private SyncService syncService = + new SyncService(versionPublicStore, versionPrivateStore, versionStageStore, + elementPublicStore, elementPrivateStore, elementStageStore); + + private RevertService revertService = + new RevertService(elementPublicStore, elementPrivateStore); @Override - public Response<Void> createItem(SessionContext context, Id id, Info info) { + public Response<Void> createItem(SessionContext context, Id itemId, Info info) { // done by state store return new Response(Void.TYPE); } @Override - public Response<Void> deleteItem(SessionContext context, Id id) { + public Response<Void> deleteItem(SessionContext context, Id itemId) { // done by state store return new Response(Void.TYPE); } @Override - public Response<Void> createItemVersion(SessionContext context, Id itemId, Id versionId, Id id2, - ItemVersionData itemVersionData) { - // done by state store + public Response<Void> createItemVersion(SessionContext context, Id itemId, Id baseVersionId, + Id versionId, ItemVersionData itemVersionData) { + Date creationTime = new Date(); + versionPrivateStore.create(context, itemId, + convertToVersionEntity(versionId, baseVersionId, creationTime, creationTime)); + + ElementContext elementContext = new ElementContext(itemId, versionId); + VersionDataElement versionData = new VersionDataElement(itemVersionData); + + if (baseVersionId == null) { + elementPrivateStore.create(context, elementContext, versionData); + } else { + copyElements(context, new ElementContext(itemId, baseVersionId), elementContext); + elementPrivateStore.update(context, elementContext, versionData); + } + return new Response(Void.TYPE); } @Override public Response<Void> updateItemVersion(SessionContext context, Id itemId, Id versionId, ItemVersionData itemVersionData) { - // done by state store + + if (elementPrivateStore.update(context, new ElementContext(itemId, versionId), + new VersionDataElement(itemVersionData))) { + + VersionEntity version = new VersionEntity(versionId); + version.setModificationTime(new Date()); + versionPrivateStore.update(context, itemId, version); + } + return new Response(Void.TYPE); } @Override public Response<Void> deleteItemVersion(SessionContext context, Id itemId, Id versionId) { - // done by state store + elementPrivateStore + .delete(context, new ElementContext(itemId, versionId), new VersionDataElement()); + + versionPrivateStore.delete(context, itemId, new VersionEntity(versionId)); return new Response(Void.TYPE); } @Override - public Response<Void> tagItemVersion(SessionContext context, Id itemId, Id versionId, Id changeId, + public Response<ItemVersionStatus> getItemVersionStatus(SessionContext context, Id itemId, + Id versionId) { + if (versionStageStore.get(context, itemId, new VersionEntity(versionId)).isPresent()) { + return new Response<>(new ItemVersionStatus(MERGING, true)); + } + + Optional<SynchronizationStateEntity> publicSyncState = + versionPublicStore.getSynchronizationState(context, itemId, versionId); + + if (!publicSyncState.isPresent()) { + return new Response<>(new ItemVersionStatus(UP_TO_DATE, true)); + } + + SynchronizationStateEntity privateSyncState = + versionPrivateStore.getSynchronizationState(context, itemId, versionId) + // TODO: 7/18/2017 ? + .orElseThrow(() -> new IllegalStateException("private version must exist")); + + return new Response<>(new ItemVersionStatus( + privateSyncState.getPublishTime().equals(publicSyncState.get().getPublishTime()) + ? UP_TO_DATE + : OUT_OF_SYNC, + privateSyncState.isDirty())); + } + + @Override + public Response<Void> tagItemVersion(SessionContext context, Id itemId, Id versionId, + Id revisionId, Tag tag) { - versionCollaborationStore.tagItemVersion(context, itemId, versionId, changeId, tag); + /* if (revisionId != null) { + throw new UnsupportedOperationException( + "In this plugin implementation tag is supported only on versionId"); + } + + copyElements(context, + new ElementContext(itemId, versionId), + new ElementContext(itemId, versionId, tag.getName()));*/ + return new Response(Void.TYPE); } @Override public Response<CollaborationPublishResult> publishItemVersion(SessionContext context, Id itemId, Id versionId, - String s) { - throw new UnsupportedOperationException("publishItemVersion"); + String message) { + try { + return new Response<>(publishService.publish(context, itemId, versionId, message)); + } catch (ZusammenException ze) { + return new Response<>( + new ReturnCode(ErrorCode.CL_ITEM_VERSION_PUBLISH, Module.ZCSP, null, ze.getReturnCode())); + } + } + + @Override + public Response<CollaborationMergeResult> syncItemVersion(SessionContext context, Id itemId, + Id versionId) { + CollaborationMergeResult result = syncService.sync(context, itemId, versionId, false); + commitStagingService.commitStaging(context, itemId, versionId); + + return new Response<>(result); } @Override - public Response<CollaborationMergeResult> syncItemVersion(SessionContext context, Id id, - Id id1) { - throw new UnsupportedOperationException("syncItemVersion"); + public Response<CollaborationMergeResult> forceSyncItemVersion(SessionContext context, Id itemId, + Id versionId) { + CollaborationMergeResult result = syncService.sync(context, itemId, versionId, true); + commitStagingService.commitStaging(context, itemId, versionId); + + return new Response<>(result); } @Override - public Response<CollaborationMergeResult> mergeItemVersion(SessionContext context, Id id, - Id id1, Id id2) { + public Response<CollaborationMergeResult> mergeItemVersion(SessionContext context, Id itemId, + Id versionId, Id sourceVersionId) { throw new UnsupportedOperationException("mergeItemVersion"); } @Override - public Response<ItemVersionHistory> listItemVersionHistory(SessionContext context, Id id, - Id id1) { - throw new UnsupportedOperationException("listItemVersionHistory"); + public Response<CollaborationItemVersionConflict> getItemVersionConflict(SessionContext context, + Id itemId, + Id versionId) { + ElementContext elementContext = new ElementContext(itemId, versionId, Id.ZERO); + + Collection<StageEntity<ElementEntity>> conflictedStagedElementDescriptors = + elementStageStore.listConflictedDescriptors(context, elementContext); + + CollaborationItemVersionConflict result = new CollaborationItemVersionConflict(); + for (StageEntity<ElementEntity> stagedElementDescriptor : conflictedStagedElementDescriptors) { + if (ROOT_ELEMENTS_PARENT_ID.equals(stagedElementDescriptor.getEntity().getId())) { + result.setVersionDataConflict( + getVersionDataConflict(context, elementContext, stagedElementDescriptor)); + } else { + result.getElementConflictDescriptors() + .add(getElementConflictDescriptor(context, elementContext, stagedElementDescriptor)); + } + } + return new Response<>(result); + } + + @Override + public Response<ItemVersionRevisions> listItemVersionRevisions(SessionContext context, Id itemId, + Id versionId) { + return new Response<>(versionPublicStore.listItemVersionRevisions(context, itemId, versionId)); } @Override - public Response<CollaborationMergeChange> resetItemVersionHistory(SessionContext context, - Id itemId, Id versionId, - String changeRef) { - return new Response<>(versionCollaborationStore.resetItemVersionHistory(context, itemId, versionId, changeRef)); + public Response<Revision> getItemVersionRevision(SessionContext context, Id itemId, Id versionId, + Id revisionId) { + throw new UnsupportedOperationException( + "get revision is not supported in the current cassandra plugin"); + } + + @Override + public Response<CollaborationMergeChange> resetItemVersionRevision(SessionContext context, + Id itemId, Id versionId, + Id revisionId) { + throw new UnsupportedOperationException("resetItemVersionRevision function not supported"); + + } + + @Override + public Response<CollaborationMergeChange> revertItemVersionRevision(SessionContext context, + Id itemId, Id versionId, + Id revisionId) { + Optional<ItemVersion> itemVersion = getItemVersion(context, itemId, versionId, revisionId); + if (!itemVersion.isPresent()) { + throw new RuntimeException(String + .format("Item %s, version %s: Cannot revert to revision %s since it is not found", + itemId, versionId, revisionId)); + } + + // TODO: 12/4/2017 force sync is done in order to clear dirty element on private + // this is temp solution that should be fixed. + forceSyncItemVersion(context, itemId, versionId); + + //updateItemVersion(context, itemId, versionId, itemVersion.get().getData()); + revertService.revert(context, itemId, versionId, revisionId); + + return new Response<>(new CollaborationMergeChange()); + } + + + @Override + public Response<Void> commitElements(SessionContext context, Id itemId, Id versionId, String s) { + // not needed + return new Response(Void.TYPE); } @Override @@ -119,52 +324,198 @@ public class CassandraCollaborationStorePluginImpl implements CollaborationStore ElementContext elementContext, Namespace namespace, Id elementId) { - return new Response<>( - elementCollaborationStore.listElements(context, elementContext, elementId)); + return new Response<>(elementPrivateStore.listSubs(context, elementContext, elementId).stream() + .map(elementEntity -> convertToCollaborationElement(elementContext, elementEntity)) + .collect(Collectors.toList())); } @Override public Response<CollaborationElement> getElement(SessionContext context, ElementContext elementContext, Namespace namespace, Id elementId) { - return new Response<>(elementCollaborationStore.getElement(context, elementContext, elementId)); + return new Response<>(elementPrivateStore.get(context, elementContext, elementId) + .map(elementEntity -> convertToCollaborationElement(elementContext, elementEntity)) + .orElse(null)); + } + + @Override + public Response<CollaborationElementConflict> getElementConflict(SessionContext context, + ElementContext elementContext, + Namespace namespace, + Id elementId) { + Optional<StageEntity<ElementEntity>> conflictedStagedElement = + elementStageStore + .getConflicted(context, elementContext, new ElementEntity(elementId)); + + return new Response<>(conflictedStagedElement + .map(stagedElement -> getElementConflict(context, elementContext, stagedElement)) + .orElse(null)); } @Override public Response<Void> createElement(SessionContext context, CollaborationElement element) { - elementCollaborationStore.createElement(context, element); + elementPrivateStore.create(context, + new ElementContext(element.getItemId(), element.getVersionId()), + convertToElementEntity(element)); return new Response(Void.TYPE); } @Override public Response<Void> updateElement(SessionContext context, CollaborationElement element) { - elementCollaborationStore.updateElement(context, element); + elementPrivateStore.update(context, + new ElementContext(element.getItemId(), element.getVersionId()), + convertToElementEntity(element)); return new Response(Void.TYPE); } @Override public Response<Void> deleteElement(SessionContext context, CollaborationElement element) { - elementCollaborationStore.deleteElement(context, element); + elementPrivateStore + .delete(context, new ElementContext(element.getItemId(), element.getVersionId()), + convertToElementEntity(element)); + return new Response(Void.TYPE); } @Override - public Response<Void> commitElements(SessionContext context, Id itemId, Id versionId, String s) { - // not needed - return new Response(Void.TYPE); + public Response<CollaborationMergeResult> resolveElementConflict(SessionContext context, + CollaborationElement element, + Resolution resolution) { + ElementContext elementContext = new ElementContext(element.getItemId(), element.getVersionId()); + elementStageStore + .resolveConflict(context, elementContext, convertToElementEntity(element), resolution); + commitStagingService.commitStaging(context, element.getItemId(), element.getVersionId()); + + return new Response<>(new CollaborationMergeResult()); } @Override - public Response<HealthInfo> checkHealth(SessionContext sessionContext) throws ZusammenException { + public Response<ItemVersion> getItemVersion(SessionContext context, Space space, Id itemId, + Id versionId, Id revisionId) { + return new Response<>(getItemVersion(context, itemId, versionId, revisionId).orElse(null)); + } - boolean health = elementCollaborationStore.checkHealth(sessionContext); - HealthInfo healthInfo ; - if (health){ - healthInfo = new HealthInfo("Collaboration", HealthStatus.UP,""); - } else { - healthInfo = new HealthInfo("Collaboration", HealthStatus.DOWN,"No Schema Available"); + @Override + public Response<HealthInfo> checkHealth(SessionContext context) throws ZusammenException { + HealthInfo healthInfo = versionPublicStore.checkHealth(context) + ? new HealthInfo(Module.ZCSP.getDescription(), HealthStatus.UP, "") + : new HealthInfo(Module.ZCSP.getDescription(), HealthStatus.DOWN, "No Schema Available"); + + return new Response<>(healthInfo); + } + + private Optional<ItemVersion> getItemVersion(SessionContext context, Id itemId, Id versionId, + Id revisionId) { + // since revisions are kept only on public - get from there + Optional<VersionEntity> versionEntity = versionPublicStore.get(context, itemId, versionId); + if (!versionEntity.isPresent()) { + return Optional.empty(); + } + + return elementPublicStore + .getDescriptor(context, new ElementContext(itemId, versionId, revisionId), + ROOT_ELEMENTS_PARENT_ID) + .map(ZusammenPluginUtil::convertToVersionData) + .map(itemVersionData -> convertToItemVersion(versionEntity.get(), itemVersionData)); + } + + private List<ElementEntity> listVersionElements(SessionContext context, + ElementContext elementContext) { + return elementPrivateStore.listIds(context, elementContext).entrySet().stream() // TODO: + // 9/5/2017 parallel + .map(entry -> elementPrivateStore.get(context, elementContext, entry.getKey()).get()) + .collect(Collectors.toList()); + } + + private void copyElements(SessionContext context, + ElementContext sourceContext, ElementContext targetContext) { + listVersionElements(context, sourceContext).forEach(element -> { + // publishTime copied as is and dirty is off + Date publishTime = + elementPrivateStore.getSynchronizationState(context, sourceContext, element.getId()) + .get().getPublishTime(); + elementPrivateStore.commitStagedCreate(context, targetContext, element, publishTime); + }); + } + + private ItemVersionDataConflict getVersionDataConflict(SessionContext context, + ElementContext elementContext, + StageEntity<ElementEntity> stagedElementDescriptor) { + ItemVersionDataConflict versionConflict = new ItemVersionDataConflict(); + versionConflict.setRemoteData(convertToVersionData(stagedElementDescriptor.getEntity())); + if (stagedElementDescriptor.getAction() == Action.UPDATE) { + versionConflict.setLocalData(getPrivateVersionData(context, elementContext)); } - return new Response<HealthInfo>(healthInfo); + return versionConflict; + } + private ItemVersionData getPrivateVersionData(SessionContext context, + ElementContext elementContext) { + return elementPrivateStore.getDescriptor(context, elementContext, ROOT_ELEMENTS_PARENT_ID) + .map(ZusammenPluginUtil::convertToVersionData) + .orElseThrow(() -> new IllegalStateException("Version must have data")); + } + + private ElementConflictDescriptor getElementConflictDescriptor(SessionContext context, + ElementContext elementContext, + StageEntity<ElementEntity> stagedElementDescriptor) { + ElementDescriptor elementDescriptorFromStage = + convertToElementDescriptor(elementContext, (stagedElementDescriptor.getEntity())); + + ElementConflictDescriptor conflictDescriptor = new ElementConflictDescriptor(); + switch (stagedElementDescriptor.getAction()) { + case CREATE: + conflictDescriptor.setRemoteElementDescriptor(elementDescriptorFromStage); + break; + case UPDATE: + conflictDescriptor.setRemoteElementDescriptor(elementDescriptorFromStage); + conflictDescriptor.setLocalElementDescriptor(convertToElementDescriptor(elementContext, + elementPrivateStore + .getDescriptor(context, elementContext, stagedElementDescriptor.getEntity().getId()) + .orElse(null)));// updated on public while deleted from private + break; + case DELETE: + conflictDescriptor.setLocalElementDescriptor(elementDescriptorFromStage); + break; + default: + break; + } + return conflictDescriptor; + } + + private void addElementsToChangedElements(ElementContext elementContext, + Collection<ElementEntity> elements, + Collection<CollaborationElementChange> changedElements, + Action action) { + elements.stream() + .map(elementEntity -> convertToElementChange(elementContext, elementEntity, action)) + .forEach(changedElements::add); + } + + private CollaborationElementConflict getElementConflict(SessionContext context, + ElementContext entityContext, + StageEntity<ElementEntity> stagedElement) { + CollaborationElement elementFromStage = + convertToCollaborationElement(entityContext, (stagedElement.getEntity())); + + CollaborationElementConflict conflict = new CollaborationElementConflict(); + switch (stagedElement.getAction()) { + case CREATE: + conflict.setRemoteElement(elementFromStage); + break; + case UPDATE: + conflict.setRemoteElement(elementFromStage); + conflict.setLocalElement( + elementPrivateStore.get(context, entityContext, stagedElement.getEntity().getId()) + .map(element -> convertToCollaborationElement(entityContext, element)) + .orElse(null));// updated on public while deleted from private + break; + case DELETE: + conflict.setLocalElement(elementFromStage); + break; + default: + break; + } + return conflict; } }
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraStateStorePluginImpl.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraStateStorePluginImpl.java index b4767b2872..3ed668e331 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraStateStorePluginImpl.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/java/org/openecomp/core/zusammen/plugin/main/CassandraStateStorePluginImpl.java @@ -17,18 +17,87 @@ package org.openecomp.core.zusammen.plugin.main; +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.ItemVersion; +import com.amdocs.zusammen.datatypes.item.ItemVersionData; import com.amdocs.zusammen.datatypes.response.Response; import com.amdocs.zusammen.plugin.statestore.cassandra.StateStoreImpl; import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; import com.amdocs.zusammen.sdk.state.types.StateElement; +import org.openecomp.core.zusammen.plugin.ZusammenPluginUtil; +import org.openecomp.core.zusammen.plugin.collaboration.ElementPrivateStore; +import org.openecomp.core.zusammen.plugin.collaboration.impl.ElementPrivateStoreImpl; +import org.openecomp.core.zusammen.plugin.dao.ElementRepository; import org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory; +import org.openecomp.core.zusammen.plugin.dao.VersionDao; +import org.openecomp.core.zusammen.plugin.dao.VersionDaoFactory; import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.VersionDataElement; +import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity; +import java.util.Collection; +import java.util.Date; +import java.util.stream.Collectors; + +import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToItemVersion; import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getSpaceName; public class CassandraStateStorePluginImpl extends StateStoreImpl { + private ElementPrivateStore elementPrivateStore = new ElementPrivateStoreImpl(); + + @Override + public Response<Collection<ItemVersion>> listItemVersions(SessionContext context, Space space, + Id itemId) { + String spaceName = getSpaceName(context, space); + return new Response<>(getVersionDao(context).list(context, spaceName, itemId).stream() + .map(versionEntity -> getItemVersion(context, spaceName, itemId, versionEntity)) + .collect(Collectors.toList())); + } + + @Override + public Response<Boolean> isItemVersionExist(SessionContext context, Space space, Id itemId, + Id versionId) { + return new Response<>( + getVersionDao(context).get(context, getSpaceName(context, space), itemId, versionId) + .isPresent()); + } + + @Override + public Response<ItemVersion> getItemVersion(SessionContext context, Space space, Id itemId, + Id versionId) { + String spaceName = getSpaceName(context, space); + return new Response<>(getVersionDao(context).get(context, spaceName, itemId, versionId) + .map(versionEntity -> getItemVersion(context, spaceName, itemId, versionEntity)) + .orElse(null)); + } + + @Override + public Response<Void> createItemVersion(SessionContext context, Space space, Id itemId, + Id baseVersionId, Id versionId, ItemVersionData data, + Date creationTime) { + // done by collaboration store + return new Response(Void.TYPE); + } + + @Override + public Response<Void> updateItemVersion(SessionContext context, Space space, Id itemId, + Id versionId, ItemVersionData data, + Date modificationTime) { + // done by collaboration store + return new Response(Void.TYPE); + } + + @Override + public Response<Void> deleteItemVersion(SessionContext context, Space space, Id itemId, + Id versionId) { + // done by collaboration store + return new Response(Void.TYPE); + } + @Override public Response<Void> createElement(SessionContext context, StateElement element) { ElementEntity elementEntity = new ElementEntity(element.getId()); @@ -37,8 +106,7 @@ public class CassandraStateStorePluginImpl extends StateStoreImpl { ElementRepositoryFactory.getInstance().createInterface(context) .createNamespace(context, new ElementEntityContext(getSpaceName(context, element.getSpace()), - element.getItemId(), element.getVersionId()), - elementEntity); + element.getItemId(), element.getVersionId()), elementEntity); // create element is done by collaboration store return new Response(Void.TYPE); } @@ -55,4 +123,46 @@ public class CassandraStateStorePluginImpl extends StateStoreImpl { return new Response(Void.TYPE); } + @Override + public Response<Collection<StateElement>> listElements(SessionContext context, + ElementContext elementContext, + Id elementId) { + return new Response(elementPrivateStore.listSubs(context, elementContext, elementId).stream() + .map(elementEntity -> ZusammenPluginUtil.getStateElement(elementContext, elementEntity)) + .collect(Collectors.toList())); + + } + + @Override + public Response<StateElement> getElement(SessionContext context, ElementContext elementContext, + Id elementId) { + + return new Response(elementPrivateStore.get(context, elementContext, elementId) + .map(elementEntity -> ZusammenPluginUtil + .getStateElement(elementContext, elementEntity)) + .orElse + (null)); + + + } + + private ItemVersion getItemVersion(SessionContext context, String spaceName, Id itemId, + VersionEntity versionEntity) { + + ItemVersionData itemVersionData = getElementRepository(context) + .get(context, new ElementEntityContext(spaceName, itemId, versionEntity.getId(), null), + new VersionDataElement()) + .map(ZusammenPluginUtil::convertToVersionData) + .orElseThrow(() -> new IllegalStateException("Version must have data")); + + return convertToItemVersion(versionEntity, itemVersionData); + } + + protected VersionDao getVersionDao(SessionContext context) { + return VersionDaoFactory.getInstance().createInterface(context); + } + + protected ElementRepository getElementRepository(SessionContext context) { + return ElementRepositoryFactory.getInstance().createInterface(context); + } } diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/resources/factoryConfiguration.json b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/resources/factoryConfiguration.json index cd1e293b4b..841e005709 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/resources/factoryConfiguration.json +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/main/resources/factoryConfiguration.json @@ -1,3 +1,8 @@ { - "org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory": "org.openecomp.core.zusammen.plugin.dao.impl.CassandraElementRepositoryFactory" + "org.openecomp.core.zusammen.plugin.dao.VersionDaoFactory": "org.openecomp.core.zusammen.plugin.dao.impl.cassandra.VersionDaoFactoryImpl", + "org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory": "org.openecomp.core.zusammen.plugin.dao.impl.cassandra.ElementRepositoryFactoryImpl", + "org.openecomp.core.zusammen.plugin.dao.VersionSynchronizationStateRepositoryFactory": "org.openecomp.core.zusammen.plugin.dao.impl.cassandra.VersionSynchronizationStateRepositoryFactoryImpl", + "org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepositoryFactory": "org.openecomp.core.zusammen.plugin.dao.impl.cassandra.ElementSynchronizationStateRepositoryFactoryImpl", + "org.openecomp.core.zusammen.plugin.dao.VersionStageRepositoryFactory": "org.openecomp.core.zusammen.plugin.dao.impl.cassandra.VersionStageRepositoryFactoryImpl", + "org.openecomp.core.zusammen.plugin.dao.ElementStageRepositoryFactory": "org.openecomp.core.zusammen.plugin.dao.impl.cassandra.ElementStageRepositoryFactoryImpl" }
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/TestUtils.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/TestUtils.java new file mode 100644 index 0000000000..79e918c808 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/TestUtils.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.openecomp.core.zusammen.plugin.collaboration; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.UserInfo; +import com.amdocs.zusammen.datatypes.item.ElementContext; +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.Relation; + +import java.util.Arrays; + +public class TestUtils { + + public static SessionContext createSessionContext(UserInfo user, String tenant) { + SessionContext context = new SessionContext(); + context.setUser(user); + context.setTenant(tenant); + return context; + } + + public static ElementContext createElementContext(Id itemId, Id versionId) { + ElementContext elementContext = new ElementContext(); + elementContext.setItemId(itemId); + elementContext.setVersionId(versionId); + return elementContext; + } + + public static Info createInfo(String value) { + Info info = new Info(); + info.setName(value); + info.addProperty("Name", "name_" + value); + info.addProperty("Desc", "desc_" + value); + return info; + } + + public static ItemVersion createItemVersion(Id id, Id baseId, String name, boolean dirty) { + ItemVersion version = new ItemVersion(); + version.setId(id); + version.setBaseId(baseId); + ItemVersionData data = new ItemVersionData(); + data.setInfo(TestUtils.createInfo(name)); + data.setRelations(Arrays.asList(new Relation(), new Relation())); + version.setData(data); + return version; + } +} diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/VersionCollaborationStoreTest.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/VersionCollaborationStoreTest.java new file mode 100644 index 0000000000..4c4621e98b --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/VersionCollaborationStoreTest.java @@ -0,0 +1,237 @@ +package org.openecomp.core.zusammen.plugin.collaboration; + +public class VersionCollaborationStoreTest {/* + private static final String TENANT = "test"; + private static final String USER = "ItemStateStoreTest_user"; + private static final SessionContext context = + TestUtils.createSessionContext(new UserInfo(USER), TENANT); + + @Mock + private VersionDao versionDaoMock; + @Mock + private ElementStore elementCollaborationStore; + @Spy + @InjectMocks + private VersionStore versionCollaborationStore; + + @BeforeMethod + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(versionCollaborationStore.getVersionDao(anyObject())).thenReturn(versionDaoMock); + } +*//* + @Test + public void testListPrivateItemVersions() throws Exception { + testListItemVersions(Space.PRIVATE, USER); + } + + @Test + public void testListPublicItemVersions() throws Exception { + testListItemVersions(Space.PUBLIC, ZusammenPluginConstants.PUBLIC_SPACE); + } + + @Test + public void testIsPrivateItemVersionExist() throws Exception { + testIsItemVersionExist(Space.PRIVATE, USER); + } + + @Test + public void testIsPublicItemVersionExist() throws Exception { + testIsItemVersionExist(Space.PUBLIC, ZusammenPluginConstants.PUBLIC_SPACE); + } + + @Test + public void testIsItemVersionExistWhenNot() throws Exception { + Id itemId = new Id(); + Id versionId = new Id(); + doReturn(Optional.empty()).when(versionDaoMock).get(context, USER, itemId, versionId); + + boolean itemExist = + versionCollaborationStore.isItemVersionExist(context, Space.PRIVATE, itemId, versionId); + Assert.assertFalse(itemExist); + } + + @Test + public void testGetPrivateItemVersion() throws Exception { + testGetItemVersion(Space.PRIVATE, USER); + } + + @Test + public void testGetPublicItemVersion() throws Exception { + testGetItemVersion(Space.PUBLIC, ZusammenPluginConstants.PUBLIC_SPACE); + } + + + @Test + public void testGetNonExistingItemVersion() throws Exception { + Id itemId = new Id(); + Id versionId = new Id(); + doReturn(Optional.empty()).when(versionDaoMock).get(context, USER, itemId, versionId); + + ItemVersion itemVersion = + versionCollaborationStore.getItemVersion(context, Space.PRIVATE, itemId, versionId); + Assert.assertNull(itemVersion); + }*//* + + @Test + public void testCreatePrivateItemVersion() throws Exception { + testCreateItemVersion(Space.PRIVATE, USER, null); + } + + @Test + public void testCreatePrivateItemVersionBasedOn() throws Exception { + testCreateItemVersion(Space.PRIVATE, USER, new Id()); + } + + @Test + public void testCreatePublicItemVersion() throws Exception { + testCreateItemVersion(Space.PUBLIC, ZusammenPluginConstants.PUBLIC_SPACE, null); + } + + @Test + public void testCreatePublicItemVersionBasedOn() throws Exception { + testCreateItemVersion(Space.PUBLIC, ZusammenPluginConstants.PUBLIC_SPACE, new Id()); + } + + @Test + public void testUpdatePrivateItemVersion() throws Exception { + testUpdateItemVersion(Space.PRIVATE, USER); + } + + @Test + public void testUpdatePublicItemVersion() throws Exception { + testUpdateItemVersion(Space.PUBLIC, ZusammenPluginConstants.PUBLIC_SPACE); + } + + @Test + public void testDeletePrivateItemVersion() throws Exception { + testDeleteItemVersion(Space.PRIVATE, USER); + } + + @Test + public void testDeletePublicItemVersion() throws Exception { + testDeleteItemVersion(Space.PUBLIC, ZusammenPluginConstants.PUBLIC_SPACE); + } + + @Test + public void testPublishItemVersionWhenNotDirty() throws Exception { + Id itemId = new Id(); + ItemVersion version = TestUtils.createItemVersion(new Id(), null, "v1", false); + doReturn(Optional.of(version)).when(versionDaoMock).get(context, USER, itemId, version.getId()); + + versionCollaborationStore.publishItemVersion(context, itemId, version.getId(), "message"); + + } +*//* + private void testIsItemVersionExist(Space space, String spaceName) { + Id itemId = new Id(); + ItemVersion retrievedVersion = TestUtils.createItemVersion(new Id(), null, "v1"); + doReturn(Optional.of(retrievedVersion)).when(versionDaoMock) + .get(context, spaceName, itemId, retrievedVersion.getId()); + + boolean itemExist = + versionCollaborationStore + .isItemVersionExist(context, space, itemId, retrievedVersion.getId()); + Assert.assertTrue(itemExist); + } + + private void testGetItemVersion(Space space, String spaceName) throws Exception { + Id itemId = new Id(); + ItemVersion retrievedVersion = TestUtils.createItemVersion(new Id(), null, "v1"); + doReturn(Optional.of(retrievedVersion)).when(versionDaoMock) + .get(context, spaceName, itemId, retrievedVersion.getId()); + + ItemVersion itemVersion = + versionCollaborationStore.getItemVersion(context, space, itemId, retrievedVersion.getId()); + Assert.assertEquals(itemVersion, retrievedVersion); + } + + private void testListItemVersions(Space space, String spaceName) { + Id itemId = new Id(); + ItemVersion v1 = TestUtils.createItemVersion(new Id(), null, "v1"); + ItemVersion v2 = TestUtils.createItemVersion(new Id(), v1.getId(), "v2"); + ItemVersion v3 = TestUtils.createItemVersion(new Id(), v2.getId(), "v3"); + List<ItemVersion> retrievedVersions = Arrays.asList(v1, v2, v3); + doReturn(retrievedVersions).when(versionDaoMock).list(context, spaceName, itemId); + + Collection<ItemVersion> itemVersions = + versionCollaborationStore.listItemVersions(context, space, itemId); + Assert.assertEquals(itemVersions, retrievedVersions); + }*//* + + private void testCreateItemVersion(Space space, String spaceName, Id baseId) { + Id itemId = new Id(); + ItemVersion v1 = TestUtils.createItemVersion(new Id(), baseId, "v1", false); + List<ElementEntity> baseVersionElements = mockVersionElements(spaceName, itemId, baseId); + + ArgumentCaptor<ItemVersion> versionCaptor = ArgumentCaptor.forClass(ItemVersion.class); + + Date creationTime = new Date(); + versionCollaborationStore + .createItemVersion(context, space, itemId, baseId, v1.getId(), v1.getData(), creationTime); + + verify(versionDaoMock).create(eq(context), eq(spaceName), eq(itemId), versionCaptor.capture()); + //baseId, v1.getId(),v1.getData(), creationTime); + + ItemVersion capturedVersion = versionCaptor.getValue(); + Assert.assertEquals(baseId, capturedVersion.getBaseId()); + Assert.assertEquals(v1.getId(), capturedVersion.getId()); + Assert.assertEquals(v1.getData(), capturedVersion.getData()); + Assert.assertEquals(creationTime, capturedVersion.getCreationTime()); +*//* verify(versionDaoMock) + .create(anyObject(), anyObject(), anyObject(), anyObject(), anyObject(), anyObject(), + anyObject());*//* + +*//* if (baseId != null) { + baseVersionElements.forEach(element -> + verify(elementCollaborationStore).create(eq(context), + eq(new ElementEntityContext(spaceName, itemId, v1.getId())), + eq(element))); + } else { + verifyZeroInteractions(elementCollaborationStore); + }*//* + } + + private void testUpdateItemVersion(Space space, String spaceName) { + Id itemId = new Id(); + ItemVersion retrievedVersion = TestUtils.createItemVersion(new Id(), null, "v1", false); + doReturn(Optional.of(retrievedVersion)).when(versionDaoMock) + .get(context, spaceName, itemId, retrievedVersion.getId()); + + ItemVersionData updatedData = new ItemVersionData(); + updatedData.setInfo(TestUtils.createInfo("v1 updated")); + updatedData.setRelations( + Arrays.asList(new Relation(), new Relation(), new Relation(), new Relation())); + versionCollaborationStore.updateItemVersion( + context, space, itemId, retrievedVersion.getId(), updatedData, new Date()); + + *//*verify(versionDaoMock) + .update(context, spaceName, itemId, retrievedVersion.getId(), updatedData, modificationTime);*//* + verify(versionDaoMock) + .update(anyObject(), anyObject(), anyObject(), anyObject()); + + } + + private void testDeleteItemVersion(Space space, String spaceName) { + Id itemId = new Id(); + Id versionId = new Id(); + + List<ElementEntity> versionElements = mockVersionElements(spaceName, itemId, versionId); + versionCollaborationStore.deleteItemVersion(context, space, itemId, versionId); + +*//* versionElements.forEach(element -> + verify(elementCollaborationStore).delete(eq(context), + eq(new ElementEntityContext(spaceName, itemId, versionId)), + eq(element)));*//* + verify(versionDaoMock).delete(context, spaceName, itemId, versionId); + } + + private List<ElementEntity> mockVersionElements(String spaceName, Id itemId, Id versionId) { + ElementEntity elm1 = new ElementEntity(new Id()); + ElementEntity elm2 = new ElementEntity(new Id()); + List<ElementEntity> baseVersionElements = Arrays.asList(elm1, elm2); +*//* doReturn(baseVersionElements).when(elementCollaborationStore) + .list(eq(context), eq(new ElementEntityContext(spaceName, itemId, versionId)));*//* + return baseVersionElements; + }*/ +}
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementStageStoreImplTest.java b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementStageStoreImplTest.java new file mode 100644 index 0000000000..7f137b01b0 --- /dev/null +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/src/test/java/org/openecomp/core/zusammen/plugin/collaboration/impl/ElementStageStoreImplTest.java @@ -0,0 +1,167 @@ +package org.openecomp.core.zusammen.plugin.collaboration.impl; + +import com.amdocs.zusammen.datatypes.Id; +import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.UserInfo; +import com.amdocs.zusammen.datatypes.item.Action; +import com.amdocs.zusammen.datatypes.item.ElementContext; +import com.amdocs.zusammen.datatypes.item.Resolution; +import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.openecomp.core.zusammen.plugin.collaboration.TestUtils; +import org.openecomp.core.zusammen.plugin.dao.ElementStageRepository; +import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity; +import org.openecomp.core.zusammen.plugin.dao.types.StageEntity; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Date; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class ElementStageStoreImplTest { + private static final UserInfo USER = new UserInfo("user"); + private static final SessionContext context = TestUtils.createSessionContext(USER, "test"); + private static final ElementContext elementContext = + TestUtils.createElementContext(new Id(), new Id()); + + @Mock + private ElementStageRepository elementStageRepositoryMock; + @Spy + private ElementStageStoreImpl elementStageStore; + + @BeforeMethod + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(elementStageStore.getElementStageRepository(anyObject())) + .thenReturn(elementStageRepositoryMock); + } + + @Test + public void testListIds() throws Exception { + + } + + @Test + public void testGet() throws Exception { + + } + + @Test + public void testGetConflicted() throws Exception { + + } + + @Test + public void testHasConflicts() throws Exception { + + } + + @Test + public void testListConflictedDescriptors() throws Exception { + + } + + @Test + public void testCreate() throws Exception { + + } + + @Test + public void testDelete() throws Exception { + + } + + @Test + public void testResolveConflictWhenNotStaged() throws Exception { + doReturn(Optional.empty()) + .when(elementStageRepositoryMock).get(anyObject(), anyObject(), anyObject()); + elementStageStore + .resolveConflict(context, elementContext, new ElementEntity(new Id()), Resolution.YOURS); + } + + @Test + public void testResolveConflictWhenNotConflicted() throws Exception { + Id elementId = new Id(); + StageEntity<ElementEntity> stagedElement = + new StageEntity<>(new ElementEntity(elementId), new Date()); + doReturn(Optional.of(stagedElement)) + .when(elementStageRepositoryMock).get(anyObject(), anyObject(), anyObject()); + elementStageStore + .resolveConflict(context, elementContext, new ElementEntity(elementId), Resolution.YOURS); + } + + @Test + public void testResolveConflictByYours() throws Exception { + Id elementId = new Id(); + StageEntity<ElementEntity> stagedElement = + new StageEntity<>(new ElementEntity(elementId), new Date()); + stagedElement.setAction(Action.UPDATE); + stagedElement.setConflicted(true); + + doReturn(Optional.of(stagedElement)) + .when(elementStageRepositoryMock).get(anyObject(), anyObject(), anyObject()); + + elementStageStore + .resolveConflict(context, elementContext, new ElementEntity(elementId), Resolution.YOURS); + + verify(elementStageRepositoryMock).markAsNotConflicted(same(context), + eq(new ElementEntityContext(USER.getUserName(), elementContext)), + same(stagedElement.getEntity()), same(Action.IGNORE)); + } + + @Test + public void testResolveConflictByYoursWithRelated() throws Exception { + Id elementId = new Id(); + StageEntity<ElementEntity> stagedElement = + new StageEntity<>(new ElementEntity(elementId), new Date()); + stagedElement.setAction(Action.UPDATE); + stagedElement.setConflicted(true); + ElementEntity relatedElement1 = new ElementEntity(new Id()); + ElementEntity relatedElement2 = new ElementEntity(new Id()); + ElementEntity relatedElement3 = new ElementEntity(new Id()); + Set<ElementEntity> relatedElements = new HashSet<>(); + relatedElements.add(relatedElement1); + relatedElements.add(relatedElement2); + relatedElements.add(relatedElement3); + stagedElement.setConflictDependents(relatedElements); + + doReturn(Optional.of(stagedElement)) + .when(elementStageRepositoryMock).get(anyObject(), anyObject(), anyObject()); + + elementStageStore + .resolveConflict(context, elementContext, new ElementEntity(elementId), Resolution.YOURS); + + ElementEntityContext elementEntityContext = + new ElementEntityContext(USER.getUserName(), elementContext); + verify(elementStageRepositoryMock).markAsNotConflicted(same(context), eq(elementEntityContext), + same(stagedElement.getEntity()), same(Action.IGNORE)); + verify(elementStageRepositoryMock).markAsNotConflicted(same(context), eq(elementEntityContext), + same(relatedElement1), same(Action.IGNORE)); + verify(elementStageRepositoryMock).markAsNotConflicted(same(context), eq(elementEntityContext), + same(relatedElement2), same(Action.IGNORE)); + verify(elementStageRepositoryMock).markAsNotConflicted(same(context), eq(elementEntityContext), + same(relatedElement3), same(Action.IGNORE)); + } + + @Test + public void testResolveConflictByTheirs() throws Exception { + + } + + @Test + public void testResolveConflictByTheirsWithRelated() throws Exception { + + } + +}
\ No newline at end of file |