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.exception.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) throws RepositoryException {
189 if (node instanceof DelegateNodeWrapper)
190 return ((DelegateNodeWrapper) node).deepUnwrap(wrapper);
191 return node;
192 }
193
194
195
196
197 public static void orderBefore(Node node, String siblingName) throws RepositoryException {
198 node.getParent().orderBefore(node.getName(), siblingName);
199 }
200
201
202
203
204 public static void orderAfter(Node node, String siblingName) throws RepositoryException {
205
206 if (siblingName == null) {
207 orderFirst(node);
208 return;
209 }
210
211 Node parent = node.getParent();
212 Node sibling = parent.getNode(siblingName);
213 Node siblingAfter = getSiblingAfter(sibling);
214
215 if (siblingAfter == null) {
216 orderLast(node);
217 return;
218 }
219
220
221 parent.orderBefore(node.getName(), siblingAfter.getName());
222 }
223
224
225
226
227 public static void orderFirst(Node node) throws RepositoryException {
228 Node parent = node.getParent();
229 NodeIterator siblings = parent.getNodes();
230 Node firstSibling = siblings.nextNode();
231 if (!firstSibling.isSame(node)) {
232 parent.orderBefore(node.getName(), firstSibling.getName());
233 }
234 }
235
236
237
238
239 public static void orderLast(Node node) throws RepositoryException {
240 node.getParent().orderBefore(node.getName(), null);
241 }
242
243
244
245
246
247 public static void orderNodeUp(Node node) throws RepositoryException {
248 Node siblingBefore = getSiblingBefore(node);
249 if (siblingBefore != null) {
250 node.getParent().orderBefore(node.getName(), siblingBefore.getName());
251 }
252 }
253
254
255
256
257
258 public static void orderNodeDown(Node node) throws RepositoryException {
259 Node siblingAfter = getSiblingAfter(node);
260 if (siblingAfter != null) {
261 node.getParent().orderBefore(siblingAfter.getName(), node.getName());
262 }
263 }
264
265 public static Node getSiblingBefore(Node node) throws RepositoryException {
266 Node parent = node.getParent();
267 NodeIterator siblings = parent.getNodes();
268 Node previousSibling = null;
269 while (siblings.hasNext()) {
270 Node sibling = siblings.nextNode();
271 if (isSame(node, sibling)) {
272 return previousSibling;
273 }
274 previousSibling = sibling;
275 }
276 return null;
277 }
278
279 public static Node getSiblingAfter(Node node) throws RepositoryException {
280 Node parent = node.getParent();
281 NodeIterator siblings = parent.getNodes();
282 while (siblings.hasNext()) {
283 Node sibling = siblings.nextNode();
284 if (isSame(node, sibling)) {
285 break;
286 }
287 }
288 return siblings.hasNext() ? siblings.nextNode() : null;
289 }
290
291 public static void moveNode(Node nodeToMove, Node newParent) throws RepositoryException {
292 if (!isSame(newParent, nodeToMove.getParent())) {
293 String newPath = combinePathAndName(newParent.getPath(), nodeToMove.getName());
294 nodeToMove.getSession().move(nodeToMove.getPath(), newPath);
295 }
296 }
297
298 public static void moveNodeBefore(Node nodeToMove, Node target) throws RepositoryException {
299 Node targetParent = target.getParent();
300 moveNode(nodeToMove, targetParent);
301 targetParent.orderBefore(nodeToMove.getName(), target.getName());
302 }
303
304 public static void moveNodeAfter(Node nodeToMove, Node target) throws RepositoryException {
305 Node targetParent = target.getParent();
306 moveNode(nodeToMove, targetParent);
307 orderAfter(nodeToMove, target.getName());
308 }
309
310 public static boolean isFirstSibling(Node node) throws RepositoryException {
311 Node parent = node.getParent();
312 NodeIterator nodes = parent.getNodes();
313 return isSame(nodes.nextNode(), node);
314 }
315
316 public static boolean isLastSibling(Node node) throws RepositoryException {
317 Node parent = node.getParent();
318 NodeIterator nodes = parent.getNodes();
319 Node last = null;
320 while (nodes.hasNext()) {
321 last = nodes.nextNode();
322 }
323 return isSame(last, node);
324 }
325
326 public static void renameNode(Node node, String newName) throws RepositoryException {
327 Node parent = node.getParent();
328 String newPath = combinePathAndName(parent.getPath(), newName);
329 node.getSession().move(node.getPath(), newPath);
330 }
331
332
333
334
335
336
337 public static boolean isGranted(Node node, long permissions) {
338 try {
339 return PermissionUtil.isGranted(node.getSession(), node.getPath(),
340 PermissionUtil.convertPermissions(permissions));
341 } catch (RepositoryException e) {
342
343 throw new RuntimeException(e);
344 }
345 }
346
347
348
349
350
351 private static boolean isSame(Node lhs, Node rhs) throws RepositoryException {
352 return unwrap(lhs).isSame(unwrap(rhs));
353 }
354
355 private static String combinePathAndName(String path, String name) {
356 if ("/".equals(path)) {
357 return "/" + name;
358 }
359 return path + "/" + name;
360 }
361
362
363
364
365
366 public static Node createPath(Node parent, String relPath, String primaryNodeTypeName) throws RepositoryException, PathNotFoundException, AccessDeniedException {
367 return createPath(parent, relPath, primaryNodeTypeName, false);
368 }
369
370
371
372
373
374 public static Node createPath(Node parent, String relPath, String primaryNodeTypeName, boolean save) throws RepositoryException, PathNotFoundException, AccessDeniedException {
375
376 String currentPath = StringUtils.removeStart(relPath, "/");
377
378 if (StringUtils.isEmpty(currentPath)) {
379 return parent;
380 }
381
382 Node root = parent;
383 String[] names = currentPath.split("/");
384
385 for (int i = 0; i < names.length; i++) {
386 String name = names[i];
387 if (root.hasNode(name)) {
388 root = root.getNode(name);
389 } else {
390 final Node newNode = root.addNode(name, primaryNodeTypeName);
391 if (save) {
392 root.getSession().save();
393 }
394 root = newNode;
395 }
396 }
397 return root;
398 }
399
400
401
402
403 public static void visit(Node node, NodeVisitor visitor) throws RepositoryException {
404 visit(node, visitor, EXCLUDE_META_DATA_FILTER);
405 }
406
407 public static void visit(Node node, NodeVisitor visitor, Predicate predicate) throws RepositoryException {
408
409 visitor.visit(node);
410 for (Node child : getNodes(node, predicate)) {
411 visit(child, visitor, predicate);
412 }
413 if (visitor instanceof PostNodeVisitor) {
414 ((PostNodeVisitor) visitor).postVisit(node);
415 }
416 }
417
418 public static Iterable<Node> getNodes(Node parent, Predicate predicate) throws RepositoryException {
419 return asIterable(new FilteringNodeIterator(parent.getNodes(), predicate));
420 }
421
422 public static Iterable<Node> getNodes(Node parent) throws RepositoryException {
423 return getNodes(parent, EXCLUDE_META_DATA_FILTER);
424 }
425
426 public static Iterable<Node> getNodes(Node parent, String nodeTypeName) throws RepositoryException {
427 return getNodes(parent, new NodeTypePredicate(nodeTypeName, false));
428 }
429
430 public static Iterable<Node> asIterable(NodeIterator iterator) {
431 return new NodeIterableAdapter(iterator);
432 }
433
434 public static List<Node> asList(Iterable<Node> nodes) {
435 List<Node> nodesList = new ArrayList<Node>();
436 for (Node node : nodes) {
437 nodesList.add(node);
438 }
439 return nodesList;
440 }
441
442
443
444
445
446 public static String getName(Node content) {
447 try {
448 return content.getName();
449 } catch (RepositoryException e) {
450 throw new RuntimeRepositoryException(e);
451 }
452 }
453
454
455
456
457 public static Iterable<Node> collectAllChildren(Node node) throws RepositoryException {
458 List<Node> nodes = new ArrayList<Node>();
459 return collectAllChildren(nodes, node, MAGNOLIA_FILTER);
460 }
461
462
463
464
465 public static Iterable<Node> collectAllChildren(Node node, Predicate predicate) throws RepositoryException {
466 List<Node> nodes = new ArrayList<Node>();
467 return collectAllChildren(nodes, node, predicate);
468 }
469
470
471
472
473
474 public static Iterable<Node> collectAllChildren(List<Node> nodes, Node parent, Predicate predicate) throws RepositoryException {
475
476 nodes.addAll(asList(getNodes(parent, predicate)));
477
478
479 Iterator<Node> allChildren = getNodes(parent, EXCLUDE_META_DATA_FILTER).iterator();
480
481
482 while (allChildren.hasNext()) {
483 collectAllChildren(nodes, allChildren.next(), predicate);
484 }
485
486 return nodes;
487 }
488
489
490
491
492 public static Collection<Node> getAncestors(Node node) throws RepositoryException {
493 List<Node> allAncestors = new ArrayList<Node>();
494 int level = node.getDepth();
495 while (level != 0) {
496 try {
497 allAncestors.add((Node) node.getAncestor(--level));
498 } catch (AccessDeniedException e) {
499 log.debug("Node " + node.getIdentifier() + " didn't allow access to Ancestor's ");
500 }
501 }
502 return allAncestors;
503 }
504
505
506
507
508 public static String getNodeIdentifierIfPossible(Node content) {
509 try {
510 return content.getIdentifier();
511 } catch (RepositoryException e) {
512 return "<not available>";
513 }
514 }
515
516 public static String getNodePathIfPossible(Node node) {
517 try {
518 return node.getPath();
519 } catch (RepositoryException e) {
520 return "<not available>";
521 }
522 }
523
524
525
526
527
528
529 public static String getPathIfPossible(Node node) {
530 try {
531 return node.getPath();
532 } catch (RepositoryException e) {
533 log.error("Failed to get handle: " + e.getMessage(), e);
534 return StringUtils.EMPTY;
535 }
536 }
537
538 }