Merge "[CPS] RI: Code Refactoring # Replace '[\s\S]' to '.' as it is same as '.'...
[cps.git] / cps-ri / src / main / java / org / onap / cps / spi / impl / CpsDataPersistenceServiceImpl.java
index e3be013..cca5d9c 100644 (file)
 
 package org.onap.cps.spi.impl;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
+import io.micrometer.core.annotation.Timed;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -80,7 +82,9 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     private final JsonObjectMapper jsonObjectMapper;
     private final SessionManager sessionManager;
 
-    private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?])?)";
+    private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@.+?])?)";
+    private static final String QUERY_ACROSS_ANCHORS = null;
+    private static final AnchorEntity ALL_ANCHORS = null;
 
     @Override
     public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentNodeXpath,
@@ -166,11 +170,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         }
     }
 
-    @Override
-    public void storeDataNode(final String dataspaceName, final String anchorName, final DataNode dataNode) {
-        storeDataNodes(dataspaceName, anchorName, Collections.singletonList(dataNode));
-    }
-
     @Override
     public void storeDataNodes(final String dataspaceName, final String anchorName,
                                final Collection<DataNode> dataNodes) {
@@ -234,6 +233,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     @Override
+    @Timed(value = "cps.data.persistence.service.datanode.get",
+            description = "Time taken to get a data node")
     public Collection<DataNode> getDataNodes(final String dataspaceName, final String anchorName,
                                              final String xpath,
                                              final FetchDescendantsOption fetchDescendantsOption) {
@@ -247,16 +248,20 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     @Override
+    @Timed(value = "cps.data.persistence.service.datanode.batch.get",
+            description = "Time taken to get data nodes")
     public Collection<DataNode> getDataNodesForMultipleXpaths(final String dataspaceName, final String anchorName,
                                                               final Collection<String> xpaths,
                                                               final FetchDescendantsOption fetchDescendantsOption) {
         final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
-        final Collection<FragmentEntity> fragmentEntities = getFragmentEntities(anchorEntity, xpaths);
+        final Collection<FragmentEntity> fragmentEntities =
+            getFragmentEntities(anchorEntity, xpaths, fetchDescendantsOption);
         return toDataNodes(fragmentEntities, fetchDescendantsOption);
     }
 
     private Collection<FragmentEntity> getFragmentEntities(final AnchorEntity anchorEntity,
-                                                           final Collection<String> xpaths) {
+                                                           final Collection<String> xpaths,
+                                                           final FetchDescendantsOption fetchDescendantsOption) {
         final Collection<String> nonRootXpaths = new HashSet<>(xpaths);
         final boolean haveRootXpath = nonRootXpaths.removeIf(CpsDataPersistenceServiceImpl::isRootXpath);
 
@@ -268,15 +273,15 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                 log.warn("Error parsing xpath \"{}\": {}", xpath, e.getMessage());
             }
         }
-        final Collection<FragmentEntity> fragmentEntities =
-            new HashSet<>(fragmentRepository.findByAnchorAndMultipleCpsPaths(anchorEntity.getId(), normalizedXpaths));
-
         if (haveRootXpath) {
-            final List<FragmentExtract> fragmentExtracts = fragmentRepository.findAllExtractsByAnchor(anchorEntity);
-            fragmentEntities.addAll(FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts));
+            normalizedXpaths.addAll(fragmentRepository.findAllXpathByAnchorAndParentIdIsNull(anchorEntity));
         }
 
-        return fragmentEntities;
+        final List<FragmentExtract> fragmentExtracts =
+            fragmentRepository.findExtractsWithDescendants(anchorEntity.getId(), normalizedXpaths,
+                fetchDescendantsOption.getDepth());
+
+        return FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts);
     }
 
     private FragmentEntity getFragmentEntity(final AnchorEntity anchorEntity, final String xpath) {
@@ -302,9 +307,12 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     }
 
     @Override
+    @Timed(value = "cps.data.persistence.service.datanode.query",
+            description = "Time taken to query data nodes")
     public List<DataNode> queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath,
                                          final FetchDescendantsOption fetchDescendantsOption) {
-        final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
+        final AnchorEntity anchorEntity = (Strings.isNullOrEmpty(anchorName)) ? ALL_ANCHORS
+                : getAnchorEntity(dataspaceName, anchorName);
         final CpsPathQuery cpsPathQuery;
         try {
             cpsPathQuery = CpsPathUtil.getCpsPathQuery(cpsPath);
@@ -316,40 +324,47 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         if (canUseRegexQuickFind(fetchDescendantsOption, cpsPathQuery)) {
             return getDataNodesUsingRegexQuickFind(fetchDescendantsOption, anchorEntity, cpsPathQuery);
         }
-        fragmentEntities = fragmentRepository.findByAnchorAndCpsPath(anchorEntity.getId(), cpsPathQuery);
+        fragmentEntities = (anchorEntity == ALL_ANCHORS) ? fragmentRepository.findByCpsPath(cpsPathQuery)
+                : fragmentRepository.findByAnchorAndCpsPath(anchorEntity.getId(), cpsPathQuery);
         if (cpsPathQuery.hasAncestorAxis()) {
-            fragmentEntities = getAncestorFragmentEntities(anchorEntity.getId(), cpsPathQuery, fragmentEntities);
+            final Collection<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
+            fragmentEntities = (anchorEntity == ALL_ANCHORS) ? getAncestorFragmentEntitiesAcrossAnchors(cpsPathQuery,
+            fragmentEntities) : getFragmentEntities(anchorEntity, ancestorXpaths, fetchDescendantsOption);
         }
         return createDataNodesFromProxiedFragmentEntities(fetchDescendantsOption, anchorEntity, fragmentEntities);
     }
 
+    @Override
+    public List<DataNode> queryDataNodesAcrossAnchors(final String dataspaceName, final String cpsPath,
+                                         final FetchDescendantsOption fetchDescendantsOption) {
+        return queryDataNodes(dataspaceName, QUERY_ACROSS_ANCHORS, cpsPath, fetchDescendantsOption);
+    }
+
     private static boolean canUseRegexQuickFind(final FetchDescendantsOption fetchDescendantsOption,
                                                 final CpsPathQuery cpsPathQuery) {
         return fetchDescendantsOption.equals(FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+            && !cpsPathQuery.hasAncestorAxis()
             && !cpsPathQuery.hasLeafConditions()
-            && !cpsPathQuery.hasTextFunctionCondition();
+            && !cpsPathQuery.hasTextFunctionCondition()
+            && !cpsPathQuery.hasContainsFunctionCondition();
     }
 
     private List<DataNode> getDataNodesUsingRegexQuickFind(final FetchDescendantsOption fetchDescendantsOption,
                                                            final AnchorEntity anchorEntity,
                                                            final CpsPathQuery cpsPathQuery) {
-        Collection<FragmentEntity> fragmentEntities;
-        final String xpathRegex = FragmentQueryBuilder.getXpathSqlRegex(cpsPathQuery, true);
-        final List<FragmentExtract> fragmentExtracts =
-            fragmentRepository.quickFindWithDescendants(anchorEntity.getId(), xpathRegex);
-        fragmentEntities = FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts);
-        if (cpsPathQuery.hasAncestorAxis()) {
-            fragmentEntities = getAncestorFragmentEntities(anchorEntity.getId(), cpsPathQuery, fragmentEntities);
-        }
+        final String xpathRegex = FragmentQueryBuilder.getXpathSqlRegexForQuickFindWithDescendants(cpsPathQuery);
+        final List<FragmentExtract> fragmentExtracts = (anchorEntity == ALL_ANCHORS)
+            ? fragmentRepository.quickFindWithDescendantsAcrossAnchors(xpathRegex)
+            : fragmentRepository.quickFindWithDescendants(anchorEntity.getId(), xpathRegex);
+        final Collection<FragmentEntity> fragmentEntities =
+            FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts);
         return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
     }
 
-    private Collection<FragmentEntity> getAncestorFragmentEntities(final int anchorId,
-                                                                   final CpsPathQuery cpsPathQuery,
-                                                                   final Collection<FragmentEntity> fragmentEntities) {
+    private Collection<FragmentEntity> getAncestorFragmentEntitiesAcrossAnchors(final CpsPathQuery cpsPathQuery,
+        final Collection<FragmentEntity> fragmentEntities) {
         final Collection<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
-        return ancestorXpaths.isEmpty() ? Collections.emptyList()
-            : fragmentRepository.findByAnchorAndMultipleCpsPaths(anchorId, ancestorXpaths);
+        return ancestorXpaths.isEmpty() ? Collections.emptyList() : fragmentRepository.findAllByXpathIn(ancestorXpaths);
     }
 
     private List<DataNode> createDataNodesFromProxiedFragmentEntities(
@@ -362,8 +377,10 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                 dataNodes.add(toDataNode(proxiedFragmentEntity, fetchDescendantsOption));
             } else {
                 final String normalizedXpath = getNormalizedXpath(proxiedFragmentEntity.getXpath());
+                final AnchorEntity anchorEntityForFragmentExtract = (anchorEntity == ALL_ANCHORS)
+                        ? proxiedFragmentEntity.getAnchor() : anchorEntity;
                 final Collection<FragmentEntity> unproxiedFragmentEntities =
-                    buildFragmentEntitiesFromFragmentExtracts(anchorEntity, normalizedXpath);
+                    buildFragmentEntitiesFromFragmentExtracts(anchorEntityForFragmentExtract, normalizedXpath);
                 for (final FragmentEntity unproxiedFragmentEntity : unproxiedFragmentEntities) {
                     dataNodes.add(toDataNode(unproxiedFragmentEntity, fetchDescendantsOption));
                 }
@@ -412,8 +429,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                                                     final CpsPathQuery cpsPathQuery) {
         final Set<String> ancestorXpath = new HashSet<>();
         final Pattern pattern =
-                Pattern.compile("([\\s\\S]*/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier())
-                        + REG_EX_FOR_OPTIONAL_LIST_INDEX + "/[\\s\\S]*");
+                Pattern.compile("(.*/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier())
+                        + REG_EX_FOR_OPTIONAL_LIST_INDEX + "/.*");
         for (final FragmentEntity fragmentEntity : fragmentEntities) {
             final Matcher matcher = pattern.matcher(fragmentEntity.getXpath());
             if (matcher.matches()) {
@@ -433,6 +450,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         return new DataNodeBuilder()
                 .withXpath(fragmentEntity.getXpath())
                 .withLeaves(leaves)
+                .withDataspace(fragmentEntity.getAnchor().getDataspace().getName())
+                .withAnchor(fragmentEntity.getAnchor().getName())
                 .withChildDataNodes(childDataNodes).build();
     }
 
@@ -466,31 +485,17 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         fragmentRepository.save(fragmentEntity);
     }
 
-    @Override
-    public void updateDataNodeAndDescendants(final String dataspaceName, final String anchorName,
-                                             final DataNode dataNode) {
-        final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
-        final FragmentEntity fragmentEntity = getFragmentEntity(anchorEntity, dataNode.getXpath());
-        updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode);
-        try {
-            fragmentRepository.save(fragmentEntity);
-        } catch (final StaleStateException staleStateException) {
-            throw new ConcurrencyException("Concurrent Transactions",
-                    String.format("dataspace :'%s', Anchor : '%s' and xpath: '%s' is updated by another transaction.",
-                            dataspaceName, anchorName, dataNode.getXpath()));
-        }
-    }
-
     @Override
     public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName,
-                                              final List<DataNode> updatedDataNodes) {
+                                              final Collection<DataNode> updatedDataNodes) {
         final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
 
         final Map<String, DataNode> xpathToUpdatedDataNode = updatedDataNodes.stream()
             .collect(Collectors.toMap(DataNode::getXpath, dataNode -> dataNode));
 
         final Collection<String> xpaths = xpathToUpdatedDataNode.keySet();
-        final Collection<FragmentEntity> existingFragmentEntities = getFragmentEntities(anchorEntity, xpaths);
+        final Collection<FragmentEntity> existingFragmentEntities =
+            getFragmentEntities(anchorEntity, xpaths, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
 
         for (final FragmentEntity existingFragmentEntity : existingFragmentEntities) {
             final DataNode updatedDataNode = xpathToUpdatedDataNode.get(existingFragmentEntity.getXpath());