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