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.beans.config.URI2RepositoryManager;
38 import info.magnolia.cms.core.AggregationState;
39 import info.magnolia.cms.core.NodeData;
40 import info.magnolia.cms.i18n.I18nContentSupport;
41 import info.magnolia.cms.util.ContentUtil;
42 import info.magnolia.cms.util.PathUtil;
43 import info.magnolia.cms.util.QueryUtil;
44 import info.magnolia.cms.util.SelectorUtil;
45 import info.magnolia.cms.util.SiblingsHelper;
46 import info.magnolia.context.MgnlContext;
47 import info.magnolia.context.WebContext;
48 import info.magnolia.context.HTMLEscapingWebContextWrapper;
49 import info.magnolia.jcr.inheritance.InheritanceNodeWrapper;
50 import info.magnolia.jcr.util.ContentMap;
51 import info.magnolia.jcr.util.MetaDataUtil;
52 import info.magnolia.jcr.util.NodeTypes;
53 import info.magnolia.jcr.util.NodeUtil;
54 import info.magnolia.jcr.util.PropertyUtil;
55 import info.magnolia.jcr.util.SessionUtil;
56 import info.magnolia.jcr.wrapper.HTMLEscapingContentDecorator;
57 import info.magnolia.jcr.wrapper.HTMLEscapingNodeWrapper;
58 import info.magnolia.jcr.wrapper.I18nNodeWrapper;
59 import info.magnolia.link.LinkUtil;
60 import info.magnolia.objectfactory.Components;
61 import info.magnolia.rendering.engine.RenderingEngine;
62 import info.magnolia.rendering.template.configured.ConfiguredInheritance;
63 import info.magnolia.rendering.template.type.DefaultTemplateTypes;
64 import info.magnolia.rendering.template.type.TemplateTypeHelper;
65 import info.magnolia.repository.RepositoryConstants;
66 import info.magnolia.templating.inheritance.DefaultInheritanceContentDecorator;
67 import info.magnolia.util.EscapeUtil;
68
69 import java.net.URI;
70 import java.net.URISyntaxException;
71 import java.util.ArrayList;
72 import java.util.Arrays;
73 import java.util.Calendar;
74 import java.util.Collection;
75 import java.util.Collections;
76 import java.util.LinkedHashMap;
77 import java.util.List;
78 import java.util.Locale;
79 import java.util.Map;
80 import java.util.Set;
81
82 import javax.inject.Inject;
83 import javax.inject.Provider;
84 import javax.jcr.Node;
85 import javax.jcr.PathNotFoundException;
86 import javax.jcr.Property;
87 import javax.jcr.PropertyType;
88 import javax.jcr.RepositoryException;
89
90 import org.apache.commons.io.FileUtils;
91 import org.apache.commons.lang3.StringUtils;
92 import org.apache.jackrabbit.util.ISO8601;
93 import org.slf4j.Logger;
94 import org.slf4j.LoggerFactory;
95
96
97
98
99 public class TemplatingFunctions {
100
101 private static final Logger log = LoggerFactory.getLogger(TemplatingFunctions.class);
102
103 private final Provider<WebContext> webContextProvider;
104 private final TemplateTypeHelper templateTypeHelper;
105 private final Provider<I18nContentSupport> i18nContentSupport;
106
107 @Inject
108 public TemplatingFunctions(TemplateTypeHelper templateTypeFunctions, Provider<I18nContentSupport> i18nContentSupport, Provider<WebContext> webContextProvider) {
109 this.webContextProvider = webContextProvider;
110 this.templateTypeHelper = templateTypeFunctions;
111 this.i18nContentSupport = i18nContentSupport;
112 }
113
114
115
116
117 @Deprecated
118 public TemplatingFunctions(Provider<AggregationState> aggregationStateProvider, TemplateTypeHelper templateTypeFunctions, Provider<I18nContentSupport> i18nContentSupport) {
119 this(templateTypeFunctions, i18nContentSupport, new Provider<WebContext>() {
120 @Override
121 public WebContext get() {
122 return Components.getComponent(WebContext.class);
123 }
124 });
125 }
126
127
128
129
130 @Deprecated
131 public TemplatingFunctions(Provider<AggregationState> aggregationStateProvider, TemplateTypeHelper templateTypeFunctions) {
132 this(templateTypeFunctions, new Provider<I18nContentSupport>() {
133 @Override
134 public I18nContentSupport get() {
135 return Components.getComponent(I18nContentSupport.class);
136 }
137 }, new Provider<WebContext>() {
138 @Override
139 public WebContext get() {
140 return Components.getComponent(WebContext.class);
141 }
142 });
143 }
144
145
146
147
148 @Deprecated
149 public TemplatingFunctions(Provider<AggregationState> aggregationStateProvider) {
150 this(Components.getComponent(TemplateTypeHelper.class), new Provider<I18nContentSupport>() {
151 @Override
152 public I18nContentSupport get() {
153 return Components.getComponent(I18nContentSupport.class);
154 }
155 }, new Provider<WebContext>() {
156 @Override
157 public WebContext get() {
158 return Components.getComponent(WebContext.class);
159 }
160 });
161 }
162
163
164
165
166
167 public Node asJCRNode(ContentMap contentMap) {
168 return contentMap == null ? null : contentMap.getJCRNode();
169 }
170
171
172
173
174
175 public ContentMap asContentMap(Node content) {
176 return content == null ? null : new ContentMap(content);
177 }
178
179
180
181
182 public List<Node> children(Node content) throws RepositoryException {
183 return content == null ? null : asNodeList(NodeUtil.getNodes(content, NodeUtil.EXCLUDE_META_DATA_FILTER));
184 }
185
186
187
188
189 public List<Node> children(Node content, String nodeTypeName) throws RepositoryException {
190 return content == null ? null : asNodeList(NodeUtil.getNodes(content, nodeTypeName));
191 }
192
193
194
195
196 public List<ContentMap> children(ContentMap content) throws RepositoryException {
197 return content == null ? null : asContentMapList(NodeUtil.getNodes(asJCRNode(content), NodeUtil.EXCLUDE_META_DATA_FILTER));
198 }
199
200
201
202
203 public List<ContentMap> children(ContentMap content, String nodeTypeName) throws RepositoryException {
204 return content == null ? null : asContentMapList(NodeUtil.getNodes(asJCRNode(content), nodeTypeName));
205 }
206
207
208
209
210 public ContentMap root(ContentMap contentMap) throws RepositoryException {
211 return contentMap == null ? null : asContentMap(this.root(contentMap.getJCRNode()));
212 }
213
214
215
216
217 public ContentMap root(ContentMap contentMap, String nodeTypeName) throws RepositoryException {
218 return contentMap == null ? null : asContentMap(this.root(contentMap.getJCRNode(), nodeTypeName));
219 }
220
221
222
223
224 public Node root(Node content) throws RepositoryException {
225 return this.root(content, null);
226 }
227
228
229
230
231 public Node root(Node content, String nodeTypeName) throws RepositoryException {
232 if (content == null) {
233 return null;
234 }
235 if (nodeTypeName == null) {
236 return (Node) content.getAncestor(0);
237 }
238 if (isRoot(content) && content.isNodeType(nodeTypeName)) {
239 return content;
240 }
241
242 Node parentNode = this.parent(content, nodeTypeName);
243 while (parent(parentNode, nodeTypeName) != null) {
244 parentNode = this.parent(parentNode, nodeTypeName);
245 }
246 return parentNode;
247 }
248
249
250
251
252 public ContentMap parent(ContentMap contentMap) throws RepositoryException {
253 return contentMap == null ? null : asContentMap(this.parent(contentMap.getJCRNode()));
254 }
255
256
257
258
259 public ContentMap parent(ContentMap contentMap, String nodeTypeName) throws RepositoryException {
260 return contentMap == null ? null : asContentMap(this.parent(contentMap.getJCRNode(), nodeTypeName));
261 }
262
263
264
265
266 public Node parent(Node content) throws RepositoryException {
267 return this.parent(content, null);
268 }
269
270
271
272
273
274 public Node parent(Node content, String nodeTypeName) throws RepositoryException {
275 if (content == null) {
276 return null;
277 }
278 if (isRoot(content)) {
279 return null;
280 }
281 if (nodeTypeName == null) {
282 return content.getParent();
283 }
284 Node parent = content.getParent();
285 while (!parent.isNodeType(nodeTypeName)) {
286 if (isRoot(parent)) {
287 return null;
288 }
289 parent = parent.getParent();
290 }
291 return parent;
292 }
293
294
295
296
297
298
299
300
301 public ContentMap page(ContentMap content) throws RepositoryException {
302 return content == null ? null : asContentMap(page(content.getJCRNode()));
303 }
304
305
306
307
308
309
310
311
312 public Node page(Node content) throws RepositoryException {
313 if (content == null) {
314 return null;
315 }
316 if (content.isNodeType(NodeTypes.Page.NAME)) {
317 return content;
318 }
319 return parent(content, NodeTypes.Page.NAME);
320 }
321
322
323
324
325 public List<ContentMap> ancestors(ContentMap contentMap) throws RepositoryException {
326 return ancestors(contentMap, null);
327 }
328
329
330
331
332 public List<ContentMap> ancestors(ContentMap contentMap, String nodeTypeName) throws RepositoryException {
333 List<Node> ancestorsAsNodes = this.ancestors(contentMap.getJCRNode(), nodeTypeName);
334 return asContentMapList(ancestorsAsNodes);
335 }
336
337
338
339
340
341 public List<Node> ancestors(Node content) throws RepositoryException {
342 return content == null ? null : this.ancestors(content, null);
343 }
344
345
346
347
348
349 public List<Node> ancestors(Node content, String nodeTypeName) throws RepositoryException {
350 if (content == null) {
351 return null;
352 }
353 List<Node> ancestors = new ArrayList<Node>();
354 int depth = content.getDepth();
355 for (int i = 1; i < depth; ++i) {
356 Node possibleAncestor = (Node) content.getAncestor(i);
357 if (nodeTypeName == null) {
358 ancestors.add(possibleAncestor);
359 } else {
360 if (possibleAncestor.isNodeType(nodeTypeName)) {
361 ancestors.add(possibleAncestor);
362 }
363 }
364 }
365 return ancestors;
366 }
367
368
369
370
371
372
373
374
375
376 public Node inherit(Node content) throws RepositoryException {
377 return inherit(content, null);
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391 public Node inherit(Node content, String relPath) throws RepositoryException {
392 return inherit(content, relPath, StringUtils.EMPTY, ConfiguredInheritance.COMPONENTS_FILTERED, ConfiguredInheritance.PROPERTIES_ALL);
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426 public Node inherit(Node content, String relPath, String nodeTypes, String nodeInheritance, String propertyInheritance) throws RepositoryException {
427 if (content == null) {
428 return null;
429 }
430
431 ConfiguredInheritance configuredInheritance = new ConfiguredInheritance();
432 if (StringUtils.isNotEmpty(nodeTypes)) {
433 configuredInheritance.setNodeTypes(Arrays.asList(StringUtils.split(nodeTypes, ",")));
434 }
435 if (StringUtils.isNotEmpty(nodeInheritance)) {
436 configuredInheritance.setComponents(nodeInheritance);
437 }
438 if (StringUtils.isNotEmpty(propertyInheritance)) {
439 configuredInheritance.setProperties(propertyInheritance);
440 }
441
442 Node inheritedNode = wrapForInheritance(content, configuredInheritance);
443
444 if (StringUtils.isBlank(relPath)) {
445 return inheritedNode;
446 }
447
448 try {
449 Node subNode = inheritedNode.getNode(relPath);
450 return NodeUtil.unwrap(subNode);
451 } catch (PathNotFoundException e) {
452
453 }
454 return null;
455 }
456
457
458
459
460 public ContentMap inherit(ContentMap content) throws RepositoryException {
461 return inherit(content, null);
462 }
463
464
465
466
467 public ContentMap inherit(ContentMap content, String relPath) throws RepositoryException {
468 if (content == null) {
469 return null;
470 }
471 Node node = inherit(content.getJCRNode(), relPath);
472 return node == null ? null : new ContentMap(node);
473 }
474
475
476
477
478 public ContentMap inherit(ContentMap content, String relPath, String nodeTypes, String nodeInheritance, String propertyInheritance) throws RepositoryException {
479 if (content == null) {
480 return null;
481 }
482 Node node = inherit(content.getJCRNode(), relPath, nodeTypes, nodeInheritance, propertyInheritance);
483 return node == null ? null : new ContentMap(node);
484 }
485
486
487
488
489
490
491
492
493 public Property inheritProperty(Node content, String relPath) throws RepositoryException {
494 if (content == null) {
495 return null;
496 }
497 if (StringUtils.isBlank(relPath)) {
498 throw new IllegalArgumentException("relative path cannot be null or empty");
499 }
500 try {
501 Node inheritedNode = wrapForInheritance(content, new ConfiguredInheritance());
502 return inheritedNode.getProperty(relPath);
503
504 } catch (PathNotFoundException e) {
505
506 } catch (RepositoryException e) {
507
508 }
509
510 return null;
511 }
512
513
514
515
516 public Property inheritProperty(ContentMap content, String relPath) throws RepositoryException {
517 if (content == null) {
518 return null;
519 }
520 return inheritProperty(content.getJCRNode(), relPath);
521 }
522
523
524
525
526 public List<Node> inheritList(Node content, String relPath) throws RepositoryException {
527 if (content == null) {
528 return null;
529 }
530 if (StringUtils.isBlank(relPath)) {
531 throw new IllegalArgumentException("Relative path cannot be null or empty");
532 }
533 Node inheritedNode = wrapForInheritance(content, new ConfiguredInheritance());
534 Node subNode = inheritedNode.getNode(relPath);
535 return children(subNode);
536 }
537
538
539
540
541 public List<ContentMap> inheritList(ContentMap content, String relPath) throws RepositoryException {
542 if (content == null) {
543 return null;
544 }
545 if (StringUtils.isBlank(relPath)) {
546 throw new IllegalArgumentException("Relative path cannot be null or empty");
547 }
548 Node node = asJCRNode(content);
549 Node inheritedNode = wrapForInheritance(node, new ConfiguredInheritance());
550 Node subNode = inheritedNode.getNode(relPath);
551 return children(new ContentMap(subNode));
552 }
553
554
555
556
557 public boolean isInherited(Node content) {
558 if (content instanceof InheritanceNodeWrapper) {
559 return ((InheritanceNodeWrapper) content).isInherited();
560 }
561 return false;
562 }
563
564
565
566
567 public boolean isInherited(ContentMap content) {
568 return isInherited(asJCRNode(content));
569 }
570
571
572
573
574
575 public boolean isFromCurrentPage(Node content) {
576 return !isInherited(content);
577 }
578
579
580
581
582 public boolean isFromCurrentPage(ContentMap content) {
583 return isFromCurrentPage(asJCRNode(content));
584 }
585
586
587
588
589
590 public String link(String workspace, String nodeIdentifier) {
591 try {
592 return LinkUtil.createLink(workspace, nodeIdentifier);
593 } catch (RepositoryException e) {
594 handleRepositoryException(e, workspace);
595 return null;
596 }
597 }
598
599
600
601
602
603
604
605
606 @Deprecated
607 public String link(Property property) {
608 try {
609 Node parentNode = null;
610 String propertyName = null;
611 if (property.getType() == PropertyType.BINARY) {
612 parentNode = property.getParent().getParent();
613 propertyName = property.getParent().getName();
614 } else {
615 parentNode = property.getParent();
616 propertyName = property.getName();
617 }
618 NodeData equivNodeData = ContentUtil.asContent(parentNode).getNodeData(propertyName);
619 return LinkUtil.createLink(equivNodeData);
620 } catch (Exception e) {
621 return null;
622 }
623 }
624
625
626
627
628
629 public String link(Node content) {
630 return content == null ? null : LinkUtil.createLink(content);
631 }
632
633
634
635
636 public String link(ContentMap contentMap) throws RepositoryException {
637 return contentMap == null ? null : this.link(asJCRNode(contentMap));
638 }
639
640 public String linkPrefix(Node content) {
641 if (!MgnlContext.isWebContext()) {
642 return MgnlContext.getContextPath();
643 }
644 String fullLinkToPage = link(content);
645 String pagePath = Components.getComponent(URI2RepositoryManager.class).getURI(LinkUtil.createLinkInstance(content));
646 int ndx = fullLinkToPage.length();
647 for (int cnt = StringUtils.countMatches(pagePath, "/"); cnt > 0; cnt--) {
648 ndx = fullLinkToPage.lastIndexOf('/', ndx - 1);
649 }
650 String linkPrefix = fullLinkToPage.substring(0, ndx);
651 return linkPrefix;
652 }
653
654
655
656
657 public String linkPrefix(ContentMap content) {
658 return linkPrefix(asJCRNode(content));
659 }
660
661
662
663
664
665
666 @Deprecated
667 public String getQueryStringAndFragment(String url) {
668 return queryStringAndFragment(url);
669 }
670
671
672
673
674 public String queryStringAndFragment(String url) {
675 String result = StringUtils.EMPTY;
676 try {
677 URI uri = new URI(url);
678 String query = uri.getQuery();
679 String fragment = uri.getFragment();
680
681 if (StringUtils.isNotEmpty(query)) {
682 result += "?" + query;
683 }
684 if (StringUtils.isNotEmpty(fragment)) {
685 result += "#" + fragment;
686 }
687 } catch (URISyntaxException e) {
688 log.warn("URL cannot be parsed. {0}, {1}", url, e.getMessage());
689 return StringUtils.EMPTY;
690 }
691 return result;
692 }
693
694
695
696
697
698
699 public String language() {
700 return i18nContentSupport.get().getLocale().toString();
701 }
702
703
704
705
706
707
708
709
710
711 public String externalLink(Node content, String linkPropertyName) {
712 String externalLink = PropertyUtil.getString(content, linkPropertyName);
713 if (StringUtils.isBlank(externalLink)) {
714 return StringUtils.EMPTY;
715 }
716
717 if (!hasProtocol(externalLink) && !externalLink.startsWith("#")) {
718 externalLink = "http://" + externalLink;
719 }
720 return EscapeUtil.escapeXss(externalLink);
721 }
722
723
724
725
726
727
728
729
730
731 public String externalLink(ContentMap content, String linkPropertyName) {
732 return externalLink(asJCRNode(content), linkPropertyName);
733 }
734
735
736
737
738
739
740
741
742
743
744 public String externalLinkTitle(Node content, String linkPropertyName, String linkTitlePropertyName) {
745 String linkTitle = PropertyUtil.getString(content, linkTitlePropertyName);
746 if (StringUtils.isNotEmpty(linkTitle)) {
747 return linkTitle;
748 }
749 return externalLink(content, linkPropertyName);
750 }
751
752
753
754
755
756
757
758
759
760
761 public String externalLinkTitle(ContentMap content, String linkPropertyName, String linkTitlePropertyName) {
762 return externalLinkTitle(asJCRNode(content), linkPropertyName, linkTitlePropertyName);
763 }
764
765
766
767
768
769
770 public boolean isEditMode() {
771
772 return isAuthorInstance() && !isPreviewMode();
773 }
774
775
776
777
778 public boolean isPreviewMode() {
779 return this.webContextProvider.get().getAggregationState().isPreviewMode();
780 }
781
782
783
784
785 public boolean isAuthorInstance() {
786 return Components.getComponent(ServerConfiguration.class).isAdmin();
787 }
788
789
790
791
792 public boolean isPublicInstance() {
793 return !isAuthorInstance();
794 }
795
796
797
798
799
800 public String createHtmlAttribute(String name, String value) {
801 value = StringUtils.trim(value);
802 if (StringUtils.isNotEmpty(value)) {
803 return new StringBuffer().append(name).append("=\"").append(value).append("\"").toString();
804 }
805 return StringUtils.EMPTY;
806 }
807
808
809
810
811 public SiblingsHelper siblings(Node node) throws RepositoryException {
812 return SiblingsHelper.of(ContentUtil.asContent(node));
813 }
814
815 public SiblingsHelper siblings(ContentMap node) throws RepositoryException {
816 return siblings(asJCRNode(node));
817 }
818
819
820
821
822
823
824 @Deprecated
825 public Node content(String path) {
826 return content(RepositoryConstants.WEBSITE, path);
827 }
828
829
830
831
832
833
834 @Deprecated
835 public Node content(String repository, String path) {
836 return SessionUtil.getNode(repository, path);
837 }
838
839
840
841
842
843
844 @Deprecated
845 public Node contentByIdentifier(String id) {
846 return contentByIdentifier(RepositoryConstants.WEBSITE, id);
847 }
848
849
850
851
852
853
854 @Deprecated
855 public Node contentByIdentifier(String repository, String id) {
856 return SessionUtil.getNodeByIdentifier(repository, id);
857 }
858
859
860
861
862 public ContentMap contentByPath(String path) {
863 return contentByPath(path, RepositoryConstants.WEBSITE);
864 }
865
866
867
868
869 public ContentMap contentByPath(String path, String workspace) {
870 return asContentMap(nodeByPath(path, workspace));
871 }
872
873
874
875
876 public ContentMap contentById(String id) {
877 return contentById(id, RepositoryConstants.WEBSITE);
878 }
879
880
881
882
883 public ContentMap contentById(String id, String workspace) {
884 return asContentMap(nodeById(id, workspace));
885 }
886
887
888
889
890 public Node nodeByPath(String path) {
891 return nodeByPath(path, RepositoryConstants.WEBSITE);
892 }
893
894
895
896
897 public Node nodeByPath(String path, String workspace) {
898 try {
899 String pathToNode = new URI(path).getPath();
900 return webContextProvider.get().getJCRSession(workspace).getNode(pathToNode);
901 } catch (URISyntaxException e) {
902 log.warn("Path cannot be parsed. {0}, {1}", path, e.getMessage());
903 return null;
904 } catch (RepositoryException e) {
905 handleRepositoryException(e, workspace);
906 return null;
907 }
908 }
909
910
911
912
913 public Node nodeById(String id) {
914 return nodeById(id, RepositoryConstants.WEBSITE);
915 }
916
917
918
919
920 public Node nodeById(String id, String workspace) {
921 try {
922 return webContextProvider.get().getJCRSession(workspace).getNodeByIdentifier(id);
923 } catch (RepositoryException e) {
924 handleRepositoryException(e, workspace);
925 return null;
926 }
927 }
928
929 private void handleRepositoryException(RepositoryException e, String workspace) {
930 final AggregationState aggregationState = webContextProvider.get().getAggregationState();
931 String template;
932 try {
933 template = NodeTypes.Renderable.getTemplate(aggregationState.getCurrentContentNode());
934 } catch (RepositoryException e1) {
935 template = "unknown";
936 }
937 log.debug("Exception in '{}' workspace when rendering template '{}' for URI '{}': {}", workspace, template, aggregationState.getOriginalBrowserURI(), e);
938
939 }
940
941
942
943
944
945
946
947
948
949
950 public Node contentByReference(Node content, String idPropertyName, String referencedWorkspace) throws RepositoryException {
951 if (content.hasProperty(idPropertyName)) {
952 final String identifier = PropertyUtil.getString(content, idPropertyName);
953 final Node node = NodeUtil.getNodeByIdentifier(referencedWorkspace, identifier);
954 return encode(wrapForI18n(node));
955 }
956 return null;
957 }
958
959
960
961
962 public ContentMap contentByReference(ContentMap content, String idPropertyName, String referencedWorkspace) throws RepositoryException {
963 Node node = asJCRNode(content);
964 return asContentMap(contentByReference(node, idPropertyName, referencedWorkspace));
965 }
966
967
968
969
970
971 public List<ContentMap> asContentMapList(Collection<Node> nodeList) {
972 if (nodeList != null) {
973 List<ContentMap> contentMapList = new ArrayList<ContentMap>();
974 for (Node node : nodeList) {
975 contentMapList.add(asContentMap(node));
976 }
977 return contentMapList;
978 }
979 return null;
980 }
981
982
983
984
985
986 public List<Node> asNodeList(Collection<ContentMap> contentMapList) {
987 if (contentMapList != null) {
988 List<Node> nodeList = new ArrayList<Node>();
989 for (ContentMap node : contentMapList) {
990 nodeList.add(node.getJCRNode());
991 }
992 return nodeList;
993 }
994 return null;
995 }
996
997
998 protected List<Node> asNodeList(Iterable<Node> nodes) {
999 List<Node> childList = new ArrayList<Node>();
1000 for (Node child : nodes) {
1001 childList.add(child);
1002 }
1003 return childList;
1004 }
1005
1006
1007 protected List<ContentMap> asContentMapList(Iterable<Node> nodes) {
1008 List<ContentMap> childList = new ArrayList<ContentMap>();
1009 for (Node child : nodes) {
1010 childList.add(new ContentMap(child));
1011 }
1012 return childList;
1013 }
1014
1015
1016
1017
1018
1019
1020
1021 private boolean hasProtocol(String link) {
1022 return link != null && link.contains("://");
1023 }
1024
1025
1026
1027
1028
1029
1030
1031 private boolean isRoot(Node content) throws RepositoryException {
1032 return content.getDepth() == 0;
1033 }
1034
1035
1036
1037
1038 public ContentMap decode(ContentMap content) {
1039 return asContentMap(decode(content.getJCRNode()));
1040 }
1041
1042
1043
1044
1045 public Node decode(Node content) {
1046 return NodeUtil.deepUnwrap(content, HTMLEscapingNodeWrapper.class);
1047 }
1048
1049
1050
1051
1052 public ContentMap encode(ContentMap content) {
1053 return content != null ? new ContentMap(new HTMLEscapingNodeWrapper(content.getJCRNode(), true)) : null;
1054 }
1055
1056
1057
1058
1059 public Node encode(Node content) {
1060 return content != null ? new HTMLEscapingNodeWrapper(content, true) : null;
1061 }
1062
1063
1064
1065
1066 public String encode(String text) {
1067 return new HTMLEscapingContentDecorator(true).decorate(text);
1068 }
1069
1070
1071
1072
1073 public Node wrapForI18n(Node content) {
1074 return content != null ? new I18nNodeWrapper(content) : null;
1075 }
1076
1077
1078
1079
1080 public ContentMap wrapForI18n(ContentMap content) {
1081 return content != null ? new ContentMap(wrapForI18n(content.getJCRNode())) : null;
1082 }
1083
1084
1085
1086
1087
1088 private Node wrapForInheritance(Node destination, ConfiguredInheritance configuredInheritance) throws RepositoryException {
1089 configuredInheritance.setEnabled(true);
1090 return new DefaultInheritanceContentDecorator(destination, configuredInheritance).wrapNode(destination);
1091 }
1092
1093
1094
1095
1096 public String metaData(Node content, String property) {
1097
1098 Object returnValue;
1099 try {
1100 if (property.equals(NodeTypes.Created.CREATED)) {
1101 returnValue = NodeTypes.Created.getCreated(content);
1102 } else if (property.equals(NodeTypes.Created.CREATED_BY)) {
1103 returnValue = NodeTypes.Created.getCreatedBy(content);
1104 } else if (property.equals(NodeTypes.LastModified.LAST_MODIFIED)) {
1105 returnValue = NodeTypes.LastModified.getLastModified(content);
1106 } else if (property.equals(NodeTypes.LastModified.LAST_MODIFIED_BY)) {
1107 returnValue = NodeTypes.LastModified.getLastModifiedBy(content);
1108 } else if (property.equals(NodeTypes.Renderable.TEMPLATE)) {
1109 returnValue = NodeTypes.Renderable.getTemplate(content);
1110 } else if (property.equals(NodeTypes.Activatable.LAST_ACTIVATED)) {
1111 returnValue = NodeTypes.Activatable.getLastActivated(content);
1112 } else if (property.equals(NodeTypes.Activatable.LAST_ACTIVATED_BY)) {
1113 returnValue = NodeTypes.Activatable.getLastActivatedBy(content);
1114 } else if (property.equals(NodeTypes.Activatable.ACTIVATION_STATUS)) {
1115 returnValue = NodeTypes.Activatable.getActivationStatus(content);
1116 } else if (property.equals(NodeTypes.Deleted.DELETED)) {
1117 returnValue = NodeTypes.Deleted.getDeleted(content);
1118 } else if (property.equals(NodeTypes.Deleted.DELETED_BY)) {
1119 returnValue = NodeTypes.Deleted.getDeletedBy(content);
1120 } else if (property.equals(NodeTypes.Deleted.COMMENT)) {
1121
1122 returnValue = NodeTypes.Deleted.getComment(content);
1123 } else {
1124
1125
1126
1127 returnValue = MetaDataUtil.getMetaData(content).getStringProperty(property);
1128
1129
1130 log.warn("Deprecated constant [{}] used to query for meta data property on node [{}]", property, NodeUtil.getPathIfPossible(content));
1131 }
1132 } catch (RepositoryException e) {
1133 log.error("An error occured while trying to get [{}] property at [{}]", property, NodeUtil.getNodePathIfPossible(content), e);
1134 return null;
1135 }
1136
1137 return returnValue instanceof Calendar ? ISO8601.format((Calendar) returnValue) : returnValue != null ? returnValue.toString() : null;
1138 }
1139
1140
1141
1142
1143 public String metaData(ContentMap content, String property) {
1144 return metaData(content.getJCRNode(), property);
1145 }
1146
1147
1148
1149
1150
1151
1152
1153 @Deprecated
1154 public Collection<Node> search(String workspace, String statement, String language, String returnItemType) {
1155 try {
1156 return NodeUtil.getCollectionFromNodeIterator(QueryUtil.search(workspace, statement, language, returnItemType));
1157 } catch (Exception e) {
1158 log.error(e.getMessage(), e);
1159 }
1160 return null;
1161 }
1162
1163
1164
1165
1166
1167
1168
1169
1170 @Deprecated
1171 public Collection<Node> simpleSearch(String workspace, String statement, String returnItemType, String startPath) {
1172 if (StringUtils.isEmpty(statement)) {
1173 log.error("Cannot search with empty statement.");
1174 return null;
1175 }
1176 String query = QueryUtil.buildQuery(statement, startPath);
1177 try {
1178 return NodeUtil.getCollectionFromNodeIterator(QueryUtil.search(workspace, query, "JCR-SQL2", returnItemType));
1179 } catch (Exception e) {
1180 log.error(e.getMessage(), e);
1181 }
1182 return null;
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194 public Node siteRoot(Node content) {
1195 return this.siteRoot(content, DefaultTemplateTypes.SITE_ROOT);
1196 }
1197
1198
1199
1200
1201 public ContentMap siteRoot(ContentMap content) {
1202 return this.siteRoot(content, DefaultTemplateTypes.SITE_ROOT);
1203 }
1204
1205
1206
1207
1208 public ContentMap siteRoot(ContentMap content, String siteRootTemplateType) {
1209 return asContentMap(siteRoot(content.getJCRNode(), siteRootTemplateType));
1210 }
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222 public Node siteRoot(Node content, String siteRootTemplateType) {
1223 if (siteRootTemplateType == null) {
1224 siteRootTemplateType = DefaultTemplateTypes.SITE_ROOT;
1225 }
1226 try {
1227 final Node page = page(content);
1228 final Node root = parentWithTemplateType(page, siteRootTemplateType);
1229 return (root == null) ? (Node) page.getAncestor(0) : root;
1230 } catch (RepositoryException e) {
1231 throw new RuntimeException("Can't access site root.", e);
1232 }
1233 }
1234
1235
1236
1237
1238
1239
1240
1241 public String templateType(Node pageNode) {
1242 return templateTypeHelper.getTemplateTypeOrDefault(pageNode);
1243 }
1244
1245
1246
1247
1248 public String templateType(ContentMap page) {
1249 return templateType(asJCRNode(page));
1250 }
1251
1252
1253
1254
1255
1256
1257
1258 public String templateSubtype(Node pageNode) {
1259 return templateTypeHelper.getTemplateSubtypeOrDefault(pageNode);
1260 }
1261
1262
1263
1264
1265 public String templateSubtype(ContentMap page) {
1266 return templateSubtype(asJCRNode(page));
1267 }
1268
1269
1270
1271
1272 public boolean hasTemplateOfType(Node pageNode, String templateType) {
1273 return templateTypeHelper.hasTemplateOfType(pageNode, templateType);
1274 }
1275
1276
1277
1278
1279 public boolean hasTemplateOfType(ContentMap page, String templateType) {
1280 return hasTemplateOfType(asJCRNode(page), templateType);
1281 }
1282
1283
1284
1285
1286 public Node parentWithTemplateType(Node pageNode, String templateType) throws RepositoryException {
1287 return templateTypeHelper.findParentWithTemplateType(pageNode, templateType);
1288 }
1289
1290
1291
1292
1293 public ContentMap parentWithTemplateType(ContentMap page, String templateType) throws RepositoryException {
1294 return asContentMap(parentWithTemplateType(asJCRNode(page), templateType));
1295 }
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307 public List<Node> contentListByTemplateType(Node searchRoot, String templateType, String templateSubtype, int maxResultSize, String andClause, String orderByClause) throws RepositoryException {
1308 return templateTypeHelper.getContentListByTemplateType(searchRoot, templateType, templateSubtype, maxResultSize, andClause, orderByClause);
1309 }
1310
1311
1312
1313
1314 public List<ContentMap> contentListByTemplateType(ContentMap searchRoot, String templateType, String templateSubtype, int maxResultSize, String andClause, String orderByClause) throws RepositoryException {
1315 return asContentMapList(contentListByTemplateType(asJCRNode(searchRoot), templateType, templateSubtype, maxResultSize, andClause, orderByClause));
1316 }
1317
1318
1319
1320
1321 public List<Node> contentListByTemplateType(Node siteRoot, String templateType, String templateSubtype) throws RepositoryException {
1322 return contentListByTemplateType(siteRoot, templateType, templateSubtype, Integer.MAX_VALUE, null, null);
1323 }
1324
1325
1326
1327
1328 public List<ContentMap> contentListByTemplateType(ContentMap siteRoot, String templateType, String templateSubtype) throws RepositoryException {
1329 return asContentMapList(contentListByTemplateType(asJCRNode(siteRoot), templateType, templateSubtype, Integer.MAX_VALUE, null, null));
1330 }
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341 public List<Node> contentListByTemplateIds(Node searchRoot, Set<String> templateIds, int maxResultSize, String andClause, String orderByClause) throws RepositoryException {
1342 return templateTypeHelper.getContentListByTemplateIds(searchRoot, templateIds, maxResultSize, andClause, orderByClause);
1343 }
1344
1345
1346
1347
1348 public List<ContentMap> contentListByTemplateIds(ContentMap searchRoot, Set<String> templateIds, int maxResultSize, String andClause, String orderByClause) throws RepositoryException {
1349 return asContentMapList(contentListByTemplateIds(asJCRNode(searchRoot), templateIds, maxResultSize, andClause, orderByClause));
1350 }
1351
1352
1353
1354
1355 public List<Node> contentListByTemplateId(Node searchRoot, String templateId) throws RepositoryException {
1356 return contentListByTemplateIds(searchRoot, Collections.singleton(templateId), Integer.MAX_VALUE, null, null);
1357 }
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368 public List<Node> contentListByTemplateId(Node searchRoot, String templateId, int maxResultSize, String andClause, String orderByClause) throws RepositoryException {
1369 return contentListByTemplateIds(searchRoot, Collections.singleton(templateId), maxResultSize, andClause, orderByClause);
1370 }
1371
1372
1373
1374
1375 public String abbreviateString(String stringToAbbreviate, int length, String suffix) {
1376 if (stringToAbbreviate == null) {
1377 return null;
1378 }
1379
1380 if (stringToAbbreviate.length() > length) {
1381 final int lengthMinusSuffix = length - suffix.length();
1382 String abbreviatedString = StringUtils.left(stringToAbbreviate, lengthMinusSuffix);
1383
1384
1385 String firstCharAfterCut = stringToAbbreviate.substring(lengthMinusSuffix, lengthMinusSuffix + 1);
1386 if (!" ".equals(firstCharAfterCut)) {
1387 abbreviatedString = StringUtils.substringBeforeLast(abbreviatedString, " ");
1388 }
1389
1390 return abbreviatedString + suffix;
1391 }
1392
1393 return stringToAbbreviate;
1394 }
1395
1396
1397
1398
1399 public String abbreviateString(String stringToAbbreviate, int length) {
1400 return abbreviateString(stringToAbbreviate, length, " ...");
1401 }
1402
1403
1404
1405
1406 public String fileExtension(String fileName) {
1407 return PathUtil.getExtension(fileName);
1408 }
1409
1410
1411
1412
1413
1414
1415 public String readableFileSize(long sizeBytes) {
1416 return FileUtils.byteCountToDisplaySize(sizeBytes);
1417 }
1418
1419
1420
1421
1422 public boolean isCurrentLocale(String language) {
1423 return StringUtils.equals(webContextProvider.get().getAggregationState().getLocale().toString(), language);
1424 }
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434 public Map<String, String> localizedLinks() throws RepositoryException {
1435 final Node currentNode = webContextProvider.get().getAggregationState().getCurrentContentNode();
1436
1437 return localizedLinks(currentNode);
1438 }
1439
1440
1441
1442
1443
1444
1445 public Map<String, String> localizedLinks(Node content) throws RepositoryException {
1446 final Node pageNode = page(content);
1447
1448 final String pageIdentifier = pageNode.getIdentifier();
1449 final Collection<Locale> locales = i18nContentSupport.get().getLocales();
1450 if (i18nContentSupport.get().isEnabled() && locales.size() > 1) {
1451 final Map<String, String> map = new LinkedHashMap<>();
1452 for (Locale locale : locales) {
1453 final String uri = createURI(pageIdentifier, locale);
1454
1455
1456 final String label = locale.toString();
1457 map.put(label, uri);
1458 }
1459 return map;
1460 }
1461
1462 return Collections.emptyMap();
1463 }
1464
1465
1466
1467
1468
1469
1470 private String createURI(final String identifier, final Locale locale) {
1471
1472
1473 final Locale currentLocale = i18nContentSupport.get().getLocale();
1474 String uri = null;
1475 final AggregationState aggregationState;
1476
1477 if (Components.getComponent(RenderingEngine.class).getEscapeHtml()) {
1478 aggregationState = new HTMLEscapingWebContextWrapper(webContextProvider.get()).getAggregationState();
1479 } else {
1480 aggregationState = webContextProvider.get().getAggregationState();
1481 }
1482 try {
1483 aggregationState.setLocale(locale);
1484 uri = LinkUtil.createAbsoluteLink(RepositoryConstants.WEBSITE, identifier);
1485 } catch (RepositoryException e) {
1486 log.error("Error creating a localized link to node with identifier {} for locale {}", identifier, locale.toString());
1487 } finally {
1488
1489 aggregationState.setLocale(currentLocale);
1490 }
1491
1492 final String selector = aggregationState.getSelector();
1493 if (StringUtils.isNotBlank(selector)) {
1494 final String defaultExtension = Components.getComponent(ServerConfiguration.class).getDefaultExtension();
1495 if (StringUtils.isNotBlank(defaultExtension)) {
1496 uri = StringUtils.substringBeforeLast(uri, "." + defaultExtension) + SelectorUtil.SELECTOR_DELIMITER + selector + SelectorUtil.SELECTOR_DELIMITER + "." + defaultExtension;
1497 } else {
1498 uri = uri + SelectorUtil.SELECTOR_DELIMITER + selector + SelectorUtil.SELECTOR_DELIMITER;
1499 }
1500 }
1501
1502 return uri;
1503 }
1504
1505 }