Clover icon

Google Sitemap Module 2.4.3

  1. Project Clover database Thu May 11 2017 16:52:32 CEST
  2. Package info.magnolia.module.googlesitemap.service

File SiteMapService.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart8.png
40% of files have more coverage

Code metrics

62
111
13
1
365
206
51
0.46
8.54
13
3.92

Classes

Class Line # Actions
SiteMapService 76 111 0% 51 43
0.768817276.9%
 

Contributing tests

This file is covered by 16 tests. .

Source view

1    /**
2    * This file Copyright (c) 2012-2017 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.googlesitemap.service;
35   
36    import info.magnolia.cms.i18n.I18nContentSupport;
37    import info.magnolia.context.MgnlContext;
38    import info.magnolia.jcr.util.NodeTypes;
39    import info.magnolia.jcr.util.NodeUtil;
40    import info.magnolia.link.LinkUtil;
41    import info.magnolia.module.googlesitemap.GoogleSiteMapConfiguration;
42    import info.magnolia.module.googlesitemap.SiteMapNodeTypes;
43    import info.magnolia.module.googlesitemap.bean.SiteMapEntry;
44    import info.magnolia.module.googlesitemap.service.query.QueryUtil;
45    import info.magnolia.module.site.Site;
46    import info.magnolia.module.site.SiteManager;
47    import info.magnolia.objectfactory.Components;
48    import info.magnolia.repository.RepositoryConstants;
49   
50    import java.util.ArrayList;
51    import java.util.HashSet;
52    import java.util.Iterator;
53    import java.util.List;
54    import java.util.Locale;
55    import java.util.Set;
56   
57    import javax.inject.Inject;
58    import javax.inject.Singleton;
59    import javax.jcr.Node;
60    import javax.jcr.NodeIterator;
61    import javax.jcr.RepositoryException;
62    import javax.jcr.Session;
63   
64    import org.apache.jackrabbit.commons.iterator.FilteringNodeIterator;
65    import org.apache.jackrabbit.commons.predicate.NodeTypePredicate;
66    import org.slf4j.Logger;
67    import org.slf4j.LoggerFactory;
68   
69    /**
70    * Main SiteMapService.
71    * This service is responsible for:
72    * Searching the appropriate nodes (pages or VirtualUri) that should be displayed (for XML rendering or Editing).
73    * From the search nodes, create SiteMapEntrys (POJO containing preformated infos used for the rendering).
74    */
75    @Singleton
 
76    public class SiteMapService {
77   
78    private static final Logger log = LoggerFactory.getLogger(SiteMapService.class);
79   
80    /**
81    * Injected service.
82    */
83    private SiteManager siteManager;
84    private I18nContentSupport i18nSupport;
85    private GoogleSiteMapConfiguration configuration;
86    private QueryUtil queryUtil;
87   
88    /**
89    * Constructor for injection.
90    *
91    * @param siteManager: Injected.
92    */
 
93  13 toggle @Inject
94    public SiteMapService(SiteManager siteManager, GoogleSiteMapConfiguration configuration, QueryUtil queryUtil) {
95  13 this.siteManager = siteManager;
96  13 this.configuration = configuration;
97  13 this.queryUtil = queryUtil;
98  13 i18nSupport = Components.getComponent(I18nContentSupport.class);
99    }
100   
101    /**
102    * Create the SiteMapEntry List corresponding to <br>
103    * - uriMapping if isForVirtualUri = true or<br>
104    * - for all child's of the rootNode that are of type MgnlNodeType.NT_CONTENT otherwise.
105    */
 
106  18 toggle public List<SiteMapEntry> getSiteMapBeans(Node siteMapNode, boolean isForVirtualUri, boolean isForEdit) throws RepositoryException {
107    // Init
108  18 List<SiteMapEntry> res = new ArrayList<SiteMapEntry>();
109  18 final String changefreq = SiteMapNodeTypes.SiteMap.getDefaultChangeFreq(siteMapNode) != null ? SiteMapNodeTypes.SiteMap.getDefaultChangeFreq(siteMapNode) : configuration.getChangeFrequency();
110  18 final Double priority = SiteMapNodeTypes.SiteMap.getDefaultPriority(siteMapNode) != null ? SiteMapNodeTypes.SiteMap.getDefaultPriority(siteMapNode) : configuration.getPriority();
111  18 Session webSiteSession = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE);
112   
113  18 NodeIterator nodeIterator = null;
114  18 if (isForVirtualUri) {
115  7 log.debug("Requested virtualUri info's for EDIT='{}", isForEdit);
116    // Create a virtualUri info beans
117  7 nodeIterator = searchVirtualUriNodes();
118  7 feedVirtualUriMapBeans(res, nodeIterator, isForEdit, changefreq, priority);
119    } else {
120  11 log.debug("Requested siteMap info's for EDIT='{}' based on the following root {} ", isForEdit, siteMapNode.getPath());
121    // Create a site info beans
122   
123  11 List<String> pages = SiteMapNodeTypes.SiteMap.getPages(siteMapNode);
124  11 for (String id : pages) {
125   
126  13 if (!webSiteSession.nodeExists(id)) {
127  0 log.debug("Page '{}' is not visible. This page will not be added to the result list", id);
128  0 continue;
129    }
130  13 Node page = webSiteSession.getNode(id);
131  13 nodeIterator = searchSiteChildNodes(page);
132  13 feedSiteMapBeans(res, nodeIterator, isForEdit, null, changefreq, priority, page.getDepth());
133    }
134    }
135   
136  18 return res;
137    }
138   
139    /**
140    * Search the nodes related to the UriMappings.
141    */
 
142  7 toggle private NodeIterator searchVirtualUriNodes() {
143  7 NodeIterator nodes = null;
144   
145  7 String xpath = "//virtualURIMapping//element(*," + NodeTypes.ContentNode.NAME + ")";
146  7 nodes = queryUtil.query(RepositoryConstants.CONFIG, xpath, "xpath", NodeTypes.ContentNode.NAME);
147   
148  7 return nodes;
149    }
150   
151    /**
152    * Extract informations form the Node and create a Bean used in the display
153    * for Edit and XML rendering.
154    */
 
155  7 toggle private void feedVirtualUriMapBeans(List<SiteMapEntry> siteMapBeans, NodeIterator nodes, boolean isForEdit, String changefreq, Double priority) throws RepositoryException {
156   
157  21 while (nodes.hasNext()) {
158    // Init
159  14 Node child = nodes.nextNode();
160  14 if (hasToBePopulated(child, true, isForEdit, null)) {
161    // Populate the Bean used by the display
162  14 SiteMapEntry siteMapBean = populateBean(child, true, isForEdit, null, null, changefreq, priority, 0);
163    // Add the bean to the result
164  14 siteMapBeans.add(siteMapBean);
165    }
166    }
167    }
168   
169    /**
170    * Search children of the root Node of type MgnlNodeType.NT_CONTENT and all inherited node types.
171    *
172    * @throws RepositoryException
173    */
 
174  79 toggle private NodeIterator searchSiteChildNodes(Node root) throws RepositoryException {
175  79 NodeIterator nodes = null;
176   
177  79 NodeTypePredicate predicate = new NodeTypePredicate(NodeTypes.Content.NAME, true);
178  79 nodes = new FilteringNodeIterator(root.getNodes(), predicate);
179   
180  79 return nodes;
181    }
182   
183    /**
184    * Create a new SiteMapEntry POJO for all node from the NodeIterator if required.
185    */
 
186  34 toggle private void feedSiteMapBeans(List<SiteMapEntry> siteMapBeans, NodeIterator nodes, boolean isForEdit, Boolean inheritedParentDisplayColor, String changefreq, Double priority, int rootLevel) throws RepositoryException {
187   
188  100 while (nodes.hasNext()) {
189    // Init
190  66 Node page = nodes.nextNode();
191  66 Site site = siteManager.getAssignedSite(page);
192  66 if (!hasToBePopulated(page, false, isForEdit, site)) {
193  0 log.debug("Page '' is not part of the site map.", NodeUtil.getNodePathIfPossible(page));
194  0 continue;
195    }
196   
197    // Populate the Bean
198  66 SiteMapEntry siteMapBean = populateBean(page, false, isForEdit, site, inheritedParentDisplayColor, changefreq, priority, rootLevel);
199  66 NodeIterator childNodes = searchSiteChildNodes(page);
200  66 boolean hasChild = (childNodes != null && childNodes.hasNext());
201   
202  66 if (isForEdit) {
203    // Handle Edit Mode. Always all the bean.
204  48 siteMapBeans.add(siteMapBean);
205   
206  48 if (hasChild) {
207    // Handle the children if any
208  21 Boolean hideNodeChildInGoogleSitemapTmp = null;
209    // Handle the color of the child to be display.
210  21 if (inheritedParentDisplayColor != null) {
211  0 hideNodeChildInGoogleSitemapTmp = inheritedParentDisplayColor;
212  21 } else if (SiteMapNodeTypes.GoogleSiteMap.isHideChildren(page)) {
213  5 hideNodeChildInGoogleSitemapTmp = Boolean.TRUE;
214    }
215   
216  21 feedSiteMapBeans(siteMapBeans, childNodes, isForEdit, hideNodeChildInGoogleSitemapTmp, changefreq, priority, rootLevel);
217    }
218   
219    } else {
220    // Handle XML Display Mode
221    // If node has to be display.
222  18 if (!SiteMapNodeTypes.GoogleSiteMap.isHide(page)) {
223    // Check Multilang.
224  14 if (i18nSupport.isEnabled() && site.getI18n().isEnabled()) {
225  0 Locale currentLocale = i18nSupport.getLocale();
226  0 for (Locale locale : site.getI18n().getLocales()) {
227  0 i18nSupport.setLocale(locale);
228  0 SiteMapEntry siteMapBeanLocale = populateBean(page, false, isForEdit, site, null, changefreq, priority, rootLevel);
229  0 if (siteMapBeanLocale != null) {
230  0 siteMapBeans.add(siteMapBeanLocale);
231    }
232    }
233  0 i18nSupport.setLocale(currentLocale);
234    } else {
235  14 siteMapBeans.add(siteMapBean);
236    }
237    }
238    // Check if Child Node has to be included
239  18 if (hasChild && !SiteMapNodeTypes.GoogleSiteMap.isHideChildren(page)) {
240    // Call recursively
241  0 feedSiteMapBeans(siteMapBeans, childNodes, isForEdit, null, changefreq, priority, rootLevel);
242    }
243    }
244    }
245    }
246   
247    /**
248    * Populate the Bean.
249    */
 
250  80 toggle private SiteMapEntry populateBean(Node child, boolean isForUriMapping, boolean isForEdit, Site site, Boolean inheritedParentDisplayColor, String changefreq, Double priority, int rootLevel) throws RepositoryException {
251  80 SiteMapEntry res = null;
252    // Populate only if true
253  80 if (hasToBePopulated(child, isForUriMapping, isForEdit, site)) {
254   
255  80 String loc = null;
256   
257    // Get loc
258  80 if (isForUriMapping) {
259  14 loc = child.hasProperty("fromURI") ? MgnlContext.getContextPath() + child.getProperty("fromURI").getString() : "";
260    } else {
261  66 loc = LinkUtil.createExternalLink(child);
262    }
263   
264    // Populate the bean:
265  80 res = new SiteMapEntry(configuration, loc, child, rootLevel, changefreq, priority);
266  80 log.debug("Populate Basic info for Node: " + child.getPath() + " with values " + res.toStringDisplay());
267   
268  80 if (isForEdit) {
269  48 res = populateBeanForEdit(child, isForUriMapping, res, inheritedParentDisplayColor);
270    }
271    }
272   
273  80 return res;
274    }
275   
276    /**
277    * Add additional info's for Edit.
278    */
 
279  48 toggle private SiteMapEntry populateBeanForEdit(Node child, boolean isForUriMapping, SiteMapEntry siteMapBean, Boolean inheritedParentDisplayColor) throws RepositoryException {
280   
281  48 if (isForUriMapping) {
282    // For VirtualUri
283  0 siteMapBean.setFrom(child.hasProperty("fromURI") ? child.getProperty("fromURI").getString() : "");
284  0 siteMapBean.setTo(child.hasProperty("toURI") ? child.getProperty("toURI").getString() : "");
285  0 siteMapBean.setStyleAlert(SiteMapNodeTypes.GoogleSiteMap.isHide(child));
286  0 log.debug("Populate Edit VirtualUri info for Node: " + child.getPath() + " with values " + siteMapBean.toStringVirtualUri());
287    } else {
288    // For Site
289  48 siteMapBean.setPageName(child.hasProperty("title") ? child.getProperty("title").getString() : "");
290  48 siteMapBean.setStyleAlert(inheritedParentDisplayColor != null ? inheritedParentDisplayColor.booleanValue() : SiteMapNodeTypes.GoogleSiteMap.isHide(child));
291  48 log.debug("Populate Edit Site info for Node: " + child.getPath() + " with values " + siteMapBean.toStringSite());
292    }
293  48 return siteMapBean;
294    }
295   
296    /**
297    * Check if the node has to be populated.<br>
298    * True for UriMapping if:<br>
299    * !hideInGoogleSitemap && node has a modification date<br>
300    * True for Site if:<br>
301    * !hideInGoogleSitemap && !hideInGoogleSitemapChildren && node has a creation date && site.isEnabled()<br>
302    */
 
303  160 toggle private boolean hasToBePopulated(Node child, boolean isForUriMapping, boolean isForEdit, Site site) throws RepositoryException {
304  160 boolean hasCreationDate = NodeTypes.Created.getCreated(child) != null;
305  160 boolean hasModificationDate = NodeTypes.LastModified.getLastModified(child) != null;
306   
307    // For edit and if has creation date --> true.
308  160 if (isForEdit) {
309  96 return hasCreationDate;
310    }
311   
312    // Node has a property set to hide node to be display --> false.
313  64 if (SiteMapNodeTypes.GoogleSiteMap.isHide(child) && (isForUriMapping || SiteMapNodeTypes.GoogleSiteMap.isHideChildren(child))) {
314  0 return false;
315    }
316    // For uriMapping.
317  64 if (isForUriMapping && hasModificationDate) {
318  28 return true;
319    }
320    // For site.
321  36 if (!isForUriMapping && site.isEnabled() && hasCreationDate) {
322  36 return true;
323    }
324  0 return false;
325    }
326   
327    /**
328    * Get Site and virtualUri informations if they are defined as components.
329    * Notice that by using a HashSet, a single object will be keeped in case of equality of the location.
330    */
 
331  6 toggle public Iterator<SiteMapEntry> getSiteMapBeans(Node siteMapNode) throws RepositoryException {
332  6 Set<SiteMapEntry> res = new HashSet<SiteMapEntry>();
333    // Return if no content set.
334  6 if (!NodeUtil.isNodeType(siteMapNode, SiteMapNodeTypes.SiteMap.NAME)) {
335  1 return res.iterator();
336    }
337    // Display Site informations part... if defined
338  5 res.addAll(getSiteMapBeans(siteMapNode, false, false));
339  5 if (SiteMapNodeTypes.SiteMap.isVirtualUriMappingIncluded(siteMapNode)) {
340  5 res.addAll(getSiteMapBeans(siteMapNode, true, false));
341    }
342  5 return res.iterator();
343    }
344   
345    /**
346    * Based on a {@link SiteMapEntry} bean, update the related page property. <br>
347    * Update the page last modification date in order to visualize that the changes has to be published <br>
348    * in order to be visible on the public instance.<br>
349    */
 
350  4 toggle public Node updatePageNode(SiteMapEntry entry) throws RepositoryException {
351  4 Node pageNode = MgnlContext.getJCRSession(RepositoryConstants.WEBSITE).getNode(entry.getPath());
352  4 return updateNode(entry, pageNode);
353    }
354   
 
355  0 toggle public Node updateVirtualUriNode(SiteMapEntry entry) throws RepositoryException {
356  0 Node virtualUriNode = MgnlContext.getJCRSession(RepositoryConstants.CONFIG).getNode(entry.getPath());
357  0 return updateNode(entry, virtualUriNode);
358    }
359   
 
360  4 toggle private Node updateNode(SiteMapEntry entry, Node node) throws RepositoryException {
361  4 SiteMapNodeTypes.GoogleSiteMap.update(node, entry.getChangefreq(), entry.getPriority(), entry.isHide(), entry.isHideChildren());
362  4 NodeTypes.LastModified.update(node);
363  4 return node;
364    }
365    }