Add collaboration feature
[sdc.git] / openecomp-be / lib / openecomp-core-lib / openecomp-zusammen-lib / openecomp-zusammen-plugin / src / main / java / org / openecomp / core / zusammen / plugin / collaboration / impl / ElementPrivateStoreImpl.java
1 package org.openecomp.core.zusammen.plugin.collaboration.impl;
2
3 import com.amdocs.zusammen.datatypes.Id;
4 import com.amdocs.zusammen.datatypes.SessionContext;
5 import com.amdocs.zusammen.datatypes.item.ElementContext;
6 import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext;
7 import org.openecomp.core.zusammen.plugin.ZusammenPluginConstants;
8 import org.openecomp.core.zusammen.plugin.collaboration.ElementPrivateStore;
9 import org.openecomp.core.zusammen.plugin.dao.ElementRepository;
10 import org.openecomp.core.zusammen.plugin.dao.ElementRepositoryFactory;
11 import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepository;
12 import org.openecomp.core.zusammen.plugin.dao.ElementSynchronizationStateRepositoryFactory;
13 import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity;
14 import org.openecomp.core.zusammen.plugin.dao.types.SynchronizationStateEntity;
15
16 import java.util.Collection;
17 import java.util.Date;
18 import java.util.HashSet;
19 import java.util.Map;
20 import java.util.Objects;
21 import java.util.Optional;
22 import java.util.stream.Collectors;
23
24 import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateElementContext;
25 import static org.openecomp.core.zusammen.plugin.ZusammenPluginUtil.getPrivateSpaceName;
26
27 public class ElementPrivateStoreImpl implements ElementPrivateStore {
28   private static final Id REVISION_ID = Id.ZERO; // the private revision id is Id.ZERO 0000000...
29
30   @Override
31   public Map<Id, Id> listIds(SessionContext context, ElementContext elementContext) {
32     return getElementRepository(context)
33         .listIds(context, new ElementEntityContext(getPrivateSpaceName(context), elementContext));
34   }
35
36   @Override
37   public Collection<ElementEntity> listSubs(SessionContext context, ElementContext elementContext,
38                                             Id elementId) {
39     if (elementId == null) {
40       elementId = ZusammenPluginConstants.ROOT_ELEMENTS_PARENT_ID;
41     }
42
43     ElementRepository elementRepository = getElementRepository(context);
44     ElementEntityContext privateContext =
45         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
46     privateContext.setRevisionId(REVISION_ID);
47     return elementRepository.get(context, privateContext, new ElementEntity(elementId))
48         .map(ElementEntity::getSubElementIds).orElse(new HashSet<>()).stream()
49         .map(subElementId -> elementRepository
50             .get(context, privateContext, new ElementEntity(subElementId)).get())
51         .filter(Objects::nonNull)
52         .collect(Collectors.toList());
53   }
54
55   @Override
56   public Optional<ElementEntity> get(SessionContext context, ElementContext elementContext,
57                                      Id elementId) {
58     ElementEntityContext privateElementContext =
59         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
60     privateElementContext.setRevisionId(REVISION_ID);
61     return getElementRepository(context)
62         .get(context, privateElementContext,
63             new ElementEntity(elementId));
64   }
65
66   @Override
67   public Optional<ElementEntity> getDescriptor(SessionContext context,
68                                                ElementContext elementContext, Id elementId) {
69     return getElementRepository(context)
70         .getDescriptor(context,
71             new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext
72                 (elementContext)),
73             new ElementEntity(elementId));
74   }
75
76   @Override
77   public Collection<SynchronizationStateEntity> listSynchronizationStates(SessionContext context,
78                                                                           ElementContext elementContext) {
79     ElementEntityContext privateElementContext =
80         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
81     return getElementSyncStateRepository(context)
82         .list(context, privateElementContext);
83   }
84
85   @Override
86   public Optional<SynchronizationStateEntity> getSynchronizationState(SessionContext context,
87                                                                       ElementContext elementContext,
88                                                                       Id elementId) {
89
90     ElementEntityContext privateElementContext =
91         new ElementEntityContext(getPrivateSpaceName(context), getPrivateElementContext
92             (elementContext));
93     return getElementSyncStateRepository(context)
94         .get(context, privateElementContext,
95             new SynchronizationStateEntity(elementId, REVISION_ID));
96   }
97
98   @Override
99   public void create(SessionContext context, ElementContext elementContext, ElementEntity element) {
100     create(context, elementContext, element, true, null);
101   }
102
103   @Override
104   public boolean update(SessionContext context, ElementContext elementContext,
105                         ElementEntity element) {
106     ElementEntityContext privateContext =
107         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
108     privateContext.setRevisionId(REVISION_ID);
109
110     if (!isElementChanged(context, privateContext, element)) {
111       return false;
112     }
113
114     getElementRepository(context).update(context, privateContext, element);
115     getElementSyncStateRepository(context).markAsDirty(context, privateContext,
116         new SynchronizationStateEntity(element.getId(), REVISION_ID));
117     return true;
118   }
119
120   @Override
121   public void delete(SessionContext context, ElementContext elementContext, ElementEntity element) {
122
123     ElementEntityContext privateElementContext =
124         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
125     privateElementContext.setRevisionId(REVISION_ID);
126     deleteElementHierarchy(context, getElementRepository(context),
127         getElementSyncStateRepository(context),
128         privateElementContext, element);
129   }
130
131   @Override
132   public void markAsPublished(SessionContext context, ElementContext elementContext, Id elementId,
133                               Date publishTime) {
134     ElementEntityContext privateContext =
135         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
136     privateContext.setRevisionId(REVISION_ID);
137     getElementSyncStateRepository(context).update(context,
138         privateContext,
139         new SynchronizationStateEntity(elementId, REVISION_ID, publishTime, false));
140   }
141
142   @Override
143   public void markDeletionAsPublished(SessionContext context, ElementContext elementContext,
144                                       Id elementId, Date publishTime) {
145
146     ElementEntityContext privateContext =
147         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
148     privateContext.setRevisionId(REVISION_ID);
149     getElementSyncStateRepository(context).delete(context,
150         privateContext,
151         new SynchronizationStateEntity(elementId, REVISION_ID));
152   }
153
154   @Override
155   public void commitStagedCreate(SessionContext context, ElementContext elementContext,
156                                  ElementEntity element, Date publishTime) {
157     create(context, elementContext, element, false, publishTime);
158   }
159
160   @Override
161   public void commitStagedUpdate(SessionContext context, ElementContext elementContext,
162                                  ElementEntity element, Date publishTime) {
163     ElementEntityContext privateContext =
164         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
165     privateContext.setRevisionId(REVISION_ID);
166
167     getElementRepository(context).update(context, privateContext, element);
168     // Currently Resolution='Other' is not supported so this is invoked after conflict was
169     // resolved with Resolution='Theirs' so dirty flag should be turned off.
170     // (if there was no conflict it's off anyway)
171     getElementSyncStateRepository(context).update(context, privateContext,
172         new SynchronizationStateEntity(element.getId(), REVISION_ID, publishTime, false));
173   }
174
175   @Override
176   public void commitStagedDelete(SessionContext context, ElementContext elementContext,
177                                  ElementEntity element) {
178     ElementEntityContext privateContext =
179         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
180     privateContext.setRevisionId(REVISION_ID);
181     getElementRepository(context).delete(context, privateContext, element);
182     getElementSyncStateRepository(context)
183         .delete(context, privateContext,
184             new SynchronizationStateEntity(element.getId(), REVISION_ID));
185   }
186
187   @Override
188   public void commitStagedIgnore(SessionContext context, ElementContext elementContext,
189                                  ElementEntity element, Date publishTime) {
190     // publish time - updated to mark that this element was already synced with this publish time
191     // (even though the local data was preferred) and to prevent this conflict again.
192     // dirty - turned on because the local data which is different than the public one was
193     // preferred. It will enable future publication of this data.
194     getElementSyncStateRepository(context).update(context,
195         new ElementEntityContext(getPrivateSpaceName(context), elementContext),
196         new SynchronizationStateEntity(element.getId(), REVISION_ID, publishTime, true));
197   }
198
199   private void create(SessionContext context, ElementContext elementContext,
200                       ElementEntity element, boolean dirty, Date publishTime) {
201     ElementEntityContext privateContext =
202         new ElementEntityContext(getPrivateSpaceName(context), elementContext);
203     privateContext.setRevisionId(REVISION_ID);
204     getElementRepository(context).create(context, privateContext, element);
205     getElementSyncStateRepository(context).create(context, privateContext,
206         new SynchronizationStateEntity(element.getId(), REVISION_ID, publishTime, dirty));
207   }
208
209
210   private void deleteElementHierarchy(
211       SessionContext context, ElementRepository elementRepository,
212       ElementSynchronizationStateRepository elementSyncStateRepository,
213       ElementEntityContext elementContext, ElementEntity element) {
214
215     Optional<ElementEntity> retrieved = elementRepository.get(context, elementContext, element);
216     if (!retrieved.isPresent()) {
217       return;
218     }
219     retrieved.get().getSubElementIds().stream()
220         .map(ElementEntity::new)
221         .forEach(subElementEntity -> deleteElementHierarchy(
222             context, elementRepository, elementSyncStateRepository, elementContext,
223             subElementEntity));
224
225     // only for the first one the parentId will populated (so it'll be removed from its parent)
226     elementRepository.delete(context, elementContext, element);
227     handleDeletedElementSyncState(context, elementSyncStateRepository, elementContext, element);
228   }
229
230   private void handleDeletedElementSyncState(SessionContext context,
231                                              ElementSynchronizationStateRepository elementSyncStateRepository,
232                                              ElementEntityContext elementContext,
233                                              ElementEntity element) {
234     SynchronizationStateEntity elementSyncState = new SynchronizationStateEntity(element.getId(),
235         REVISION_ID);
236     if (elementSyncStateRepository.get(context, elementContext, elementSyncState).
237         orElseThrow(
238             () -> new IllegalStateException("Synchronization state must exist for an element"))
239         .getPublishTime() == null) {
240       elementSyncStateRepository.delete(context, elementContext, elementSyncState);
241     } else {
242       elementSyncStateRepository.markAsDirty(context, elementContext, elementSyncState);
243     }
244   }
245
246   private boolean isElementChanged(SessionContext context,
247                                    ElementEntityContext elementContext,
248                                    ElementEntity newElement) {
249     return getElementHash(context, elementContext, new ElementEntity(newElement.getId()))
250         .map(existingHash -> !newElement.getElementHash().equals(existingHash))
251         .orElse(true);
252   }
253
254   private Optional<Id> getElementHash(SessionContext context,
255                                       ElementEntityContext elementEntityContext,
256                                       ElementEntity element) {
257     return getElementRepository(context).getHash(context, elementEntityContext, element);
258   }
259
260   protected ElementRepository getElementRepository(SessionContext context) {
261     return ElementRepositoryFactory.getInstance().createInterface(context);
262   }
263
264   protected ElementSynchronizationStateRepository getElementSyncStateRepository(
265       SessionContext context) {
266     return ElementSynchronizationStateRepositoryFactory.getInstance().createInterface(context);
267   }
268
269 }