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