org.apache.jackrabbit.webdav.simple.VersionControlledResourceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jackrabbit-jcr-server Show documentation
Show all versions of jackrabbit-jcr-server Show documentation
WebDAV server implementations for JCR
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. The ASF licenses this file to You
* under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.webdav.simple;
import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.version.Version;
import javax.jcr.version.VersionHistory;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavResource;
import org.apache.jackrabbit.webdav.DavResourceFactory;
import org.apache.jackrabbit.webdav.DavResourceLocator;
import org.apache.jackrabbit.webdav.DavServletResponse;
import org.apache.jackrabbit.webdav.DavSession;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.DavMethods;
import org.apache.jackrabbit.webdav.jcr.JcrDavException;
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
import org.apache.jackrabbit.webdav.property.HrefProperty;
import org.apache.jackrabbit.webdav.version.LabelInfo;
import org.apache.jackrabbit.webdav.version.MergeInfo;
import org.apache.jackrabbit.webdav.version.UpdateInfo;
import org.apache.jackrabbit.webdav.version.VersionControlledResource;
import org.apache.jackrabbit.webdav.version.VersionHistoryResource;
import org.apache.jackrabbit.webdav.version.VersionResource;
import org.apache.jackrabbit.webdav.version.VersionableResource;
import org.apache.jackrabbit.webdav.version.report.ReportType;
import org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* VersionControlledResourceImpl
represents a JCR node item and
* covers all functionality related to versioning of {@link Node}s.
*
* @see Node
*/
public class VersionControlledResourceImpl extends DeltaVResourceImpl
implements VersionControlledResource {
private static final Logger log = LoggerFactory.getLogger(VersionControlledResourceImpl.class);
/**
* Create a new {@link org.apache.jackrabbit.webdav.DavResource}.
*
* @param locator
* @param factory
* @param session
* @param config
* @param item
* @throws DavException
*/
public VersionControlledResourceImpl(DavResourceLocator locator, DavResourceFactory factory, DavSession session, ResourceConfig config, Item item) throws DavException {
super(locator, factory, session, config, item);
initSupportedReports();
}
/**
* Create a new {@link org.apache.jackrabbit.webdav.DavResource}.
*
* @param locator
* @param factory
* @param session
* @param config
* @param isCollection
* @throws DavException
*/
public VersionControlledResourceImpl(DavResourceLocator locator, DavResourceFactory factory, DavSession session, ResourceConfig config, boolean isCollection) throws DavException {
super(locator, factory, session, config, isCollection);
initSupportedReports();
}
//--------------------------------------------------------< DavResource >---
/**
* Return a comma separated string listing the supported method names.
*
* @return the supported method names.
* @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
*/
@Override
public String getSupportedMethods() {
StringBuffer sb = new StringBuffer(super.getSupportedMethods());
// Versioning support
sb.append(", ").append(VersionableResource.METHODS);
if (isVersionControlled()) {
try {
if (getNode().isCheckedOut()) {
sb.append(", ").append(DavMethods.METHOD_CHECKIN);
} else {
sb.append(", ").append(DavMethods.METHOD_CHECKOUT);
sb.append(", ").append(DavMethods.METHOD_LABEL);
}
} catch (RepositoryException e) {
// should not occur.
log.error(e.getMessage());
}
}
return sb.toString();
}
//------------------------------------------< VersionControlledResource >---
/**
* Adds version control to this resource. If the resource is already under
* version control, this method has no effect. If this resource is a Collection
* resource this method fails with {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}.
*
* @throws org.apache.jackrabbit.webdav.DavException if this resource does not
* exist yet, is a collection or if an error occurs while making the
* underlying node versionable.
* @see org.apache.jackrabbit.webdav.version.VersionableResource#addVersionControl()
*/
public void addVersionControl() throws DavException {
if (!exists()) {
throw new DavException(DavServletResponse.SC_NOT_FOUND);
}
if (isCollection()) {
// since the version-controlled-collection feature is not supported
// collections may not be put under dav version control even if
// the underlying node was / could be made jcr versionable.
throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
}
if (!isVersionControlled()) {
Node item = getNode();
try {
item.addMixin(JcrConstants.MIX_VERSIONABLE);
item.save();
} catch (RepositoryException e) {
throw new JcrDavException(e);
}
} // else: is already version controlled -> ignore
}
/**
* Calls {@link javax.jcr.Node#checkin()} on the underlying repository node.
*
* @throws org.apache.jackrabbit.webdav.DavException
* @see org.apache.jackrabbit.webdav.version.VersionControlledResource#checkin()
*/
public String checkin() throws DavException {
if (!exists()) {
throw new DavException(DavServletResponse.SC_NOT_FOUND);
}
if (!isVersionControlled()) {
throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
}
try {
Version v = getNode().checkin();
String versionHref = getLocatorFromNode(v).getHref(false);
return versionHref;
} catch (RepositoryException e) {
// UnsupportedRepositoryException should not occur
throw new JcrDavException(e);
}
}
/**
* Calls {@link javax.jcr.Node#checkout()} on the underlying repository node.
*
* @throws org.apache.jackrabbit.webdav.DavException
* @see org.apache.jackrabbit.webdav.version.VersionControlledResource#checkout()
*/
public void checkout() throws DavException {
if (!exists()) {
throw new DavException(DavServletResponse.SC_NOT_FOUND);
}
if (!isVersionControlled()) {
throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
}
try {
getNode().checkout();
} catch (RepositoryException e) {
// UnsupportedRepositoryException should not occur
throw new JcrDavException(e);
}
}
/**
* UNCHECKOUT cannot be implemented on top of JSR 170 repository.
* Therefore this methods always throws a DavException
with error code
* {@link org.apache.jackrabbit.webdav.DavServletResponse#SC_NOT_IMPLEMENTED}.
*
* @throws org.apache.jackrabbit.webdav.DavException
* @see org.apache.jackrabbit.webdav.version.VersionControlledResource#uncheckout()
*/
public void uncheckout() throws DavException {
throw new DavException(DavServletResponse.SC_NOT_IMPLEMENTED);
}
/**
* UPDATE feature is not (yet) supported. This method allows fails with
* {@link DavServletResponse#SC_NOT_IMPLEMENTED}.
*
* @param updateInfo
* @return
* @throws DavException
* @see VersionControlledResource#update(UpdateInfo)
*/
public MultiStatus update(UpdateInfo updateInfo) throws DavException {
throw new DavException(DavServletResponse.SC_NOT_IMPLEMENTED);
}
/**
* MERGE feature is not (yet) supported. This method allows fails with
* {@link DavServletResponse#SC_NOT_IMPLEMENTED}.
*
* @param mergeInfo
* @return
* @throws DavException
* @see VersionControlledResource#merge(MergeInfo)
*/
public MultiStatus merge(MergeInfo mergeInfo) throws DavException {
throw new DavException(DavServletResponse.SC_NOT_IMPLEMENTED);
}
/**
* Modify the labels present with the versions of this resource.
*
* @param labelInfo
* @throws DavException
* @see VersionControlledResource#label(LabelInfo)
* @see javax.jcr.version.VersionHistory#addVersionLabel(String, String, boolean)
* @see javax.jcr.version.VersionHistory#removeVersionLabel(String)
*/
public void label(LabelInfo labelInfo) throws DavException {
if (labelInfo == null) {
throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Valid label request body required.");
}
if (!exists()) {
throw new DavException(DavServletResponse.SC_NOT_FOUND);
}
try {
if (!isVersionControlled() || getNode().isCheckedOut()) {
throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "A LABEL request may only be applied to a version-controlled, checked-in resource.");
}
DavResource[] resArr = this.getReferenceResources(CHECKED_IN);
if (resArr.length == 1 && resArr[0] instanceof VersionResource) {
((VersionResource)resArr[0]).label(labelInfo);
} else {
throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "DAV:checked-in property on '" + getHref() + "' did not point to a single VersionResource.");
}
} catch (RepositoryException e) {
throw new JcrDavException(e);
}
}
/**
* Returns the {@link javax.jcr.version.VersionHistory} associated with the repository node.
* If the node is not versionable an exception is thrown.
*
* @return the {@link VersionHistoryResource} associated with this resource.
* @throws org.apache.jackrabbit.webdav.DavException
* @see org.apache.jackrabbit.webdav.version.VersionControlledResource#getVersionHistory()
* @see javax.jcr.Node#getVersionHistory()
*/
public VersionHistoryResource getVersionHistory() throws DavException {
if (!exists()) {
throw new DavException(DavServletResponse.SC_NOT_FOUND);
}
if (!isVersionControlled()) {
throw new DavException(DavServletResponse.SC_FORBIDDEN);
}
try {
VersionHistory vh = getNode().getVersionHistory();
DavResourceLocator loc = getLocatorFromNode(vh);
DavResource vhr = createResourceFromLocator(loc);
if (vhr instanceof VersionHistoryResource) {
return (VersionHistoryResource)vhr;
} else {
// severe error since resource factory doesn't behave correctly.
throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR);
}
} catch (RepositoryException e) {
throw new JcrDavException(e);
}
}
//--------------------------------------------------------------------------
/**
* Define the set of reports supported by this resource.
*
* @see SupportedReportSetProperty
* @see DeltaVResourceImpl#initSupportedReports()
*/
@Override
protected void initSupportedReports() {
super.initSupportedReports();
if (exists()) {
supportedReports.addReportType(ReportType.LOCATE_BY_HISTORY);
if (isVersionControlled()) {
supportedReports.addReportType(ReportType.VERSION_TREE);
}
}
}
/**
* Fill the property set for this resource.
* @see DavResourceImpl#initProperties()
*/
@Override
protected void initProperties() {
if (!propsInitialized) {
super.initProperties();
if (isVersionControlled()) {
Node n = getNode();
// properties defined by RFC 3253 for version-controlled resources
try {
// DAV:version-history (computed)
String vhHref = getLocatorFromNode(n.getVersionHistory()).getHref(true);
properties.add(new HrefProperty(VERSION_HISTORY, vhHref, true));
// DAV:auto-version property: there is no auto version, explicit CHECKOUT is required.
properties.add(new DefaultDavProperty(AUTO_VERSION, null, true));
// baseVersion -> used for DAV:checked-out or DAV:checked-in
String baseVHref = getLocatorFromNode(n.getBaseVersion()).getHref(false);
if (n.isCheckedOut()) {
// DAV:predecessors property
if (n.hasProperty(JcrConstants.JCR_PREDECESSORS)) {
Value[] pv = n.getProperty(JcrConstants.JCR_PREDECESSORS).getValues();
Node[] predecessors = new Node[pv.length];
for (int i = 0; i < pv.length; i++) {
predecessors[i] = n.getSession().getNodeByIdentifier(pv[i].getString());
}
properties.add(getHrefProperty(VersionResource.PREDECESSOR_SET, predecessors, true, false));
}
// DAV:checked-out property (protected)
properties.add(new HrefProperty(CHECKED_OUT, baseVHref, true));
} else {
// DAV:checked-in property (protected)
properties.add(new HrefProperty(CHECKED_IN, baseVHref, true));
}
} catch (RepositoryException e) {
log.error(e.getMessage());
}
}
}
}
/**
* @return true, if this resource is a non-collection resource and represents
* an existing repository node that has the mixin nodetype 'mix:versionable' set.
*/
private boolean isVersionControlled() {
boolean vc = false;
// since the version-controlled-collection feature is not supported
// all collection are excluded from version-control even if the
// underlying node was JCR versionable.
if (exists() && !isCollection()) {
Node item = getNode();
try {
vc = item.isNodeType(JcrConstants.MIX_VERSIONABLE);
} catch (RepositoryException e) {
log.warn(e.getMessage());
}
}
return vc;
}
}