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.jcr.util;
35
36 import info.magnolia.cms.core.MgnlNodeType;
37 import info.magnolia.cms.security.AccessDeniedException;
38 import info.magnolia.cms.security.PermissionUtil;
39 import info.magnolia.context.MgnlContext;
40 import info.magnolia.jcr.RuntimeRepositoryException;
41 import info.magnolia.jcr.iterator.NodeIterableAdapter;
42 import info.magnolia.jcr.predicate.AbstractPredicate;
43 import info.magnolia.jcr.wrapper.DelegateNodeWrapper;
44 import info.magnolia.jcr.wrapper.JCRPropertiesFilteringNodeWrapper;
45
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.HashSet;
49 import java.util.Iterator;
50 import java.util.List;
51
52 import javax.jcr.Node;
53 import javax.jcr.NodeIterator;
54 import javax.jcr.PathNotFoundException;
55 import javax.jcr.Property;
56 import javax.jcr.RepositoryException;
57 import javax.jcr.Session;
58 import javax.jcr.nodetype.NodeType;
59 import javax.jcr.nodetype.NodeTypeManager;
60
61 import org.apache.commons.lang.StringUtils;
62 import org.apache.jackrabbit.commons.iterator.FilteringNodeIterator;
63 import org.apache.jackrabbit.commons.predicate.NodeTypePredicate;
64 import org.apache.jackrabbit.commons.predicate.Predicate;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68
69
70
71
72
73 public class NodeUtil {
74
75 private static final Logger log = LoggerFactory.getLogger(NodeUtil.class);
76
77
78
79
80 public static Predicate ALL_NODES_EXCEPT_JCR_FILTER = new AbstractPredicate<Node>() {
81 @Override
82 public boolean evaluateTyped(Node node) {
83 try {
84 return !node.getName().startsWith(MgnlNodeType.JCR_PREFIX);
85 } catch (RepositoryException e) {
86 return false;
87 }
88 }
89 };
90
91
92
93
94 public static AbstractPredicate<Node> EXCLUDE_META_DATA_FILTER = new AbstractPredicate<Node>() {
95
96 @Override
97 public boolean evaluateTyped(Node node) {
98 try {
99 return !node.getName().startsWith(MgnlNodeType.JCR_PREFIX)
100 && !NodeUtil.isNodeType(node, MgnlNodeType.NT_METADATA);
101 } catch (RepositoryException e) {
102 return false;
103 }
104 }
105 };
106
107
108
109
110 public static AbstractPredicate<Node> MAGNOLIA_FILTER = new AbstractPredicate<Node>() {
111
112 @Override
113 public boolean evaluateTyped(Node node) {
114
115 try {
116 String nodeTypeName = node.getPrimaryNodeType().getName();
117
118 return nodeTypeName.startsWith(MgnlNodeType.MGNL_PREFIX);
119 } catch (RepositoryException e) {
120
121 log.error("Unable to read nodetype for node {}", getNodePathIfPossible(node));
122 }
123 return false;
124 }
125 };
126
127
128
129
130 public static Node getNodeByIdentifier(String workspace, String identifier) throws RepositoryException {
131 Node target = null;
132 Session jcrSession;
133 if (workspace == null || identifier == null) {
134 return target;
135 }
136
137 jcrSession = MgnlContext.getJCRSession(workspace);
138 if (jcrSession != null) {
139 target = jcrSession.getNodeByIdentifier(identifier);
140 }
141 return target;
142 }
143
144
145
146
147 public static boolean hasMixin(Node node, String mixinName) throws RepositoryException {
148 if (StringUtils.isBlank(mixinName)) {
149 throw new IllegalArgumentException("Mixin name can't be empty.");
150 }
151 for (NodeType type : node.getMixinNodeTypes()) {
152 if (mixinName.equals(type.getName())) {
153 return true;
154 }
155 }
156 return false;
157 }
158
159
160
161
162
163 public static boolean isNodeType(Node node, String type) throws RepositoryException {
164 node = NodeUtil.deepUnwrap(node, JCRPropertiesFilteringNodeWrapper.class);
165 final String actualType = node.getProperty(MgnlNodeType.JCR_PRIMARY_TYPE).getString();
166
167
168 if (MgnlNodeType.NT_FROZENNODE.equals(actualType) && !(MgnlNodeType.NT_FROZENNODE.equals(type))) {
169 final Property p = node.getProperty(MgnlNodeType.JCR_FROZEN_PRIMARY_TYPE);
170 final String s = p.getString();
171 NodeTypeManager ntManager = node.getSession().getWorkspace().getNodeTypeManager();
172 NodeType primaryNodeType = ntManager.getNodeType(s);
173 return primaryNodeType.isNodeType(type);
174 }
175 return node.isNodeType(type);
176 }
177
178 public static Node unwrap(Node node) throws RepositoryException {
179 Node unwrappedNode = node;
180 while (unwrappedNode instanceof DelegateNodeWrapper) {
181 unwrappedNode = ((DelegateNodeWrapper) unwrappedNode).getWrappedNode();
182 }
183 return unwrappedNode;
184 }
185
186
187
188
189
190 public static Node deepUnwrap(Node node, Class<? extends DelegateNodeWrapper> wrapper) {
191 if (node instanceof DelegateNodeWrapper) {
192 return ((DelegateNodeWrapper) node).deepUnwrap(wrapper);
193 }
194 return node;
195 }
196
197
198
199
200
201 public static Node deepUnwrapAll(Node node, Class<? extends DelegateNodeWrapper> wrapperClass) {
202 while (node instanceof DelegateNodeWrapper) {
203 Node unwrapped = ((DelegateNodeWrapper) node).deepUnwrap(wrapperClass);
204
205 if (unwrapped == node) {
206 break;
207 }
208 node = unwrapped;
209 }
210 return node;
211 }
212
213 public static boolean isWrappedWith(Node node, Class<? extends DelegateNodeWrapper> wrapper) {
214 if (wrapper.isInstance(node)){
215 return true;
216 }
217
218 if (node instanceof DelegateNodeWrapper) {
219 return isWrappedWith(((DelegateNodeWrapper)node).getWrappedNode(), wrapper);
220 }
221 return false;
222 }
223
224
225
226
227
228 public static void orderBefore(Node node, String siblingName) throws RepositoryException {
229 node.getParent().orderBefore(node.getName(), siblingName);
230 }
231
232
233
234
235 public static void orderAfter(Node node, String siblingName) throws RepositoryException {
236
237 if (siblingName == null) {
238 orderFirst(node);
239 return;
240 }
241
242 Node parent = node.getParent();
243 Node sibling = parent.getNode(siblingName);
244 Node siblingAfter = getSiblingAfter(sibling);
245
246 if (siblingAfter == null) {
247 orderLast(node);
248 return;
249 }
250
251
252 parent.orderBefore(node.getName(), siblingAfter.getName());
253 }
254
255
256
257
258 public static void orderFirst(Node node) throws RepositoryException {
259 Node parent = node.getParent();
260 NodeIterator siblings = parent.getNodes();
261 Node firstSibling = siblings.nextNode();
262 if (!firstSibling.isSame(node)) {
263 parent.orderBefore(node.getName(), firstSibling.getName());
264 }
265 }
266
267
268
269
270 public static void orderLast(Node node) throws RepositoryException {
271 node.getParent().orderBefore(node.getName(), null);
272 }
273
274
275
276
277
278 public static void orderNodeUp(Node node) throws RepositoryException {
279 Node siblingBefore = getSiblingBefore(node);
280 if (siblingBefore != null) {
281 node.getParent().orderBefore(node.getName(), siblingBefore.getName());
282 }
283 }
284
285
286
287
288
289 public static void orderNodeDown(Node node) throws RepositoryException {
290 Node siblingAfter = getSiblingAfter(node);
291 if (siblingAfter != null) {
292 node.getParent().orderBefore(siblingAfter.getName(), node.getName());
293 }
294 }
295
296 public static Node getSiblingBefore(Node node) throws RepositoryException {
297 Node parent = node.getParent();
298 NodeIterator siblings = parent.getNodes();
299 Node previousSibling = null;
300 while (siblings.hasNext()) {
301 Node sibling = siblings.nextNode();
302 if (isSame(node, sibling)) {
303 return previousSibling;
304 }
305 previousSibling = sibling;
306 }
307 return null;
308 }
309
310 public static Node getSiblingAfter(Node node) throws RepositoryException {
311 Node parent = node.getParent();
312 NodeIterator siblings = parent.getNodes();
313 while (siblings.hasNext()) {
314 Node sibling = siblings.nextNode();
315 if (isSame(node, sibling)) {
316 break;
317 }
318 }
319 return siblings.hasNext() ? siblings.nextNode() : null;
320 }
321
322
323
324
325
326
327
328 public static Iterable<Node> getSiblings(Node node) throws RepositoryException {
329 Node parent = node.getParent();
330 Iterable<Node> allSiblings = NodeUtil.getNodes(parent);
331 List<Node> siblings = new ArrayList<Node>();
332
333 for(Node sibling: allSiblings) {
334 if (!NodeUtil.isSame(node, sibling)) {
335 siblings.add(sibling);
336 }
337 }
338 return siblings;
339 }
340
341
342
343
344
345
346
347 public static Iterable<Node> getSiblings(Node node, String nodeTypeName) throws RepositoryException {
348 Node parent = node.getParent();
349 Iterable<Node> allSiblings = NodeUtil.getNodes(parent, nodeTypeName);
350 List<Node> sameTypeSiblings = new ArrayList<Node>();
351
352 for(Node sibling: allSiblings) {
353 if (!NodeUtil.isSame(node, sibling)) {
354 sameTypeSiblings.add(sibling);
355 }
356 }
357 return sameTypeSiblings;
358 }
359
360
361
362
363
364
365
366 public static Iterable<Node> getSiblings(Node node, Predicate predicate) throws RepositoryException {
367 Node parent = node.getParent();
368 Iterable<Node> allSiblings = NodeUtil.getNodes(parent, predicate);
369 List<Node> sameTypeSiblings = new ArrayList<Node>();
370
371 for(Node sibling: allSiblings) {
372 if (!NodeUtil.isSame(node, sibling)) {
373 sameTypeSiblings.add(sibling);
374 }
375 }
376 return sameTypeSiblings;
377 }
378
379
380
381
382
383
384 public static Iterable<Node> getSiblingsBefore(Node node) throws RepositoryException {
385 int toIndex = 0;
386 Node parent = node.getParent();
387 List<Node> allSiblings = NodeUtil.asList(NodeUtil.getNodes(parent));
388
389 for(Node sibling: allSiblings) {
390 if (NodeUtil.isSame(node, sibling)) {
391 break;
392 }
393 toIndex++;
394 }
395 return allSiblings.subList(0, toIndex);
396 }
397
398
399
400
401
402
403 public static Iterable<Node> getSiblingsAfter(Node node) throws RepositoryException {
404 int fromIndex = 0;
405 Node parent = node.getParent();
406 List<Node> allSiblings = NodeUtil.asList(NodeUtil.getNodes(parent));
407
408 for(Node sibling: allSiblings) {
409 if (NodeUtil.isSame(node, sibling)) {
410 fromIndex++;
411 break;
412 }
413 fromIndex++;
414 }
415 return allSiblings.subList(fromIndex, allSiblings.size());
416 }
417
418
419
420
421
422
423
424 public static Iterable<Node> getSiblingsBefore(Node node, String nodeTypeName) throws RepositoryException {
425 Node parent = node.getParent();
426 Iterable<Node> allSiblings = NodeUtil.getNodes(parent);
427 List<Node> sameTypeSiblings = new ArrayList<Node>();
428
429 for(Node sibling: allSiblings) {
430 if (NodeUtil.isSame(node, sibling)) {
431 break;
432 }
433 if (isNodeType(sibling, nodeTypeName)) {
434 sameTypeSiblings.add(sibling);
435 }
436 }
437 return sameTypeSiblings;
438 }
439
440
441
442
443
444
445
446 public static Iterable<Node> getSiblingsAfter(Node node, String nodeTypeName) throws RepositoryException {
447 Node parent = node.getParent();
448 List<Node> allSiblings = NodeUtil.asList(NodeUtil.getNodes(parent));
449 int fromIndex = 0;
450
451 for(Node sibling: allSiblings) {
452 fromIndex++;
453 if (NodeUtil.isSame(node, sibling)) {
454 break;
455 }
456 }
457
458 List<Node> sameTypeSiblings = new ArrayList<Node>();
459 for(Node sibling: allSiblings.subList(fromIndex, allSiblings.size())) {
460 if (isNodeType(sibling, nodeTypeName)) {
461 sameTypeSiblings.add(sibling);
462 }
463 }
464 return sameTypeSiblings;
465 }
466
467 public static void moveNode(Node nodeToMove, Node newParent) throws RepositoryException {
468 if (!isSame(newParent, nodeToMove.getParent())) {
469 String newPath = combinePathAndName(newParent.getPath(), nodeToMove.getName());
470 nodeToMove.getSession().move(nodeToMove.getPath(), newPath);
471 }
472 }
473
474 public static void moveNodeBefore(Node nodeToMove, Node target) throws RepositoryException {
475 Node targetParent = target.getParent();
476 moveNode(nodeToMove, targetParent);
477 targetParent.orderBefore(nodeToMove.getName(), target.getName());
478 }
479
480 public static void moveNodeAfter(Node nodeToMove, Node target) throws RepositoryException {
481 Node targetParent = target.getParent();
482 moveNode(nodeToMove, targetParent);
483 orderAfter(nodeToMove, target.getName());
484 }
485
486 public static boolean isFirstSibling(Node node) throws RepositoryException {
487 Node parent = node.getParent();
488 NodeIterator nodes = parent.getNodes();
489 return isSame(nodes.nextNode(), node);
490 }
491
492
493
494
495 public static boolean isSameNameSiblings(Node node1, Node node2) throws RepositoryException {
496 Node parent1 = node1.getParent();
497 Node parent2 = node2.getParent();
498 return isSame(parent1, parent2) && node1.getName().equals(node2.getName());
499 }
500
501 public static boolean isLastSibling(Node node) throws RepositoryException {
502 Node parent = node.getParent();
503 NodeIterator nodes = parent.getNodes();
504 Node last = null;
505 while (nodes.hasNext()) {
506 last = nodes.nextNode();
507 }
508 return isSame(last, node);
509 }
510
511 public static void renameNode(Node node, String newName) throws RepositoryException {
512 Node parent = node.getParent();
513 String newPath = combinePathAndName(parent.getPath(), newName);
514 node.getSession().move(node.getPath(), newPath);
515 }
516
517
518
519
520
521
522
523 public static boolean isGranted(Node node, long permissions) {
524 try {
525 return PermissionUtil.isGranted(node, permissions);
526 } catch (RepositoryException e) {
527
528 throw new RuntimeException(e);
529 }
530 }
531
532
533
534
535
536 public static boolean isSame(Node lhs, Node rhs) throws RepositoryException {
537 return unwrap(lhs).isSame(unwrap(rhs));
538 }
539
540 public static String combinePathAndName(String path, String name) {
541 if ("/".equals(path)) {
542 return "/" + name;
543 }
544 return path + "/" + name;
545 }
546
547
548
549
550
551 public static Node createPath(Node parent, String relPath, String primaryNodeTypeName) throws RepositoryException, PathNotFoundException, AccessDeniedException {
552 return createPath(parent, relPath, primaryNodeTypeName, false);
553 }
554
555
556
557
558
559 public static Node createPath(Node parent, String relPath, String primaryNodeTypeName, boolean save) throws RepositoryException, PathNotFoundException, AccessDeniedException {
560
561 String currentPath = StringUtils.removeStart(relPath, "/");
562
563 if (StringUtils.isEmpty(currentPath)) {
564 return parent;
565 }
566
567 Node root = parent;
568 String[] names = currentPath.split("/");
569
570 for (int i = 0; i < names.length; i++) {
571 String name = names[i];
572 if (root.hasNode(name)) {
573 root = root.getNode(name);
574 } else {
575 final Node newNode = root.addNode(name, primaryNodeTypeName);
576 if (save) {
577 root.getSession().save();
578 }
579 root = newNode;
580 }
581 }
582 return root;
583 }
584
585
586
587
588 public static void visit(Node node, NodeVisitor visitor) throws RepositoryException {
589 visit(node, visitor, EXCLUDE_META_DATA_FILTER);
590 }
591
592 public static void visit(Node node, NodeVisitor visitor, Predicate predicate) throws RepositoryException {
593
594 visitor.visit(node);
595 for (Node child : getNodes(node, predicate)) {
596 visit(child, visitor, predicate);
597 }
598 if (visitor instanceof PostNodeVisitor) {
599 ((PostNodeVisitor) visitor).postVisit(node);
600 }
601 }
602
603 public static Iterable<Node> getNodes(Node parent, Predicate predicate) throws RepositoryException {
604 return asIterable(new FilteringNodeIterator(parent.getNodes(), predicate));
605 }
606
607 public static Iterable<Node> getNodes(Node parent) throws RepositoryException {
608 return getNodes(parent, EXCLUDE_META_DATA_FILTER);
609 }
610
611 public static Iterable<Node> getNodes(Node parent, String nodeTypeName) throws RepositoryException {
612 return getNodes(parent, new NodeTypePredicate(nodeTypeName, false));
613 }
614
615 public static Iterable<Node> asIterable(NodeIterator iterator) {
616 return new NodeIterableAdapter(iterator);
617 }
618
619 public static List<Node> asList(Iterable<Node> nodes) {
620 List<Node> nodesList = new ArrayList<Node>();
621 for (Node node : nodes) {
622 nodesList.add(node);
623 }
624 return nodesList;
625 }
626
627
628
629
630
631 public static String getName(Node content) {
632 try {
633 return content.getName();
634 } catch (RepositoryException e) {
635 throw new RuntimeRepositoryException(e);
636 }
637 }
638
639
640
641
642 public static Iterable<Node> collectAllChildren(Node node) throws RepositoryException {
643 List<Node> nodes = new ArrayList<Node>();
644 return collectAllChildren(nodes, node, MAGNOLIA_FILTER);
645 }
646
647
648
649
650 public static Iterable<Node> collectAllChildren(Node node, Predicate predicate) throws RepositoryException {
651 List<Node> nodes = new ArrayList<Node>();
652 return collectAllChildren(nodes, node, predicate);
653 }
654
655
656
657
658
659 public static Iterable<Node> collectAllChildren(List<Node> nodes, Node parent, Predicate predicate) throws RepositoryException {
660
661 nodes.addAll(asList(getNodes(parent, predicate)));
662
663
664 Iterator<Node> allChildren = getNodes(parent, EXCLUDE_META_DATA_FILTER).iterator();
665
666
667 while (allChildren.hasNext()) {
668 collectAllChildren(nodes, allChildren.next(), predicate);
669 }
670
671 return nodes;
672 }
673
674
675
676
677 public static Collection<Node> getAncestors(Node node) throws RepositoryException {
678 List<Node> allAncestors = new ArrayList<Node>();
679 int level = node.getDepth();
680 while (level != 0) {
681 try {
682 allAncestors.add((Node) node.getAncestor(--level));
683 } catch (AccessDeniedException e) {
684 log.debug("Node " + node.getIdentifier() + " didn't allow access to Ancestor's ");
685 }
686 }
687 return allAncestors;
688 }
689
690
691
692
693 public static String getNodeIdentifierIfPossible(Node content) {
694 try {
695 return content.getIdentifier();
696 } catch (RepositoryException e) {
697 return "<not available>";
698 }
699 }
700
701 public static String getNodePathIfPossible(Node node) {
702 try {
703 return node.getPath();
704 } catch (RepositoryException e) {
705 return "<not available>";
706 }
707 }
708
709
710
711
712
713
714 public static String getPathIfPossible(Node node) {
715 try {
716 return node.getPath();
717 } catch (RepositoryException e) {
718 log.error("Failed to get handle: " + e.getMessage(), e);
719 return StringUtils.EMPTY;
720 }
721 }
722
723 public static NodeIterator filterNodeType(NodeIterator iterator, String nodeType){
724 return new FilteringNodeIterator(iterator, new info.magnolia.jcr.predicate.NodeTypePredicate(nodeType));
725 }
726
727 public static NodeIterator filterDuplicates(NodeIterator iterator){
728 return new FilteringNodeIterator(iterator, new info.magnolia.jcr.predicate.DuplicateNodePredicate());
729 }
730
731 public static NodeIterator filterParentNodeType(NodeIterator iterator, final String nodeType) throws RepositoryException{
732 return new FilteringNodeIterator(iterator, new info.magnolia.jcr.predicate.NodeTypeParentPredicate(nodeType)) {
733 @Override
734 public Node nextNode(){
735 Node node = super.nextNode();
736 try {
737 while(node.getDepth() != 0 && !node.isNodeType(nodeType)){
738 if(node.getDepth() != 0){
739 node = node.getParent();
740 }
741 }
742 } catch (RepositoryException e) {
743 throw new RuntimeException(e.getMessage(), e);
744 }
745 return node;
746 }
747 };
748 }
749
750 public static Collection<Node> getCollectionFromNodeIterator(NodeIterator iterator){
751 Collection<Node> nodeCollection = new HashSet<Node>(150);
752 while(iterator.hasNext()){
753 nodeCollection.add(iterator.nextNode());
754 }
755 return nodeCollection;
756 }
757 }