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