+ @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 DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
+ final CpsPathQuery cpsPathQuery;
+ try {
+ cpsPathQuery = CpsPathUtil.getCpsPathQuery(cpsPath);
+ } catch (final PathParsingException pathParsingException) {
+ throw new CpsPathException(pathParsingException.getMessage());
+ }
+
+ Collection<FragmentEntity> fragmentEntities;
+ fragmentEntities = fragmentRepository.findByAnchorAndCpsPath(anchorEntity, cpsPathQuery);
+ if (cpsPathQuery.hasAncestorAxis()) {
+ final Collection<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
+ fragmentEntities = fragmentRepository.findByAnchorAndXpathIn(anchorEntity, ancestorXpaths);
+ }
+ fragmentEntities = fragmentRepository.prefetchDescendantsOfFragmentEntities(fetchDescendantsOption,
+ fragmentEntities);
+ return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
+ }
+
+ @Override
+ @Timed(value = "cps.data.persistence.service.datanode.query.anchors",
+ description = "Time taken to query data nodes across all anchors or list of anchors")
+ public List<DataNode> queryDataNodesAcrossAnchors(final String dataspaceName, final String cpsPath,
+ final FetchDescendantsOption fetchDescendantsOption,
+ final PaginationOption paginationOption) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final CpsPathQuery cpsPathQuery;
+ try {
+ cpsPathQuery = CpsPathUtil.getCpsPathQuery(cpsPath);
+ } catch (final PathParsingException e) {
+ throw new CpsPathException(e.getMessage());
+ }
+
+ final List<Long> anchorIds;
+ if (paginationOption == NO_PAGINATION) {
+ anchorIds = Collections.emptyList();
+ } else {
+ anchorIds = getAnchorIdsForPagination(dataspaceEntity, cpsPathQuery, paginationOption);
+ if (anchorIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ }
+ Collection<FragmentEntity> fragmentEntities =
+ fragmentRepository.findByDataspaceAndCpsPath(dataspaceEntity, cpsPathQuery, anchorIds);
+
+ if (cpsPathQuery.hasAncestorAxis()) {
+ final Collection<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
+ if (anchorIds.isEmpty()) {
+ fragmentEntities = fragmentRepository.findByDataspaceAndXpathIn(dataspaceEntity, ancestorXpaths);
+ } else {
+ fragmentEntities = fragmentRepository.findByAnchorIdsAndXpathIn(
+ anchorIds.toArray(new Long[0]), ancestorXpaths.toArray(new String[0]));
+ }
+
+ }
+ fragmentEntities = fragmentRepository.prefetchDescendantsOfFragmentEntities(fetchDescendantsOption,
+ fragmentEntities);
+ return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
+ }
+
+ private List<DataNode> createDataNodesFromFragmentEntities(final FetchDescendantsOption fetchDescendantsOption,
+ final Collection<FragmentEntity> fragmentEntities) {
+ final List<DataNode> dataNodes = new ArrayList<>(fragmentEntities.size());
+ for (final FragmentEntity fragmentEntity : fragmentEntities) {
+ dataNodes.add(toDataNode(fragmentEntity, fetchDescendantsOption));
+ }
+ return Collections.unmodifiableList(dataNodes);
+ }
+
+ @Override
+ public String startSession() {
+ return sessionManager.startSession();
+ }
+
+ @Override
+ public void closeSession(final String sessionId) {
+ sessionManager.closeSession(sessionId, SessionManager.WITH_COMMIT);
+ }
+
+ @Override
+ public void lockAnchor(final String sessionId, final String dataspaceName,
+ final String anchorName, final Long timeoutInMilliseconds) {
+ sessionManager.lockAnchor(sessionId, dataspaceName, anchorName, timeoutInMilliseconds);
+ }
+
+ @Override
+ public Integer countAnchorsForDataspaceAndCpsPath(final String dataspaceName, final String cpsPath) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final CpsPathQuery cpsPathQuery;
+ try {
+ cpsPathQuery = CpsPathUtil.getCpsPathQuery(cpsPath);
+ } catch (final PathParsingException e) {
+ throw new CpsPathException(e.getMessage());
+ }
+ final List<Long> anchorIdList = getAnchorIdsForPagination(dataspaceEntity, cpsPathQuery, NO_PAGINATION);
+ return anchorIdList.size();
+ }
+
+ private DataNode toDataNode(final FragmentEntity fragmentEntity,
+ final FetchDescendantsOption fetchDescendantsOption) {
+ final List<DataNode> childDataNodes = getChildDataNodes(fragmentEntity, fetchDescendantsOption);
+ Map<String, Serializable> leaves = new HashMap<>();
+ if (fragmentEntity.getAttributes() != null) {
+ leaves = jsonObjectMapper.convertJsonString(fragmentEntity.getAttributes(), Map.class);
+ }
+ return new DataNodeBuilder()
+ .withXpath(fragmentEntity.getXpath())
+ .withLeaves(leaves)
+ .withDataspace(fragmentEntity.getAnchor().getDataspace().getName())
+ .withAnchor(fragmentEntity.getAnchor().getName())
+ .withChildDataNodes(childDataNodes).build();
+ }
+
+ private FragmentEntity toFragmentEntity(final AnchorEntity anchorEntity, final DataNode dataNode) {
+ return FragmentEntity.builder()
+ .anchor(anchorEntity)
+ .xpath(dataNode.getXpath())
+ .attributes(jsonObjectMapper.asJsonString(dataNode.getLeaves()))
+ .build();
+ }
+
+
+