View Javadoc

1   /**
2    * This file Copyright (c) 2008-2010 esense GmbH
3    * (http://www.esense.ch). All rights reserved.
4    *
5    *
6    * This program and the accompanying materials are made
7    * available under the terms of the Magnolia Network Agreement
8    * which accompanies this distribution, and is available at
9    * http://www.magnolia.info/mna.html
10   *
11   * Any modifications to this file must keep this entire header
12   * intact.
13   *
14   */
15  package ch.esense.magnolia.module.googlesitemap.tags;
16  
17  import info.magnolia.cms.beans.config.ServerConfiguration;
18  import info.magnolia.cms.core.Content;
19  import info.magnolia.cms.core.HierarchyManager;
20  import info.magnolia.cms.core.ItemType;
21  import info.magnolia.cms.i18n.I18nContentSupport;
22  import info.magnolia.cms.i18n.I18nContentSupportFactory;
23  import info.magnolia.cms.util.QueryUtil;
24  import info.magnolia.context.MgnlContext;
25  import info.magnolia.context.MgnlContext.VoidOp;
26  import info.magnolia.module.templating.MagnoliaTemplatingUtilities;
27  
28  import java.io.IOException;
29  import java.text.SimpleDateFormat;
30  import java.util.ArrayList;
31  import java.util.Calendar;
32  import java.util.Collection;
33  import java.util.Iterator;
34  import java.util.Locale;
35  
36  import javax.jcr.RepositoryException;
37  import javax.servlet.http.HttpServletRequest;
38  import javax.servlet.jsp.JspException;
39  import javax.servlet.jsp.JspWriter;
40  import javax.servlet.jsp.tagext.TagSupport;
41  
42  import org.apache.commons.lang.StringUtils;
43  import org.apache.commons.lang.exception.NestableRuntimeException;
44  import org.apache.log4j.Logger;
45  
46  /**
47   * Draws a simple google sitemap.
48   *
49   * @author Tom Wespi
50   * @version $Revision: $ ($Author: $)
51   */
52  public class SitemapTag extends TagSupport {
53  
54      /**
55       * Default name for "priority" nodeData.
56       */
57      public static final String DEFAULT_PRIORITY_NODEDATA = "googleSitemapPriority"; //$NON-NLS-1$
58  
59      /**
60       * Default name for "changefreq" nodeData.
61       */
62      public static final String DEFAULT_CHANGEFREQ_NODEDATA = "googleSitemapChangefreq"; //$NON-NLS-1$
63  
64      /**
65       * Default name for "hideInGoogleSitemap" nodeData.
66       */
67      public static final String DEFAULT_HIDEINGOOGLESITEMAP_NODEDATA = "googleSitemapHide"; //$NON-NLS-1$
68  
69      /**
70       * Default name for "hideInGoogleSitemapChildren" nodeData.
71       */
72      public static final String DEFAULT_HIDEINGOOGLESITEMAPCHILDREN_NODEDATA = "googleSitemapHideChildren"; //$NON-NLS-1$
73  
74      /**
75       * Default name for "workspace" attribute.
76       */
77      public static final String DEFAULT_WORKSPACE = "website"; //$NON-NLS-1$
78  
79      /**
80       * Default value for "mode" attribute.
81       */
82      public static final String DEFAULT_MODE_VALUE = "xml"; //$NON-NLS-1$
83  
84      /**
85       * Stable serialVersionUID.
86       */
87      private static final long serialVersionUID = 222L;
88  
89      private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
90  
91      private static final Logger log = Logger.getLogger(SitemapTag.class);
92  
93      /**
94       * Start Node.
95       */
96      private String startNode;
97  
98      /**
99       * Workspace.
100      */
101     private String workspace;
102 
103     /**
104      * Name for the "hide in google sitemap" nodeData.
105      */
106     private String hideInGoogleSitemap;
107 
108     /**
109      * Name for the "hide in google sitemap children" nodeData.
110      */
111     private String hideInGoogleSitemapChildren;
112 
113     /**
114      * Name for the "priority" nodeData.
115      */
116     private String priority;
117 
118     /**
119      * Name for the "changefreq" nodeData.
120      */
121     private String changefreq;
122 
123     /**
124      * level of the menu according to the start for the navigation.
125      */
126     private int level;
127 
128     final I18nContentSupport i18nSupport = I18nContentSupportFactory.getI18nSupport();
129 
130     /**
131      * Setter for the <code>startNode</code> tag attribute.
132      *
133      * @param startNode
134      *            where to start in the tree
135      */
136     public void setWorkspace(String workspace) {
137         this.workspace = workspace;
138     }
139 
140     /**
141      * Setter for the <code>startNode</code> tag attribute.
142      *
143      * @param startNode
144      *            where to start in the tree
145      */
146     public void setStartNode(String startNode) {
147         this.startNode = startNode;
148     }
149 
150     /**
151      * Setter for <code>priority</code> tag attribute.
152      *
153      * @param priority
154      *            name for the "priority" nodeData.
155      */
156     public void setPriority(String priority) {
157         this.priority = priority;
158     }
159 
160     /**
161      * Setter for <code>hideInGoogleSitemap</code> tag attribute.
162      *
163      * @param hideInGoogleSitemap
164      *            name for the "hideInGoogleSitemap" nodeData.
165      */
166     public void setHideInGoogleSitemap(String hideInGoogleSitemap) {
167         this.hideInGoogleSitemap = hideInGoogleSitemap;
168     }
169 
170     /**
171      * Setter for <code>hideInGoogleSitemapChildren</code> tag attribute.
172      *
173      * @param hideInGoogleSitemap
174      *            name for the "hideInGoogleSitemap" nodeData.
175      */
176     public void setHideInGoogleSitemapChildren(
177             String hideInGoogleSitemapChildren) {
178         this.hideInGoogleSitemapChildren = hideInGoogleSitemapChildren;
179     }
180 
181     /**
182      * Setter for <code>changefreq</code> tag attribute.
183      *
184      * @param changefreq
185      *            name for the "changefreq" nodeData.
186      */
187     public void setChangefreq(String changefreq) {
188         this.changefreq = changefreq;
189     }
190 
191     /**
192      * @see javax.servlet.jsp.tagext.Tag#doEndTag()
193      */
194     public int doEndTag() throws JspException {
195         Content activePage = MgnlContext.getAggregationState().getMainContent();
196         JspWriter out = this.pageContext.getOut();
197         final HierarchyManager hm = MgnlContext.getHierarchyManager("website");
198 
199         Collection locales = new ArrayList();
200 
201         if (i18nSupport.isEnabled()) {
202             locales = i18nSupport.getLocales();
203         }
204         // defaultBaseUrl
205         final String defaultBaseUrl = ServerConfiguration.getInstance()
206                 .getDefaultBaseUrl();
207 
208         try {
209 
210             if (this.workspace.equals("website"))
211                 if (this.startNode == null) {
212                     drawChildren(activePage.getAncestor(0), activePage, out,
213                             level + 1, defaultBaseUrl, locales);
214                 } else {
215                     drawChildren(hm.getContent(this.startNode), activePage,
216                             out, level + 1, defaultBaseUrl,
217                             locales);
218                 }
219             else if (this.workspace.equals("config")) {
220                 final JspWriter o = out;
221                 new VoidOp(){
222                     public void doExec() {
223                         final String xpath = "//virtualURIMapping//element(*,mgnl:contentNode)";
224                         final Collection nodes = QueryUtil.query("config", xpath, "xpath", "mgnl:contentNode");
225                         try {
226                             drawVirtualURIMapping(nodes, o, defaultBaseUrl);
227                         } catch (IOException e) {
228                             e.printStackTrace();
229                         } catch (RepositoryException e) {
230                             e.printStackTrace();
231                         }
232                     }
233                 };
234             }
235         }
236 
237         catch (RepositoryException e) {
238             // log.error("RepositoryException caught while drawing navigation: " + e.getMessage(), e); //$NON-NLS-1$
239             log.warn("RepositoryException caught while drawing navigation"); //$NON-NLS-1$
240             return EVAL_PAGE;
241         } catch (IOException e) {
242             // should never happen
243             throw new NestableRuntimeException(e);
244         }
245         return EVAL_PAGE;
246 
247     }
248 
249     /**
250      * @see javax.servlet.jsp.tagext.Tag#release()
251      */
252     public void release() {
253         this.startNode = null;
254         this.level = 1;
255         super.release();
256     }
257 
258     private void drawVirtualURIMapping(Collection nodes, JspWriter out,
259             String defaultBaseUrl) throws IOException, RepositoryException {
260 
261         if (nodes.size() == 0) {
262             return;
263         }
264 
265         for (Iterator iter = nodes.iterator(); iter.hasNext();) {
266             Content node = (Content) iter.next();
267 
268             // priority
269             double priority = 0.5;
270             if (node.hasNodeData(StringUtils.defaultString(this.priority,
271                     DEFAULT_PRIORITY_NODEDATA))) {
272                 priority = node.getNodeData(
273                         StringUtils.defaultString(this.priority,
274                                 DEFAULT_PRIORITY_NODEDATA)).getDouble();
275             }
276 
277             // changefreq
278             String changefreq = "weekly";
279             if (node.hasNodeData(StringUtils.defaultString(this.changefreq,
280                     DEFAULT_CHANGEFREQ_NODEDATA))) {
281                 changefreq = node.getNodeData(
282                         StringUtils.defaultString(this.changefreq,
283                                 DEFAULT_CHANGEFREQ_NODEDATA)).getString();
284             }
285 
286             if (!node.getNodeData(
287                     StringUtils.defaultString(this.hideInGoogleSitemap,
288                             DEFAULT_HIDEINGOOGLESITEMAP_NODEDATA)).getBoolean()) {
289                 if (node.getMetaData().hasProperty("mgnl:lastmodified")) {
290                     out.print("<url>"); //$NON-NLS-1$
291                     out.print("<loc>"); //$NON-NLS-1$
292                     // defaultBaseUrl
293                     out.print(defaultBaseUrl);
294                     // context path
295                     out.print(((HttpServletRequest) this.pageContext
296                             .getRequest()).getContextPath());
297                     // handle
298                     out.print(node.getNodeData("fromURI").getString());
299 
300                     out.print("</loc>"); //$NON-NLS-1$
301                     out.print("<lastmod>"); //$NON-NLS-1$
302                     out.print(DATE_FORMAT.format(node.getMetaData().getModificationDate().getTime()));
303                     out.print("</lastmod>"); //$NON-NLS-1$
304                     out.print("<changefreq>"); //$NON-NLS-1$
305                     out.print(changefreq);
306                     out.print("</changefreq>"); //$NON-NLS-1$
307                     out.print("<priority>"); //$NON-NLS-1$
308                     out.print(Double.toString(priority));
309                     out.print("</priority>"); //$NON-NLS-1$
310                     out.print("</url>"); //$NON-NLS-1$
311                 }
312             }
313         }
314     }
315 
316     /**
317      * Draws the sitemap.
318      */
319     private void drawChildren(Content page, Content activePage, JspWriter out,
320             int level, String defaultBaseUrl, Collection locales)
321             throws IOException, RepositoryException {
322         Collection children = page.getChildren(ItemType.CONTENT);
323 
324         if (children.size() == 0) {
325             return;
326         }
327 
328         // id has childs but every is hide in nav
329         Iterator it = children.iterator();
330 
331         it = children.iterator();
332 
333         while (it.hasNext()) {
334             Content child = (Content) it.next();
335 
336             if (!child.getNodeData(
337                     StringUtils.defaultString(this.hideInGoogleSitemap,
338                             DEFAULT_HIDEINGOOGLESITEMAP_NODEDATA)).getBoolean()) {
339 
340             }
341 
342             // priority
343             double priority = 0.5;
344             if (child.hasNodeData(StringUtils.defaultString(this.priority,
345                     DEFAULT_PRIORITY_NODEDATA))) {
346                 priority = child.getNodeData(
347                         StringUtils.defaultString(this.priority,
348                                 DEFAULT_PRIORITY_NODEDATA)).getDouble();
349             }
350 
351             // changefreq
352             String changefreq = "weekly";
353             if (child.hasNodeData(StringUtils.defaultString(this.changefreq,
354                     DEFAULT_CHANGEFREQ_NODEDATA))) {
355                 changefreq = child.getNodeData(
356                         StringUtils.defaultString(this.changefreq,
357                                 DEFAULT_CHANGEFREQ_NODEDATA)).getString();
358             }
359 
360             boolean showChildren = true;
361             // hide all children
362             if (child.getNodeData(
363                     StringUtils.defaultString(this.hideInGoogleSitemap,
364                             DEFAULT_HIDEINGOOGLESITEMAPCHILDREN_NODEDATA))
365                     .getBoolean()) {
366                 showChildren = false;
367             }
368 
369             if (!child.getNodeData(
370                     StringUtils.defaultString(this.hideInGoogleSitemap,
371                             DEFAULT_HIDEINGOOGLESITEMAP_NODEDATA)).getBoolean()
372                     && !child
373                             .getNodeData(
374                                     StringUtils
375                                             .defaultString(
376                                                     this.hideInGoogleSitemap,
377                                                     DEFAULT_HIDEINGOOGLESITEMAPCHILDREN_NODEDATA))
378                             .getBoolean()) {
379                 if (locales.isEmpty()) {
380                     out.print("<url>"); //$NON-NLS-1$
381                     out.print("<loc>"); //$NON-NLS-1$
382                     // defaultBaseUrl
383                     out.print(defaultBaseUrl);
384                     // context path
385                     out.print(((HttpServletRequest) this.pageContext
386                             .getRequest()).getContextPath());
387                     // handle
388                     out.print(child.getHandle());
389                     out.print(".html"); //$NON-NLS-1$
390                     out.print("</loc>"); //$NON-NLS-1$
391                     out.print("<lastmod>"); //$NON-NLS-1$
392                     Calendar lastMod = child.getMetaData().getModificationDate();
393                     out.print(DATE_FORMAT.format(lastMod != null ? lastMod.getTime(): child.getMetaData().getCreationDate().getTime()));
394                     out.print("</lastmod>"); //$NON-NLS-1$
395                     out.print("<changefreq>"); //$NON-NLS-1$
396                     out.print(changefreq);
397                     out.print("</changefreq>"); //$NON-NLS-1$
398                     out.print("<priority>"); //$NON-NLS-1$
399                     out.print(Double.toString(priority));
400                     out.print("</priority>"); //$NON-NLS-1$
401                     out.print("</url>"); //$NON-NLS-1$
402 
403                 } else {
404                     Locale currentLocale = i18nSupport.getLocale();
405                     for (Iterator iter = locales.iterator(); iter.hasNext();) {
406                         Locale locale = (Locale) iter.next();
407                         out.print("<url>"); //$NON-NLS-1$
408                         out.print("<loc>"); //$NON-NLS-1$
409                         // defaultBaseUrl
410                         out.print(defaultBaseUrl);
411                         // context path
412                         out.print(((HttpServletRequest) this.pageContext
413                                 .getRequest()).getContextPath());
414                         i18nSupport.setLocale(locale);
415                         out.print(MagnoliaTemplatingUtilities.getInstance().createLink(child));
416                         out.print("</loc>"); //$NON-NLS-1$
417                         out.print("<lastmod>"); //$NON-NLS-1$
418                         Calendar lastMod = child.getMetaData().getModificationDate();
419                         out.print(DATE_FORMAT.format(lastMod != null ? lastMod.getTime(): child.getMetaData().getCreationDate().getTime()));
420                         out.print("</lastmod>"); //$NON-NLS-1$
421                         out.print("<changefreq>"); //$NON-NLS-1$
422                         out.print(changefreq);
423                         out.print("</changefreq>"); //$NON-NLS-1$
424                         out.print("<priority>"); //$NON-NLS-1$
425                         out.print(Double.toString(priority));
426                         out.print("</priority>"); //$NON-NLS-1$
427                         out.print("</url>"); //$NON-NLS-1$
428                     }
429                     //set back to current locale
430                     i18nSupport.setLocale(currentLocale);
431                 }
432             }
433             if (showChildren) {
434                 drawChildren(child, activePage, out, level + 1,
435                         defaultBaseUrl, locales);
436             }
437         }
438     }
439 }