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.core.version;
35
36 import info.magnolia.cms.core.AbstractContent;
37 import info.magnolia.cms.core.Content;
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.NodeData;
42 import info.magnolia.cms.security.AccessDeniedException;
43 import info.magnolia.cms.security.AccessManager;
44 import info.magnolia.cms.security.Permission;
45 import info.magnolia.cms.util.ContentWrapper;
46 import info.magnolia.cms.util.NodeDataWrapper;
47 import info.magnolia.cms.util.Rule;
48 import info.magnolia.objectfactory.Components;
49 import info.magnolia.repository.RepositoryManager;
50
51 import java.util.ArrayList;
52 import java.util.Calendar;
53 import java.util.Collection;
54 import java.util.Comparator;
55 import java.util.List;
56
57 import javax.jcr.Node;
58 import javax.jcr.PathNotFoundException;
59 import javax.jcr.PropertyType;
60 import javax.jcr.RepositoryException;
61 import javax.jcr.Value;
62 import javax.jcr.Workspace;
63 import javax.jcr.lock.Lock;
64 import javax.jcr.lock.LockException;
65 import javax.jcr.nodetype.NodeType;
66 import javax.jcr.nodetype.NodeTypeManager;
67 import javax.jcr.version.Version;
68 import javax.jcr.version.VersionHistory;
69 import javax.jcr.version.VersionIterator;
70
71 import org.apache.commons.lang3.StringUtils;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75
76
77
78
79 public class ContentVersion extends DefaultContent {
80
81
82
83
84 private final class ContentVersionChildWrapper extends ContentWrapper {
85 private final Content parent;
86
87 private ContentVersionChildWrapper(Content wrappedContent, Content parent) {
88 super(wrappedContent);
89 this.parent = parent;
90 }
91
92 @Override
93 public Content getParent() throws RepositoryException {
94 return parent;
95 }
96
97
98
99
100 @Override
101 public String getHandle() {
102 try {
103 return getParent().getHandle() + "/" + getName();
104 } catch (RepositoryException e) {
105 throw new RuntimeException("Can't create handle for versioned node.", e);
106 }
107 }
108
109
110
111
112 @Override
113 public NodeData newNodeDataInstance(String name, int type, boolean createIfNotExisting) throws AccessDeniedException, RepositoryException {
114 return new NodeDataWrapper(super.newNodeDataInstance(name, type, createIfNotExisting)) {
115 @Override
116 public String getHandle() {
117 return ContentVersionChildWrapper.this.getHandle() + "/" + getName();
118 }
119 };
120 }
121
122 @Override
123 protected Content wrap(Content node) {
124 return new ContentVersionChildWrapper(node, this);
125 }
126 }
127
128 private static Logger log = LoggerFactory.getLogger(ContentVersion.class);
129
130
131
132
133 public static final String VERSION_USER = "versionUser";
134
135
136
137
138 public static final String NAME = "name";
139
140
141
142
143 private final Version state;
144
145
146
147
148 private final Content base;
149
150
151
152
153 private Rule rule;
154
155 private final Version versionedNode;
156
157
158
159
160 @Deprecated
161 public ContentVersion(Version thisVersion, Content base) throws RepositoryException {
162 this(Components.getComponent(RepositoryManager.class), thisVersion, base);
163 }
164
165 public ContentVersion(RepositoryManager repositoryManager, Version thisVersion, Content base) throws RepositoryException {
166 super(repositoryManager);
167
168 if (thisVersion == null) {
169 throw new RepositoryException("Failed to get ContentVersion, version does not exist");
170 }
171 this.versionedNode = thisVersion;
172 if (thisVersion instanceof VersionedNode) {
173 this.state = ((VersionedNode) thisVersion).unwrap();
174 } else {
175 this.state = thisVersion;
176 }
177 this.base = base;
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 this.init();
203 }
204
205
206
207
208 private void init() throws RepositoryException {
209 this.setNode(this.state.getNode(ItemType.JCR_FROZENNODE));
210 try {
211 if (!StringUtils.equalsIgnoreCase(this.state.getName(), VersionManager.ROOT_VERSION)) {
212 this.rule = VersionManager.getInstance().getUsedFilter(this.getJCRNode());
213 }
214 } catch (Exception e) {
215 log.error(e.getMessage(), e);
216 }
217 if (this.rule == null) {
218 log.info("failed to get filter used for creating this version, use open filter");
219 this.rule = new Rule();
220 }
221 }
222
223
224
225
226
227
228 public Calendar getCreated() throws RepositoryException {
229 return this.state.getCreated();
230 }
231
232
233
234
235
236
237 public String getVersionLabel() throws RepositoryException {
238 return this.state.getName();
239 }
240
241
242
243
244
245
246 public VersionHistory getContainingHistory() throws RepositoryException {
247 return this.state.getContainingHistory();
248 }
249
250
251
252
253 @Override
254 public String getName() {
255 try {
256 return VersionManager.getInstance().getSystemNode(this.getJCRNode()).getProperty(NAME).getString();
257 } catch (RepositoryException re) {
258 log.error("Failed to retrieve name from version system node", re);
259 return "";
260 }
261 }
262
263
264
265
266 public String getUserName() {
267 try {
268 return VersionManager.getInstance().getSystemNode(this.getJCRNode()).getProperty(VERSION_USER).getString();
269 } catch (RepositoryException re) {
270 log.error("Failed to retrieve user from version system node", re);
271 return "";
272 }
273 }
274
275
276
277
278 @Override
279 public String getHandle() {
280 return this.base.getHandle();
281 }
282
283
284
285
286
287 @Override
288 public Content getContent(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException {
289
290 if (super.hasContent(name)) {
291 return new ContentVersionChildWrapper(super.getContent(name), this);
292 }
293 Content content = base.getContent(name);
294
295 if (!rule.isAllowed(content.getJCRNode())) {
296 return content;
297 }
298 throw new PathNotFoundException(base.getHandle() + "/" + name);
299 }
300
301
302
303
304 @Override
305 public boolean hasContent(String name) throws RepositoryException {
306 if (super.hasContent(name)) {
307 return true;
308 } else if (base.hasContent(name)) {
309 Content content = base.getContent(name);
310
311 if (!rule.isAllowed(content.getJCRNode())) {
312 return true;
313 }
314 }
315 return false;
316 }
317
318
319
320
321 @Override
322 public Content createContent(String name) throws AccessDeniedException {
323 throw new AccessDeniedException("Not allowed to write on version preview");
324 }
325
326
327
328
329 @Override
330 public Content createContent(String name, String contentType) throws AccessDeniedException {
331 throw new AccessDeniedException("Not allowed to write on version preview");
332 }
333
334
335
336
337 @Override
338 public Content createContent(String name, ItemType contentType) throws AccessDeniedException {
339 throw new AccessDeniedException("Not allowed to write on version preview");
340 }
341
342
343
344
345 @Override
346 public NodeData createNodeData(String name) throws AccessDeniedException {
347 throw new AccessDeniedException("Not allowed to write on version preview");
348 }
349
350
351
352
353 public NodeData createNodeData(String name, Value value, int type) throws AccessDeniedException {
354 throw new AccessDeniedException("Not allowed to write on version preview");
355 }
356
357
358
359
360 @Override
361 public NodeData createNodeData(String name, Value value) throws AccessDeniedException {
362 throw new AccessDeniedException("Not allowed to write on version preview");
363 }
364
365
366
367
368 @Override
369 public NodeData createNodeData(String name, int type) throws AccessDeniedException {
370 throw new AccessDeniedException("Not allowed to write on version preview");
371 }
372
373
374
375
376 @Override
377 public void deleteNodeData(String name) throws RepositoryException {
378 throw new AccessDeniedException("Not allowed to write on version preview");
379 }
380
381
382
383
384 @Override
385 public void updateMetaData() throws AccessDeniedException {
386 throw new AccessDeniedException("Not allowed to write on version preview");
387 }
388
389
390
391
392
393 @Override
394 public Collection<Content> getChildren(ContentFilter filter, String namePattern, Comparator<Content> orderCriteria) {
395 ArrayList<Content> result = new ArrayList<Content>();
396 result.addAll(wrap(super.getChildren(filter, namePattern, orderCriteria)));
397
398 Collection<Content> transientChildren = ((AbstractContent) this.base).getChildren(filter, namePattern, orderCriteria);
399 for (Content transientChild : transientChildren) {
400 try {
401 if (!rule.isAllowed(transientChild.getJCRNode())) {
402 result.add(transientChild);
403 }
404 } catch (RepositoryException e) {
405 throw new RuntimeException("Can't determine node type of " + transientChild, e);
406 }
407 }
408
409 return result;
410 }
411
412 private Collection<Content> wrap(Collection<Content> children) {
413 List<Content> transformed = new ArrayList<Content>();
414 for (Content child : children) {
415 transformed.add(new ContentVersionChildWrapper(child, this));
416 }
417 return transformed;
418 }
419
420
421
422
423 @Override
424 public boolean hasChildren() {
425 return (this.getChildren().size() > 0);
426 }
427
428
429
430
431
432 @Override
433 public boolean hasChildren(String contentType) {
434 return (this.getChildren(contentType).size() > 0);
435 }
436
437
438
439
440 @Override
441 public Content getParent() throws PathNotFoundException, RepositoryException, AccessDeniedException {
442 return this.base.getParent();
443 }
444
445 @Override
446 public Content getAncestor(int level) throws PathNotFoundException, RepositoryException, AccessDeniedException {
447 return this.base.getAncestor(level);
448 }
449
450
451
452
453
454
455
456 @Override
457 public Collection<Content> getAncestors() throws PathNotFoundException, RepositoryException {
458 return this.base.getAncestors();
459 }
460
461
462
463
464
465
466
467 @Override
468 public int getLevel() throws PathNotFoundException, RepositoryException {
469 return this.base.getLevel();
470 }
471
472
473
474
475 @Override
476 public void orderBefore(String srcName, String beforeName) throws RepositoryException {
477 throw new AccessDeniedException("Not allowed to write on version preview");
478 }
479
480
481
482
483
484
485
486
487
488
489 @Override
490 public int getIndex() throws RepositoryException {
491 return this.base.getIndex();
492 }
493
494
495
496
497
498
499 @Override
500 public NodeType getNodeType() throws RepositoryException {
501 log.warn("This is a Version node, it will always return NT_FROZEN as node type.");
502 log.warn("Use getNodeTypeName to retrieve base node primary type");
503 return super.getNodeType();
504 }
505
506
507
508
509 @Override
510 public void restore(String versionName, boolean removeExisting) throws RepositoryException {
511 throw new AccessDeniedException("Not allowed to write on version preview");
512 }
513
514
515
516
517 @Override
518 public void restore(Version version, boolean removeExisting) throws RepositoryException {
519 throw new AccessDeniedException("Not allowed to write on version preview");
520 }
521
522
523
524
525 @Override
526 public void restore(Version version, String relPath, boolean removeExisting) throws RepositoryException {
527 throw new AccessDeniedException("Not allowed to write on version preview");
528 }
529
530
531
532
533 @Override
534 public void restoreByLabel(String versionLabel, boolean removeExisting) throws RepositoryException {
535 throw new AccessDeniedException("Not allowed to write on version preview");
536 }
537
538
539
540
541 @Override
542 public Version addVersion() throws RepositoryException {
543 throw new AccessDeniedException("Not allowed to add version on version preview");
544 }
545
546
547
548
549 @Override
550 public Version addVersion(Rule rule) throws RepositoryException {
551 throw new AccessDeniedException("Not allowed to add version on version preview");
552 }
553
554
555
556
557 @Override
558 public boolean isModified() {
559 log.error("Not valid for version");
560 return false;
561 }
562
563
564
565
566 @Override
567 public VersionHistory getVersionHistory() throws RepositoryException {
568 throw new AccessDeniedException("Not allowed to read VersionHistory of Version");
569 }
570
571
572
573
574 @Override
575 public VersionIterator getAllVersions() throws RepositoryException {
576 throw new AccessDeniedException("Not allowed to get VersionIterator of Version");
577 }
578
579
580
581
582 @Override
583 public ContentVersion getBaseVersion() throws RepositoryException {
584 throw new AccessDeniedException("Not allowed to get base version of Version");
585 }
586
587
588
589
590 @Override
591 public ContentVersion getVersionedContent(Version version) throws RepositoryException {
592 throw new AccessDeniedException("Not allowed to get preview of Version itself");
593 }
594
595
596
597
598 @Override
599 public ContentVersion getVersionedContent(String versionName) throws RepositoryException {
600 throw new AccessDeniedException("Not allowed to get preview of Version itself");
601 }
602
603
604
605
606 @Override
607 public void save() throws RepositoryException {
608 throw new AccessDeniedException("Not allowed to write on version preview");
609 }
610
611
612
613
614
615
616
617 @Override
618 public boolean isGranted(long permissions) {
619 return (permissions & Permission.READ) == permissions;
620 }
621
622
623
624
625 @Override
626 public void delete() throws RepositoryException {
627 throw new AccessDeniedException("Not allowed to write on version preview");
628 }
629
630
631
632
633 @Override
634 public void delete(String path) throws RepositoryException {
635 throw new AccessDeniedException("Not allowed to write on version preview");
636 }
637
638
639
640
641
642
643 @Override
644 public String getUUID() {
645 return this.base.getUUID();
646 }
647
648
649
650
651 @Override
652 public void addMixin(String type) throws RepositoryException {
653 throw new AccessDeniedException("Not allowed to write on version preview");
654 }
655
656
657
658
659 @Override
660 public void removeMixin(String type) throws RepositoryException {
661 throw new AccessDeniedException("Not allowed to write on version preview");
662 }
663
664
665
666
667 @Override
668 public Lock lock(boolean isDeep, boolean isSessionScoped) throws LockException, RepositoryException {
669 throw new AccessDeniedException("Lock not supported on version preview");
670 }
671
672
673
674
675 @Override
676 public Lock lock(boolean isDeep, boolean isSessionScoped, long yieldFor) throws LockException, RepositoryException {
677 throw new AccessDeniedException("Lock not supported on version preview");
678 }
679
680
681
682
683 @Override
684 public Lock getLock() throws LockException, RepositoryException {
685 throw new AccessDeniedException("Lock not supported on version preview");
686 }
687
688
689
690
691 @Override
692 public void unlock() throws LockException, RepositoryException {
693 throw new AccessDeniedException("Lock not supported on version preview");
694 }
695
696
697
698
699 @Override
700 public boolean holdsLock() throws RepositoryException {
701 throw new AccessDeniedException("Lock not supported on version preview");
702 }
703
704
705
706
707 @Override
708 public boolean isLocked() throws RepositoryException {
709 throw new AccessDeniedException("Lock not supported on version preview");
710 }
711
712
713
714
715 @Override
716 public HierarchyManager getHierarchyManager() {
717 return this.base.getHierarchyManager();
718 }
719
720
721
722
723
724
725 @Deprecated
726 @Override
727 public AccessManager getAccessManager() {
728 return this.base.getAccessManager();
729 }
730
731 @Override
732 public Workspace getWorkspace() throws RepositoryException {
733 return this.base.getWorkspace();
734 }
735
736 @Override
737 public boolean hasNodeData(String name) throws RepositoryException {
738 if (this.node.hasProperty(name)) {
739 return true;
740 }
741 if (this.node.hasNode(name) && this.node.getNode(name).getProperty("jcr:frozenPrimaryType").getValue().getString().equals(ItemType.NT_RESOURCE)) {
742 return true;
743 }
744 return false;
745 }
746
747 @Override
748 protected int determineNodeDataType(String name) {
749
750 try {
751 if (this.node.hasProperty(name)) {
752 return this.node.getProperty(name).getType();
753 }
754 if (this.node.hasNode(name) && this.node.getNode(name).getProperty("jcr:frozenPrimaryType").getValue().getString().equals(ItemType.NT_RESOURCE)) {
755 return PropertyType.BINARY;
756 }
757 } catch (RepositoryException e) {
758 throw new IllegalStateException("Can't determine property type of [" + getHandle() + "/" + name + "]", e);
759 }
760 return PropertyType.UNDEFINED;
761 }
762
763 @Override
764 public NodeType[] getMixinNodeTypes() throws RepositoryException {
765 Value[] vals = this.node.getProperty("jcr:frozenMixinTypes").getValues();
766 NodeTypeManager typeMan = getJCRNode().getSession().getWorkspace().getNodeTypeManager();
767 NodeType[] types = new NodeType[vals.length];
768 int i = 0;
769 for (Value val : vals) {
770 types[i++] = typeMan.getNodeType(val.getString());
771 }
772 return types;
773 }
774
775
776
777
778
779
780
781
782 public Version[] getPredecessors() throws RepositoryException {
783
784 return this.state.getPredecessors();
785 }
786
787 @Override
788 public Node getJCRNode() {
789
790 try {
791 if (versionedNode.hasNode("jcr:frozenNode")) {
792 return versionedNode.getFrozenNode();
793 }
794 } catch (RepositoryException e) {
795 log.error("Failed to retrieve frozen node from version {}", versionedNode, e);
796 }
797
798 return versionedNode;
799 }
800 }