12fd2dabba8851d506c62f47fcbe77cdf39876f9
[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   private String getVersionId(ElementEntityContext elementContext) {
102     return elementContext.getChangeRef() == null
103         ? elementContext.getVersionId().toString()
104         : elementContext.getChangeRef();
105   }
106
107   private ElementNamespaceAccessor getElementNamespaceAccessor(SessionContext context) {
108     return CassandraDaoUtils.getAccessor(context, ElementNamespaceAccessor.class);
109   }
110
111   private ElementAccessor getElementAccessor(SessionContext context) {
112     return CassandraDaoUtils.getAccessor(context, ElementAccessor.class);
113   }
114
115   private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) {
116     return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class);
117   }
118
119   private void createElement(SessionContext context, ElementEntityContext elementContext,
120                              ElementEntity element) {
121     Set<String> subElementIds =
122         element.getSubElementIds().stream().map(Id::toString).collect(Collectors.toSet());
123     String versionId = getVersionId(elementContext);
124
125     getElementAccessor(context).create(
126         elementContext.getSpace(),
127         elementContext.getItemId().toString(),
128         versionId,
129         element.getId().toString(),
130         element.getParentId().toString(),
131         element.getNamespace().toString(),
132         JsonUtil.object2Json(element.getInfo()),
133         JsonUtil.object2Json(element.getRelations()),
134         element.getData(),
135         element.getSearchableData(),
136         element.getVisualization(),
137         subElementIds);
138
139     getVersionElementsAccessor(context).addElements(
140         Collections.singleton(element.getId().toString()),
141         elementContext.getSpace(),
142         elementContext.getItemId().toString(),
143         versionId);
144   }
145
146   private void updateElement(SessionContext context, ElementEntityContext elementContext,
147                              ElementEntity element) {
148     getElementAccessor(context).update(
149         JsonUtil.object2Json(element.getInfo()),
150         JsonUtil.object2Json(element.getRelations()),
151         element.getData(),
152         element.getSearchableData(),
153         element.getVisualization(),
154         elementContext.getSpace(),
155         elementContext.getItemId().toString(),
156         elementContext.getVersionId().toString(),
157         element.getId().toString());
158   }
159
160   private void deleteElement(SessionContext context, ElementEntityContext elementContext,
161                              ElementEntity element) {
162     String versionId = getVersionId(elementContext);
163
164     getElementAccessor(context).delete(
165         elementContext.getSpace(),
166         elementContext.getItemId().toString(),
167         versionId,
168         element.getId().toString());
169
170     getVersionElementsAccessor(context).removeElements(
171         Collections.singleton(element.getId().toString()),
172         elementContext.getSpace(),
173         elementContext.getItemId().toString(),
174         versionId);
175   }
176
177   private void addElementToParent(SessionContext context, ElementEntityContext elementContext,
178                                   ElementEntity element) {
179     getElementAccessor(context).addSubElements(
180         Collections.singleton(element.getId().toString()),
181         elementContext.getSpace(),
182         elementContext.getItemId().toString(),
183         getVersionId(elementContext),
184         element.getParentId().toString());
185   }
186
187   private void removeElementFromParent(SessionContext context, ElementEntityContext elementContext,
188                                        ElementEntity element) {
189     if (element.getParentId() == null) {
190       return;
191     }
192     getElementAccessor(context).removeSubElements(
193         Collections.singleton(element.getId().toString()),
194         elementContext.getSpace(),
195         elementContext.getItemId().toString(),
196         getVersionId(elementContext),
197         element.getParentId().toString());
198   }
199
200   private ElementEntity getElementEntity(ElementEntity element, Row row) {
201     element.setNamespace(getNamespace(row.getString(ElementField.NAMESPACE)));
202     element.setParentId(new Id(row.getString(ElementField.PARENT_ID)));
203     element.setInfo(json2Object(row.getString(ElementField.INFO), Info.class));
204     element.setRelations(
205         json2Object(row.getString(ElementField.RELATIONS), new TypeToken<ArrayList<Relation>>() {
206         }.getType()));
207     element.setData(row.getBytes(ElementField.DATA));
208     element.setSearchableData(row.getBytes(ElementField.SEARCHABLE_DATA));
209     element.setVisualization(row.getBytes(ElementField.VISUALIZATION));
210     element.setSubElementIds(row.getSet(ElementField.SUB_ELEMENT_IDS, String.class)
211         .stream().map(Id::new).collect(Collectors.toSet()));
212     return element;
213   }
214
215   private Namespace getNamespace(String namespaceStr) {
216     Namespace namespace = new Namespace();
217     if (namespaceStr != null) {
218       namespace.setValue(namespaceStr);
219     }
220     return namespace;
221   }
222
223   private static <T> T json2Object(String json, Type typeOfT) {
224     return json == null ? null : JsonUtil.json2Object(json, typeOfT);
225   }
226
227   private Set<String> getVersionElementIds(SessionContext context,
228                                            ElementEntityContext elementContext) {
229     Row row = getVersionElementsAccessor(context).get(
230         elementContext.getSpace(),
231         elementContext.getItemId().toString(),
232         getVersionId(elementContext)).one();
233     return row == null
234         ? new HashSet<>()
235         : row.getSet(CassandraElementRepository.VersionElementsField.ELEMENT_IDS, String.class);
236   }
237
238   /*
239 CREATE TABLE IF NOT EXISTS element_namespace (
240         space text,
241         item_id text,
242         element_id text,
243         namespace text,
244         PRIMARY KEY (( space, item_id, element_id ))
245 );
246    */
247   @Accessor
248   interface ElementNamespaceAccessor {
249     @Query(
250         "UPDATE element_namespace SET namespace=:ns " +
251             "WHERE space=:space AND item_id=:item AND element_id=:id ")
252     void create(@Param("space") String space,
253                 @Param("item") String itemId,
254                 @Param("id") String elementId,
255                 @Param("ns") String namespace);
256   }
257
258   /*
259 CREATE TABLE IF NOT EXISTS element (
260         space text,
261         item_id text,
262         version_id text,
263         element_id text,
264         parent_id text,
265         namespace text,
266         info text,
267         relations text,
268         data blob,
269         searchable_data blob,
270         visualization blob,
271         sub_element_ids set<text>,
272         PRIMARY KEY (( space, item_id, version_id, element_id ))
273 );
274    */
275   @Accessor
276   interface ElementAccessor {
277     @Query(
278         "UPDATE element SET parent_id=:parentId, namespace=:ns, info=:info, relations=:rels, " +
279             "data=:data, searchable_data=:searchableData, visualization=:visualization, " +
280             "sub_element_ids=sub_element_ids+:subs " +
281             "WHERE space=:space AND item_id=:item AND version_id=:ver AND element_id=:id ")
282     void create(@Param("space") String space,
283                 @Param("item") String itemId,
284                 @Param("ver") String versionId,
285                 @Param("id") String elementId,
286                 @Param("parentId") String parentElementId,
287                 @Param("ns") String namespace,
288                 @Param("info") String info,
289                 @Param("rels") String relations,
290                 @Param("data") ByteBuffer data,
291                 @Param("searchableData") ByteBuffer searchableData,
292                 @Param("visualization") ByteBuffer visualization,
293                 @Param("subs") Set<String> subElementIds);
294
295     @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=?" +
296         " WHERE space=? AND item_id=? AND version_id=? AND element_id=?  ")
297     void update(String info, String relations, ByteBuffer data, ByteBuffer searchableData,
298                 ByteBuffer visualization, String space, String itemId, String versionId,
299                 String elementId);
300
301     @Query("DELETE FROM element WHERE space=? AND item_id=? AND version_id=? AND element_id=?")
302     void delete(String space, String itemId, String versionId, String elementId);
303
304     @Query("SELECT parent_id, namespace, info, relations, data, searchable_data, visualization, " +
305         "sub_element_ids FROM element " +
306         "WHERE space=? AND item_id=? AND version_id=? AND element_id=? ")
307     ResultSet get(String space, String itemId, String versionId, String elementId);
308
309     @Query("UPDATE element SET sub_element_ids=sub_element_ids+? " +
310         " WHERE space=? AND item_id=? AND version_id=? AND element_id=?  ")
311     void addSubElements(Set<String> subElementIds, String space, String itemId, String versionId,
312                         String elementId);
313
314     @Query("UPDATE element SET sub_element_ids=sub_element_ids-? " +
315         " WHERE space=? AND item_id=? AND version_id=? AND element_id=? ")
316     void removeSubElements(Set<String> subElementIds, String space, String itemId, String versionId,
317                            String elementId);
318   }
319
320   private static final class ElementField {
321     private static final String NAMESPACE = "namespace";
322     private static final String PARENT_ID = "parent_id";
323     private static final String INFO = "info";
324     private static final String RELATIONS = "relations";
325     private static final String DATA = "data";
326     private static final String SEARCHABLE_DATA = "searchable_data";
327     private static final String VISUALIZATION = "visualization";
328     private static final String SUB_ELEMENT_IDS = "sub_element_ids";
329   }
330
331   /*
332   CREATE TABLE IF NOT EXISTS version_elements (
333     space text,
334     item_id text,
335     version_id text,
336     element_ids set<text>,
337     PRIMARY KEY (( space, item_id, version_id ))
338   );
339    */
340   @Accessor
341   interface VersionElementsAccessor {
342
343     @Query("UPDATE version_elements SET element_ids=element_ids+? " +
344         "WHERE space=? AND item_id=? AND version_id=?")
345     void addElements(Set<String> elementIds, String space, String itemId, String versionId);
346
347     @Query("UPDATE version_elements SET element_ids=element_ids-? " +
348         "WHERE space=? AND item_id=? AND version_id=?")
349     void removeElements(Set<String> elementIds, String space, String itemId, String versionId);
350
351     @Query("SELECT element_ids FROM version_elements WHERE space=? AND item_id=? AND version_id=?")
352     ResultSet get(String space, String itemId, String versionId);
353   }
354
355   private static final class VersionElementsField {
356     private static final String ELEMENT_IDS = "element_ids";
357   }
358 }