Unit Tests
[sdc.git] / 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
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.core.zusammen.plugin.dao.impl.cassandra;
18
19 import com.amdocs.zusammen.datatypes.Id;
20 import com.amdocs.zusammen.datatypes.Namespace;
21 import com.amdocs.zusammen.datatypes.SessionContext;
22 import com.amdocs.zusammen.datatypes.item.Info;
23 import com.amdocs.zusammen.datatypes.item.Relation;
24 import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext;
25 import com.amdocs.zusammen.utils.fileutils.json.JsonUtil;
26 import com.datastax.driver.core.ResultSet;
27 import com.datastax.driver.core.Row;
28 import com.datastax.driver.mapping.annotations.Accessor;
29 import com.datastax.driver.mapping.annotations.Param;
30 import com.datastax.driver.mapping.annotations.Query;
31 import com.google.gson.reflect.TypeToken;
32 import org.openecomp.core.zusammen.plugin.ZusammenPluginConstants;
33 import org.openecomp.core.zusammen.plugin.dao.ElementRepository;
34 import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity;
35
36 import java.lang.reflect.Type;
37 import java.nio.ByteBuffer;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Optional;
44 import java.util.Set;
45 import java.util.TreeMap;
46 import java.util.stream.Collectors;
47
48 public class ElementRepositoryImpl implements ElementRepository {
49
50   @Override
51   public Map<Id, Id> listIds(SessionContext context, ElementEntityContext elementContext) {
52
53     if (elementContext.getRevisionId() == null) {
54       String revisionId = calculateLastRevisionId(context, elementContext);
55       if (revisionId == null) {
56         return new HashMap<>();
57       }
58
59       elementContext.setRevisionId(new Id(revisionId));
60     }
61     return getVersionElementIds(context, elementContext).entrySet().stream().collect(Collectors
62         .toMap(entry -> new Id(entry.getKey()), entry -> new Id(entry.getValue())));
63
64    /* return getVersionElementIds(context, elementContext).stream()
65         .map(Id::new)
66         .collect(Collectors.toList());*/
67
68   }
69
70   @Override
71   public void create(SessionContext context, ElementEntityContext elementContext,
72                      ElementEntity element) {
73     createElement(context, elementContext, element);
74     addElementToParent(context, elementContext, element);
75   }
76
77   @Override
78   public void update(SessionContext context, ElementEntityContext elementContext,
79                      ElementEntity element) {
80
81     Id elementRevisionId = getElementRevision(context, elementContext, element.getId());
82     if (elementRevisionId.equals(elementContext.getRevisionId())) {
83       updateElement(context, elementContext, element);
84     } else {
85       createElement(context, elementContext, element);
86     }
87   }
88
89   @Override
90   public void delete(SessionContext context, ElementEntityContext elementContext,
91                      ElementEntity element) {
92     removeElementFromParent(context, elementContext, element);
93     deleteElement(context, elementContext, element);
94   }
95
96   @Override
97   public Optional<ElementEntity> get(SessionContext context, ElementEntityContext elementContext,
98                                      ElementEntity element) {
99     String revisionId = calculateElementRevisionId(context, elementContext, element);
100     if (revisionId == null) {
101       return Optional.empty();
102     }
103
104     Row row = getElementAccessor(context).get(
105         elementContext.getSpace(),
106         elementContext.getItemId().toString(),
107         elementContext.getVersionId().toString(),
108         element.getId().toString(),
109         revisionId).one();
110
111     return row == null ? Optional.empty() : Optional.of(getElementEntity(element, row));
112   }
113
114   @Override
115   public Optional<ElementEntity> getDescriptor(SessionContext context,
116                                                ElementEntityContext elementContext,
117                                                ElementEntity element) {
118     String revisionId = calculateElementRevisionId(context, elementContext, element);
119     if (revisionId == null) {
120       return Optional.empty();
121     }
122
123     Row row = getElementAccessor(context).getDescriptor(
124         elementContext.getSpace(),
125         elementContext.getItemId().toString(),
126         elementContext.getVersionId().toString(),
127         element.getId().toString(),
128         revisionId).one();
129
130     return row == null ? Optional.empty() : Optional.of(getElementEntityDescriptor(element, row));
131   }
132
133   @Override
134   public void createNamespace(SessionContext context, ElementEntityContext elementContext,
135                               ElementEntity element) {
136     getElementNamespaceAccessor(context).create(elementContext.getItemId().toString(),
137         element.getId().toString(),
138         element.getNamespace().toString());
139   }
140
141   @Override
142   public Optional<Id> getHash(SessionContext context, ElementEntityContext elementContext,
143                               ElementEntity element) {
144     String revisionId = calculateElementRevisionId(context, elementContext, element);
145     if (revisionId == null) {
146       return Optional.empty();
147     }
148
149     Row row = getElementAccessor(context).getHash(
150         elementContext.getSpace(),
151         elementContext.getItemId().toString(),
152         elementContext.getVersionId().getValue(),
153         element.getId().toString(),
154         revisionId).one();
155
156     return row == null ? Optional.empty() : Optional.of(getElementHash(row));
157   }
158
159   private String calculateElementRevisionId(SessionContext context,
160                                             ElementEntityContext elementContext,
161                                             ElementEntity element) {
162
163     if (elementContext.getSpace().equals(ZusammenPluginConstants.PUBLIC_SPACE)) {
164
165       String versionRevision;
166       if (elementContext.getRevisionId() == null) {
167         versionRevision = calculateLastRevisionId(context, elementContext);
168       } else {
169         versionRevision = elementContext.getRevisionId().getValue();
170       }
171
172       elementContext.setRevisionId(new Id(versionRevision));
173       Map<String, String> elementIds = getVersionElementIds(context, elementContext);
174       if (elementIds.containsKey(element.getId().getValue())) {
175         return elementIds.get(element.getId().getValue());
176       } else {
177         return null;
178       }
179
180     } else {
181       return Id.ZERO.getValue();
182     }
183   }
184
185   private String calculateLastRevisionId(SessionContext context, ElementEntityContext
186       elementContext) {
187     List<Row> rows = getVersionElementsAccessor(context).listRevisions(elementContext.getSpace(),
188         elementContext
189             .getItemId().toString(), elementContext.getVersionId().toString()).all();
190     if (rows == null || rows.size() == 0) {
191       return null;
192     }
193     rows.sort((o1, o2) -> o1.getDate(VersionElementsField.PUBLISH_TIME)
194         .after(o2.getDate(VersionElementsField.PUBLISH_TIME)) ? -1 : 1);
195     return rows.get(0).getString(VersionElementsField.REVISION_ID);
196   }
197
198   /*private static String getVersionId(ElementEntityContext elementContext) {
199     return elementContext.getRevisionId() == null
200         ? elementContext.getVersionId().toString()
201         : elementContext.getRevisionId().getValue();
202   }*/
203
204   private ElementNamespaceAccessor getElementNamespaceAccessor(SessionContext context) {
205     return CassandraDaoUtils.getAccessor(context, ElementNamespaceAccessor.class);
206   }
207
208   private ElementAccessor getElementAccessor(SessionContext context) {
209     return CassandraDaoUtils.getAccessor(context, ElementAccessor.class);
210   }
211
212   private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) {
213     return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class);
214   }
215
216   private void createElement(SessionContext context, ElementEntityContext elementContext,
217                              ElementEntity element) {
218     createElementRow(context, elementContext, element);
219
220     Map<String, String> elementIds = new TreeMap<>();
221     elementIds.put(element.getId().toString(), elementContext.getRevisionId().getValue());
222     getVersionElementsAccessor(context).addElements(
223         elementIds,
224         elementContext.getSpace(),
225         elementContext.getItemId().toString(),
226         elementContext.getVersionId().getValue(),
227         elementContext.getRevisionId().getValue());
228   }
229
230   private void createElementRow(SessionContext context, ElementEntityContext elementContext,
231                                 ElementEntity element) {
232     Set<String> subElementIds =
233         element.getSubElementIds().stream().map(Id::toString).collect(Collectors.toSet());
234
235     getElementAccessor(context).create(
236         elementContext.getSpace(),
237         elementContext.getItemId().toString(),
238         elementContext.getVersionId().getValue(),
239         element.getId().toString(),
240         elementContext.getRevisionId().getValue(),
241         element.getParentId() == null ? null : element.getParentId().toString(),
242         element.getNamespace() == null ? null : element.getNamespace().toString(),
243         JsonUtil.object2Json(element.getInfo()),
244         JsonUtil.object2Json(element.getRelations()),
245         element.getData(),
246         element.getSearchableData(),
247         element.getVisualization(),
248         subElementIds,
249         element.getElementHash().getValue());
250   }
251
252   private void updateElement(SessionContext context, ElementEntityContext elementContext,
253                              ElementEntity element) {
254
255
256     if (element.getParentId() == null) {
257       getElementAccessor(context).update(
258           JsonUtil.object2Json(element.getInfo()),
259           JsonUtil.object2Json(element.getRelations()),
260           element.getData(),
261           element.getSearchableData(),
262           element.getVisualization(),
263           element.getElementHash().getValue(),
264           elementContext.getSpace(),
265           elementContext.getItemId().toString(),
266           elementContext.getVersionId().toString(),
267           element.getId().toString(),
268           elementContext.getRevisionId().getValue());
269     } else {
270       getElementAccessor(context).update(
271           JsonUtil.object2Json(element.getInfo()),
272           JsonUtil.object2Json(element.getRelations()),
273           element.getData(),
274           element.getSearchableData(),
275           element.getVisualization(),
276           element.getElementHash().getValue(),
277           element.getParentId().getValue(),
278           elementContext.getSpace(),
279           elementContext.getItemId().toString(),
280           elementContext.getVersionId().toString(),
281           element.getId().getValue(),
282           elementContext.getRevisionId().getValue());
283     }
284
285     Map<String, String> elementIds = new TreeMap<>();
286     elementIds.put(element.getId().getValue(), elementContext.getRevisionId().getValue());
287     getVersionElementsAccessor(context).addElements(
288         elementIds,
289         elementContext.getSpace(),
290         elementContext.getItemId().toString(),
291         elementContext.getVersionId().getValue(),
292         elementContext.getRevisionId().getValue());
293   }
294
295   private void deleteElement(SessionContext context, ElementEntityContext elementContext,
296                              ElementEntity element) {
297
298
299     getElementAccessor(context).delete(
300         elementContext.getSpace(),
301         elementContext.getItemId().toString(),
302         elementContext.getVersionId().toString(),
303         element.getId().toString(),
304         elementContext.getRevisionId().getValue());
305
306     getVersionElementsAccessor(context).removeElements(
307         Collections.singleton(element.getId().toString()),
308         elementContext.getSpace(),
309         elementContext.getItemId().toString(),
310         elementContext.getVersionId().toString(),
311         elementContext.getRevisionId().getValue());
312   }
313
314   private void addElementToParent(SessionContext context, ElementEntityContext elementContext,
315                                   ElementEntity element) {
316     if (element.getParentId() == null) {
317       return;
318     }
319
320
321     getElementAccessor(context).addSubElements(
322         Collections.singleton(element.getId().toString()),
323         elementContext.getSpace(),
324         elementContext.getItemId().toString(),
325         elementContext.getVersionId().toString(),
326         element.getParentId().toString(),
327         elementContext.getRevisionId().getValue());
328
329     Map<String, String> elementIds = new TreeMap<>();
330     elementIds.put(element.getParentId().toString(), elementContext.getRevisionId().getValue());
331     getVersionElementsAccessor(context).addElements(elementIds, elementContext.getSpace(),
332         elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(),
333         elementContext.getRevisionId().getValue());
334   }
335
336   private void removeElementFromParent(SessionContext context, ElementEntityContext elementContext,
337                                        ElementEntity element) {
338
339     if (element.getParentId() == null) {
340       return;
341     }
342
343     Optional<ElementEntity> parentElement =
344         get(context, elementContext, new ElementEntity(element.getParentId()));
345     if (!parentElement.isPresent()) {
346       return;
347     }
348     getElementAccessor(context).removeSubElements(
349         Collections.singleton(element.getId().toString()),
350         elementContext.getSpace(),
351         elementContext.getItemId().toString(),
352         elementContext.getVersionId().toString(),
353         element.getParentId().toString(),
354         elementContext.getRevisionId().getValue());
355
356     getVersionElementsAccessor(context)
357         .removeElements(Collections.singleton(element.getId().toString()),
358             elementContext.getSpace(),
359             elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(),
360             elementContext.getRevisionId().getValue());
361
362     Map<String, String> elementIds = new TreeMap<>();
363     elementIds.put(element.getParentId().toString(), elementContext.getRevisionId().getValue());
364     getVersionElementsAccessor(context).addElements(elementIds, elementContext.getSpace(),
365         elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(),
366         elementContext.getRevisionId().getValue());
367   }
368
369   static ElementEntity getElementEntityDescriptor(ElementEntity element, Row row) {
370     element.setNamespace(getNamespace(row.getString(ElementField.NAMESPACE)));
371     element.setParentId(getParentId(row.getString(ElementField.PARENT_ID)));
372     element.setInfo(json2Object(row.getString(ElementField.INFO), Info.class));
373     element.setRelations(
374         json2Object(row.getString(ElementField.RELATIONS), new TypeToken<ArrayList<Relation>>() {
375         }.getType()));
376
377     element.setSubElementIds(row.getSet(ElementField.SUB_ELEMENT_IDS, String.class)
378         .stream().map(Id::new).collect(Collectors.toSet()));
379     return element;
380   }
381
382   static ElementEntity getElementEntity(ElementEntity element, Row row) {
383     getElementEntityDescriptor(element, row);
384
385     element.setData(row.getBytes(ElementField.DATA));
386     element.setSearchableData(row.getBytes(ElementField.SEARCHABLE_DATA));
387     element.setVisualization(row.getBytes(ElementField.VISUALIZATION));
388     element.setElementHash(new Id(row.getString(ElementField.ELEMENT_HASH)));
389     return element;
390   }
391
392   private Id getElementHash(Row row) {
393     return new Id(row.getString(ElementField.ELEMENT_HASH));
394   }
395
396   private static Id getParentId(String parentIdStr) {
397     return parentIdStr == null ? null : new Id(parentIdStr);
398   }
399
400   private static Namespace getNamespace(String namespaceStr) {
401     Namespace namespace = new Namespace();
402     if (namespaceStr != null) {
403       namespace.setValue(namespaceStr);
404     }
405     return namespace;
406   }
407
408   private static <T> T json2Object(String json, Type typeOfT) {
409     return json == null ? null : JsonUtil.json2Object(json, typeOfT);
410   }
411
412   private Map<String, String> getVersionElementIds(SessionContext context,
413                                                    ElementEntityContext elementContext) {
414     Row row = getVersionElementsAccessor(context).get(
415         elementContext.getSpace(),
416         elementContext.getItemId().toString(),
417         elementContext.getVersionId().getValue(),
418         elementContext.getRevisionId().getValue()).one();
419     return row == null
420         ? new HashMap<>()
421         : row.getMap(ElementRepositoryImpl.VersionElementsField.ELEMENT_IDS, String.class, String
422             .class);
423   }
424
425   private Id getElementRevision(SessionContext context, ElementEntityContext elementContext
426       , Id elementId) {
427     Map<Id, Id> versionElementIds =
428         listIds(context, new ElementEntityContext
429             (elementContext.getSpace(), elementContext.getItemId(), elementContext.getVersionId(),
430                 elementContext.getRevisionId()));
431     return versionElementIds.get(elementId);
432
433   }
434
435
436   /*
437 CREATE TABLE IF NOT EXISTS element_namespace (
438         item_id text,
439         element_id text,
440         namespace text,
441         PRIMARY KEY (( item_id, element_id ))
442 );
443    */
444   @Accessor
445   interface ElementNamespaceAccessor {
446     @Query("UPDATE element_namespace SET namespace=:ns " +
447         "WHERE item_id=:item AND element_id=:id ")
448     void create(@Param("item") String itemId,
449                 @Param("id") String elementId,
450                 @Param("ns") String namespace);
451   }
452
453   @Accessor
454   interface ElementAccessor {
455     @Query(
456         "UPDATE element SET parent_id=:parentId, namespace=:ns, info=:info, relations=:rels, " +
457             "data=:data, searchable_data=:searchableData, visualization=:visualization, " +
458             "sub_element_ids=sub_element_ids+:subs , element_hash=:elementHash " +
459             " WHERE space=:space AND item_id=:item AND version_id=:ver AND element_id=:id AND " +
460             "revision_id=:rev ")
461     void create(@Param("space") String space,
462                 @Param("item") String itemId,
463                 @Param("ver") String versionId,
464                 @Param("id") String elementId,
465                 @Param("rev") String revisionId,
466                 @Param("parentId") String parentElementId,
467                 @Param("ns") String namespace,
468                 @Param("info") String info,
469                 @Param("rels") String relations,
470                 @Param("data") ByteBuffer data,
471                 @Param("searchableData") ByteBuffer searchableData,
472                 @Param("visualization") ByteBuffer visualization,
473                 @Param("subs") Set<String> subElementIds,
474                 @Param("elementHash") String elementHash);
475
476
477     @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=? ," +
478         "element_hash=? , parent_id=? " +
479         " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=?  ")
480     void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData,
481                 ByteBuffer visualization, String elementHash, String parentId, String space, String
482                     itemId, String
483                     versionId, String elementId, String revisionId);
484
485     @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=? ," +
486         "element_hash=? " +
487         " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=?  ")
488     void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData,
489                 ByteBuffer visualization, String elementHash, String space, String
490                     itemId, String
491                     versionId, String elementId, String revisionId);
492
493     @Query(
494         "DELETE FROM element WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ")
495     void delete(String space, String itemId, String versionId, String elementId, String revisionId);
496
497     @Query("SELECT parent_id, namespace, info, relations, data, searchable_data, visualization, " +
498         "sub_element_ids,element_hash FROM element " +
499         "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ")
500     ResultSet get(String space, String itemId, String versionId, String elementId, String
501         revisionId);
502
503     @Query("SELECT parent_id, namespace, info, relations, sub_element_ids FROM element " +
504         "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ")
505     ResultSet getDescriptor(String space, String itemId, String versionId, String elementId,
506                             String revisionId);
507
508     @Query("UPDATE element SET sub_element_ids=sub_element_ids+? " +
509         " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=?  ")
510     void addSubElements(Set<String> subElementIds, String space, String itemId, String versionId,
511                         String elementId, String revisionId);
512
513     @Query("UPDATE element SET sub_element_ids=sub_element_ids-? " +
514         " WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ")
515     void removeSubElements(Set<String> subElementIds, String space, String itemId, String versionId,
516                            String elementId, String revisionId);
517
518     @Query("SELECT element_hash FROM element " +
519         "WHERE space=? AND item_id=? AND version_id=? AND element_id=? AND revision_id=? ")
520     ResultSet getHash(String space, String itemId, String versionId, String elementId, String
521         revisionId);
522   }
523
524   private static final class ElementField {
525     private static final String NAMESPACE = "namespace";
526     private static final String PARENT_ID = "parent_id";
527     private static final String INFO = "info";
528     private static final String RELATIONS = "relations";
529     private static final String DATA = "data";
530     private static final String SEARCHABLE_DATA = "searchable_data";
531     private static final String VISUALIZATION = "visualization";
532     private static final String SUB_ELEMENT_IDS = "sub_element_ids";
533     private static final String ELEMENT_HASH = "element_hash";
534   }
535
536   @Accessor
537   interface VersionElementsAccessor {
538
539     @Query("UPDATE version_elements SET element_ids=element_ids+ ? " +
540         "WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ")
541     void addElements(Map<String, String> elementIds, String space, String itemId, String versionId,
542                      String versionRevisionId);
543
544     @Query("UPDATE version_elements SET element_ids=element_ids-? " +
545         "WHERE space=? AND item_id=? AND version_id=? AND revision_id=?")
546     void removeElements(Set<String> elementIds, String space, String itemId, String versionId,
547                         String revisionId);
548
549     @Query(
550         "SELECT element_ids FROM version_elements WHERE space=? AND item_id=? AND version_id=? AND revision_id=? ")
551     ResultSet get(String space, String itemId, String versionId, String revisionId);
552
553     @Query(
554         "SELECT revision_id,publish_time FROM version_elements WHERE space=? AND item_id=? AND " +
555             "version_id=? ")
556     ResultSet listRevisions(String space, String itemId, String versionId);
557
558   }
559
560   private static final class VersionElementsField {
561     private static final String ELEMENT_IDS = "element_ids";
562     private static final String REVISION_ID = "revision_id";
563     private static final String PUBLISH_TIME = "publish_time";
564   }
565 }