View Javadoc

1   /**
2    * This file Copyright (c) 2003-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.templating;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.core.ItemType;
38  import info.magnolia.cms.beans.config.ObservedManager;
39  import info.magnolia.content2bean.Content2BeanException;
40  import info.magnolia.content2bean.Content2BeanUtil;
41  import info.magnolia.objectfactory.Components;
42  
43  import javax.jcr.RepositoryException;
44  import java.util.ArrayList;
45  import java.util.Collection;
46  import java.util.Hashtable;
47  import java.util.Iterator;
48  import java.util.List;
49  import java.util.Map;
50  
51  
52  /**
53   * Manages the templates of the system.
54   * @author philipp
55   */
56  public class TemplateManager extends ObservedManager {
57  
58      private static final String DELETED_PAGE_TEMPLATE = "mgnlDeleted";
59  
60      /**
61       * The cached templates.
62       */
63      private final Map<String, Template> cachedContent = new Hashtable<String, Template>();
64  
65      /**
66       * The templates visible in the templates selection.
67       */
68      private final List<Template> visibleTemplates = new ArrayList<Template>();
69  
70      /**
71       * Called by the ObservedManager.
72       */
73      @Override
74      protected void onRegister(Content node) {
75          try {
76              log.info("Loading Template info from {}", node.getHandle()); //$NON-NLS-1$
77  
78              // It makes possibly to use templates defined within subfolders of /module/templating/Templates
79              Collection<Content> children = collectChildren(node);
80  
81              if ((children != null) && !(children.isEmpty())) {
82                  Iterator<Content> templates = children.iterator();
83                  cacheContent(templates);
84              }
85  
86              log.debug("Template info loaded from {}", node.getHandle()); //$NON-NLS-1$
87          }
88          catch (Exception re) {
89              log.error("Failed to load Template info from " + node.getHandle() + ": " + re.getMessage(), re);
90          }
91  
92      }
93  
94      @Override
95      protected void onClear() {
96          this.cachedContent.clear();
97          this.visibleTemplates.clear();
98      }
99  
100     /**
101      * Returns the cached content of the requested template. TemplateInfo properties:
102      * <ol>
103      * <li> title - title describing template</li>
104      * <li> type - jsp / servlet</li>
105      * <li> path - jsp / servlet path</li>
106      * <li> description - description of a template</li>
107      * </ol>
108      * @return TemplateInfo
109      * @deprecated since 4.0 Use {@link #getTemplateDefinition(String)} instead
110      */
111     @Deprecated
112     public Template getInfo(String key) {
113         return getTemplateDefinition(key);
114     }
115 
116     /**
117      * Returns the cached content of the requested template. TemplateInfo properties:
118      * <ol>
119      * <li> title - title describing template</li>
120      * <li> type - jsp / servlet</li>
121      * <li> path - jsp / servlet path</li>
122      * <li> description - description of a template</li>
123      * </ol>
124      * @return TemplateInfo
125      */
126     public Template getTemplateDefinition(String key) {
127         return cachedContent.get(key);
128     }
129 
130     /**
131      * Returns the cached content of the requested template. TemplateInfo properties:
132      * <ol>
133      * <li> title - title describing template</li>
134      * <li> type - jsp / servlet</li>
135      * <li> path - jsp / servlet path</li>
136      * <li> description - description of a template</li>
137      * </ol>
138      * @return TemplateInfo
139      */
140     public Template getInfo(String key, String extension) {
141         Template template = cachedContent.get(key);
142 
143         if (template == null) {
144             return null;
145         }
146         Template subtemplate = template.getSubTemplate(extension);
147         if (subtemplate != null) {
148             return subtemplate;
149         }
150 
151         return template;
152     }
153 
154     /**
155      * Adds templates definition to TemplatesInfo cache.
156      * @param templates iterator as read from the repository
157      * @param visibleTemplates List in with all visible templates will be added
158      */
159     private void addTemplatesToCache(Iterator<Content> templates, List<Template> visibleTemplates) {
160         while (templates.hasNext()) {
161             Content c = templates.next();
162 
163             try {
164                 Template ti = (Template) Content2BeanUtil.toBean(c, true, Template.class);
165                 cachedContent.put(ti.getName(), ti);
166                 if (ti.isVisible() && !DELETED_PAGE_TEMPLATE.equals(ti.getName())) {
167                     visibleTemplates.add(ti);
168                 }
169 
170                 log.debug("Registering template [{}]", ti.getName());
171             }
172             catch (Content2BeanException e) {
173                 log.error("Can't register template ["+c.getName()+"]",e);
174             }
175 
176         }
177     }
178 
179     /**
180      * Load content of this template info page in a hash table caching at the system load, this will save lot of time on
181      * every request while matching template info.
182      */
183     private void cacheContent(Iterator<Content> templates) {
184         if (templates != null) {
185             addTemplatesToCache(templates, visibleTemplates);
186         }
187     }
188 
189     /**
190      * Recursive search for content nodes contains template data (looks up subfolders).
191      * @author <a href="mailto:tm@touk.pl">Tomasz Mazan</a>
192      * @param cnt current folder to look for template's nodes
193      * @return collection of template's content nodes from current folder and descendants
194      */
195     private Collection<Content> collectChildren(Content cnt) {
196         // Collect template's content node - children of current node
197         Collection<Content> children = cnt.getChildren(ItemType.CONTENTNODE);
198 
199         // Look into subfolders
200         Collection<Content> subFolders = cnt.getChildren(ItemType.CONTENT);
201         if ((subFolders != null) && !(subFolders.isEmpty())) {
202 
203             for (Content subCnt : subFolders) {
204                 Collection<Content> grandChildren = collectChildren(subCnt);
205 
206                 if ((grandChildren != null) && !(grandChildren.isEmpty())) {
207                     children.addAll(grandChildren);
208                 }
209             }
210 
211         }
212 
213         return children;
214     }
215 
216     public Iterator<Template> getAvailableTemplates(Content node) {
217         List<Template> templateList = new ArrayList<Template>();
218 
219         try {
220             if (node != null && node.hasMixin(ItemType.DELETED_NODE_MIXIN)) {
221                 templateList.add(getTemplateDefinition(DELETED_PAGE_TEMPLATE));
222                 return templateList.iterator();
223             }
224         } catch (RepositoryException e) {
225             log.error("Failed to check node for deletion status.", e);
226         }
227         for (Template template : visibleTemplates) {
228 
229             if (template.isAvailable(node)) {
230                 templateList.add(template);
231             }
232         }
233         return templateList.iterator();
234     }
235 
236     /**
237      * Get templates collection.
238      * @return Collection list containing templates as Template objects
239      */
240     public Iterator<Template> getAvailableTemplates() {
241         return visibleTemplates.iterator();
242     }
243 
244     /**
245      * Get the Template that could be used for the provided Content as a default.
246      */
247     public Template getDefaultTemplate(Content node) {
248         Template tmpl;
249         try {
250             // try to use the same as the parent
251             tmpl = this.getTemplateDefinition(node.getParent().getTemplate());
252             if(tmpl != null && tmpl.isAvailable(node)){
253                 return tmpl;
254             }
255             // otherwise use the first available template
256             else{
257                 Iterator<Template> templates = getAvailableTemplates(node);
258                 if (templates.hasNext()) {
259                     return templates.next();
260                 }
261             }
262         }
263         catch (RepositoryException e) {
264             log.error("Can't resolve default template for node " + node.getHandle(), e);
265         }
266         return null;
267     }
268 
269     /**
270      * @return Returns the instance.
271      */
272     public static TemplateManager getInstance() {
273         return Components.getSingleton(TemplateManager.class);
274     }
275 
276 }