View Javadoc

1   /**
2    * This file Copyright (c) 2008-2011 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.templatingkit.templates.category;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.core.MgnlNodeType;
38  import info.magnolia.cms.core.search.Query;
39  import info.magnolia.cms.util.ContentUtil;
40  import info.magnolia.cms.util.QueryUtil;
41  import info.magnolia.jcr.wrapper.I18nNodeWrapper;
42  import info.magnolia.module.templatingkit.templates.pages.STKPage;
43  import info.magnolia.objectfactory.Components;
44  import info.magnolia.registry.RegistrationException;
45  import info.magnolia.rendering.template.TemplateDefinition;
46  import info.magnolia.rendering.template.registry.TemplateDefinitionRegistry;
47  
48  import java.util.ArrayList;
49  import java.util.HashSet;
50  import java.util.Iterator;
51  import java.util.List;
52  import java.util.Set;
53  
54  import javax.jcr.Node;
55  import javax.jcr.RepositoryException;
56  import javax.jcr.Session;
57  
58  import org.apache.commons.lang.StringUtils;
59  import org.slf4j.Logger;
60  import org.slf4j.LoggerFactory;
61  
62  
63  /**
64   * Few util methods to use template categories.
65   * @author pbracher
66   * @version $Id$
67   *
68   */
69  public class TemplateCategoryUtil {
70  
71      private static TemplateDefinitionRegistry templateDefinitionRegistry = Components.getComponent(TemplateDefinitionRegistry.class);
72  
73      private static Logger log = LoggerFactory.getLogger(TemplateCategoryUtil.class);
74  
75      /**
76       * FIXME nested method call: for work around {@link Content}.
77       */
78      public static String getTemplateCategory(Node pageNode) {
79          return getTemplateCategory(ContentUtil.asContent(pageNode));
80      }
81  
82      /**
83       * Returns the category of the template assigned to a node, if the assigned template is not an STK template it
84       * default to {@link TemplateCategory#CONTENT} and if there is no template assigned or the assigned template doesn't
85       * exists it returns the empty string.
86       */
87      public static String getTemplateCategory(Content pageNode) {
88          final String templateId = pageNode.getTemplate();
89          try {
90              TemplateDefinition template = templateDefinitionRegistry.getTemplateDefinition(templateId);
91              if (template instanceof STKPage) {
92                  STKPage stkTemplate = (STKPage) template;
93                  return stkTemplate.getCategory();
94              }
95              return TemplateCategory.CONTENT;
96          } catch (RegistrationException e) {
97              log.debug(e.getMessage(), e);
98              return "";
99          }
100     }
101 
102     /**
103      * FIXME nested method call: for work around {@link Content}.
104      */
105     public static String getTemplateSubCategory(Node pageNode) {
106         return getTemplateSubCategory(ContentUtil.asContent(pageNode));
107     }
108 
109     /**
110      * Returns the sub-category of the template assigned to a node, if the assigned template is not an STK template it
111      * default to {@link TemplateCategory#CONTENT} and if there is no template assigned or the assigned template doesn't
112      * exists it returns the empty string.
113      */
114     public static String getTemplateSubCategory(Content pageNode) {
115         final String templateId = pageNode.getTemplate();
116         try {
117             TemplateDefinition template = templateDefinitionRegistry.getTemplateDefinition(templateId);
118             if (template instanceof STKPage) {
119                 STKPage stkTemplate = (STKPage) template;
120                 return stkTemplate.getSubcategory();
121             }
122             return TemplateCategory.CONTENT;
123         } catch (RegistrationException e) {
124             return "";
125         }
126     }
127 
128     /**
129      * FIXME nested method call: for work around {@link Content}.
130      */
131     public static boolean hasTemplateOfCategory(Node pageNode, String templateCatergory) {
132         return hasTemplateOfCategory(ContentUtil.asContent(pageNode), templateCatergory);
133     }
134 
135     public static boolean hasTemplateOfCategory(Content pageNode, String templateCatergory) {
136         return TemplateCategoryUtil.getTemplateCategory(pageNode).equals(templateCatergory);
137     }
138 
139     /**
140      * FIXME nested method call: for work around {@link Content}.
141      */
142     public static Node findParentWithTemplateCategory(Node pageNode, String templateCategory) throws RepositoryException {
143         Content parent = findParentWithTemplateCategory(ContentUtil.asContent(pageNode), templateCategory);
144         return parent != null ? parent.getJCRNode() : null;
145     }
146 
147     public static Content findParentWithTemplateCategory(Content pageNode, String templateCategory) throws RepositoryException {
148         Content current = pageNode;
149         // in a multi site environment the root might be the home page
150         while(current.getLevel()>=0){
151             if(TemplateCategoryUtil.hasTemplateOfCategory(current, templateCategory)) {
152                 return current;
153             }
154             //avoid javax.jcr.ItemNotFoundException: root node doesn't have a parent
155             if(current.getLevel() == 0) {
156                 break;
157             }
158             current = current.getParent();
159         }
160         return null;
161     }
162 
163     /**
164      * FIXME nested method call: for work around {@link Content}.
165      */
166     public static boolean isContentPage(Node pageNode){
167         return isContentPage(ContentUtil.asContent(pageNode));
168     }
169 
170     public static boolean isContentPage(Content pageNode){
171         return !TemplateCategoryUtil.hasTemplateOfCategory(pageNode, TemplateCategory.HOME) && !!TemplateCategoryUtil.hasTemplateOfCategory(pageNode, TemplateCategory.SECTION);
172     }
173 
174     public static List<Node> getContentListByTemplateCategorySubCategory(Node siteRoot, String category, String subCategory) throws RepositoryException {
175         return getContentListByTemplateCategorySubCategory(siteRoot, category, subCategory,Integer.MAX_VALUE, null, null);
176     }
177 
178     public static List<Node> getContentListByTemplateCategorySubCategory(Node siteRoot, String category, String subCategory, int maxResultSize, String andClause, String orderBy) throws RepositoryException {
179         final Set<String> templateIds = new HashSet<String>();
180         final Iterator<TemplateDefinition> templatesIterator = templateDefinitionRegistry.getTemplateDefinitions().iterator();
181         while (templatesIterator.hasNext()) {
182             final TemplateDefinition template = templatesIterator.next();
183             if(template instanceof STKPage) {
184                 final STKPage stkTemplate = (STKPage)template;
185                 if(StringUtils.equals(stkTemplate.getCategory(), category) //TODO: the second condition fails
186                       && (StringUtils.isEmpty(subCategory) || StringUtils.equals(stkTemplate.getSubcategory(), subCategory) )) {
187                   templateIds.add(template.getId());
188                 }
189              }
190          }
191         if (!templateIds.isEmpty()) {
192             return getContentListByTemplateNames(siteRoot, templateIds, maxResultSize, andClause, orderBy);
193         } else {
194             return new ArrayList<Node>();
195         }
196     }
197 
198     public static List<Node> getContentListByTemplateName(Node searchRoot, String templateName) throws RepositoryException {
199         return getContentListByTemplateName(searchRoot, templateName, Integer.MAX_VALUE, null, null);
200     }
201 
202     public static List<Node> getContentListByTemplateName(Node searchRoot, String templateName, int maxResultSize, String andClause, String orderByClause) throws RepositoryException {
203         Set<String> templateNames = new HashSet<String>();
204         templateNames.add(templateName);
205         return getContentListByTemplateNames(searchRoot, templateNames, maxResultSize, andClause, orderByClause);
206     }
207 
208     /**
209      * Find content objects with one of the given templates below a given search root.
210      * @param searchRoot
211      * @param templateIds
212      * @param maxResultSize setting this can drastically improve query performance, if you are interested only in a fixed number of leading result objects
213      * @param andClause an additional "AND" clause in SQL syntax, excluding the "AND" itself, e.g. "date IS NOT NULL"
214      * @param orderByClause an "ORDER BY" clause in SQL syntax, excluding the "ORDER BY" itself, e.g. "date desc" or "date asc"
215      * @return
216      * @throws RepositoryException
217      */
218     public static List<Node> getContentListByTemplateNames(Node searchRoot, Set<String> templateIds, int maxResultSize, String andClause, String orderByClause) throws RepositoryException{
219         Session session = searchRoot.getSession();
220         String path  = searchRoot.getPath();
221         String repository = session.getWorkspace().getName();
222 
223         StringBuffer sql = new StringBuffer("select * from nt:base where jcr:path like '" + path +"/%'");
224         if (templateIds!=null && !templateIds.isEmpty()) {
225             sql.append(" AND (");
226             Iterator<String> templateNamesIter = templateIds.iterator();
227             do  {
228                 sql.append("mgnl:template = '" + templateNamesIter.next() + "'");
229                 if (templateNamesIter.hasNext()) {
230                     sql.append(" OR ");
231                 }
232             } while (templateNamesIter.hasNext());
233             sql.append(")");
234         }
235         if (andClause != null) {
236             sql.append(" AND " + andClause);
237         }
238         if (orderByClause != null) {
239             sql.append(" ORDER BY " + orderByClause);
240         }
241 
242         //FIXME QueryUtil should use directly javax.jcr.query API, to migrate core.search
243         List<Content> itemsListFromQuery = (List<Content>) QueryUtil.query(repository, sql.toString(), Query.SQL , MgnlNodeType.NT_CONTENT, maxResultSize);
244         List<Node> itemsList = new ArrayList<Node>(itemsListFromQuery.size());
245 
246         // wrap all
247         for (int i = 0; i < itemsListFromQuery.size(); i++) {
248             itemsList.add(i, new I18nNodeWrapper(itemsListFromQuery.get(i).getJCRNode()));
249         }
250         return itemsList;
251     }
252 
253     public static Node getNearestContentByTemplateCategorySubCategory(Node siteRoot, String category, String subCategory, Node current) throws RepositoryException {
254 
255         List<Node> nodeList = getContentListByTemplateCategorySubCategory(siteRoot, category, subCategory);
256         if(!nodeList.isEmpty()) {
257             Node bestMatching = null;
258             int bestMatchingLength =-1;
259             for (Node node : nodeList) {
260                 int matchingLegth = StringUtils.indexOfDifference(node.getPath(), current.getPath());
261                 if (matchingLegth > bestMatchingLength) {
262                     bestMatchingLength = matchingLegth;
263                     bestMatching = node;
264                 }
265             }
266             return bestMatching;
267         }
268         return null;
269     }
270 }