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