View Javadoc

1   /**
2    * This file Copyright (c) 2003-2010 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
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.Rule;
50  import info.magnolia.cms.util.SimpleUrlPattern;
51  
52  import java.util.ArrayList;
53  import java.util.Calendar;
54  import java.util.Collection;
55  import java.util.List;
56  
57  import javax.jcr.PathNotFoundException;
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.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   * @author Sameer Charles
75   * $Id: ContentVersion.java 32886 2010-03-17 08:00:02Z had $
76   */
77  public class ContentVersion extends DefaultContent {
78  
79      private final class FixParentContentWrapper extends ContentWrapper {
80          private final Content parent;
81  
82          private FixParentContentWrapper(Content wrappedContent, Content parent) {
83              super(wrappedContent);
84              this.parent = parent;
85          }
86  
87          @Override
88          public Content getParent() throws RepositoryException {
89              return parent;
90          }
91  
92          @Override
93          protected Content wrap(Content node) {
94              return new FixParentContentWrapper(node, this);
95          }
96      }
97  
98      /**
99       * Logger.
100      */
101     private static Logger log = LoggerFactory.getLogger(ContentVersion.class);
102 
103     /**
104      * user who created this version
105      */
106     public static final String VERSION_USER = "versionUser"; //$NON-NLS-1$
107 
108     /**
109      * name of the base node
110      */
111     public static final String NAME = "name";
112 
113     /**
114      * version node (nt:version)
115      */
116     private Version state;
117 
118     /**
119      * base content
120      */
121     private AbstractContent base;
122 
123     /**
124      * Rule used to create this version
125      */
126     private Rule rule;
127 
128     /**
129      * package private constructor
130      * @param thisVersion
131      * @param base content on which this version is based on
132      * @throws RepositoryException
133      */
134     public ContentVersion(Version thisVersion, AbstractContent base) throws RepositoryException {
135         if (thisVersion == null) {
136             throw new RepositoryException("Failed to get ContentVersion, version does not exist");
137         }
138         this.state = thisVersion;
139         this.base = base;
140 
141         this.hierarchyManager = new HierarchyManagerWrapper(base.getHierarchyManager()) {
142             private AccessManagerImpl accessManager;
143 
144             {
145                 // child nodes (and metaData if nothing else) depends on this to have access when root access is restricted for given user
146                 List<Permission> permissions = new ArrayList<Permission>(getWrappedHierarchyManager().getAccessManager().getPermissionList());
147                 PermissionImpl p = new PermissionImpl();
148                 p.setPattern(new SimpleUrlPattern("/jcr:system/jcr:versionStorage/*"));
149                 // read only
150                 p.setPermissions(8);
151                 permissions.add(p);
152                 // use dedicated AM and not the one base share with its parent
153                 accessManager = new AccessManagerImpl();
154                 accessManager.setPermissionList(permissions);
155             }
156 
157             @Override
158             public AccessManager getAccessManager() {
159                 return accessManager;
160             }
161         };
162         this.init();
163     }
164 
165     /**
166      * Set frozen node of this version as working node
167      * @throws RepositoryException
168      */
169     private void init() throws RepositoryException {
170         this.setNode(this.state.getNode(ItemType.JCR_FROZENNODE));
171         try {
172             if (!StringUtils.equalsIgnoreCase(this.state.getName(), VersionManager.ROOT_VERSION)) {
173                 this.rule = VersionManager.getInstance().getUsedFilter(this);
174             }
175         }
176         catch (Exception e) {
177             log.error(e.getMessage(), e);
178         }
179         if (this.rule == null) {
180             log.info("failed to get filter used for creating this version, use open filter");
181             this.rule = new Rule();
182         }
183     }
184 
185     /**
186      * Get creation date of this version
187      * @throws RepositoryException
188      * @return creation date as calendar
189      */
190     public Calendar getCreated() throws RepositoryException {
191         return this.state.getCreated();
192     }
193 
194     /**
195      * Return the name of the version represented by this object
196      * @return the versions name
197      * @throws RepositoryException
198      */
199     public String getVersionLabel() throws RepositoryException {
200         return this.state.getName();
201     }
202 
203     /**
204      * Get containing version history
205      * @throws RepositoryException
206      * @return version history associated to this version
207      */
208     public VersionHistory getContainingHistory() throws RepositoryException {
209         return this.state.getContainingHistory();
210     }
211 
212     /**
213      * The original name of the node.
214      */
215     public String getName() {
216         try {
217             return VersionManager.getInstance().getSystemNode(this).getNodeData(NAME).getString();
218         }
219         catch (RepositoryException re) {
220             log.error("Failed to retrieve name from version system node", re);
221             return "";
222         }
223     }
224 
225     /**
226      * The name of the user who created this version
227      */
228     public String getUserName() {
229         try {
230             return VersionManager.getInstance().getSystemNode(this).getNodeData(VERSION_USER).getString();
231         }
232         catch (RepositoryException re) {
233             log.error("Failed to retrieve user from version system node", re);
234             return "";
235         }
236     }
237 
238     /**
239      * get original path of this versioned content
240      */
241     public String getHandle() {
242         return this.base.getHandle();
243     }
244 
245     public Content getContent(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException {
246         return new FixParentContentWrapper(super.getContent(name), this);
247     }
248 
249     /**
250      * create Content node under the current node with the specified name
251      * @param name of the node to be created as <code>Content</code>
252      * @return newly created <node>Content </node>
253      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
254      * rights to complete the operation
255      */
256     public Content createContent(String name) throws AccessDeniedException {
257         throw new AccessDeniedException("Not allowed to write on version preview");
258     }
259 
260     /**
261      * create Content node under the current node with the specified name
262      * @param name of the node to be created as <code>Content</code>
263      * @param contentType JCR node type as configured
264      * @return newly created <node>Content </node>
265      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
266      * rights to complete the operation
267      */
268     public Content createContent(String name, String contentType) throws AccessDeniedException {
269         throw new AccessDeniedException("Not allowed to write on version preview");
270     }
271 
272     /**
273      * Create Content node under the current node with the specified name.
274      * @param name of the node to be created as <code>Content</code>
275      * @param contentType ItemType
276      * @return newly created <node>Content </node>
277      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
278      * rights to complete the operation
279      */
280     public Content createContent(String name, ItemType contentType) throws AccessDeniedException {
281         throw new AccessDeniedException("Not allowed to write on version preview");
282     }
283 
284     /**
285      * create top level NodeData object
286      * @param name to be created
287      * @return NodeData requested <code>NodeData</code> object
288      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
289      * rights to complete the operation
290      */
291     public NodeData createNodeData(String name) throws AccessDeniedException {
292         throw new AccessDeniedException("Not allowed to write on version preview");
293     }
294 
295     /**
296      * Create NodeData with the given value and type.
297      * @param name to be created
298      * @param value to be set initially
299      * @param type propertyType
300      * @return NodeData requested <code>NodeData</code> object
301      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
302      * rights to complete the operation
303      */
304     public NodeData createNodeData(String name, Value value, int type) throws AccessDeniedException {
305         throw new AccessDeniedException("Not allowed to write on version preview");
306     }
307 
308     /**
309      * Create NodeData with the given value and type.
310      * @param name to be created
311      * @param value to be set initially
312      * @return NodeData requested <code>NodeData</code> object
313      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
314      * rights to complete the operation
315      */
316     public NodeData createNodeData(String name, Value value) throws AccessDeniedException {
317         throw new AccessDeniedException("Not allowed to write on version preview");
318     }
319 
320     /**
321      * create top level NodeData object
322      * @param name to be created
323      * @param type propertyType
324      * @return NodeData requested <code>NodeData</code> object
325      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
326      * rights to complete the operation
327      */
328     public NodeData createNodeData(String name, int type) throws AccessDeniedException {
329         throw new AccessDeniedException("Not allowed to write on version preview");
330     }
331 
332     /**
333      * delete NodeData with the specified name
334      * @throws javax.jcr.RepositoryException if an error occurs
335      */
336     public void deleteNodeData(String name) throws RepositoryException {
337         throw new AccessDeniedException("Not allowed to write on version preview");
338     }
339 
340     /**
341      * you could call this method anytime to update working page properties - Modification date & Author ID
342      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
343      * rights to complete the operation
344      */
345     public void updateMetaData() throws AccessDeniedException {
346         throw new AccessDeniedException("Not allowed to write on version preview");
347     }
348 
349     /**
350      * gets a Collection containing all child nodes of the same NodeType as "this" object.
351      * @return Collection of content objects
352      */
353     public Collection<Content> getChildren() {
354         try {
355             if (this.rule.isAllowed(this.base.getNodeTypeName())) {
356                 return wrap(super.getChildren());
357             }
358         }
359         catch (RepositoryException re) {
360             log.error(re.getMessage(), re);
361         }
362         return this.base.getChildren();
363     }
364 
365     /**
366      * Get collection of specified content type
367      * @param contentType JCR node type as configured
368      * @return Collection of content nodes
369      */
370     public Collection<Content> getChildren(String contentType) {
371         if (this.rule.isAllowed(contentType)) {
372             return wrap(super.getChildren(contentType));
373         }
374         return this.base.getChildren(contentType);
375     }
376 
377     /**
378      * Get collection of specified content type
379      * @param contentType ItemType
380      * @return Collection of content nodes
381      */
382     public Collection<Content> getChildren(ItemType contentType) {
383         return this.getChildren(contentType.getSystemName());
384     }
385 
386     /**
387      * Get collection of specified content type.
388      * @param contentType JCR node type as configured
389      * @param namePattern
390      * @return Collection of content nodes
391      */
392     public Collection<Content> getChildren(String contentType, String namePattern) {
393         if (this.rule.isAllowed(contentType)) {
394             return wrap(super.getChildren(contentType, namePattern));
395         }
396         return this.base.getChildren(contentType, namePattern);
397     }
398 
399     private Collection<Content> wrap(Collection<Content> children) {
400         List<Content> transformed = new ArrayList<Content>();
401         for (Content child : children) {
402             transformed.add(new FixParentContentWrapper(child, this));
403         }
404         return transformed;
405     }
406 
407     /**
408      * @return Boolean, if sub node(s) exists
409      */
410     public boolean hasChildren() {
411         return (this.getChildren().size() > 0);
412     }
413 
414     /**
415      * @param contentType JCR node type as configured
416      * @return Boolean, if sub <code>collectionType</code> exists
417      */
418     public boolean hasChildren(String contentType) {
419         return (this.getChildren(contentType).size() > 0);
420     }
421 
422     /**
423      * get parent content object
424      * @return Content representing parent node
425      * @throws javax.jcr.PathNotFoundException
426      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
427      * rights to complete the operation
428      * @throws javax.jcr.RepositoryException if an error occurs
429      */
430     public Content getParent() throws PathNotFoundException, RepositoryException, AccessDeniedException {
431         return this.base.getParent();
432     }
433 
434     /**
435      * get absolute parent object starting from the root node
436      * @param level level at which the requested node exist, relative to the ROOT node
437      * @return Content representing parent node
438      * @throws info.magnolia.cms.security.AccessDeniedException if the current session does not have sufficient access
439      * rights to complete the operation
440      * @throws javax.jcr.RepositoryException if an error occurs
441      */
442     public Content getAncestor(int level) throws PathNotFoundException, RepositoryException, AccessDeniedException {
443         return this.base.getAncestor(level);
444     }
445 
446     /**
447      * Convenience method for taglib
448      * @return Content representing node on level 0
449      * @throws javax.jcr.RepositoryException if an error occurs
450      */
451     public Collection<Content> getAncestors() throws PathNotFoundException, RepositoryException {
452         return this.base.getAncestors();
453     }
454 
455     /**
456      * get node level from the ROOT node : FIXME implement getDepth in javax.jcr
457      * @return level at which current node exist, relative to the ROOT node
458      * @throws javax.jcr.PathNotFoundException
459      * @throws javax.jcr.RepositoryException if an error occurs
460      */
461     public int getLevel() throws PathNotFoundException, RepositoryException {
462         return this.base.getLevel();
463     }
464 
465     /**
466      * move current node to the specified location above the named <code>beforename</code>
467      * @param srcName where current node has to be moved
468      * @param beforeName name of the node before the current node has to be placed
469      * @throws javax.jcr.RepositoryException if an error occurs
470      */
471     public void orderBefore(String srcName, String beforeName) throws RepositoryException {
472         throw new AccessDeniedException("Not allowed to write on version preview");
473     }
474 
475     /**
476      * This method returns the index of this node within the ordered set of its same-name sibling nodes. This index is
477      * the one used to address same-name siblings using the square-bracket notation, e.g., /a[3]/b[4]. Note that the
478      * index always starts at 1 (not 0), for compatibility with XPath. As a result, for nodes that do not have
479      * same-name-siblings, this method will always return 1.
480      * @return The index of this node within the ordered set of its same-name sibling nodes.
481      * @throws javax.jcr.RepositoryException if an error occurs
482      */
483     public int getIndex() throws RepositoryException {
484         return this.base.getIndex();
485     }
486 
487     /**
488      * returns primary node type definition of the associated Node of this object
489      * @throws RepositoryException if an error occurs
490      */
491     public NodeType getNodeType() throws RepositoryException {
492         log.warn("This is a Version node, it will always return NT_FROZEN as node type.");
493         log.warn("Use getNodeTypeName to retrieve base node primary type");
494         return super.getNodeType();
495     }
496 
497     /**
498      * Restores this node to the state defined by the version with the specified versionName.
499      * @param versionName
500      * @param removeExisting
501      * @throws javax.jcr.RepositoryException if an error occurs
502      */
503     public void restore(String versionName, boolean removeExisting) throws RepositoryException {
504         throw new AccessDeniedException("Not allowed to write on version preview");
505     }
506 
507     /**
508      * Restores this node to the state defined by the specified version.
509      * @param version
510      * @param removeExisting
511      * @throws javax.jcr.RepositoryException if an error occurs
512      */
513     public void restore(Version version, boolean removeExisting) throws RepositoryException {
514         throw new AccessDeniedException("Not allowed to write on version preview");
515     }
516 
517     /**
518      * Restores the specified version to relPath, relative to this node.
519      * @param version
520      * @param relPath
521      * @param removeExisting
522      * @throws javax.jcr.RepositoryException if an error occurs
523      */
524     public void restore(Version version, String relPath, boolean removeExisting) throws RepositoryException {
525         throw new AccessDeniedException("Not allowed to write on version preview");
526     }
527 
528     /**
529      * Restores this node to the state recorded in the version specified by versionLabel.
530      * @param versionLabel
531      * @param removeExisting
532      * @throws javax.jcr.RepositoryException if an error occurs
533      */
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      * add version leaving the node checked out
540      * @throws javax.jcr.RepositoryException if an error occurs
541      */
542     public Version addVersion() throws RepositoryException {
543         throw new AccessDeniedException("Not allowed to add version on version preview");
544     }
545 
546     /**
547      * add version leaving the node checked out
548      * @param rule to be used to collect content
549      * @throws javax.jcr.RepositoryException if an error occurs
550      * @see info.magnolia.cms.util.Rule
551      */
552     public Version addVersion(Rule rule) throws RepositoryException {
553         throw new AccessDeniedException("Not allowed to add version on version preview");
554     }
555 
556     /**
557      * Returns <code>true</code> if this <code>Item</code> has been saved but has subsequently been modified through
558      * the current session and therefore the state of this item as recorded in the session differs from the state of
559      * this item as saved. Within a transaction, <code>isModified</code> on an <code>Item</code> may return
560      * <code>false</code> (because the <code>Item</code> has been saved since the modification) even if the
561      * modification in question is not in persistent storage (because the transaction has not yet been committed). <p/>
562      * Note that in level 1 (that is, read-only) implementations, this method will always return <code>false</code>.
563      * @return <code>true</code> if this item is modified; <code>false</code> otherwise.
564      */
565     public boolean isModified() {
566         log.error("Not valid for version");
567         return false;
568     }
569 
570     /**
571      * @return version history
572      * @throws javax.jcr.RepositoryException if an error occurs
573      */
574     public VersionHistory getVersionHistory() throws RepositoryException {
575         throw new AccessDeniedException("Not allowed to read VersionHistory of Version");
576     }
577 
578     /**
579      * @return Version iterator retreived from version history
580      * @throws javax.jcr.RepositoryException if an error occurs
581      */
582     public VersionIterator getAllVersions() throws RepositoryException {
583         throw new AccessDeniedException("Not allowed to get VersionIterator of Version");
584     }
585 
586     /**
587      * get the current base version of this node
588      * @return base ContentVersion
589      * @throws javax.jcr.UnsupportedRepositoryOperationException
590      * @throws javax.jcr.RepositoryException
591      */
592     public ContentVersion getBaseVersion() throws RepositoryException {
593         throw new AccessDeniedException("Not allowed to get base version of Version");
594     }
595 
596     /**
597      * get content view over the jcr version object
598      * @param version
599      * @return version object wrapped in ContentVersion
600      * @see info.magnolia.cms.core.version.ContentVersion
601      */
602     public ContentVersion getVersionedContent(Version version) throws RepositoryException {
603         throw new AccessDeniedException("Not allowed to get preview of Version itself");
604     }
605 
606     /**
607      * get content view over the jcr version object
608      * @param versionName
609      * @return version object wrapped in ContentVersion
610      * @see info.magnolia.cms.core.version.ContentVersion
611      */
612     public ContentVersion getVersionedContent(String versionName) throws RepositoryException {
613         throw new AccessDeniedException("Not allowed to get preview of Version itself");
614     }
615 
616     /**
617      * Persists all changes to the repository if validation succeds
618      * @throws javax.jcr.RepositoryException if an error occurs
619      */
620     public void save() throws RepositoryException {
621         throw new AccessDeniedException("Not allowed to write on version preview");
622     }
623 
624     /**
625      * checks for the allowed access rights
626      * @param permissions as defined in javax.jcr.Permission
627      * @return true is the current user has specified access on this node.
628      */
629     public boolean isGranted(long permissions) {
630         return (permissions & Permission.READ) == permissions;
631     }
632 
633     /**
634      * Remove this path
635      * @throws javax.jcr.RepositoryException if an error occurs
636      */
637     public void delete() throws RepositoryException {
638         throw new AccessDeniedException("Not allowed to write on version preview");
639     }
640 
641     /**
642      * Remove specified path
643      * @throws javax.jcr.RepositoryException if an error occurs
644      */
645     public void delete(String path) throws RepositoryException {
646         throw new AccessDeniedException("Not allowed to write on version preview");
647     }
648 
649     /**
650      * UUID of the node refrenced by this object
651      * @return uuid
652      */
653     public String getUUID() {
654         return this.base.getUUID();
655     }
656 
657     /**
658      * add specified mixin type if allowed
659      * @param type mixin type to be added
660      * @throws javax.jcr.RepositoryException if an error occurs
661      */
662     public void addMixin(String type) throws RepositoryException {
663         throw new AccessDeniedException("Not allowed to write on version preview");
664     }
665 
666     /**
667      * Removes the specified mixin node type from this node. Also removes mixinName from this node's jcr:mixinTypes
668      * property. <b>The mixin node type removal takes effect on save</b>.
669      * @param type , mixin type to be removed
670      * @throws javax.jcr.RepositoryException if an error occurs
671      */
672     public void removeMixin(String type) throws RepositoryException {
673         throw new AccessDeniedException("Not allowed to write on version preview");
674     }
675 
676     /**
677      * places a lock on this object
678      * @param isDeep if true this lock will apply to this node and all its descendants; if false, it applies only to
679      * this node.
680      * @param isSessionScoped if true, this lock expires with the current session; if false it expires when explicitly
681      * or automatically unlocked for some other reason.
682      * @return A Lock object containing a lock token.
683      * @throws javax.jcr.lock.LockException if this node is already locked or <code>isDeep</code> is true and a
684      * descendant node of this node already holds a lock.
685      * @throws javax.jcr.RepositoryException if an error occurs
686      * @see javax.jcr.Node#lock(boolean, boolean)
687      */
688     public Lock lock(boolean isDeep, boolean isSessionScoped) throws LockException, RepositoryException {
689         throw new AccessDeniedException("Lock not supported on version preview");
690     }
691 
692     /**
693      * places a lock on this object
694      * @param isDeep if true this lock will apply to this node and all its descendants; if false, it applies only to
695      * this node.
696      * @param isSessionScoped if true, this lock expires with the current session; if false it expires when explicitly
697      * or automatically unlocked for some other reason.
698      * @param yieldFor number of milliseconds for which this method will try to get a lock
699      * @return A Lock object containing a lock token.
700      * @throws javax.jcr.lock.LockException if this node is already locked or <code>isDeep</code> is true and a
701      * descendant node of this node already holds a lock.
702      * @throws javax.jcr.RepositoryException if an error occurs
703      * @see javax.jcr.Node#lock(boolean, boolean)
704      */
705     public Lock lock(boolean isDeep, boolean isSessionScoped, long yieldFor) throws LockException, RepositoryException {
706         throw new AccessDeniedException("Lock not supported on version preview");
707     }
708 
709     /**
710      * Returns the Lock object that applies to this node. This may be either a lock on this node itself or a deep lock
711      * on a node above this node.
712      * @throws javax.jcr.lock.LockException If no lock applies to this node, a LockException is thrown.
713      * @throws javax.jcr.RepositoryException if an error occurs
714      */
715     public Lock getLock() throws LockException, RepositoryException {
716         throw new AccessDeniedException("Lock not supported on version preview");
717     }
718 
719     /**
720      * Removes the lock on this node. Also removes the properties jcr:lockOwner and jcr:lockIsDeep from this node. These
721      * changes are persisted automatically; <b>there is no need to call save</b>.
722      * @throws javax.jcr.lock.LockException if either does not currently hold a lock, or holds a lock for which this
723      * Session does not have the correct lock token
724      * @throws javax.jcr.RepositoryException if an error occurs
725      */
726     public void unlock() throws LockException, RepositoryException {
727         throw new AccessDeniedException("Lock not supported on version preview");
728     }
729 
730     /**
731      * Returns true if this node holds a lock; otherwise returns false. To hold a lock means that this node has actually
732      * had a lock placed on it specifically, as opposed to just having a lock apply to it due to a deep lock held by a
733      * node above.
734      * @return a boolean
735      * @throws javax.jcr.RepositoryException if an error occurs
736      */
737     public boolean holdsLock() throws RepositoryException {
738         throw new AccessDeniedException("Lock not supported on version preview");
739     }
740 
741     /**
742      * Returns true if this node is locked either as a result of a lock held by this node or by a deep lock on a node
743      * above this node; otherwise returns false.
744      * @return a boolean
745      * @throws javax.jcr.RepositoryException if an error occurs
746      */
747     public boolean isLocked() throws RepositoryException {
748         throw new AccessDeniedException("Lock not supported on version preview");
749     }
750 
751     /**
752      * Get hierarchy manager if previously set for this object
753      * @return HierarchyManager
754      */
755     public HierarchyManager getHierarchyManager() {
756         return this.base.getHierarchyManager();
757     }
758 
759     /**
760      * Get access manager if previously set for this object
761      * @return AccessManager
762      * @deprecated use getHierarchyManager instead
763      */
764     public AccessManager getAccessManager() {
765         return this.base.getAccessManager();
766     }
767 
768     @Override
769     public Workspace getWorkspace() throws RepositoryException {
770         return this.base.getWorkspace();
771     }
772 
773 }