/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UnlockMethod.java,v 1.30.2.1 2004/02/05 16:11:23 mholz Exp $
* $Revision: 1.30.2.1 $
* $Date: 2004/02/05 16:11:23 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed 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.slide.webdav.method;
import java.io.IOException;
import java.util.Enumeration;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.lock.LockTokenNotFoundException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.Configuration;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.PreconditionViolationException;
import org.apache.slide.webdav.util.VersioningHelper;
import org.apache.slide.webdav.util.ViolatedPrecondition;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.CheckedOutVersionControlled;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.apache.util.WebdavStatus;
/**
* UNLOCK method.
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
*/
public class UnlockMethod extends AbstractWebdavMethod {
public static final String LOCK_TOKEN_HEADER_MISSING = "Lock-Token header missing";
public static final String INVALID_LOCK_TOKEN = "Lock-Token is invalid";
public static final String UNLOCK_NOT_ALLOWED = "Principal is neither the lock-owner nor has DAV:unlock privilege";
public static final String IS_NOT_LOCK_ROOT = "Please try to unlock the root of the lock: ";
// ----------------------------------------------------- Instance Variables
/**
* Resource to unlock.
*/
private String resourcePath;
/**
* Id.
*/
private String lockId;
// ----------------------------------------------------------- Constructors
/**
* Constructor.
*
* @param token the token for accessing the namespace
* @param config configuration of the WebDAV servlet
*/
public UnlockMethod(NamespaceAccessToken token,
WebdavServletConfig config) {
super(token, config);
}
// ------------------------------------------------------ Protected Methods
/**
* Parse the request.
*
* @exception WebdavException Bad request
*/
protected void parseRequest()
throws WebdavException {
// Loads the associated object from the store.
resourcePath = requestUri;
if (resourcePath == null) {
resourcePath = "/";
}
lockId = requestHeaders.getLockToken();
if (lockId == null) {
sendError( WebdavStatus.SC_PRECONDITION_FAILED, LOCK_TOKEN_HEADER_MISSING);
throw new WebdavException( WebdavStatus.SC_PRECONDITION_FAILED );
}
}
/**
* Execute the request.
*
* @exception WebdavException
*/
protected void executeRequest()
throws WebdavException {
// Prevent dirty reads
slideToken.setForceStoreEnlistment(true);
try {
checkPreconditions();
lock.unlock(slideToken, requestUri, lockId);
NodeRevisionDescriptors revisionDescriptors =
content.retrieve(slideToken, requestUri);
NodeRevisionDescriptor revisionDescriptor =
content.retrieve(slideToken, revisionDescriptors);
// Check if resource must be checked in due to auto-versioning
// semantics.
ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(token, requestUri, revisionDescriptor);
if( Configuration.useVersionControl() &&
(resourceKind instanceof CheckedOutVersionControlled) ) {
NodeProperty checkinLocktokenProperty =
revisionDescriptor.getProperty(DeltavConstants.I_CHECKIN_LOCKTOKEN,
NamespaceCache.SLIDE_URI);
if (checkinLocktokenProperty == null) {
// retry with default (DAV:) namespace which was the
// former namespace of this property
checkinLocktokenProperty =
revisionDescriptor.getProperty(DeltavConstants.I_CHECKIN_LOCKTOKEN);
}
if ( (checkinLocktokenProperty != null) && (checkinLocktokenProperty.getValue() != null) &&
lockId.equals(checkinLocktokenProperty.getValue().toString()) ) {
VersioningHelper versionHelper = VersioningHelper.getVersioningHelper(slideToken, token, req, resp, config);
versionHelper.checkin(revisionDescriptors, revisionDescriptor, false, false, true);
}
}
// Checking if the resource at the URI isn't a lock-null
// resource, in which case we must attempt to delete it
ObjectNode node = structure.retrieve(slideToken, requestUri);
if (isLockNull(revisionDescriptor)) {
content.remove(slideToken, requestUri, revisionDescriptor);
content.remove(slideToken, revisionDescriptors);
structure.remove(slideToken, node);
}
resp.setStatus(WebdavStatus.SC_NO_CONTENT);
}
catch (PreconditionViolationException e) {
try {
sendPreconditionViolation(e);
throw e;
} catch (IOException x) {}
throw new WebdavException(e.getStatusCode());
}
catch (Exception e) {
int statusCode = getErrorCode( e );
sendError(statusCode, e);
throw new WebdavException( statusCode );
}
}
/**
* Get return status based on exception type.
*/
protected int getErrorCode(Exception ex) {
try {
throw ex;
} catch (RevisionDescriptorNotFoundException e) {
return WebdavStatus.SC_OK;
} catch (LinkedObjectNotFoundException e) {
return WebdavStatus.SC_NOT_FOUND;
} catch (Exception e) {
return super.getErrorCode(e);
}
}
/**
* Returns true
*/
protected boolean methodNeedsTransactionSupport() {
return true;
}
private void checkPreconditions() throws SlideException {
Enumeration locksAll = lock.enumerateLocks(slideToken, resourcePath, true);
if (!locksAll.hasMoreElements()) {
return;
}
NodeLock nodeLock = findMatchingNodeLock(false);
if (nodeLock != null) {
if (!lock.checkLockOwner(slideToken, nodeLock)) {
throw new PreconditionViolationException(
new ViolatedPrecondition("lock-owner-or-unlock-privilege",
WebdavStatus.SC_FORBIDDEN,
UNLOCK_NOT_ALLOWED),
resourcePath
);
}
}
else {
nodeLock = findMatchingNodeLock(true);
if (nodeLock != null) {
throw new PreconditionViolationException(
new ViolatedPrecondition("lock-root",
WebdavStatus.SC_CONFLICT,
IS_NOT_LOCK_ROOT+getFullPath(nodeLock.getObjectUri())),
resourcePath
);
}
else {
throw new PreconditionViolationException(
new ViolatedPrecondition("valid-lock-token",
WebdavStatus.SC_CONFLICT,
INVALID_LOCK_TOKEN),
resourcePath
);
}
}
}
private NodeLock findMatchingNodeLock(boolean inherited) throws ObjectNotFoundException, LockTokenNotFoundException, ServiceAccessException {
NodeLock nodeLock = null;
Enumeration locks = lock.enumerateLocks(slideToken, resourcePath, inherited);
while ( nodeLock == null && locks.hasMoreElements() ) {
NodeLock nl = (NodeLock) locks.nextElement();
if (nl.getLockId().equals(lockId)) {
nodeLock = nl;
}
}
return nodeLock;
}
}