[SDC] Onboarding 1710 rebase.
[sdc.git] / openecomp-be / lib / openecomp-core-lib / openecomp-zusammen-lib / openecomp-zusammen-plugin / src / main / java / org / openecomp / core / zusammen / plugin / dao / impl / CassandraElementRepository.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;
18
19 import com.datastax.driver.core.ResultSet;
20 import com.datastax.driver.core.Row;
21 import com.datastax.driver.mapping.annotations.Accessor;
22 import com.datastax.driver.mapping.annotations.Param;
23 import com.datastax.driver.mapping.annotations.Query;
24 import com.google.gson.reflect.TypeToken;
25 import com.amdocs.zusammen.datatypes.Id;
26 import com.amdocs.zusammen.datatypes.Namespace;
27 import com.amdocs.zusammen.datatypes.SessionContext;
28 import com.amdocs.zusammen.datatypes.item.Info;
29 import com.amdocs.zusammen.datatypes.item.Relation;
30 import com.amdocs.zusammen.plugin.statestore.cassandra.dao.types.ElementEntityContext;
31 import com.amdocs.zusammen.utils.fileutils.json.JsonUtil;
32 import org.openecomp.core.zusammen.plugin.dao.ElementRepository;
33 import org.openecomp.core.zusammen.plugin.dao.types.ElementEntity;
34
35 import java.lang.reflect.Type;
36 import java.nio.ByteBuffer;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.HashSet;
41 import java.util.Objects;
42 import java.util.Optional;
43 import java.util.Set;
44 import java.util.stream.Collectors;
45
46 public class CassandraElementRepository implements ElementRepository {
47
48   @Override
49   public Collection<ElementEntity> list(SessionContext context,
50                                         ElementEntityContext elementContext) {
51     Set<String> elementIds = getVersionElementIds(context, elementContext);
52
53     return elementIds.stream()
54         .map(elementId -> get(context, elementContext, new ElementEntity(new Id(elementId))).get())
55         .filter(Objects::nonNull)
56         .collect(Collectors.toList());
57   }
58
59   @Override
60   public void create(SessionContext context, ElementEntityContext elementContext,
61                      ElementEntity element) {
62     createElement(context, elementContext, element);
63     addElementToParent(context, elementContext, element);
64   }
65
66   @Override
67   public void update(SessionContext context, ElementEntityContext elementContext,
68                      ElementEntity element) {
69     updateElement(context, elementContext, element);
70   }
71
72   @Override
73   public void delete(SessionContext context, ElementEntityContext elementContext,
74                      ElementEntity element) {
75     removeElementFromParent(context, elementContext, element);
76     deleteElement(context, elementContext, element);
77   }
78
79   @Override
80   public Optional<ElementEntity> get(SessionContext context, ElementEntityContext elementContext,
81                                      ElementEntity element) {
82     Row row = getElementAccessor(context).get(
83         elementContext.getSpace(),
84         elementContext.getItemId().toString(),
85         getVersionId(elementContext),
86         element.getId().toString()).one();
87
88     return row == null ? Optional.empty() : Optional.of(getElementEntity(element, row));
89   }
90
91   @Override
92   public void createNamespace(SessionContext context, ElementEntityContext elementContext,
93                               ElementEntity element) {
94     getElementNamespaceAccessor(context).create(
95         elementContext.getSpace(),
96         elementContext.getItemId().toString(),
97         element.getId().toString(),
98         element.getNamespace().toString());
99   }
100
101   @Override
102   public boolean checkHealth(SessionContext context) {
103     ResultSet resultSet = getVersionElementsAccessor(context).checkHealth();
104     return resultSet.getColumnDefinitions().contains("element_ids");
105   }
106
107   private String getVersionId(ElementEntityContext elementContext) {
108     return elementContext.getChangeRef() == null
109         ? elementContext.getVersionId().toString()
110         : elementContext.getChangeRef();
111   }
112
113   private ElementNamespaceAccessor getElementNamespaceAccessor(SessionContext context) {
114     return CassandraDaoUtils.getAccessor(context, ElementNamespaceAccessor.class);
115   }
116
117   private ElementAccessor getElementAccessor(SessionContext context) {
118     return CassandraDaoUtils.getAccessor(context, ElementAccessor.class);
119   }
120
121   private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) {
122     return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class);
123   }
124
125   private void createElement(SessionContext context, ElementEntityContext elementContext,
126                              ElementEntity element) {
127     Set<String> subElementIds =
128         element.getSubElementIds().stream().map(Id::toString).collect(Collectors.toSet());
129     String versionId = getVersionId(elementContext);
130
131     getElementAccessor(context).create(
132         elementContext.getSpace(),
133         elementContext.getItemId().toString(),
134         versionId,
135         element.getId().toString(),
136         element.getParentId().toString(),
137         element.getNamespace().toString(),
138         JsonUtil.object2Json(element.getInfo()),
139         JsonUtil.object2Json(element.getRelations()),
140         element.getData(),
141         element.getSearchableData(),
142         element.getVisualization(),
143         subElementIds);
144
145     getVersionElementsAccessor(context).addElements(
146         Collections.singleton(element.getId().toString()),
147         elementContext.getSpace(),
148         elementContext.getItemId().toString(),
149         versionId);
150   }
151
152   private void updateElement(SessionContext context, ElementEntityContext elementContext,
153                              ElementEntity element) {
154     getElementAccessor(context).update(
155         JsonUtil.object2Json(element.getInfo()),
156         JsonUtil.object2Json(element.getRelations()),
157         element.getData(),
158         element.getSearchableData(),
159         element.getVisualization(),
160         elementContext.getSpace(),
161         elementContext.getItemId().toString(),
162         elementContext.getVersionId().toString(),
163         element.getId().toString());
164   }
165
166   private void deleteElement(SessionContext context, ElementEntityContext elementContext,
167                              ElementEntity element) {
168     String versionId = getVersionId(elementContext);
169
170     getElementAccessor(context).delete(
171         elementContext.getSpace(),
172         elementContext.getItemId().toString(),
173         versionId,
174         element.getId().toString());
175
176     getVersionElementsAccessor(context).removeElements(
177         Collections.singleton(element.getId().toString()),
178         elementContext.getSpace(),
179         elementContext.getItemId().toString(),
180         versionId);
181   }
182
183   private void addElementToParent(SessionContext context, ElementEntityContext elementContext,
184                                   ElementEntity element) {
185     getElementAccessor(context).addSubElements(
186         Collections.singleton(element.getId().toString()),
187         elementContext.getSpace(),
188         elementContext.getItemId().toString(),
189         getVersionId(elementContext),
190         element.getParentId().toString());
191   }
192
193   private void removeElementFromParent(SessionContext context, ElementEntityContext elementContext,
194                                        ElementEntity element) {
195     if (element.getParentId() == null) {
196       return;
197     }
198     getElementAccessor(context).removeSubElements(
199         Collections.singleton(element.getId().toString()),
200         elementContext.getSpace(),
201         elementContext.getItemId().toString(),
202         getVersionId(elementContext),
203         element.getParentId().toString());
204   }
205
206   private ElementEntity getElementEntity(ElementEntity element, Row row) {
207     element.setNamespace(getNamespace(row.getString(ElementField.NAMESPACE)));
208     element.setParentId(new Id(row.getString(ElementField.PARENT_ID)));
209     element.setInfo(json2Object(row.getString(ElementField.INFO), Info.class));
210     element.setRelations(
211         json2Object(row.getString(ElementField.RELATIONS), new TypeToken<ArrayList<Relation>>() {
212         }.getType()));
213     element.setData(row.getBytes(ElementField.DATA));
214     element.setSearchableData(row.getBytes(ElementField.SEARCHABLE_DATA));
215     element.setVisualization(row.getBytes(ElementField.VISUALIZATION));
216     element.setSubElementIds(row.getSet(ElementField.SUB_ELEMENT_IDS, String.class)
217         .stream().map(Id::new).collect(Collectors.toSet()));
218     return element;
219   }
220
221   private Namespace getNamespace(String namespaceStr) {
222     Namespace namespace = new Namespace();
223     if (namespaceStr != null) {
224       namespace.setValue(namespaceStr);
225     }
226     return namespace;
227   }
228
229   private static <T> T json2Object(String json, Type typeOfT) {
230     return json == null ? null : JsonUtil.json2Object(json, typeOfT);
231   }
232
233   private Set<String> getVersionElementIds(SessionContext context,
234                                            ElementEntityContext elementContext) {
235     Row row = getVersionElementsAccessor(context).get(
236         elementContext.getSpace(),
237         elementContext.getItemId().toString(),
238         getVersionId(elementContext)).one();
239     return row == null
240         ? new HashSet<>()
241         : row.getSet(CassandraElementRepository.VersionElementsField.ELEMENT_IDS, String.class);
242   }
243
244   /*
245 CREATE TABLE IF NOT EXISTS element_namespace (
246         space text,
247         item_id text,
248         element_id text,
249         namespace text,
250         PRIMARY KEY (( space, item_id, element_id ))
251 );
252    */
253   @Accessor
254   interface ElementNamespaceAccessor {
255     @Query(
256         "UPDATE element_namespace SET namespace=:ns " +
257             "WHERE space=:space AND item_id=:item AND element_id=:id ")
258     void create(@Param("space") String space,
259                 @Param("item") String itemId,
260                 @Param("id") String elementId,
261                 @Param("ns") String namespace);
262   }
263
264   /*
265 CREATE TABLE IF NOT EXISTS element (
266         space text,
267         item_id text,
268         version_id text,
269         element_id text,
270         parent_id text,
271         namespace text,
272         info text,
273         relations text,
274         data blob,
275         searchable_data blob,
276         visualization blob,
277         sub_element_ids set<text>,
278         PRIMARY KEY (( space, item_id, version_id, element_id ))
279 );
280    */
281   @Accessor
282   interface ElementAccessor {
283     @Query(
284         "UPDATE element SET parent_id=:parentId, namespace=:ns, info=:info, relations=:rels, " +
285             "data=:data, searchable_data=:searchableData, visualization=:visualization, " +
286             "sub_element_ids=sub_element_ids+:subs " +
287             "WHERE space=:space AND item_id=:item AND version_id=:ver AND element_id=:id ")
288     void create(@Param("space") String space,
289                 @Param("item") String itemId,
290                 @Param("ver") String versionId,
291                 @Param("id") String elementId,
292                 @Param("parentId") String parentElementId,
293                 @Param("ns") String namespace,
294                 @Param("info") String info,
295                 @Param("rels") String relations,
296                 @Param("data") ByteBuffer data,
297                 @Param("searchableData") ByteBuffer searchableData,
298                 @Param("visualization") ByteBuffer visualization,
299                 @Param("subs") Set<String> subElementIds);
300
301     @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=?" +
302         " WHERE space=? AND item_id=? AND version_id=? AND element_id=?  ")
303     void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData,
304                 ByteBuffer visualization, String space, String itemId, String versionId,
305                 String elementId);
306
307     @Query("DELETE FROM element WHERE space=? AND item_id=? AND version_id=? AND element_id=?")
308     void delete(String space, String itemId, String versionId, String elementId);
309
310     @Query("SELECT parent_id, namespace, info, relations, data, searchable_data, visualization, " +
311         "sub_element_ids FROM element " +
312         "WHERE space=? AND item_id=? AND version_id=? AND element_id=? ")
313     ResultSet get(String space, String itemId, String versionId, String elementId);
314
315     @Query("UPDATE element SET sub_element_ids=sub_element_ids+? " +
316         " WHERE space=? AND item_id=? AND version_id=? AND element_id=?  ")
317     void addSubElements(Set<String> subElementIds, String space, String itemId, String versionId,
318                         String elementId);
319
320     @Query("UPDATE element SET sub_element_ids=sub_element_ids-? " +
321         " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ")
322     void removeSubElements(Set<String> subElementIds, String space, String itemId, String versionId,
323                            String elementId);
324   }
325
326   private static final class ElementField {
327     private static final String NAMESPACE = "namespace";
328     private static final String PARENT_ID = "parent_id";
329     private static final String INFO = "info";
330     private static final String RELATIONS = "relations";
331     private static final String DATA = "data";
332     private static final String SEARCHABLE_DATA = "searchable_data";
333     private static final String VISUALIZATION = "visualization";
334     private static final String SUB_ELEMENT_IDS = "sub_element_ids";
335   }
336
337   /*
338   CREATE TABLE IF NOT EXISTS version_elements (
339     space text,
340     item_id text,
341     version_id text,
342     element_ids set<text>,
343     PRIMARY KEY (( space, item_id, version_id ))
344   );
345    */
346   @Accessor
347   interface VersionElementsAccessor {
348
349     @Query("UPDATE version_elements SET element_ids=element_ids+? " +
350         "WHERE space=? AND item_id=? AND version_id=?")
351     void addElements(Set<String> elementIds, String space, String itemId, String versionId);
352
353     @Query("UPDATE version_elements SET element_ids=element_ids-? " +
354         "WHERE space=? AND item_id=? AND version_id=?")
355     void removeElements(Set<String> elementIds, String space, String itemId, String versionId);
356
357     @Query("SELECT element_ids FROM version_elements WHERE space=? AND item_id=? AND version_id=?")
358     ResultSet get(String space, String itemId, String versionId);
359
360     @Query("SELECT element_ids FROM version_elements LIMIT 1")
361     ResultSet checkHealth();
362   }
363
364   private static final class VersionElementsField {
365     private static final String ELEMENT_IDS = "element_ids";
366   }
367 }