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 &lt;label&gt;
       * element</code>.
       */
      public static final String MUST_START_WITH_LABEL = "Request content must start 
with a &lt;"+E_LABEL+"&gt; element";
      
      /**
       * String constant for <code>Request content &lt;label&gt; element must
       * contain either &lt;add&gt;, &lt;set&gt; or &lt;remove&gt;</code>.
       */
      public static final String LABEL_MUST_CONTAIN_EITHER_ADD_SET_OR_REMOVE =
          "Request content &lt;label&gt; element must contain either &lt;" +
          E_ADD + "&gt;, &lt;" + E_SET + "&gt; or &lt;" + E_REMOVE + "&gt;";
      
      
      
      
      /**
       * 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>&lt;code&gt;DAV:must-be-checked-in&lt;/code&gt;</li>
       * <li>&lt;code&gt;DAV:must-select-version-in-history&lt;/code&gt;</li>
       * <li>&lt;code&gt;DAV:must-be-new-label&lt;/code&gt;</li>
       * <li>&lt;code&gt;DAV:label-must-exist&lt;/code&gt;</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>&lt;label-name-set&gt;</code> property that contains a
       * <code>&lt;label-name&gt;</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]>

Reply via email to