2  * Copyright © 2016-2017 European Support Limited
 
   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
 
   8  *     http://www.apache.org/licenses/LICENSE-2.0
 
  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.
 
  17 package org.openecomp.core.zusammen.plugin.dao.impl.cassandra;
 
  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;
 
  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;
 
  43 import java.util.Optional;
 
  45 import java.util.TreeMap;
 
  46 import java.util.stream.Collectors;
 
  48 public class ElementRepositoryImpl implements ElementRepository {
 
  51   public Map<Id, Id> listIds(SessionContext context, ElementEntityContext elementContext) {
 
  53     if (elementContext.getRevisionId() == null) {
 
  54       String revisionId = calculateLastRevisionId(context, elementContext);
 
  55       if (revisionId == null) {
 
  56         return new HashMap<>();
 
  59       elementContext.setRevisionId(new Id(revisionId));
 
  61     return getVersionElementIds(context, elementContext).entrySet().stream().collect(Collectors
 
  62         .toMap(entry -> new Id(entry.getKey()), entry -> new Id(entry.getValue())));
 
  64    /* return getVersionElementIds(context, elementContext).stream()
 
  66         .collect(Collectors.toList());*/
 
  71   public void create(SessionContext context, ElementEntityContext elementContext,
 
  72                      ElementEntity element) {
 
  73     createElement(context, elementContext, element);
 
  74     addElementToParent(context, elementContext, element);
 
  78   public void update(SessionContext context, ElementEntityContext elementContext,
 
  79                      ElementEntity element) {
 
  81     Id elementRevisionId = getElementRevision(context, elementContext, element.getId());
 
  82     if (elementRevisionId.equals(elementContext.getRevisionId())) {
 
  83       updateElement(context, elementContext, element);
 
  85       createElement(context, elementContext, element);
 
  90   public void delete(SessionContext context, ElementEntityContext elementContext,
 
  91                      ElementEntity element) {
 
  92     removeElementFromParent(context, elementContext, element);
 
  93     deleteElement(context, elementContext, element);
 
  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();
 
 104     Row row = getElementAccessor(context).get(
 
 105         elementContext.getSpace(),
 
 106         elementContext.getItemId().toString(),
 
 107         elementContext.getVersionId().toString(),
 
 108         element.getId().toString(),
 
 111     return row == null ? Optional.empty() : Optional.of(getElementEntity(element, row));
 
 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();
 
 123     Row row = getElementAccessor(context).getDescriptor(
 
 124         elementContext.getSpace(),
 
 125         elementContext.getItemId().toString(),
 
 126         elementContext.getVersionId().toString(),
 
 127         element.getId().toString(),
 
 130     return row == null ? Optional.empty() : Optional.of(getElementEntityDescriptor(element, row));
 
 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());
 
 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();
 
 149     Row row = getElementAccessor(context).getHash(
 
 150         elementContext.getSpace(),
 
 151         elementContext.getItemId().toString(),
 
 152         elementContext.getVersionId().getValue(),
 
 153         element.getId().toString(),
 
 156     return row == null ? Optional.empty() : Optional.of(getElementHash(row));
 
 159   private String calculateElementRevisionId(SessionContext context,
 
 160                                             ElementEntityContext elementContext,
 
 161                                             ElementEntity element) {
 
 163     if (elementContext.getSpace().equals(ZusammenPluginConstants.PUBLIC_SPACE)) {
 
 165       String versionRevision;
 
 166       if (elementContext.getRevisionId() == null) {
 
 167         versionRevision = calculateLastRevisionId(context, elementContext);
 
 169         versionRevision = elementContext.getRevisionId().getValue();
 
 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());
 
 181       return Id.ZERO.getValue();
 
 185   private String calculateLastRevisionId(SessionContext context, ElementEntityContext
 
 187     List<Row> rows = getVersionElementsAccessor(context).listRevisions(elementContext.getSpace(),
 
 189             .getItemId().toString(), elementContext.getVersionId().toString()).all();
 
 190     if (rows == null || rows.size() == 0) {
 
 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);
 
 198   /*private static String getVersionId(ElementEntityContext elementContext) {
 
 199     return elementContext.getRevisionId() == null
 
 200         ? elementContext.getVersionId().toString()
 
 201         : elementContext.getRevisionId().getValue();
 
 204   private ElementNamespaceAccessor getElementNamespaceAccessor(SessionContext context) {
 
 205     return CassandraDaoUtils.getAccessor(context, ElementNamespaceAccessor.class);
 
 208   private ElementAccessor getElementAccessor(SessionContext context) {
 
 209     return CassandraDaoUtils.getAccessor(context, ElementAccessor.class);
 
 212   private VersionElementsAccessor getVersionElementsAccessor(SessionContext context) {
 
 213     return CassandraDaoUtils.getAccessor(context, VersionElementsAccessor.class);
 
 216   private void createElement(SessionContext context, ElementEntityContext elementContext,
 
 217                              ElementEntity element) {
 
 218     createElementRow(context, elementContext, element);
 
 220     Map<String, String> elementIds = new TreeMap<>();
 
 221     elementIds.put(element.getId().toString(), elementContext.getRevisionId().getValue());
 
 222     getVersionElementsAccessor(context).addElements(
 
 224         elementContext.getSpace(),
 
 225         elementContext.getItemId().toString(),
 
 226         elementContext.getVersionId().getValue(),
 
 227         elementContext.getRevisionId().getValue());
 
 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());
 
 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()),
 
 246         element.getSearchableData(),
 
 247         element.getVisualization(),
 
 249         element.getElementHash().getValue());
 
 252   private void updateElement(SessionContext context, ElementEntityContext elementContext,
 
 253                              ElementEntity element) {
 
 256     if (element.getParentId() == null) {
 
 257       getElementAccessor(context).update(
 
 258           JsonUtil.object2Json(element.getInfo()),
 
 259           JsonUtil.object2Json(element.getRelations()),
 
 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());
 
 270       getElementAccessor(context).update(
 
 271           JsonUtil.object2Json(element.getInfo()),
 
 272           JsonUtil.object2Json(element.getRelations()),
 
 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());
 
 285     Map<String, String> elementIds = new TreeMap<>();
 
 286     elementIds.put(element.getId().getValue(), elementContext.getRevisionId().getValue());
 
 287     getVersionElementsAccessor(context).addElements(
 
 289         elementContext.getSpace(),
 
 290         elementContext.getItemId().toString(),
 
 291         elementContext.getVersionId().getValue(),
 
 292         elementContext.getRevisionId().getValue());
 
 295   private void deleteElement(SessionContext context, ElementEntityContext elementContext,
 
 296                              ElementEntity element) {
 
 299     getElementAccessor(context).delete(
 
 300         elementContext.getSpace(),
 
 301         elementContext.getItemId().toString(),
 
 302         elementContext.getVersionId().toString(),
 
 303         element.getId().toString(),
 
 304         elementContext.getRevisionId().getValue());
 
 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());
 
 314   private void addElementToParent(SessionContext context, ElementEntityContext elementContext,
 
 315                                   ElementEntity element) {
 
 316     if (element.getParentId() == null) {
 
 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());
 
 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());
 
 336   private void removeElementFromParent(SessionContext context, ElementEntityContext elementContext,
 
 337                                        ElementEntity element) {
 
 339     if (element.getParentId() == null) {
 
 343     Optional<ElementEntity> parentElement =
 
 344         get(context, elementContext, new ElementEntity(element.getParentId()));
 
 345     if (!parentElement.isPresent()) {
 
 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());
 
 356     getVersionElementsAccessor(context)
 
 357         .removeElements(Collections.singleton(element.getId().toString()),
 
 358             elementContext.getSpace(),
 
 359             elementContext.getItemId().getValue(), elementContext.getVersionId().getValue(),
 
 360             elementContext.getRevisionId().getValue());
 
 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());
 
 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>>() {
 
 377     element.setSubElementIds(row.getSet(ElementField.SUB_ELEMENT_IDS, String.class)
 
 378         .stream().map(Id::new).collect(Collectors.toSet()));
 
 382   static ElementEntity getElementEntity(ElementEntity element, Row row) {
 
 383     getElementEntityDescriptor(element, row);
 
 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)));
 
 392   private Id getElementHash(Row row) {
 
 393     return new Id(row.getString(ElementField.ELEMENT_HASH));
 
 396   private static Id getParentId(String parentIdStr) {
 
 397     return parentIdStr == null ? null : new Id(parentIdStr);
 
 400   private static Namespace getNamespace(String namespaceStr) {
 
 401     Namespace namespace = new Namespace();
 
 402     if (namespaceStr != null) {
 
 403       namespace.setValue(namespaceStr);
 
 408   private static <T> T json2Object(String json, Type typeOfT) {
 
 409     return json == null ? null : JsonUtil.json2Object(json, typeOfT);
 
 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();
 
 421         : row.getMap(ElementRepositoryImpl.VersionElementsField.ELEMENT_IDS, String.class, String
 
 425   private Id getElementRevision(SessionContext context, ElementEntityContext elementContext
 
 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);
 
 437 CREATE TABLE IF NOT EXISTS element_namespace (
 
 441         PRIMARY KEY (( item_id, element_id ))
 
 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);
 
 454   interface ElementAccessor {
 
 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 " +
 
 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);
 
 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
 
 483                     versionId, String elementId, String revisionId);
 
 485     @Query("UPDATE element SET info=?, relations=?, data=?, searchable_data=?, visualization=? ," +
 
 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
 
 491                     versionId, String elementId, String revisionId);
 
 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);
 
 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
 
 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,
 
 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);
 
 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);
 
 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
 
 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";
 
 537   interface VersionElementsAccessor {
 
 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);
 
 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,
 
 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);
 
 554         "SELECT revision_id,publish_time FROM version_elements WHERE space=? AND item_id=? AND " +
 
 556     ResultSet listRevisions(String space, String itemId, String versionId);
 
 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";