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