View Javadoc
1   /**
2    * This file Copyright (c) 2003-2014 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.cms.core.Content;
37  import info.magnolia.cms.core.ItemType;
38  import info.magnolia.context.MgnlContext;
39  import info.magnolia.jcr.util.NodeUtil;
40  
41  import org.apache.commons.lang.StringUtils;
42  import org.apache.commons.lang.time.DateUtils;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
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 java.util.ArrayList;
57  import java.util.Arrays;
58  import java.util.Calendar;
59  import java.util.Collection;
60  import java.util.Collections;
61  import java.util.HashSet;
62  import java.util.Iterator;
63  import java.util.Set;
64  
65  /**
66   * Util to execute queries as simple as possible.
67   * @version $Id$
68   *
69   */
70  public class QueryUtil {
71  
72      private static Logger log = LoggerFactory.getLogger(QueryUtil.class);
73  
74      /**
75       * Executes a query.
76       * @deprecated Since 4.5.4 use search methods.
77       */
78      public static Collection<Content> query(String repository, String statement) {
79          return query(repository, statement, "sql");
80      }
81  
82      /**
83       * Executes a query.
84       * @deprecated Since 4.5.4 use search methods.
85       */
86      public static Collection<Content> query(String repository, String statement, String language) {
87          return query(repository, statement, language, ItemType.NT_BASE);
88      }
89  
90      /**
91      * @deprecated Since 4.5.4 use search methods.
92      */
93      public static Collection<Content> exceptionThrowingQuery(String repository, String statement, String language, String returnItemType) throws RepositoryException {
94          return exceptionThrowingQuery(repository, statement, language, returnItemType, Long.MAX_VALUE);
95      }
96  
97      /**
98       * Executes a query, throwing any exceptions that arise as a result.
99       * @deprecated Since 4.5.4 use search methods.
100      */
101     public static Collection<Content> exceptionThrowingQuery(String repository, String statement, String language, String returnItemType,
102         long maxResultSize) throws RepositoryException {
103         Collection<Content> results = new ArrayList<Content>();
104         if(maxResultSize <= 0){
105             maxResultSize = Long.MAX_VALUE;
106         }
107         NodeIterator iterator = search(repository, statement, language, returnItemType);
108 
109         long count = 1;
110         while(iterator.hasNext() && count <= maxResultSize){
111             results.add(ContentUtil.getContent(repository, iterator.nextNode().getPath()));
112             count++;
113         }
114         return results;
115     }
116 
117     /**
118      * @deprecated Since 4.5.4 use search methods.
119      */
120     public static Collection<Content> query(String repository, String statement, String language, String returnItemType) {
121         return query(repository, statement, language, returnItemType, Long.MAX_VALUE);
122     }
123 
124     /**
125      * Executes a query - if an exception is thrown, it is logged and an empty collection is
126      * returned.
127      * @deprecated Since 4.5.4 use search methods.
128      */
129     @SuppressWarnings("unchecked")
130     // Collections.EMPTY_LIST;
131     public static Collection<Content> query(String repository, String statement, String language, String returnItemType, long maxResultSize) {
132         try {
133             return exceptionThrowingQuery(repository, statement, language, returnItemType, maxResultSize);
134         }
135         catch (Exception e) {
136             log.error("can't execute query [" + statement + "], will return empty collection", e);
137         }
138         return Collections.EMPTY_LIST;
139     }
140 
141     /**
142      * @param month 1-12 (as opposed to java.util.Calendar 0-11 notation)
143      * @deprecated
144      */
145     public static String createDateExpression(int year, int month, int day) {
146         Calendar cal = Calendar.getInstance();
147         cal.set(year, month - 1, day);
148         return createDateExpression(cal);
149     }
150 
151     /**
152      * Expression representing a date.
153      * @deprecated since 4.5.4 use info.magnolia.cms.util.DateUtil.createDateExpression(calendar)
154      */
155     public static String createDateExpression(Calendar calendar) {
156         return DateUtil.createDateExpression(calendar);
157     }
158 
159     /**
160      * @param month 1-12 (as opposed to java.util.Calendar 0-11 notation)
161      * @deprecated
162      */
163     public static String createDateTimeExpression(int year, int month, int day, int hour, int minutes, int seconds) {
164         Calendar cal = Calendar.getInstance();
165         cal.set(year, month - 1, day, hour, minutes, seconds);
166         return createDateTimeExpression(cal);
167     }
168 
169     /**
170      * Expression representing a date and time.
171      * @deprecated since 4.5.4 use info.magnolia.cms.util.DateUtil.createDateTimeExpression(calendar)
172      */
173     public static String createDateTimeExpression(Calendar calendar) {
174         return DateUtil.createDateTimeExpression(calendar);
175     }
176 
177     /**
178      * @param month 1-12 (as opposed to java.util.Calendar 0-11 notation)
179      * @deprecated
180      */
181     public static String createDateTimeExpressionIgnoreTimeZone(int year, int month, int day, int hour, int minutes, int seconds) {
182         Calendar cal = Calendar.getInstance(DateUtils.UTC_TIME_ZONE);
183         cal.set(year, month - 1, day, hour, minutes, seconds);
184         return createDateTimeExpression(cal);
185     }
186 
187     /**
188      * Do not consider the timezone.
189      * @deprecated since 4.5.4 use info.magnolia.cms.util.DateUtil.createDateTimeExpressionIgnoreTimeZone(calendar)
190      */
191     public static String createDateTimeExpressionIgnoreTimeZone(Calendar calendar) {
192         return DateUtil.createDateTimeExpressionIgnoreTimeZone(calendar);
193     }
194     
195     /**
196      * Executes the query based on QOM and then pops-up in the node hierarchy until returnItemType is found. If the result
197      * is not returnItemType or none of its parents are then next node in result is checked.
198      * Duplicate nodes are removed from result.
199      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
200      * @param model
201      * @param returnItemType
202      * @return Result as NodeIterator
203      * @throws InvalidQueryException
204      * @throws RepositoryException
205      */
206     public static NodeIterator search(QueryObjectModel model, String returnItemType) throws InvalidQueryException, RepositoryException{
207         return NodeUtil.filterDuplicates(NodeUtil.filterParentNodeType(model.execute().getNodes(), returnItemType));
208     }
209 
210     /**
211      * Executes the query with given language.Unlike in the old API item type has to be specified in query itself.
212      * <code>SELECT * FROM [mgnl:page]</code> example for selecting just pages in JCR SQL2 language.
213      * Duplicate nodes are removed from result.
214      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
215      * @param workspace
216      * @param statement
217      * @param language
218      * @return Result as NodeIterator
219      * @throws InvalidQueryException
220      * @throws RepositoryException
221      */
222     public static NodeIterator search(String workspace, String statement, String language) throws InvalidQueryException, RepositoryException{
223         Session session = MgnlContext.getJCRSession(workspace);
224         QueryManager manager = session.getWorkspace().getQueryManager();
225         Query query = manager.createQuery(statement, language);
226 
227         return NodeUtil.filterDuplicates(query.execute().getNodes());
228     }
229 
230     /**
231      * Executes the query using JCR SQL2 language. Unlike in the old API item type has to be specified in query itself.
232      * <code>SELECT * FROM [mgnl:page]</code> example for selecting just pages.
233      * For executing old query use info.magnolia.cms.util.QueryUtil.search(String workspace, String statement, String language)
234      * where you specify <code>Query.SQL</code> as the language.
235      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
236      * @param workspace
237      * @param statement
238      * @return Result as NodeIterator
239      * @throws InvalidQueryException
240      * @throws RepositoryException
241      */
242     public static NodeIterator search(String workspace, String statement) throws InvalidQueryException, RepositoryException{
243         return search(workspace, statement, javax.jcr.query.Query.JCR_SQL2);
244     }
245 
246     /**
247      * Searches for statement and then pops-up in the node hierarchy until returnItemType is found. If the result
248      * is not returnItemType or none of its parents are then next node in result is checked. Duplicate nodes are
249      * removed from result.
250      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
251      * @param workspace
252      * @param statement
253      * @param language
254      * @param returnItemType
255      * @return query result as collection of nodes
256      * @throws LoginException
257      * @throws RepositoryException
258      */
259     public static NodeIterator search(String workspace, String statement, String language, String returnItemType) throws LoginException, RepositoryException{
260         return search(workspace, statement, language, returnItemType, false);
261     }
262 
263     /**
264      * Searches for statement and then pops-up in the node hierarchy until returnItemType is found. If the result
265      * is not returnItemType or none of its parents are then next node in result is checked. Duplicate nodes are
266      * removed from result.
267      * If isSelector is set to true then returnItemType will be used as the selector and result will contain only nodes
268      * that are marked by this selector.
269      * For date/time expressions use <code>DateUtil.create*Expression()</code> methods.
270      * @return iterator of nodes
271      */
272     public static NodeIterator search(String workspace, String statement, String language, String returnItemType, boolean isSelector) throws RepositoryException {
273         Session session = MgnlContext.getJCRSession(workspace);
274         QueryManager manager = session.getWorkspace().getQueryManager();
275         Query query = manager.createQuery(statement, language);
276         QueryResult result = query.execute();
277 
278         if (isSelector) {
279             return NodeUtil.filterDuplicates(NodeUtil.filterParentNodeType(result.getRows(), returnItemType));
280         }
281         return NodeUtil.filterDuplicates(NodeUtil.filterParentNodeType(result.getNodes(), returnItemType));
282     }
283     
284     /**
285      * Creates a simple SQL2 query statement.
286      * 
287      * @param statement
288      * @param startPath
289      */
290     public static String buildQuery (String statement, String startPath){
291         Set<String> arguments = new HashSet<String>(Arrays.asList(StringUtils.splitByWholeSeparator(statement, ",")));
292 
293         Iterator<String> argIt = arguments.iterator();
294         String queryString = "select * from [nt:base] as t where ISDESCENDANTNODE(["+startPath+"])";
295         while(argIt.hasNext()){
296             queryString = queryString + " AND contains(t.*, '"+argIt.next()+"')";
297         }
298         log.debug("query string: " + queryString);
299         return queryString;
300     }
301 }