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