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