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