View Javadoc
1   /*
2    * Copyright 2024 Bloomreach B.V. (https://www.bloomreach.com)
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  package org.onehippo.forge.content.exim.repository.jaxrs.util;
17  
18  import java.util.Collection;
19  import java.util.HashSet;
20  import java.util.LinkedHashSet;
21  import java.util.Set;
22  
23  import javax.jcr.Node;
24  import javax.jcr.NodeIterator;
25  import javax.jcr.RepositoryException;
26  import javax.jcr.Session;
27  import javax.jcr.query.Query;
28  import javax.jcr.query.QueryResult;
29  
30  import org.apache.commons.lang3.StringUtils;
31  import org.onehippo.forge.content.exim.core.util.HippoNodeUtils;
32  import org.onehippo.forge.content.exim.repository.jaxrs.param.ExecutionParams;
33  import org.onehippo.forge.content.exim.repository.jaxrs.param.QueriesAndPaths;
34  import org.onehippo.forge.content.exim.repository.jaxrs.param.Result;
35  import org.onehippo.forge.content.exim.repository.jaxrs.param.ResultItem;
36  
37  /**
38   * Utility to collect {@link ResultItem}s based on various conditions.
39   */
40  public class ResultItemSetCollector {
41  
42      private ResultItemSetCollector() {
43      }
44  
45      /**
46       * Collect {@link ResultItem}s from the given {@code params} by picking nodes from the given paths or querying
47       * nodes from the given queries.
48       * @param session JCR session
49       * @param params ExecutionParams instance
50       * @return collected {@link ResultItem}s
51       * @throws RepositoryException if repository exception occurs
52       */
53      public static Result collectItemsFromExecutionParams(final Session session, final ExecutionParams params)
54              throws RepositoryException {
55          Result result = new Result();
56  
57          QueriesAndPaths binaries = params.getBinaries();
58  
59          if (binaries != null) {
60              Set<String> binaryPathsCache = new LinkedHashSet<>();
61              fillResultItemsForNodePaths(session, binaries.getPaths(), true, binaryPathsCache, result);
62              fillResultItemsFromQueries(session, binaries.getQueries(), true, binaryPathsCache, result);
63          }
64  
65          QueriesAndPaths documents = params.getDocuments();
66  
67          if (documents != null) {
68              Set<String> documentPathsCache = new LinkedHashSet<>();
69              fillResultItemsForNodePaths(session, documents.getPaths(), false, documentPathsCache, result);
70              fillResultItemsFromQueries(session, documents.getQueries(), false, documentPathsCache, result);
71          }
72  
73          return result;
74      }
75  
76      /**
77       * Collect nodes from {@code nodePaths} with validations and fill {@link ResultItem} instances in {@code resultOut}.
78       * @param session JCR session
79       * @param nodePaths document or binary node paths to validate
80       * @param binary flag whether the node paths are for binary content or not
81       * @param pathsCache node path cache set, which can be useful if you want to avoid putting the same items multiple times.
82       *                   This can be null.
83       * @param resultOut {@link Result} instance
84       * @throws RepositoryException if repository exception occurs
85       */
86      public static void fillResultItemsForNodePaths(Session session, Collection<String> nodePaths,
87              boolean binary, Set<String> pathsCache, Result resultOut) throws RepositoryException {
88          if (pathsCache == null) {
89              pathsCache = new HashSet<>();
90          }
91  
92          for (String path : nodePaths) {
93              if ((binary && !HippoNodeUtils.isBinaryPath(path)) || (!binary && !HippoNodeUtils.isDocumentPath(path))) {
94                  continue;
95              }
96  
97              if (!session.nodeExists(path)) {
98                  continue;
99              }
100 
101             Node handle = HippoNodeUtils.getHippoDocumentHandle(session.getNode(path));
102 
103             if (handle == null) {
104                 continue;
105             }
106 
107             String handlePath = handle.getPath();
108 
109             if (pathsCache.contains(handlePath)) {
110                 continue;
111             }
112 
113             Node firstVariant = HippoNodeUtils.getFirstVariantNode(handle);
114 
115             if (firstVariant == null) {
116                 continue;
117             }
118 
119             pathsCache.add(handlePath);
120             ResultItem item = new ResultItem(handlePath, firstVariant.getPrimaryNodeType().getName());
121             resultOut.addItem(item);
122         }
123     }
124 
125     /**
126      * Collect nodes by executing the {@code queries} with validations and fill {@link ResultItem} instances in
127      * {@code resultOut}.
128      * @param session JCR session
129      * @param queries JCR query statements for documents or binaries
130      * @param binary flag whether the node paths are for binary content or not
131      * @param pathsCache node path cache set, which can be useful if you want to avoid putting the same items multiple times.
132      *                   This can be null.
133      * @param resultOut {@link Result} instance
134      * @throws RepositoryException if repository exception occurs
135      */
136     public static void fillResultItemsFromQueries(Session session, Collection<String> queries,
137             boolean binary, Set<String> pathsCache, Result resultOut) throws RepositoryException {
138         for (String query : queries) {
139             if (StringUtils.isBlank(query)) {
140                 continue;
141             }
142 
143             if (!StringUtils.startsWith(query, "/") || StringUtils.startsWithIgnoreCase(query, "select")) {
144                 continue;
145             }
146 
147             final String language = (StringUtils.startsWithIgnoreCase(query, "select")) ? Query.SQL : Query.XPATH;
148             Query jcrQuery = session.getWorkspace().getQueryManager().createQuery(query, language);
149             QueryResult queryResult = jcrQuery.execute();
150 
151             for (NodeIterator nodeIt = queryResult.getNodes(); nodeIt.hasNext();) {
152                 Node node = nodeIt.nextNode();
153 
154                 if (node == null) {
155                     continue;
156                 }
157 
158                 String nodePath = node.getPath();
159 
160                 if ((binary && !HippoNodeUtils.isBinaryPath(nodePath)) || (!binary && !HippoNodeUtils.isDocumentPath(nodePath))) {
161                     continue;
162                 }
163 
164                 Node handle = HippoNodeUtils.getHippoDocumentHandle(node);
165 
166                 if (handle == null) {
167                     continue;
168                 }
169 
170                 String handlePath = handle.getPath();
171 
172                 if (pathsCache.contains(handlePath)) {
173                     continue;
174                 }
175 
176                 Node firstVariant = HippoNodeUtils.getFirstVariantNode(handle);
177 
178                 if (firstVariant == null) {
179                     continue;
180                 }
181 
182                 pathsCache.add(handlePath);
183                 ResultItem item = new ResultItem(handlePath, firstVariant.getPrimaryNodeType().getName());
184                 resultOut.addItem(item);
185             }
186         }
187     }
188 }