1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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.predicate.AbstractPredicate;
39 import info.magnolia.jcr.util.NodeTypes;
40 import info.magnolia.jcr.util.NodeUtil;
41 import info.magnolia.jcr.util.SessionUtil;
42 import info.magnolia.jcr.wrapper.JCRMgnlPropertiesFilteringNodeWrapper;
43 import info.magnolia.link.LinkUtil;
44 import info.magnolia.module.googlesitemap.GoogleSiteMapConfiguration;
45 import info.magnolia.module.googlesitemap.bean.SiteMapEntry;
46 import info.magnolia.module.googlesitemap.service.query.QueryUtil;
47 import info.magnolia.module.templatingkit.sites.Site;
48 import info.magnolia.module.templatingkit.sites.SiteManager;
49 import info.magnolia.objectfactory.Components;
50 import info.magnolia.repository.RepositoryConstants;
51
52 import java.util.ArrayList;
53 import java.util.Calendar;
54 import java.util.HashSet;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Locale;
58 import java.util.Set;
59
60 import javax.inject.Inject;
61 import javax.inject.Singleton;
62 import javax.jcr.Node;
63 import javax.jcr.NodeIterator;
64 import javax.jcr.Property;
65 import javax.jcr.PropertyIterator;
66 import javax.jcr.RepositoryException;
67
68 import org.apache.commons.lang.StringUtils;
69 import org.apache.jackrabbit.commons.iterator.FilteringNodeIterator;
70 import org.apache.jackrabbit.commons.predicate.NodeTypePredicate;
71 import org.apache.jackrabbit.commons.predicate.Predicate;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75
76
77
78
79
80
81
82
83
84
85 @Singleton
86 public class SiteMapService {
87
88 private static final Logger log = LoggerFactory.getLogger(SiteMapService.class);
89
90
91 private static Predicate All_Site_Nodes = new AbstractPredicate<Node>() {
92 @Override
93 public boolean evaluateTyped(Node node) {
94 try {
95 return node.getName().startsWith(GoogleSiteMapConfiguration.SITE_DIALOG_CONFIGURATION_NAME);
96 } catch (RepositoryException e) {
97 return false;
98 }
99 }
100 };
101
102
103
104
105 private SiteManager siteManager;
106 private I18nContentSupport i18nSupport;
107 private GoogleSiteMapConfiguration configuration;
108 private QueryUtil queryUtil;
109
110
111
112
113
114
115 @Inject
116 public SiteMapService(SiteManager siteManager, GoogleSiteMapConfiguration configuration, QueryUtil queryUtil) {
117 this.siteManager = siteManager;
118 this.configuration = configuration;
119 this.queryUtil = queryUtil;
120 i18nSupport = Components.getComponent(I18nContentSupport.class);
121 }
122
123
124
125
126
127 public List<SiteMapEntry> getSiteMapBeanForVirtualUri( boolean isForEdit) throws RepositoryException{
128
129 List<SiteMapEntry> res = new ArrayList<SiteMapEntry>();
130 NodeIterator nodeIterator = null;
131
132 log.info("Requested virtualUri info's for EDIT ");
133
134 nodeIterator = searchVirtualUriNodes();
135 feedVirtualUriMapBeans(res, nodeIterator, isForEdit);
136
137 return res;
138 }
139
140
141
142
143 public List<SiteMapEntry> getSiteMapBeanForSite(Node rootNode, boolean isForEdit) throws RepositoryException{
144
145 List<SiteMapEntry> res = new ArrayList<SiteMapEntry>();
146 NodeIterator nodeIterator = null;
147
148 log.info("Requested siteMap info's for EDIT based on the following root: "+rootNode.getPath());
149
150 nodeIterator = searchSiteChildNodes(rootNode);
151 feedSiteMapBeans(res, nodeIterator, isForEdit, null);
152
153 return res;
154 }
155
156
157
158
159 private NodeIterator searchVirtualUriNodes() {
160 NodeIterator nodes = null;
161
162 String xpath = "//virtualURIMapping//element(*," + NodeTypes.ContentNode.NAME + ")";
163 nodes = queryUtil.query(RepositoryConstants.CONFIG, xpath, "xpath", NodeTypes.ContentNode.NAME);
164
165 return nodes;
166 }
167
168
169
170
171
172
173 private void feedVirtualUriMapBeans(List<SiteMapEntry> siteMapBeans, NodeIterator nodes, boolean isForEdit) throws RepositoryException {
174 while(nodes.hasNext()) {
175
176 Node child = nodes.nextNode();
177 if(hasToBePopulated(child, true, isForEdit, null)) {
178
179 SiteMapEntry siteMapBean = populateBean(child, true, isForEdit , null, null);
180
181 siteMapBeans.add(siteMapBean);
182 }
183 }
184 }
185
186
187
188
189
190
191 private NodeIterator searchSiteChildNodes(Node root) throws RepositoryException {
192 NodeIterator nodes = null;
193
194 NodeTypePredicate predicate = new NodeTypePredicate(NodeTypes.Content.NAME, true);
195 nodes = new FilteringNodeIterator(root.getNodes(), predicate);
196
197 return nodes;
198 }
199
200
201
202
203
204 private void feedSiteMapBeans(List<SiteMapEntry> siteMapBeans, NodeIterator nodes, boolean isForEdit, Boolean inheritedParentDisplayColor) throws RepositoryException {
205
206 while(nodes.hasNext()) {
207
208 Node child = nodes.nextNode();
209 Site site = siteManager.getAssignedSite(child);
210
211 if(hasToBePopulated(child, false, isForEdit, site)) {
212
213 SiteMapEntry siteMapBean = populateBean(child, false, isForEdit , site, inheritedParentDisplayColor);
214 NodeIterator childNodes = searchSiteChildNodes(child);
215 boolean hasChild = (childNodes!=null && childNodes.hasNext()) ? true:false;
216
217 if(isForEdit) {
218
219 siteMapBeans.add(siteMapBean);
220
221 if(hasChild) {
222
223 Boolean hideNodeChildInGoogleSitemapTmp = null;
224
225 if(inheritedParentDisplayColor != null) {
226 hideNodeChildInGoogleSitemapTmp = inheritedParentDisplayColor;
227 }else if(hideNodeChildInGoogleSitemap(child)) {
228 hideNodeChildInGoogleSitemapTmp = Boolean.TRUE;
229 }
230
231 feedSiteMapBeans(siteMapBeans, childNodes, isForEdit, hideNodeChildInGoogleSitemapTmp);
232 }
233
234 } else {
235
236
237 if (!hideNodeInGoogleSitemap(child)){
238
239 if(i18nSupport.isEnabled() && site.getI18n().isEnabled()) {
240 Locale currentLocale = i18nSupport.getLocale();
241 for(Locale locale:site.getI18n().getLocales() ){
242 i18nSupport.setLocale(locale);
243 SiteMapEntry siteMapBeanLocale = populateBean(child, false, isForEdit, site, null);
244 if(siteMapBeanLocale != null) {
245 siteMapBeans.add(siteMapBeanLocale);
246 }
247 }
248 i18nSupport.setLocale(currentLocale);
249 } else {
250 siteMapBeans.add(siteMapBean);
251 }
252 }
253
254 if(hasChild && !hideNodeChildInGoogleSitemap(child)) {
255
256 feedSiteMapBeans(siteMapBeans, childNodes, isForEdit, null);
257 }
258
259 }
260
261 }
262
263 }
264 }
265
266
267
268
269 private SiteMapEntry populateBean( Node child, boolean isForUriMapping, boolean isForEdit, Site site, Boolean inheritedParentDisplayColor ) throws RepositoryException {
270 SiteMapEntry res = null;
271
272 if(hasToBePopulated(child, isForUriMapping, isForEdit, site)) {
273 double priority = 0.5;
274 String changefreq = "weekly";
275 String lastmod = "";
276 int level = -1;
277 String loc = null;
278
279
280 level = child.getDepth();
281
282
283 if(child.hasProperty(GoogleSiteMapConfiguration.DEFAULT_PRIORITY_NODEDATA)) {
284 priority = child.getProperty(GoogleSiteMapConfiguration.DEFAULT_PRIORITY_NODEDATA).getDouble();
285 }
286
287
288 if(child.hasProperty(GoogleSiteMapConfiguration.DEFAULT_CHANGEFREQ_NODEDATA)) {
289 changefreq = child.getProperty(GoogleSiteMapConfiguration.DEFAULT_CHANGEFREQ_NODEDATA).getString();
290 }
291
292
293 Calendar date = null;
294 if (NodeTypes.LastModified.getLastModified(child) != null) {
295 date = NodeTypes.LastModified.getLastModified(child);
296 } else {
297 date = NodeTypes.Created.getCreated(child);
298 }
299 lastmod = configuration.getFastDateFormat().format(date.getTime());
300
301
302 if(isForUriMapping) {
303 loc = child.hasProperty("fromURI")? MgnlContext.getContextPath()+child.getProperty("fromURI").getString() : "";
304 }else {
305 loc = LinkUtil.createExternalLink(child);
306 }
307
308
309 res = new SiteMapEntry(loc, lastmod, changefreq, Double.toString(priority), level);
310 log.debug("Populate Basic info for Node: "+child.getPath()+ " with values "+res.toStringDisplay());
311
312 if(isForEdit) {
313 res = populateBeanForEdit(child, isForUriMapping, res, inheritedParentDisplayColor);
314 }
315 }
316
317 return res;
318 }
319
320
321
322
323
324 private SiteMapEntry populateBeanForEdit(Node child, boolean isForUriMapping, SiteMapEntry siteMapBean, Boolean inheritedParentDisplayColor) throws RepositoryException {
325
326 siteMapBean.setPath(child.getPath());
327
328 if(isForUriMapping) {
329
330 siteMapBean.setFrom(child.hasProperty("fromURI")?child.getProperty("fromURI").getString():"");
331 siteMapBean.setTo(child.hasProperty("toURI")?child.getProperty("toURI").getString():"");
332 siteMapBean.setStyleAlert(hideNodeInGoogleSitemap(child));
333 log.debug("Populate Edit VirtualUri info for Node: "+child.getPath()+ " with values "+siteMapBean.toStringVirtualUri());
334 } else {
335
336 siteMapBean.setPageName(child.hasProperty("title")?child.getProperty("title").getString():"");
337 siteMapBean.setStyleAlert(inheritedParentDisplayColor!=null?inheritedParentDisplayColor.booleanValue():hideNodeInGoogleSitemap(child));
338 log.debug("Populate Edit Site info for Node: "+child.getPath()+ " with values "+siteMapBean.toStringSite());
339 }
340 return siteMapBean;
341 }
342
343
344
345
346
347
348
349
350
351
352 private boolean hasToBePopulated( Node child, boolean isForUriMapping, boolean isForEdit, Site site ) throws RepositoryException {
353 boolean hasCreationDate = NodeTypes.Created.getCreated(child) != null;
354 boolean hasModificationDate = NodeTypes.LastModified.getLastModified(child) != null;
355 boolean hasTemplate = StringUtils.isNotBlank(NodeTypes.Renderable.getTemplate(child));
356
357
358 if (hasTemplate && NodeTypes.Renderable.getTemplate(child).endsWith(GoogleSiteMapConfiguration.SITE_MAP_TEMPLATE_NAME)) {
359 return false;
360 }
361
362
363 if(isForEdit) {
364 return hasCreationDate;
365 }
366
367
368 if(hideNodeInGoogleSitemap(child) && (isForUriMapping || hideNodeChildInGoogleSitemap(child))) {
369 return false;
370 }
371
372 if(isForUriMapping && hasModificationDate) {
373 return true;
374 }
375
376 if(!isForUriMapping && site.isEnabled() && hasCreationDate ) {
377 return true;
378 }
379
380 return false;
381 }
382
383
384
385
386 private boolean hideNodeInGoogleSitemap(Node child) throws RepositoryException {
387 boolean res = false;
388
389 if(child.hasProperty(GoogleSiteMapConfiguration.DEFAULT_HIDEINGOOGLESITEMAP_NODEDATA)) {
390 res = child.getProperty(GoogleSiteMapConfiguration.DEFAULT_HIDEINGOOGLESITEMAP_NODEDATA).getBoolean();
391 }
392
393 return res;
394 }
395
396
397
398
399 private boolean hideNodeChildInGoogleSitemap(Node child) throws RepositoryException {
400 boolean res = false;
401
402 if(child.hasProperty(GoogleSiteMapConfiguration.DEFAULT_HIDEINGOOGLESITEMAPCHILDREN_NODEDATA)) {
403 res = child.getProperty(GoogleSiteMapConfiguration.DEFAULT_HIDEINGOOGLESITEMAPCHILDREN_NODEDATA).getBoolean();
404 }
405
406 return res;
407 }
408
409
410
411
412
413
414 public Iterator<SiteMapEntry> getSiteMapBeans(Node content) throws RepositoryException {
415 Set<SiteMapEntry> res = new HashSet<SiteMapEntry>();
416
417 if (!NodeUtil.isNodeType(content, GoogleSiteMapConfiguration.NODE_TYPE)) {
418 return res.iterator();
419 }
420
421
422 Node node = null;
423 Iterator<Node> iterator = NodeUtil.collectAllChildren(content, All_Site_Nodes).iterator();
424 while (iterator.hasNext()) {
425
426 node = iterator.next();
427
428 Node childNode = new JCRMgnlPropertiesFilteringNodeWrapper(node);
429 PropertyIterator properties = childNode.getProperties();
430
431 while (properties.hasNext()) {
432 Property property = properties.nextProperty();
433 Node root = SessionUtil.getNode(RepositoryConstants.WEBSITE, property.getString());
434
435 res.addAll(getSiteMapBeanForSite(root, false));
436
437 }
438 }
439
440 boolean includeVirtualUris =
441 content.hasProperty(GoogleSiteMapConfiguration.INCLUDE_VIRTUAL_URI_MAPPINGS_PROPERTIES) &&
442 content.getProperty(GoogleSiteMapConfiguration.INCLUDE_VIRTUAL_URI_MAPPINGS_PROPERTIES).getBoolean();
443 if (includeVirtualUris) {
444 res.addAll(getSiteMapBeanForVirtualUri(false));
445 }
446 return res.iterator();
447 }
448
449 }