View Javadoc
1   /**
2    * This file Copyright (c) 2003-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.util;
35  
36  import info.magnolia.context.MgnlContext;
37  import info.magnolia.jcr.util.NodeUtil;
38  
39  import java.util.Arrays;
40  import java.util.Calendar;
41  import java.util.HashSet;
42  import java.util.Iterator;
43  import java.util.Set;
44  import java.util.TimeZone;
45  
46  import javax.jcr.LoginException;
47  import javax.jcr.NodeIterator;
48  import javax.jcr.RepositoryException;
49  import javax.jcr.Session;
50  import javax.jcr.query.InvalidQueryException;
51  import javax.jcr.query.Query;
52  import javax.jcr.query.QueryManager;
53  import javax.jcr.query.QueryResult;
54  import javax.jcr.query.qom.QueryObjectModel;
55  
56  import org.apache.commons.lang3.StringUtils;
57  import org.slf4j.Logger;
58  import org.slf4j.LoggerFactory;
59  
60  /**
61   * Util to execute queries as simple as possible.
62   */
63  public class QueryUtil {
64  
65      private static Logger log = LoggerFactory.getLogger(QueryUtil.class);
66  
67      /**
68       * @param month 1-12 (as opposed to java.util.Calendar 0-11 notation)
69       * @deprecated
70       */
71      @Deprecated
72      public static String createDateExpression(int year, int month, int day) {
73          Calendar cal = Calendar.getInstance();
74          cal.set(year, month - 1, day);
75          return createDateExpression(cal);
76      }
77  
78      /**
79       * Expression representing a date.
80       *
81       * @deprecated since 4.5.4 use info.magnolia.cms.util.DateUtil.createDateExpression(calendar)
82       */
83      @Deprecated
84      public static String createDateExpression(Calendar calendar) {
85          return DateUtil.createDateExpression(calendar);
86      }
87  
88      /**
89       * @param month 1-12 (as opposed to java.util.Calendar 0-11 notation)
90       * @deprecated
91       */
92      @Deprecated
93      public static String createDateTimeExpression(int year, int month, int day, int hour, int minutes, int seconds) {
94          Calendar cal = Calendar.getInstance();
95          cal.set(year, month - 1, day, hour, minutes, seconds);
96          return createDateTimeExpression(cal);
97      }
98  
99      /**
100      * Expression representing a date and time.
101      *
102      * @deprecated since 4.5.4 use info.magnolia.cms.util.DateUtil.createDateTimeExpression(calendar)
103      */
104     @Deprecated
105     public static String createDateTimeExpression(Calendar calendar) {
106         return DateUtil.createDateTimeExpression(calendar);
107     }
108 
109     /**
110      * @param month 1-12 (as opposed to java.util.Calendar 0-11 notation)
111      * @deprecated
112      */
113     @Deprecated
114     public static String createDateTimeExpressionIgnoreTimeZone(int year, int month, int day, int hour, int minutes, int seconds) {
115         Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
116         cal.set(year, month - 1, day, hour, minutes, seconds);
117         return createDateTimeExpression(cal);
118     }
119 
120     /**
121      * Do not consider the timezone.
122      *
123      * @deprecated since 4.5.4 use info.magnolia.cms.util.DateUtil.createDateTimeExpressionIgnoreTimeZone(calendar)
124      */
125     @Deprecated
126     public static String createDateTimeExpressionIgnoreTimeZone(Calendar calendar) {
127         return DateUtil.createDateTimeExpressionIgnoreTimeZone(calendar);
128     }
129 
130     /**
131      * Executes the query based on QOM and then pops-up in the node hierarchy until returnItemType is found. If the result
132      * is not returnItemType or none of its parents are then next node in result is checked.
133      * Duplicate nodes are removed from result.
134      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
135      *
136      * @return Result as NodeIterator
137      */
138     public static NodeIterator search(QueryObjectModel model, String returnItemType) throws InvalidQueryException, RepositoryException {
139         return NodeUtil.filterDuplicates(NodeUtil.filterParentNodeType(model.execute().getNodes(), returnItemType));
140     }
141 
142     /**
143      * Executes the query with given language.Unlike in the old API item type has to be specified in query itself.
144      * <code>SELECT * FROM [mgnl:page]</code> example for selecting just pages in JCR SQL2 language.
145      * Duplicate nodes are removed from result.
146      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
147      *
148      * @return Result as NodeIterator
149      */
150     public static NodeIterator search(String workspace, String statement, String language) throws InvalidQueryException, RepositoryException {
151         Session session = MgnlContext.getJCRSession(workspace);
152         QueryManager manager = session.getWorkspace().getQueryManager();
153         Query query = manager.createQuery(statement, language);
154 
155         return NodeUtil.filterDuplicates(query.execute().getNodes());
156     }
157 
158     /**
159      * Executes the query using JCR SQL2 language. Unlike in the old API item type has to be specified in query itself.
160      * <code>SELECT * FROM [mgnl:page]</code> example for selecting just pages.
161      * For executing old query use info.magnolia.cms.util.QueryUtil.search(String workspace, String statement, String language)
162      * where you specify <code>Query.SQL</code> as the language.
163      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
164      *
165      * @return Result as NodeIterator
166      */
167     public static NodeIterator search(String workspace, String statement) throws InvalidQueryException, RepositoryException {
168         return search(workspace, statement, javax.jcr.query.Query.JCR_SQL2);
169     }
170 
171     /**
172      * Searches for statement and then pops-up in the node hierarchy until returnItemType is found. If the result
173      * is not returnItemType or none of its parents are then next node in result is checked. Duplicate nodes are
174      * removed from result.
175      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
176      *
177      * @return query result as collection of nodes
178      */
179     public static NodeIterator search(String workspace, String statement, String language, String returnItemType) throws LoginException, RepositoryException {
180         return search(workspace, statement, language, returnItemType, false);
181     }
182 
183     /**
184      * Searches for statement and then pops-up in the node hierarchy until returnItemType is found. If the result
185      * is not returnItemType or none of its parents are then next node in result is checked. Duplicate nodes are
186      * removed from result.
187      * If isSelector is set to true then returnItemType will be used as the selector and result will contain only nodes
188      * that are marked by this selector.
189      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
190      *
191      * @return iterator of nodes
192      */
193     public static NodeIterator search(String workspace, String statement, String language, String returnItemType, boolean isSelector) throws RepositoryException {
194         Session session = MgnlContext.getJCRSession(workspace);
195         QueryManager manager = session.getWorkspace().getQueryManager();
196         Query query = manager.createQuery(statement, language);
197         QueryResult result = query.execute();
198 
199         if (isSelector) {
200             return NodeUtil.filterDuplicates(NodeUtil.filterParentNodeType(result.getRows(), returnItemType));
201         }
202         return NodeUtil.filterDuplicates(NodeUtil.filterParentNodeType(result.getNodes(), returnItemType));
203     }
204 
205     /**
206      * Creates a simple SQL2 query statement.
207      */
208     public static String buildQuery(String statement, String startPath) {
209         Set<String> arguments = new HashSet<String>(Arrays.asList(StringUtils.splitByWholeSeparator(statement, ",")));
210 
211         Iterator<String> argIt = arguments.iterator();
212         String queryString = "select * from [nt:base] as t where ISDESCENDANTNODE([" + startPath + "])";
213         while (argIt.hasNext()) {
214             queryString = queryString + " AND contains(t.*, '" + argIt.next() + "')";
215         }
216         log.debug("query string: {}", queryString);
217         return queryString;
218     }
219 }