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