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