View Javadoc

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