View Javadoc

1   /**
2    * This file Copyright (c) 2008-2010 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.module.rssaggregator.util;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.core.ItemType;
38  import info.magnolia.cms.core.search.Query;
39  import info.magnolia.cms.util.QueryUtil;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  import javax.jcr.RepositoryException;
44  import java.util.ArrayList;
45  import java.util.Collection;
46  import static java.util.Collections.*;
47  import java.util.List;
48  
49  /**
50   * Convenience class to simplify use of Magnolia queries and the mapping of their results to types. <p/> Note that all
51   * queries performed by this class are logged at DEBUG level for convenient debugging when necessary.
52   *
53   * @author Rob van der Linden Vooren
54   * @see ContentMapper
55   */
56  public class MagnoliaTemplate implements MagnoliaQueryOperations {
57  
58      /** Logger for this instance. */
59      protected Logger logger = LoggerFactory.getLogger(getClass());
60  
61      /** {@inheritDoc} */
62      public <T> List<T> queryForList(String repository, String query, String language, ItemType type, ContentMapper<T> mapper) {
63          return query(repository, query, language, type, mapper);
64      }
65  
66      /** {@inheritDoc} */
67      public <T> T queryForObject(String repository, String query, String language, ItemType type, ContentMapper<T> mapper) {
68          List<T> results = query(repository, query, language, type, mapper);
69          return singleResult(results);
70      }
71  
72      /** {@inheritDoc} */
73      public <T> List<T> xpathQueryForList(String repository, String query, ItemType type, ContentMapper<T> mapper) throws DataAccessException {
74          return queryForList(repository, query, Query.XPATH, type, mapper);
75      }
76  
77      /** {@inheritDoc} */
78      public <T> T xpathQueryForObject(String repository, String query, ItemType type, ContentMapper<T> mapper) throws DataAccessException {
79          return queryForObject(repository, query, Query.XPATH, type, mapper);
80      }
81  
82      /** {@inheritDoc} */
83      public Content xpathQueryForContent(String repository, String query, ItemType type) throws DataAccessException {
84          return queryForObject(repository, query, Query.XPATH, type, new ContentMapper<Content>() {
85              public Content map(Content content) throws RepositoryException {
86                  return content;
87              }
88          });
89      }
90  
91      // Helper methods
92  
93      protected <T> List<T> query(String repository, String query, String language, ItemType type, ContentMapper<T> mapper) throws DataAccessException {
94          Collection<Content> contents = queryInternal(repository, query, language, type);
95          if (contents.isEmpty()) {
96              return emptyList();
97          }
98          List<T> result = new ArrayList<T>(contents.size());
99          for (Content content : contents) {
100             try {
101                 result.add(mapper.map(content));
102             } catch (RepositoryException re) {
103                 throw new DataAccessException(String.format("Failed to map content '%s' using mapper '%s'", content, mapper.getClass()));
104             }
105         }
106         return result;
107     }
108 
109     /**
110      * Performs the actual query execution. Purposely delegates to {@link QueryUtil#exceptionThrowingQuery(String,
111      * String, String, String) QueryUtil.exceptionThrowingQuery(..)} in order to provide flexibility with regards to
112      * error handling, by translating any {@link RepositoryException} into an unchecked {@link DataAccessException}.
113      * This allows for optional exception handling and logging, making it a better alternative then using {@link
114      * QueryUtil#query(String, String) QueryUtil.query(..)} direcltly, which logs the error and then directly swallows
115      * the {@link RepositoryException exception}. Execute a query for a result list of type T, for the given query.
116      *
117      * @param repository the repository to execute query against
118      * @param query      query to execute
119      * @param language   query language (either {@value Query#XPATH} or {@value Query#SQL}).
120      * @param type       the type of the item to query for
121      * @return the result object of the required type, or {@code null} in case of a {@code null} query
122      * @throws DataAccessException if there is any problem executing the query
123      */
124     protected <T> Collection<T> queryInternal(String repository, String query, String language, ItemType type) {
125         try {
126             return doExceptionThrowingQuery(repository, query, language, type);
127         } catch (RepositoryException re) {
128             throw new DataAccessException("A repository exception occurred", re);
129         }
130     }
131 
132     @SuppressWarnings("unchecked")
133     protected <T> Collection<T> doExceptionThrowingQuery(String repository, String query, String language, ItemType type) throws RepositoryException {
134         logger.debug("Executing {} query for '{}' in repository '{}': \"{}\"", new Object[] {language,
135                 type.getSystemName(), repository, query}
136         );
137         Collection<T> results = (Collection<T>) QueryUtil.exceptionThrowingQuery(repository, query, language, type.getSystemName());
138         logger.debug("Query returned %s result(s)", (results == null) ? null : results.size());
139         return results;
140     }
141 
142     /**
143      * Return a single result object from the given collection or {@code null} if the collection is empty or null.
144      *
145      * @param results the result collection (may be {@code null})
146      * @return the single result object, or {@code null} when no result
147      * @throws IncorrectResultSizeDataAccessException
148      *          if collection contains more than one element
149      */
150     protected static <T> T singleResult(Collection<T> results) throws IncorrectResultSizeDataAccessException {
151         int size = (results == null ? 0 : results.size());
152         if (size == 0) {
153             return null;
154         }
155         if (results.size() > 1) {
156             throw new IncorrectResultSizeDataAccessException(1, size);
157         }
158         return results.iterator().next();
159     }
160 
161 }