juergen 02/04/30 01:46:00
Added: src/webdav/server/org/apache/slide/webdav/method
LabelMethod.java
Log:
Initial revision.
(ralf)
Revision Changes Path
1.1
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LabelMethod.java
Index: LabelMethod.java
===================================================================
/*
* $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/LabelMethod.java,v
1.1 2002/04/30 08:46:00 juergen Exp $
* $Revision: 1.1 $
* $Date: 2002/04/30 08:46:00 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Slide", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.slide.webdav.method;
// import list
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException ;
import org.xml.sax.SAXException;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.NestedSlideException;
import org.apache.slide.common.SlideException;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.util.VersioningHelper;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.ViolatedPrecondition;
import org.apache.slide.webdav.util.PreconditionViolationException;
import org.apache.slide.webdav.util.LabeledRevisionNotFoundException;
import org.apache.slide.webdav.util.PropertyHelper;
import org.apache.slide.webdav.util.UriHandler;
import org.apache.slide.webdav.util.XMLValue;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.CheckedInVersionControlled;
import org.apache.slide.webdav.util.resourcekind.VersionControlled;
import org.apache.slide.webdav.util.resourcekind.Version;
import org.apache.util.WebdavStatus;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
/**
* LABEL method.
*
* @version $Revision: 1.1 $
*
* @author <a href="mailto:[EMAIL PROTECTED]">Ralf Stuckert</a>
*/
public class LabelMethod extends AbstractMultistatusResponseMethod implements
DeltavConstants {
/**
** String constant for <code>Request content missing</code>.
**/
public static final String CONTENT_MISSING = "Request content missing";
/**
** String constant for <code>Label missing</code>.
**/
public static final String LABEL_MISSING = "Label missing";
/**
* String constant for <code>"Request content must start with a <label>
* element</code>.
*/
public static final String MUST_START_WITH_LABEL = "Request content must start
with a <"+E_LABEL+"> element";
/**
* String constant for <code>Request content <label> element must
* contain either <add>, <set> or <remove></code>.
*/
public static final String LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE =
"Request content <label> element must contain either <" +
E_ADD + ">, <" + E_SET + "> or <" + E_REMOVE + ">";
/**
* Resource to be written.
*/
private String resourcePath;
/**
* Indicates if the resource to delete is a collection.
*/
protected boolean isCollection = false;
/**
* The VersioningHelper used by this instance.
*/
protected VersioningHelper versioningHelper = null;
/**
* Indicates which label operation to perform:
* <code>add</code>, <code>set</code> or <code>remove</code>.
*/
protected String operation = null;
/**
* The label to add/set/remove.
*/
protected String label = null;
/**
* The value of the <code>Label</code> header
*/
protected String labelHeader = null;
/**
* LABEL method constructor.
*
* @param token the Namespace access token.
* @param req the HTTP request.
* @param resp the HTTP response.
* @param config the servlet config.
*/
public LabelMethod( NamespaceAccessToken token, HttpServletRequest req,
HttpServletResponse resp, WebdavServletConfig config) {
super(token, req, resp, config);
readRequestContent();
versioningHelper = VersioningHelper.getVersioningHelper(slideToken,
token,
req,
resp,
config);
}
/**
* Parse WebDAV XML query.
*
* @throws WebdavException
* @throws IOException
*/
protected void parseRequest() throws WebdavException, IOException {
resourcePath = requestUri;
if (resourcePath == null) {
resourcePath = "/";
}
labelHeader = req.getHeader(DeltavConstants.H_LABEL);
try{
retrieveRequestContent();
Document document = getRequestContent();
if (document == null) {
throw new SAXException(CONTENT_MISSING);
}
Element root = document.getRootElement();
if (root == null) {
throw new SAXException(CONTENT_MISSING);
}
if ( ! DeltavConstants.E_LABEL.equals(root.getName())) {
throw new SAXException(MUST_START_WITH_LABEL);
}
Element current = root.getChild(DeltavConstants.E_ADD,
PropertyHelper.davNamespace);
Element operationElement = null;
if (current != null) {
operationElement = current;
}
current = root.getChild(DeltavConstants.E_SET,
PropertyHelper.davNamespace);
if ( current != null) {
if (operationElement != null) {
throw new
SAXException(LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE);
}
operationElement = current;
}
current = root.getChild(DeltavConstants.E_REMOVE,
PropertyHelper.davNamespace);
if ( current != null) {
if (operationElement != null) {
throw new
SAXException(LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE);
}
operationElement = current;
}
if (operationElement == null) {
throw new SAXException(LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE);
}
operation = operationElement.getName();
Element labelName =
operationElement.getChild(DeltavConstants.E_LABEL_NAME, PropertyHelper.davNamespace);
if ( (labelName == null) ||
(labelName.getText() == null) ||
(labelName.getText().length() == 0) ) {
throw new SAXException(LABEL_MISSING);
}
label = labelName.getText();
}
catch (SAXException e){
resp.sendError(WebdavStatus.SC_BAD_REQUEST, e.getMessage());
throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
}
catch (IOException e){
resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
}
catch (ParserConfigurationException e){
resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
}
}
/**
* Execute the request.
*
* @throws WebdavException
* @throws IOException
*/
protected void executeRequest() throws WebdavException, IOException {
// Prevent dirty reads
slideToken.setForceStoreEnlistment(true);
isCollection = isCollection(resourcePath);
try {
labelResource(resourcePath);
}
catch (NestedSlideException nestedSlideException) {
// If it's not a collection, we don't want to give a 207,
// because it's silly, and it confuses many clients (such as
// MS Web Folders).
if (generate207Response(isCollection, nestedSlideException, requestUri))
{
String errorMessage = generateErrorMessage(nestedSlideException);
// Write it on the servlet writer
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
try {
resp.setContentType(TEXT_XML_UTF_8);
resp.getWriter().write(errorMessage);
} catch(IOException ex) {
// Critical error ... Servlet container is dead or something
ex.printStackTrace();
throw new WebdavException
(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
}
} else {
// Returning 207 on non-collection requests is generally
// considered bad. So let's not do it, since this way
// makes clients generally behave better.
SlideException exception =
(SlideException)nestedSlideException.enumerateExceptions().nextElement();
resp.setStatus(getErrorCode(exception));
if (exception instanceof PreconditionViolationException) {
try {
sendPreconditionViolation((PreconditionViolationException)exception);
} catch(IOException ex) {
// Critical error ... Servlet container is dead or something
ex.printStackTrace();
throw new WebdavException
(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
}
}
}
//
// make sure the transaction is aborted
// throw any WebDAV exception to indicate the transaction wants to be
aborted
//
throw new WebdavException(WebdavStatus.SC_ACCEPTED, false);
}
finally {
resp.setHeader(H_CACHE_CONTROL, NO_CACHE);
}
}
/**
* Labels the reource identified by the given <code>resourcePath</code>.
* If the resource is a collection and a <code>Depth</code> header is specified
* than the request is applied recursivly. If an attempt to label a resource
* fails, the corresponding Exception is contained in the thrown
* NestedSlideException.
*
* @param resourcePath the path of the resource to label.
*
* @throws NestedSlideException, if an attempt to label a resource fails.
*/
protected void labelResource(String resourcePath) throws NestedSlideException {
NestedSlideException nestedSlideException = new NestedSlideException(null);
labelResource(resourcePath, getDepth(), nestedSlideException);
if ( ! nestedSlideException.isEmpty() ) {
throw nestedSlideException;
}
}
/**
* Labels the reource identified by the given <code>resourcePath</code>.
* If the resource is a collection and the <code>depth</code> > 0
* than the request is applied recursivly. If an attempt to label a resource
* fails, the corresponding Exception will be added to the given
* <code>nestedSlideException</code>.
*
* @param resourcePath the path of the resource to label.
* @param depth the depth to use if the resource is a
collection.
* @param nestedSlideException the NestedSlideException to add all
occurring
* Exceptions to.
*/
protected void labelResource(String resourcePath, int depth,
NestedSlideException nestedSlideException) {
try {
if ( ! isCollection(resourcePath) ) {
ViolatedPrecondition violatedPrecondition =
getPreconditionViolation(resourcePath);
if (violatedPrecondition != null) {
throw new PreconditionViolationException(violatedPrecondition,
resourcePath);
}
performLabelOperation(resourcePath);
}
else if (depth > 0) {
// process children recursivly
ObjectNode currentNode = structure.retrieve(slideToken,
resourcePath);
Enumeration childrenEnum = structure.getChildren(slideToken,
currentNode);
if (childrenEnum != null) {
while (childrenEnum.hasMoreElements()) {
labelResource(((ObjectNode)childrenEnum.nextElement()).getUri(), depth-1,
nestedSlideException);
}
}
}
}
catch (SlideException e) {
nestedSlideException.addException(e);
}
catch (JDOMException e) {
nestedSlideException.addException(new SlideException(e.getMessage()));
}
}
/**
* Perform the LABEL operation means it either adds, sets or removes the label.
*
* @param resourcePath the resource to add/set/remove the label.
*
* @throws JDOMException
* @throws SlideException
*/
private void performLabelOperation(String resourcePath) throws JDOMException,
SlideException {
String labeledResourceUri = getResourceUri(resourcePath,
req.getHeader(H_LABEL));
NodeRevisionDescriptors revisionDescriptors =
versioningHelper.retrieveRevisionDescriptors(labeledResourceUri);
NodeRevisionDescriptor revisionDescriptor =
versioningHelper.retrieveLatestRevisionDescriptor(labeledResourceUri,
revisionDescriptors);
ResourceKind resourceKind =
AbstractResourceKind.determineResourceKind(revisionDescriptor);
if (resourceKind instanceof Version) {
if (DeltavConstants.E_REMOVE.equals(operation)) {
PropertyHelper.removeElementFromProperty(revisionDescriptor,
P_LABEL_NAME_SET,
P_LABEL_NAME,
label);
content.store(slideToken, revisionDescriptors.getUri(),
revisionDescriptor, null);
}
if (DeltavConstants.E_SET.equals(operation)) {
try {
NodeRevisionDescriptor alreadyLabeledDescriptor =
versioningHelper.retrieveLabeledRevision(revisionDescriptors.getUri(),
label);
PropertyHelper.removeElementFromProperty(alreadyLabeledDescriptor,
P_LABEL_NAME_SET,
P_LABEL_NAME,
label);
content.store(slideToken, revisionDescriptors.getUri(),
alreadyLabeledDescriptor, null);
}
catch (LabeledRevisionNotFoundException e) {
e.printStackTrace();
}
}
if (DeltavConstants.E_ADD.equals(operation) ||
DeltavConstants.E_SET.equals(operation) ) {
PropertyHelper.addElementToProperty(revisionDescriptor,
P_LABEL_NAME_SET,
P_LABEL_NAME,
label);
content.store(slideToken, revisionDescriptors.getUri(),
revisionDescriptor, null);
}
}
}
/**
* Checks the (DeltaV) preconditions
* <ul>
* <li><code>DAV:must-be-checked-in</code></li>
* <li><code>DAV:must-select-version-in-history</code></li>
* <li><code>DAV:must-be-new-label</code></li>
* <li><code>DAV:label-must-exist</code></li>
* </ul>
*
* @param resourcePath the URI of the resource.
*
* @return the precondition that has been violated (if any).
*
* @throws SlideException
*/
protected ViolatedPrecondition getPreconditionViolation(String resourcePath)
throws SlideException {
ViolatedPrecondition violatedPrecondition = null;
NodeRevisionDescriptors revisionDescriptors =
versioningHelper.retrieveRevisionDescriptors(resourcePath);
NodeRevisionDescriptor revisionDescriptor =
versioningHelper.retrieveLatestRevisionDescriptor(resourcePath,
revisionDescriptors);
ResourceKind resourceKind =
AbstractResourceKind.determineResourceKind(revisionDescriptor);
// check <DAV:must-be-checked-in>
if ( (resourceKind instanceof VersionControlled) &&
!(resourceKind instanceof CheckedInVersionControlled) ) {
return new ViolatedPrecondition(DeltavConstants.C_MUST_BE_CHECKED_IN,
WebdavStatus.SC_CONFLICT);
}
// check <DAV:must-select-version-in-history>
if ( (resourceKind instanceof VersionControlled) &&
(labelHeader != null) ) {
try {
versioningHelper.getLabeledResourceUri(resourcePath, labelHeader);
}
catch (LabeledRevisionNotFoundException e) {
return new
ViolatedPrecondition(DeltavConstants.C_MUST_SELECT_VERSION_IN_HISTORY,
WebdavStatus.SC_CONFLICT);
}
}
try {
String slideResourceUri = getResourceUri(resourcePath, labelHeader);
revisionDescriptors =
versioningHelper.retrieveRevisionDescriptors(slideResourceUri);
revisionDescriptor =
versioningHelper.retrieveLatestRevisionDescriptor(slideResourceUri,
revisionDescriptors);
resourceKind =
AbstractResourceKind.determineResourceKind(revisionDescriptor);
if (resourceKind instanceof Version) {
// check <DAV:label-must-exist>
if (DeltavConstants.E_REMOVE.equals(operation)) {
if ( ! hasLabel(revisionDescriptor, label) ) {
return new
ViolatedPrecondition(DeltavConstants.C_LABEL_MUST_EXIST,
WebdavStatus.SC_CONFLICT);
}
}
try {
versioningHelper.retrieveLabeledRevision(revisionDescriptors.getUri(), label);
// check <DAV:must-be-new-label>
if (DeltavConstants.E_ADD.equals(operation)) {
return new
ViolatedPrecondition(DeltavConstants.C_MUST_BE_NEW_LABEL,
WebdavStatus.SC_CONFLICT);
}
}
catch (LabeledRevisionNotFoundException e) {}
}
}
catch (LabeledRevisionNotFoundException e) {
// check <DAV:label-must-exist>
if (DeltavConstants.E_REMOVE.equals(operation)) {
return new ViolatedPrecondition(DeltavConstants.C_LABEL_MUST_EXIST,
WebdavStatus.SC_CONFLICT);
}
}
return violatedPrecondition;
}
/**
* Returns the value of the <code>Depth</code> header. If not specified,
* <code>0</code> is used as default.
*
* @return the value of the <code>Depth</code> header.
*/
protected int getDepth() {
int depth = 0;
try {
depth = Integer.parseInt(req.getHeader(H_DEPTH));
}
catch (NumberFormatException e) {}
return depth;
}
/**
* Returns <code>true</code> if the given <code>revisionDescriptor</code>
* has a <code><label-name-set></code> property that contains a
* <code><label-name></code> element with the given <code>label</code>.
*
* @param revisionDescriptor the NodeRevisionDescriptor to check.
* @param label the label to look for.
*
* @return <code>true</code>, if the label was found.
*/
protected boolean hasLabel(NodeRevisionDescriptor revisionDescriptor, String
label) {
boolean containsLabel = false;
NodeProperty labelNameSetProperty =
revisionDescriptor.getProperty(DeltavConstants.P_LABEL_NAME_SET);
if ( (labelNameSetProperty != null) && (labelNameSetProperty.getValue() !=
null) ) {
try {
XMLValue xmlValue = new
XMLValue(labelNameSetProperty.getValue().toString());
Iterator iterator = xmlValue.iterator();
while ( !containsLabel && iterator.hasNext()) {
containsLabel =
label.equals(((Element)iterator.next()).getText());
}
}
catch (JDOMException e) {}
catch (IllegalArgumentException e) {}
}
return containsLabel;
}
/**
* Returns the Uri of the resource identified by the given
<code>resourcePath</code>
* and the given <code>label</code>. If the <code>label</code> is
<code>null</code>
* and the resource is a VCR, the associated VR is returned.
*
* @param resourcePath the path of the resource.
* @param label the label (may be <code>null</code>).
*
* @return the Uri of the resource identified by the given
<code>resourcePath</code>
* and the given <code>label</code>.
*
* @throws SlideException
*/
protected String getResourceUri(String resourcePath, String label) throws
SlideException {
String labeledResourceUri =
versioningHelper.getLabeledResourceUri(resourcePath,
label);
NodeRevisionDescriptors revisionDescriptors =
versioningHelper.retrieveRevisionDescriptors(labeledResourceUri);
NodeRevisionDescriptor revisionDescriptor =
versioningHelper.retrieveLatestRevisionDescriptor(labeledResourceUri,
revisionDescriptors);
ResourceKind resourceKind =
AbstractResourceKind.determineResourceKind(revisionDescriptor);
if (resourceKind instanceof VersionControlled) {
labeledResourceUri = versioningHelper.getUriOfAssociatedVR(resourcePath);
}
return labeledResourceUri;
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>