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