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.templating.functions;
35
36 import info.magnolia.cms.beans.config.ServerConfiguration;
37 import info.magnolia.cms.core.AggregationState;
38 import info.magnolia.cms.core.MetaData;
39 import info.magnolia.cms.core.MgnlNodeType;
40 import info.magnolia.cms.core.NodeData;
41 import info.magnolia.cms.i18n.I18nContentSupportFactory;
42 import info.magnolia.cms.util.ContentUtil;
43 import info.magnolia.cms.util.QueryUtil;
44 import info.magnolia.cms.util.SiblingsHelper;
45 import info.magnolia.jcr.inheritance.InheritanceNodeWrapper;
46 import info.magnolia.jcr.util.ContentMap;
47 import info.magnolia.jcr.util.NodeUtil;
48 import info.magnolia.jcr.util.PropertyUtil;
49 import info.magnolia.jcr.util.SessionUtil;
50 import info.magnolia.jcr.wrapper.HTMLEscapingNodeWrapper;
51 import info.magnolia.link.LinkUtil;
52 import info.magnolia.objectfactory.Components;
53 import info.magnolia.rendering.template.configured.ConfiguredInheritance;
54 import info.magnolia.repository.RepositoryConstants;
55 import info.magnolia.templating.inheritance.DefaultInheritanceContentDecorator;
56
57 import java.util.ArrayList;
58 import java.util.Collection;
59 import java.util.List;
60
61 import javax.inject.Inject;
62 import javax.inject.Provider;
63 import javax.jcr.Node;
64 import javax.jcr.PathNotFoundException;
65 import javax.jcr.Property;
66 import javax.jcr.PropertyType;
67 import javax.jcr.RepositoryException;
68
69 import org.apache.commons.lang.StringUtils;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73
74
75
76
77
78 public class TemplatingFunctions {
79
80 private static final Logger log = LoggerFactory.getLogger(TemplatingFunctions.class);
81
82 private final Provider<AggregationState> aggregationStateProvider;
83
84
85 @Inject
86 public TemplatingFunctions(Provider<AggregationState> aggregationStateProvider) {
87 this.aggregationStateProvider = aggregationStateProvider;
88 }
89
90
91 public Node asJCRNode(ContentMap contentMap) {
92 return contentMap == null ? null : contentMap.getJCRNode();
93 }
94
95 public ContentMap asContentMap(Node content) {
96 return content == null ? null : new ContentMap(content);
97 }
98
99 public List<Node> children(Node content) throws RepositoryException {
100 return content == null ? null : asNodeList(NodeUtil.getNodes(content, NodeUtil.EXCLUDE_META_DATA_FILTER));
101 }
102
103 public List<Node> children(Node content, String nodeTypeName) throws RepositoryException {
104 return content == null ? null : asNodeList(NodeUtil.getNodes(content, nodeTypeName));
105 }
106
107 public List<ContentMap> children(ContentMap content) throws RepositoryException {
108 return content == null ? null : asContentMapList(NodeUtil.getNodes(asJCRNode(content), NodeUtil.EXCLUDE_META_DATA_FILTER));
109 }
110
111 public List<ContentMap> children(ContentMap content, String nodeTypeName) throws RepositoryException {
112 return content == null ? null : asContentMapList(NodeUtil.getNodes(asJCRNode(content), nodeTypeName));
113 }
114
115 public ContentMap root(ContentMap contentMap) throws RepositoryException {
116 return contentMap == null ? null : asContentMap(this.root(contentMap.getJCRNode()));
117 }
118
119 public ContentMap root(ContentMap contentMap, String nodeTypeName) throws RepositoryException {
120 return contentMap == null ? null : asContentMap(this.root(contentMap.getJCRNode(), nodeTypeName));
121 }
122
123 public Node root(Node content) throws RepositoryException {
124 return this.root(content, null);
125 }
126
127 public Node root(Node content, String nodeTypeName) throws RepositoryException {
128 if (content == null) {
129 return null;
130 }
131 if (nodeTypeName == null) {
132 return (Node) content.getAncestor(0);
133 }
134 if (isRoot(content) && content.isNodeType(nodeTypeName)) {
135 return content;
136 }
137
138 Node parentNode = this.parent(content, nodeTypeName);
139 while (parent(parentNode, nodeTypeName) != null) {
140 parentNode = this.parent(parentNode, nodeTypeName);
141 }
142 return parentNode;
143 }
144
145 public ContentMap parent(ContentMap contentMap) throws RepositoryException {
146 return contentMap == null ? null : asContentMap(this.parent(contentMap.getJCRNode()));
147 }
148
149 public ContentMap parent(ContentMap contentMap, String nodeTypeName) throws RepositoryException {
150 return contentMap == null ? null : asContentMap(this.parent(contentMap.getJCRNode(), nodeTypeName));
151 }
152
153 public Node parent(Node content) throws RepositoryException {
154 return this.parent(content, null);
155 }
156
157 public Node parent(Node content, String nodeTypeName) throws RepositoryException {
158 if (content == null) {
159 return null;
160 }
161 if (isRoot(content)) {
162 return null;
163 }
164 if (nodeTypeName == null) {
165 return content.getParent();
166 }
167 Node parent = content.getParent();
168 while (!parent.isNodeType(nodeTypeName)) {
169 if (isRoot(parent)) {
170 return null;
171 }
172 parent = parent.getParent();
173 }
174 return parent;
175 }
176
177
178
179
180
181
182
183
184
185 public ContentMap page(ContentMap content) throws RepositoryException {
186 return content == null ? null : asContentMap(page(content.getJCRNode()));
187 }
188
189
190
191
192
193
194
195
196
197 public Node page(Node content) throws RepositoryException {
198 if (content == null) {
199 return null;
200 }
201 if (content.isNodeType(MgnlNodeType.NT_PAGE)) {
202 return content;
203 }
204 return parent(content, MgnlNodeType.NT_PAGE);
205 }
206
207 public List<ContentMap> ancestors(ContentMap contentMap) throws RepositoryException {
208 return ancestors(contentMap, null);
209 }
210
211 public List<ContentMap> ancestors(ContentMap contentMap, String nodeTypeName) throws RepositoryException {
212 List<Node> ancestorsAsNodes = this.ancestors(contentMap.getJCRNode(), nodeTypeName);
213 return asContentMapList(ancestorsAsNodes);
214 }
215
216 public List<Node> ancestors(Node content) throws RepositoryException {
217 return content == null ? null : this.ancestors(content, null);
218 }
219
220 public List<Node> ancestors(Node content, String nodeTypeName) throws RepositoryException {
221 if (content == null) {
222 return null;
223 }
224 List<Node> ancestors = new ArrayList<Node>();
225 int depth = content.getDepth();
226 for (int i = 1; i < depth; ++i) {
227 Node possibleAncestor = (Node) content.getAncestor(i);
228 if (nodeTypeName == null) {
229 ancestors.add(possibleAncestor);
230 } else {
231 if (possibleAncestor.isNodeType(nodeTypeName)) {
232 ancestors.add(possibleAncestor);
233 }
234 }
235 }
236 return ancestors;
237 }
238
239 public Node inherit(Node content) throws RepositoryException {
240 return inherit(content, null);
241 }
242
243 public Node inherit(Node content, String relPath) throws RepositoryException {
244 if (content == null) {
245 return null;
246 }
247 Node inheritedNode = wrapForInheritance(content);
248
249 if (StringUtils.isBlank(relPath)) {
250 return inheritedNode;
251 }
252
253 try {
254 Node subNode = inheritedNode.getNode(relPath);
255 return NodeUtil.unwrap(subNode);
256 } catch (PathNotFoundException e) {
257
258 }
259 return null;
260 }
261
262 public ContentMap inherit(ContentMap content) throws RepositoryException {
263 return inherit(content, null);
264 }
265
266 public ContentMap inherit(ContentMap content, String relPath) throws RepositoryException {
267 if (content == null) {
268 return null;
269 }
270 Node node = inherit(content.getJCRNode(), relPath);
271 return node == null ? null : new ContentMap(node);
272 }
273
274
275 public Property inheritProperty(Node content, String relPath) throws RepositoryException {
276 if (content == null) {
277 return null;
278 }
279 if (StringUtils.isBlank(relPath)) {
280 throw new IllegalArgumentException("relative path cannot be null or empty");
281 }
282 try {
283 Node inheritedNode = wrapForInheritance(content);
284 return inheritedNode.getProperty(relPath);
285
286 } catch (PathNotFoundException e) {
287
288 } catch (RepositoryException e) {
289
290 }
291
292 return null;
293 }
294
295 public Property inheritProperty(ContentMap content, String relPath) throws RepositoryException {
296 if (content == null) {
297 return null;
298 }
299 return inheritProperty(content.getJCRNode(), relPath);
300 }
301
302 public List<Node> inheritList(Node content, String relPath) throws RepositoryException {
303 if (content == null) {
304 return null;
305 }
306 if (StringUtils.isBlank(relPath)) {
307 throw new IllegalArgumentException("relative path cannot be null or empty");
308 }
309 Node inheritedNode = wrapForInheritance(content);
310 Node subNode = inheritedNode.getNode(relPath);
311 return children(subNode);
312 }
313
314 public List<ContentMap> inheritList(ContentMap content, String relPath) throws RepositoryException {
315 if (content == null) {
316 return null;
317 }
318 if (StringUtils.isBlank(relPath)) {
319 throw new IllegalArgumentException("relative path cannot be null or empty");
320 }
321 Node node = asJCRNode(content);
322 Node inheritedNode = wrapForInheritance(node);
323 Node subNode = inheritedNode.getNode(relPath);
324 return children(new ContentMap(subNode));
325 }
326
327 public boolean isInherited(Node content) {
328 if (content instanceof InheritanceNodeWrapper) {
329 return ((InheritanceNodeWrapper) content).isInherited();
330 }
331 return false;
332 }
333
334 public boolean isInherited(ContentMap content) {
335 return isInherited(asJCRNode(content));
336 }
337
338 public boolean isFromCurrentPage(Node content) {
339 return !isInherited(content);
340 }
341
342 public boolean isFromCurrentPage(ContentMap content) {
343 return isFromCurrentPage(asJCRNode(content));
344 }
345
346
347
348
349 public String link(String workspace, String nodeIdentifier) {
350 try {
351 return LinkUtil.createLink(workspace, nodeIdentifier);
352 } catch (RepositoryException e) {
353 return null;
354 }
355 }
356
357
358
359
360
361
362 @Deprecated
363 public String link(Property property) {
364 try {
365 Node parentNode = null;
366 String propertyName = null;
367 if (property.getType() == PropertyType.BINARY) {
368 parentNode = property.getParent().getParent();
369 propertyName = property.getParent().getName();
370 } else {
371 parentNode = property.getParent();
372 propertyName = property.getName();
373 }
374 NodeData equivNodeData = ContentUtil.asContent(parentNode).getNodeData(propertyName);
375 return LinkUtil.createLink(equivNodeData);
376 } catch (Exception e) {
377 return null;
378 }
379 }
380
381
382
383 public String link(Node content) {
384 return content == null ? null : LinkUtil.createLink(ContentUtil.asContent(content));
385 }
386
387 public String link(ContentMap contentMap) throws RepositoryException {
388 return contentMap == null ? null : this.link(asJCRNode(contentMap));
389 }
390
391
392
393
394
395 public String language(){
396 return I18nContentSupportFactory.getI18nSupport().getLocale().toString();
397 }
398
399
400
401
402
403
404
405
406 public String externalLink(Node content, String linkPropertyName) {
407 String externalLink = PropertyUtil.getString(content, linkPropertyName);
408 if (StringUtils.isBlank(externalLink)) {
409 return StringUtils.EMPTY;
410 }
411 if (!hasProtocol(externalLink)) {
412 externalLink = "http://" + externalLink;
413 }
414 return externalLink;
415 }
416
417
418
419
420
421
422
423
424
425 public String externalLink(ContentMap content, String linkPropertyName) {
426 return externalLink(asJCRNode(content), linkPropertyName);
427 }
428
429
430
431
432
433
434
435
436
437
438 public String externalLinkTitle(Node content, String linkPropertyName, String linkTitlePropertyName) {
439 String linkTitle = PropertyUtil.getString(content, linkTitlePropertyName);
440 if (StringUtils.isNotEmpty(linkTitle)) {
441 return linkTitle;
442 }
443 return externalLink(content, linkPropertyName);
444 }
445
446
447
448
449
450
451
452
453
454
455 public String externalLinkTitle(ContentMap content, String linkPropertyName, String linkTitlePropertyName) {
456 return externalLinkTitle(asJCRNode(content), linkPropertyName, linkTitlePropertyName);
457 }
458
459 public boolean isEditMode() {
460
461 return isAuthorInstance() && !isPreviewMode();
462 }
463
464 public boolean isPreviewMode() {
465 return this.aggregationStateProvider.get().isPreviewMode();
466 }
467
468 public boolean isAuthorInstance() {
469 return Components.getComponent(ServerConfiguration.class).isAdmin();
470 }
471
472 public boolean isPublicInstance() {
473 return !isAuthorInstance();
474 }
475
476
477
478
479
480 public String createHtmlAttribute(String name, String value) {
481 value = StringUtils.trim(value);
482 if (StringUtils.isNotEmpty(value)) {
483 return new StringBuffer().append(name).append("=\"").append(value).append("\"").toString();
484 }
485 return StringUtils.EMPTY;
486 }
487
488
489
490
491 public SiblingsHelper siblings(Node node) throws RepositoryException {
492 return SiblingsHelper.of(ContentUtil.asContent(node));
493 }
494
495 public SiblingsHelper siblings(ContentMap node) throws RepositoryException {
496 return siblings(asJCRNode(node));
497 }
498
499
500
501
502
503 public Node content(String path){
504 return content(RepositoryConstants.WEBSITE, path);
505 }
506
507
508
509
510
511 public Node content(String repository, String path){
512 return SessionUtil.getNode(repository, path);
513 }
514
515
516
517
518
519 public Node contentByIdentifier(String id){
520 return contentByIdentifier(RepositoryConstants.WEBSITE, id);
521 }
522
523
524
525
526
527 public Node contentByIdentifier(String repository, String id){
528 return SessionUtil.getNodeByIdentifier(repository, id);
529 }
530
531 public List<ContentMap> asContentMapList(Collection<Node> nodeList) {
532 if (nodeList != null) {
533 List<ContentMap> contentMapList = new ArrayList<ContentMap>();
534 for (Node node : nodeList) {
535 contentMapList.add(asContentMap(node));
536 }
537 return contentMapList;
538 }
539 return null;
540 }
541
542 public List<Node> asNodeList(Collection<ContentMap> contentMapList) {
543 if (contentMapList != null) {
544 List<Node> nodeList = new ArrayList<Node>();
545 for (ContentMap node : contentMapList) {
546 nodeList.add(node.getJCRNode());
547 }
548 return nodeList;
549 }
550 return null;
551 }
552
553
554 protected List<Node> asNodeList(Iterable<Node> nodes) {
555 List<Node> childList = new ArrayList<Node>();
556 for (Node child : nodes) {
557 childList.add(child);
558 }
559 return childList;
560 }
561
562
563 protected List<ContentMap> asContentMapList(Iterable<Node> nodes) {
564 List<ContentMap> childList = new ArrayList<ContentMap>();
565 for (Node child : nodes) {
566 childList.add(new ContentMap(child));
567 }
568 return childList;
569 }
570
571
572
573
574
575
576
577 private boolean hasProtocol(String link) {
578 return link != null && link.contains("://");
579 }
580
581
582
583
584
585
586
587 private boolean isRoot(Node content) throws RepositoryException {
588 return content.getDepth() == 0;
589 }
590
591
592
593
594 public ContentMap decode(ContentMap content){
595 return asContentMap(decode(content.getJCRNode()));
596 }
597
598
599
600
601 public Node decode(Node content){
602 return NodeUtil.deepUnwrap(content, HTMLEscapingNodeWrapper.class);
603 }
604
605
606
607
608 public Node encode(Node content){
609 return content != null ? new HTMLEscapingNodeWrapper(content, true) : null;
610 }
611
612 private Node wrapForInheritance(Node destination) throws RepositoryException {
613 ConfiguredInheritance inheritanceConfiguration = new ConfiguredInheritance();
614 inheritanceConfiguration.setEnabled(true);
615 return new DefaultInheritanceContentDecorator(destination, inheritanceConfiguration).wrapNode(destination);
616 }
617
618
619
620
621 public String metaData(Node content, String property){
622 try {
623 if(content.hasNode(MetaData.DEFAULT_META_NODE)){
624 Node node = content.getNode(MetaData.DEFAULT_META_NODE);
625 if(node.hasProperty(property)) {
626 return PropertyUtil.getPropertyOrNull(node, property).getString();
627 } else if(node.hasProperty(RepositoryConstants.NAMESPACE_PREFIX + ":" + property)) {
628 return PropertyUtil.getPropertyOrNull(node, RepositoryConstants.NAMESPACE_PREFIX + ":" + property).getString();
629 }
630 }
631 } catch (RepositoryException e) {
632 throw new RuntimeException(e);
633 }
634 return null;
635 }
636
637
638
639
640 public String metaData(ContentMap content, String property){
641 return metaData(content.getJCRNode(), property);
642 }
643
644
645
646
647
648
649
650
651
652 public Collection<Node> search(String workspace, String statement, String language, String returnItemType){
653 try {
654 return NodeUtil.getCollectionFromNodeIterator(QueryUtil.search(workspace, statement, language, returnItemType));
655 } catch (Exception e) {
656 log.error(e.getMessage(), e);
657 }
658 return null;
659 }
660
661
662
663
664
665
666
667
668
669 public Collection<Node> simpleSearch(String workspace, String statement, String returnItemType, String startPath){
670 if(StringUtils.isEmpty(statement)){
671 log.error("Cannot search with empty statement.");
672 return null;
673 }
674 String query = QueryUtil.buildQuery(statement, startPath);
675 try {
676 return NodeUtil.getCollectionFromNodeIterator(QueryUtil.search(workspace, query, "JCR-SQL2", returnItemType));
677 } catch (Exception e) {
678 log.error(e.getMessage(), e);
679 }
680 return null;
681 }
682 }