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