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