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