1 package org.openecomp.core.zusammen.plugin.collaboration;
 
   3 import com.amdocs.zusammen.datatypes.Id;
 
   4 import com.amdocs.zusammen.datatypes.SessionContext;
 
   5 import com.amdocs.zusammen.datatypes.item.Action;
 
   6 import com.amdocs.zusammen.datatypes.item.ElementContext;
 
   7 import com.amdocs.zusammen.datatypes.response.ReturnCode;
 
   8 import com.amdocs.zusammen.datatypes.response.ZusammenException;
 
   9 import com.amdocs.zusammen.sdk.collaboration.types.CollaborationMergeChange;
 
  10 import com.amdocs.zusammen.sdk.collaboration.types.CollaborationPublishResult;
 
  11 import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity;
 
  12 import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity;
 
  13 import org.openecomp.core.zusammen.plugin.dao.types.VersionEntity;
 
  15 import java.util.Collection;
 
  16 import java.util.Date;
 
  18 import java.util.Optional;
 
  19 import java.util.UUID;
 
  21 import static com.amdocs.zusammen.datatypes.response.Module.ZCSP;
 
  22 import static org.openecomp.core.zusammen.plugin.ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID;
 
  23 import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToElementChange;
 
  24 import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.convertToVersionChange;
 
  25 import static org.openecomp.core.zusammen.plugin.collaboration.ErrorCode.NO_CHANGES_TO_PUBLISH;
 
  27 public class PublishService {
 
  28   // TODO: 6/29/2017 throw ZusammenException with ReturnCode when needed.
 
  29   private static final String PUSH_NON_EXISTING_VERSION =
 
  30       "Item Id %s, version Id %s: Non existing version cannot be pushed.";
 
  32   private VersionPublicStore versionPublicStore;
 
  33   private VersionPrivateStore versionPrivateStore;
 
  34   private ElementPublicStore elementPublicStore;
 
  35   private ElementPrivateStore elementPrivateStore;
 
  37   public PublishService(VersionPublicStore versionPublicStore,
 
  38                         VersionPrivateStore versionPrivateStore,
 
  39                         ElementPublicStore elementPublicStore,
 
  40                         ElementPrivateStore elementPrivateStore) {
 
  41     this.versionPublicStore = versionPublicStore;
 
  42     this.versionPrivateStore = versionPrivateStore;
 
  43     this.elementPublicStore = elementPublicStore;
 
  44     this.elementPrivateStore = elementPrivateStore;
 
  47   public CollaborationPublishResult publish(SessionContext context, Id itemId, Id versionId,
 
  49     CollaborationPublishResult result = new CollaborationPublishResult();
 
  50     result.setChange(new CollaborationMergeChange());
 
  52     Date publishTime = new Date();
 
  53     Id revisionId = new Id(UUID.randomUUID().toString());
 
  54     boolean versionFirstPublication = publishVersion(context, itemId, versionId, revisionId,
 
  56     if (versionFirstPublication) {
 
  57       publishAllElements(context, new ElementContext(itemId, versionId, revisionId), publishTime,
 
  60       publishDirtyElements(context, new ElementContext(itemId, versionId, revisionId), publishTime,
 
  66   private boolean publishVersion(SessionContext context, Id itemId, Id versionId, Id revisionId,
 
  67                                  Date publishTime, String message) {
 
  68     SynchronizationStateEntity privateVersionSyncState =
 
  69         versionPrivateStore.getSynchronizationState(context, itemId, versionId)
 
  70             .orElseThrow(() -> new IllegalArgumentException(
 
  71                 String.format(PUSH_NON_EXISTING_VERSION, itemId.toString(), versionId.toString())));
 
  73     if (!privateVersionSyncState.isDirty()) {
 
  74       throw new ZusammenException(new ReturnCode(NO_CHANGES_TO_PUBLISH, ZCSP,
 
  75           String.format(Message.NO_CHANGES_TO_PUBLISH, itemId, versionId), null));
 
  78     Optional<SynchronizationStateEntity> publicVersionSyncState =
 
  79         versionPublicStore.getSynchronizationState(context, itemId, versionId);
 
  81     // private must be synced with public (if public exists)
 
  82     if (publicVersionSyncState.isPresent() &&
 
  83         !privateVersionSyncState.getPublishTime()
 
  84             .equals(publicVersionSyncState.get().getPublishTime())) {
 
  85       // should not happen as it is validated in zusammen-core
 
  86       throw new UnsupportedOperationException("Out of sync item version can not be publish");
 
  89     boolean versionFirstPublication;
 
  90     Map<Id, Id> versionElementIds =
 
  91         elementPublicStore.listIds(context, new ElementContext(itemId,
 
  93     if (publicVersionSyncState.isPresent()) {
 
  94       versionPublicStore.update(context, itemId, new VersionEntity(versionId), revisionId,
 
  95           versionElementIds,publishTime,message);
 
  96       versionFirstPublication = false;
 
  98       VersionEntity privateVersion = versionPrivateStore.get(context, itemId, versionId)
 
  99           .orElseThrow(() -> new IllegalArgumentException(
 
 100               String.format(PUSH_NON_EXISTING_VERSION, itemId.toString(), versionId.toString())));
 
 101       versionPublicStore.create(context, itemId, privateVersion, revisionId,versionElementIds,
 
 102           publishTime,message);
 
 103       versionFirstPublication = true;
 
 105     versionPrivateStore.markAsPublished(context, itemId, versionId, publishTime);
 
 106     return versionFirstPublication;
 
 109   private void publishAllElements(SessionContext context, ElementContext elementContext,
 
 110                                   Date publishTime, CollaborationPublishResult result) {
 
 111     Collection<SynchronizationStateEntity> privateElementSyncStates =
 
 112         elementPrivateStore.listSynchronizationStates(context, elementContext);
 
 114     for (SynchronizationStateEntity privateElementSyncState : privateElementSyncStates) {
 
 115       Optional<ElementEntity> privateElement =
 
 116           elementPrivateStore.get(context, elementContext, privateElementSyncState.getId());
 
 118       if (!privateElement.isPresent()) {
 
 121       ElementEntity elementToPublish = privateElement.get();
 
 123       elementPublicStore.create(context, elementContext, elementToPublish,
 
 124           privateElementSyncState.isDirty() ? publishTime
 
 125               : privateElementSyncState.getPublishTime());
 
 127       if (privateElementSyncState.isDirty()) {
 
 129             .markAsPublished(context, elementContext, privateElementSyncState.getId(), publishTime);
 
 131       updateResult(elementContext, elementToPublish, Action.CREATE,
 
 132           ROOT_ELEMENTS_PARENT_ID.equals(privateElementSyncState.getId()), result);
 
 136   private void publishDirtyElements(SessionContext context, ElementContext elementContext,
 
 137                                     Date publishTime, CollaborationPublishResult result) {
 
 139     Id revisionId = elementContext.getRevisionId();
 
 140     elementContext.setRevisionId(revisionId);
 
 141     ElementContext privateElementContext = new ElementContext(elementContext.getItemId(),
 
 142         elementContext.getVersionId(),Id.ZERO);
 
 143     Collection<SynchronizationStateEntity> privateElementSyncStates =
 
 144         elementPrivateStore.listSynchronizationStates(context, elementContext);
 
 146     Collection<SynchronizationStateEntity> publicElementSyncStates =
 
 147         elementPublicStore.listSynchronizationStates(context, elementContext);
 
 149     for (SynchronizationStateEntity privateElementSyncState : privateElementSyncStates) {
 
 150       if (!privateElementSyncState.isDirty()) {
 
 154       Optional<ElementEntity> privateElement =
 
 155           elementPrivateStore.get(context, privateElementContext, privateElementSyncState.getId());
 
 157       ElementEntity elementToPublish;
 
 158       Action actionOnPublic;
 
 159       if (privateElement.isPresent()) {
 
 160         elementToPublish = privateElement.get();
 
 162         if (publicElementSyncStates.contains(privateElementSyncState)) {
 
 164           elementPublicStore.update(context, elementContext, elementToPublish, publishTime);
 
 165           actionOnPublic = Action.UPDATE;
 
 167           elementPublicStore.create(context, elementContext, elementToPublish, publishTime);
 
 168           actionOnPublic = Action.CREATE;
 
 172             .markAsPublished(context, privateElementContext, privateElementSyncState.getId(), publishTime);
 
 175             elementPublicStore.get(context, elementContext, privateElementSyncState.getId())
 
 176                 .orElseThrow(() -> new IllegalStateException(
 
 177                     "Element that should be deleted from public must exist there"));
 
 178         elementPublicStore.delete(context, elementContext, elementToPublish, publishTime);
 
 179         actionOnPublic = Action.DELETE;
 
 182             .markDeletionAsPublished(context, privateElementContext, privateElementSyncState.getId(),
 
 186       updateResult(elementContext, elementToPublish, actionOnPublic,
 
 187           ROOT_ELEMENTS_PARENT_ID.equals(privateElementSyncState.getId()), result);
 
 191   private void updateResult(ElementContext elementContext, ElementEntity element,
 
 192                             Action action, boolean versionDataElement,
 
 193                             CollaborationPublishResult result) {
 
 194     if (versionDataElement) {
 
 195       result.getChange().setChangedVersion(convertToVersionChange(elementContext, element, action));
 
 197       result.getChange().getChangedElements()
 
 198           .add(convertToElementChange(elementContext, element, action));