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.cms.util;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.Content.ContentFilter;
38 import info.magnolia.cms.core.DefaultContent;
39 import info.magnolia.cms.core.HierarchyManager;
40 import info.magnolia.cms.core.ItemType;
41 import info.magnolia.cms.core.Path;
42 import info.magnolia.cms.security.AccessDeniedException;
43 import info.magnolia.context.MgnlContext;
44 import info.magnolia.jcr.util.NodeUtil;
45
46 import java.io.File;
47 import java.io.FileInputStream;
48 import java.io.FileOutputStream;
49 import java.io.IOException;
50 import java.util.ArrayList;
51 import java.util.Collection;
52 import java.util.Comparator;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.regex.Matcher;
56 import java.util.regex.Pattern;
57
58 import javax.jcr.ImportUUIDBehavior;
59 import javax.jcr.Node;
60 import javax.jcr.PathNotFoundException;
61 import javax.jcr.RepositoryException;
62 import javax.jcr.Session;
63
64 import org.apache.commons.io.FileUtils;
65 import org.apache.commons.io.IOUtils;
66 import org.apache.commons.lang3.StringUtils;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71
72
73
74
75 @Deprecated
76 public class ContentUtil {
77 private final static Logger log = LoggerFactory.getLogger(ContentUtil.class);
78
79
80
81
82 public static ContentFilter ALL_NODES_CONTENT_FILTER = new ContentFilter() {
83
84 @Override
85 public boolean accept(Content content) {
86 return true;
87 }
88 };
89
90
91
92
93 public static ContentFilter ALL_NODES_EXCEPT_JCR_CONTENT_FILTER = new ContentFilter() {
94
95 @Override
96 public boolean accept(Content content) {
97 return !content.getName().startsWith("jcr:");
98 }
99 };
100
101
102
103
104 public static ContentFilter EXCLUDE_META_DATA_CONTENT_FILTER = new ContentFilter() {
105 @Override
106 public boolean accept(Content content) {
107 return !content.getName().startsWith("jcr:") && !content.isNodeType(ItemType.NT_METADATA);
108 }
109 };
110
111
112
113
114 public static ContentFilter MAGNOLIA_FILTER = new ContentFilter() {
115 @Override
116 public boolean accept(Content content) {
117
118 try {
119 String nodetype = content.getNodeType().getName();
120
121 return nodetype.startsWith("mgnl:");
122 } catch (RepositoryException e) {
123 log.error("Unable to read nodetype for node {}", content.getHandle());
124 }
125 return false;
126 }
127 };
128
129
130
131
132
133 public static interface Visitor {
134 void visit(Content node) throws Exception;
135 }
136
137
138
139
140 public static interface PostVisitor extends Visitor {
141 void postVisit(Content node) throws Exception;
142 }
143
144
145
146
147
148
149
150 public static Content getContent(String repository, String path) {
151 try {
152 return MgnlContext.getHierarchyManager(repository).getContent(path);
153 } catch (RepositoryException e) {
154 return null;
155 }
156 }
157
158
159
160
161 public static Content getContentByUUID(String repository, String uuid) {
162 try {
163 return MgnlContext.getHierarchyManager(repository).getContentByUUID(uuid);
164 } catch (RepositoryException e) {
165 return null;
166 }
167 }
168
169
170
171
172
173
174
175 public static Content getContent(Content node, String name) {
176 try {
177 return node.getContent(name);
178 } catch (RepositoryException e) {
179 return null;
180 }
181 }
182
183
184
185
186 public static Content getOrCreateContent(Content node, String name, ItemType contentType) throws AccessDeniedException, RepositoryException {
187 return getOrCreateContent(node, name, contentType, false);
188 }
189
190
191
192
193 public static Content getOrCreateContent(Content node, String name, ItemType contentType, boolean save)
194 throws AccessDeniedException, RepositoryException {
195 Content res = null;
196 try {
197 res = node.getContent(name);
198 } catch (PathNotFoundException e) {
199 res = node.createContent(name, contentType);
200 if (save) {
201 res.getParent().save();
202 }
203 }
204 return res;
205 }
206
207
208
209
210 public static Content getCaseInsensitive(Content node, String name) {
211 if (name == null || node == null) {
212 return null;
213 }
214 name = name.toLowerCase();
215 for (Content child : node.getChildren(ALL_NODES_CONTENT_FILTER)) {
216 if (child.getName().toLowerCase().equals(name)) {
217 return child;
218 }
219 }
220 return null;
221 }
222
223
224
225
226 public static List<Content> collectAllChildren(Content node) {
227 List<Content> nodes = new ArrayList<Content>();
228 return collectAllChildren(nodes, node, new ItemType[]{ItemType.CONTENT, ItemType.CONTENTNODE});
229 }
230
231
232
233
234
235
236 public static List<Content> collectAllChildren(Content node, ContentFilter filter) {
237 List<Content> nodes = new ArrayList<Content>();
238 return collectAllChildren(nodes, node, filter);
239 }
240
241
242
243
244
245
246 private static List<Content> collectAllChildren(List<Content> nodes, Content node, ContentFilter filter) {
247
248 Collection<Content> children = node.getChildren(filter);
249 for (Content child : children) {
250 nodes.add(child);
251 }
252
253
254 Collection<Content> allChildren = node.getChildren(EXCLUDE_META_DATA_CONTENT_FILTER);
255
256
257 for (Content child : allChildren) {
258 collectAllChildren(nodes, child, filter);
259 }
260
261 return nodes;
262 }
263
264
265
266
267 public static List<Content> collectAllChildren(Content node, ItemType type) {
268 List<Content> nodes = new ArrayList<Content>();
269 return collectAllChildren(nodes, node, new ItemType[]{type});
270 }
271
272
273
274
275 public static Collection<Content> getAllChildren(Content node) {
276 return node.getChildren(EXCLUDE_META_DATA_CONTENT_FILTER);
277 }
278
279
280
281
282 public static Collection<Content> getAllChildren(Content node, Comparator<Content> comp) {
283 return node.getChildren(EXCLUDE_META_DATA_CONTENT_FILTER, comp);
284 }
285
286
287
288
289 public static List<Content> collectAllChildren(Content node, ItemType[] types) {
290 List<Content> nodes = new ArrayList<Content>();
291 return collectAllChildren(nodes, node, types);
292 }
293
294
295
296
297 private static List<Content> collectAllChildren(List<Content> nodes, Content node, ItemType[] types) {
298 for (int i = 0; i < types.length; i++) {
299 ItemType type = types[i];
300
301 Collection<Content> children = node.getChildren(type);
302 for (Content child : children) {
303 nodes.add(child);
304 collectAllChildren(nodes, child, types);
305 }
306 }
307 return nodes;
308 }
309
310
311
312
313
314 public static Content getAncestorOfType(final Content firstNode, final String nodeType) throws RepositoryException {
315 Content node = firstNode;
316 while (!node.isNodeType(nodeType)) {
317 node = node.getParent();
318 if (node.getLevel() == 0) {
319 throw new RepositoryException("No ancestor of type " + nodeType + " found for " + firstNode);
320 }
321 }
322 return node;
323 }
324
325
326
327
328 public static void orderBefore(Content nodeToMove, String targetNodeName) throws RepositoryException {
329 nodeToMove.getParent().orderBefore(nodeToMove.getName(), targetNodeName);
330 }
331
332
333
334
335
336
337 public static void orderAfter(Content nodeToMove, String targetNodeName) throws RepositoryException {
338 Content parent = nodeToMove.getParent();
339 Boolean readyToMove = false;
340
341 Collection<Content> children = new ArrayList<Content>(ContentUtil.getAllChildren(parent));
342 for (Content child : children) {
343 if (readyToMove) {
344 parent.orderBefore(nodeToMove.getName(), child.getName());
345 readyToMove = false;
346 break;
347 }
348
349 if (child.getName().equals(targetNodeName)) {
350 readyToMove = true;
351 }
352 }
353
354 if (readyToMove) {
355 for (Content child : children) {
356 if (!nodeToMove.getName().equals(child.getName())) {
357 parent.orderBefore(child.getName(), nodeToMove.getName());
358 }
359 }
360 }
361 }
362
363 public static void orderNodes(Content node, String[] nodes) throws RepositoryException {
364 for (int i = nodes.length - 1; i > 0; i--) {
365 node.orderBefore(nodes[i - 1], nodes[i]);
366 }
367 }
368
369
370
371
372 public static void orderNodes(Content node, Comparator<Content> comparator) throws RepositoryException {
373 Collection<Content> children = ContentUtil.getAllChildren(node, comparator);
374 String[] names = new String[children.size()];
375
376 int i = 0;
377 for (Content childNode : children) {
378 names[i] = childNode.getName();
379 i++;
380 }
381 orderNodes(node, names);
382 }
383
384 public static void visit(Content node, Visitor visitor) throws Exception {
385 visit(node, visitor, EXCLUDE_META_DATA_CONTENT_FILTER);
386 }
387
388 public static void visit(Content node, Visitor visitor, ContentFilter filter) throws Exception {
389 visitor.visit(node);
390 for (Content content : node.getChildren(filter)) {
391 visit(content, visitor, filter);
392 }
393 if (visitor instanceof PostVisitor) {
394 ((PostVisitor) visitor).postVisit(node);
395 }
396 }
397
398 public static Content createPath(HierarchyManager hm, String path) throws AccessDeniedException,
399 PathNotFoundException, RepositoryException {
400 return createPath(hm, path, false);
401 }
402
403 public static Content createPath(HierarchyManager hm, String path, boolean save) throws AccessDeniedException,
404 PathNotFoundException, RepositoryException {
405 return createPath(hm, path, ItemType.CONTENT, save);
406 }
407
408 public static Content createPath(HierarchyManager hm, String path, ItemType type) throws AccessDeniedException,
409 PathNotFoundException, RepositoryException {
410 return createPath(hm, path, type, false);
411 }
412
413 public static Content createPath(HierarchyManager hm, String path, ItemType type, boolean save) throws AccessDeniedException,
414 PathNotFoundException, RepositoryException {
415 Content root = hm.getRoot();
416 return createPath(root, path, type, save);
417 }
418
419 public static Content createPath(Content parent, String path, ItemType type) throws RepositoryException,
420 PathNotFoundException, AccessDeniedException {
421 return createPath(parent, path, type, false);
422 }
423
424 public static Content createPath(Content parent, String path, ItemType type, boolean save) throws RepositoryException,
425 PathNotFoundException, AccessDeniedException {
426
427 path = StringUtils.removeStart(path, "/");
428
429 if (StringUtils.isEmpty(path)) {
430 return parent;
431 }
432
433 String[] names = path.split("/");
434
435 for (int i = 0; i < names.length; i++) {
436 String name = names[i];
437 if (parent.hasContent(name)) {
438 parent = parent.getContent(name);
439 } else {
440 final Content newNode = parent.createContent(name, type);
441 if (save) {
442 parent.save();
443 }
444 parent = newNode;
445 }
446 }
447 return parent;
448 }
449
450 public static String uuid2path(String repository, String uuid) {
451 if (StringUtils.isNotEmpty(uuid)) {
452 HierarchyManager hm = MgnlContext.getHierarchyManager(repository);
453 try {
454 Content node = hm.getContentByUUID(uuid);
455 return node.getHandle();
456 } catch (Exception e) {
457
458 }
459
460 }
461 return uuid;
462 }
463
464 public static String path2uuid(String repository, String path) {
465 if (StringUtils.isNotEmpty(path)) {
466 HierarchyManager hm = MgnlContext.getHierarchyManager(repository);
467 try {
468 Content node = hm.getContent(path);
469 return node.getUUID();
470 } catch (Exception e) {
471
472 }
473
474 }
475 return path;
476 }
477
478 public static void deleteAndRemoveEmptyParents(Content node) throws PathNotFoundException, RepositoryException,
479 AccessDeniedException {
480 deleteAndRemoveEmptyParents(node, 0);
481 }
482
483 public static void deleteAndRemoveEmptyParents(Content node, int level) throws PathNotFoundException, RepositoryException,
484 AccessDeniedException {
485 Content parent = null;
486 if (node.getLevel() != 0) {
487 parent = node.getParent();
488 }
489 node.delete();
490 if (parent != null && parent.getLevel() > level && parent.getChildren(ContentUtil.EXCLUDE_META_DATA_CONTENT_FILTER).size() == 0) {
491 deleteAndRemoveEmptyParents(parent, level);
492 }
493 }
494
495
496
497
498
499
500
501 public static void copyInSession(Content src, String dest) throws RepositoryException {
502 NodeUtil.copyInSession(src.getJCRNode(), dest);
503 }
504
505
506
507
508 public static void moveInSession(Content src, String dest) throws RepositoryException {
509 src.getWorkspace().getSession().move(src.getHandle(), dest);
510 }
511
512 public static void rename(Content node, String newName) throws RepositoryException {
513 Content parent = node.getParent();
514 String placedBefore = null;
515 for (Iterator<Content> iter = parent.getChildren(node.getNodeTypeName()).iterator(); iter.hasNext(); ) {
516 Content child = iter.next();
517 if (child.getUUID().equals(node.getUUID())) {
518 if (iter.hasNext()) {
519 child = iter.next();
520 placedBefore = child.getName();
521 }
522 }
523 }
524
525 moveInSession(node, PathUtil.createPath(node.getParent().getHandle(), newName));
526
527
528 if (placedBefore != null) {
529 parent.orderBefore(newName, placedBefore);
530 parent.save();
531 }
532 }
533
534
535
536
537
538
539
540
541
542 public static void changeNodeType(Content node, ItemType newType, boolean replaceAll) throws RepositoryException {
543 if (node == null) {
544 throw new IllegalArgumentException("Content can't be null");
545 }
546 if (newType == null) {
547 throw new IllegalArgumentException("ItemType can't be null");
548 }
549 final String oldTypeName = node.getNodeTypeName();
550 final String newTypeName = newType.getSystemName();
551 if (newTypeName.equals(oldTypeName)) {
552 log.info("Old node type and new one are the same {}. Nothing to change.", newTypeName);
553 return;
554 }
555 final Pattern nodeTypePattern = Pattern.compile("(<sv:property\\s+sv:name=\"jcr:primaryType\"\\s+sv:type=\"Name\"><sv:value>)(" + oldTypeName + ")(</sv:value>)");
556 final String replacement = "$1" + newTypeName + "$3";
557
558 log.debug("pattern is {}", nodeTypePattern.pattern());
559 log.debug("replacement string is {}", replacement);
560 log.debug("replaceAll? {}", replaceAll);
561
562 final String destParentPath = StringUtils.defaultIfEmpty(StringUtils.substringBeforeLast(node.getHandle(), "/"), "/");
563 final Session session = node.getWorkspace().getSession();
564 FileOutputStream outStream = null;
565 FileInputStream inStream = null;
566 File file = null;
567
568 try {
569 file = File.createTempFile("mgnl", null, Path.getTempDirectory());
570 outStream = new FileOutputStream(file);
571 session.exportSystemView(node.getHandle(), outStream, false, false);
572 outStream.flush();
573 final String fileContents = FileUtils.readFileToString(file);
574 log.debug("content string is {}", fileContents);
575 final Matcher matcher = nodeTypePattern.matcher(fileContents);
576 String replaced = null;
577
578 log.debug("starting find&replace...");
579 long start = System.currentTimeMillis();
580 if (matcher.find()) {
581 log.debug("{} will be replaced", node.getHandle());
582 if (replaceAll) {
583 replaced = matcher.replaceAll(replacement);
584 } else {
585 replaced = matcher.replaceFirst(replacement);
586 }
587 log.debug("replaced string is {}", replaced);
588 } else {
589 log.debug("{} won't be replaced", node.getHandle());
590 return;
591 }
592 log.debug("find&replace operations took {}ms", (System.currentTimeMillis() - start));
593
594 FileUtils.writeStringToFile(file, replaced);
595 inStream = new FileInputStream(file);
596 session.importXML(
597 destParentPath,
598 inStream,
599 ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
600
601 } catch (IOException e) {
602 throw new RepositoryException("Can't replace node " + node.getHandle(), e);
603 } finally {
604 IOUtils.closeQuietly(outStream);
605 IOUtils.closeQuietly(inStream);
606 FileUtils.deleteQuietly(file);
607 }
608 }
609
610 public static Content asContent(Node content) {
611 if (content == null) {
612 return null;
613 }
614 return new DefaultContent(content);
615 }
616 }