juergen     02/05/07 06:07:19

  Modified:    src/webdav/server/org/apache/slide/webdav/method
                        UpdateMethod.java
  Log:
  Implemented additional semantics for LABEL feature.
  Implement multistatus response with requested properties.
  (ralf)
  
  Revision  Changes    Path
  1.2       +299 -28   
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UpdateMethod.java
  
  Index: UpdateMethod.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UpdateMethod.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- UpdateMethod.java 1 May 2002 15:04:35 -0000       1.1
  +++ UpdateMethod.java 7 May 2002 13:07:19 -0000       1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UpdateMethod.java,v
 1.1 2002/05/01 15:04:35 pnever Exp $
  - * $Revision: 1.1 $
  - * $Date: 2002/05/01 15:04:35 $
  + * $Header: 
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/UpdateMethod.java,v
 1.2 2002/05/07 13:07:19 juergen Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/05/07 13:07:19 $
    *
    * ====================================================================
    *
  @@ -82,7 +82,9 @@
   import org.apache.slide.common.NamespaceAccessToken;
   import org.apache.slide.common.RequestedProperties;
   import org.apache.slide.common.RequestedPropertiesImpl;
  +import org.apache.slide.common.SlideException;
   import org.apache.slide.structure.SubjectNode;
  +import org.apache.slide.structure.ObjectNode;
   import org.apache.slide.content.NodeProperty;
   import org.apache.slide.content.NodeRevisionContent;
   import org.apache.slide.content.NodeRevisionDescriptor;
  @@ -90,11 +92,22 @@
   import org.apache.slide.content.NodeRevisionNumber;
   import org.apache.slide.webdav.WebdavServletConfig;
   import org.apache.slide.webdav.WebdavException;
  +
  +import org.apache.slide.webdav.util.AbstractWebdavHelper;
   import org.apache.slide.webdav.util.VersioningHelper;
   import org.apache.slide.webdav.util.UriHandler;
   import org.apache.slide.webdav.util.DeltavConstants;
   import org.apache.slide.webdav.util.ViolatedPrecondition;
  +import org.apache.slide.webdav.util.PropertyHelper;
  +import org.apache.slide.webdav.util.PropertyRetriever;
  +import org.apache.slide.webdav.util.PropertyRetrieverImpl;
  +import org.apache.slide.webdav.util.LabeledRevisionNotFoundException;
   import org.apache.slide.webdav.util.PreconditionViolationException;
  +
  +import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
  +import org.apache.slide.webdav.util.resourcekind.ResourceKind;
  +import org.apache.slide.webdav.util.resourcekind.CheckedInVersionControlled;
  +
   import org.apache.util.WebdavStatus;
   
   /**
  @@ -111,9 +124,27 @@
       /** The update source */
       private String updateSourcePath;
       
  +    /** The label of the update source */
  +    private String updateLabelName;
  +    
       /** Requested properties */
       private RequestedProperties requestedProps;
       
  +    /**
  +     * The VersioningHelper used by this instance.
  +     */
  +    protected VersioningHelper versioningHelper = null;
  +    
  +    /**
  +     * The URI of the server, e.g. <code>localhost:4000</code>.
  +     */
  +    protected String serverUri = null;
  +    
  +    /**
  +     * The PropertyRetriever used to retrieve any requested properties.
  +     */
  +    protected PropertyRetriever propertyRetriever = null;
  +    
       
       /**
        * UPDATE method constructor.
  @@ -128,7 +159,11 @@
                                   WebdavServletConfig config)
       {
           super(token, req, resp, config);
  +        versioningHelper =  VersioningHelper.getVersioningHelper(
  +            slideToken, token, req, resp, getConfig() );
           readRequestContent();
  +        serverUri = req.getServerName() + ":" + req.getServerPort();
  +        propertyRetriever = new PropertyRetrieverImpl(token, slideToken);
       }
       
       /**
  @@ -137,24 +172,48 @@
        * @exception WebdavException
        */
       protected void parseRequest() throws WebdavException, IOException {
  +        
           resourcePath = requestUri;
           if (resourcePath == null) {
               resourcePath = "/";
           }
   
           if( req.getContentLength() == 0 ) {
  -            Domain.warn( "Request body required" );
  -            resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
  +            resp.sendError(WebdavStatus.SC_BAD_REQUEST, "Request body required");
               throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
           }
           
           try{
               retrieveRequestContent();
  +            parseUpdateRequestContent();
  +        }
  +        catch( org.xml.sax.SAXException x ){
  +            resp.sendError(WebdavStatus.SC_BAD_REQUEST, x.getMessage());
  +            throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
  +        }
  +        catch( IOException x ){
  +            resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  +            throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  +        }
  +        catch( javax.xml.parsers.ParserConfigurationException x ){
  +            resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  +            throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  +        }
  +    }
  +    
  +    /**
  +     * Parses the expected request content specified for the Update method.
  +     *
  +     * @throws     WebdavException
  +     * @throws     IOException
  +     */
  +    private void parseUpdateRequestContent() throws WebdavException, IOException {
  +        
               Element ue = getRequestContent().getRootElement();
               Element ve = null;
               if( ue == null || !ue.getName().equals(E_UPDATE) ) {
  -                Domain.warn( "Root element must be "+E_UPDATE );
  -                resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
  +            resp.sendError(WebdavStatus.SC_BAD_REQUEST,
  +                           "Root element must be &lt;"+E_UPDATE+"&gt;");
                   throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
               }
               Iterator i = ue.getChildren().iterator();
  @@ -162,8 +221,13 @@
                   Element e = (Element)i.next();
                   if( e.getName().equals(E_VERSION) ) {
                       if( updateSourcePath != null ) {
  -                        Domain.warn( "At most one "+E_VERSION+" element allowed" );
  -                        resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
  +                    resp.sendError(WebdavStatus.SC_BAD_REQUEST,
  +                                   "At most one &lt;"+E_VERSION+"&gt; element 
allowed" );
  +                    throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
  +                }
  +                if (updateLabelName != null) {
  +                    resp.sendError(WebdavStatus.SC_BAD_REQUEST,
  +                                   "Either a &lt;"+E_VERSION+"&gt; OR a 
&lt;"+E_LABEL_NAME+"&gt; element allowed");
                           throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
                       }
                       // get the href element
  @@ -175,32 +239,32 @@
                           updateSourcePath = getSlidePath( hre.getText() );
                       }
                       catch( Exception x ) {
  -                        Domain.warn( E_VERSION+" element must contain "+E_HREF+" 
element" );
  -                        resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
  +                    resp.sendError(WebdavStatus.SC_BAD_REQUEST,
  +                                   "&lt;"+E_VERSION+"&gt; element must contain 
&lt;"+E_HREF+"&gt; element" );
                           throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
                       }
                   }
                   if( e.getName().equals(E_PROP) ) {
                       if( requestedProps != null ) {
  -                        Domain.warn( "At most one "+E_PROP+" element allowed" );
  -                        resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
  +                    resp.sendError(WebdavStatus.SC_BAD_REQUEST,
  +                                   "At most one "+E_PROP+" element allowed" );
                           throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
                       }
                       requestedProps = new RequestedPropertiesImpl( e );
                   }
  +            if( e.getName().equals(E_LABEL_NAME) ) {
  +                if (updateSourcePath != null) {
  +                    resp.sendError(WebdavStatus.SC_BAD_REQUEST,
  +                                   "Either a &lt;"+E_VERSION+"&gt; OR a 
&lt;"+E_LABEL_NAME+"&gt; element allowed");
  +                    throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
               }
  -        }
  -        catch( org.xml.sax.SAXException x ){
  -            resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
  +                if( updateLabelName != null ) {
  +                    resp.sendError(WebdavStatus.SC_BAD_REQUEST,
  +                                   "At most one &lt;"+E_LABEL_NAME+"&gt; element 
allowed" );
               throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
           }
  -        catch( IOException x ){
  -            resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  -            throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  +                updateLabelName = e.getText();
           }
  -        catch( javax.xml.parsers.ParserConfigurationException x ){
  -            resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
  -            throw new WebdavException(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
           }
       }
       
  @@ -215,21 +279,228 @@
           slideToken.setForceStoreEnlistment(true);
           
           try {
  -            VersioningHelper vh = VersioningHelper.getVersioningHelper(
  -                slideToken, token, req, resp, getConfig() );
  -            vh.update( resourcePath, updateSourcePath );
  -        }
  -        catch (PreconditionViolationException e) {
  -            sendPreconditionViolation(e);
  -            throw e;
  +            Element multistatusElement = new Element(E_MULTISTATUS,
  +                                                     
Namespace.getNamespace(DEFAULT_NAMESPACE));
  +            
  +            update(updateSourcePath, updateLabelName, resourcePath, getDepth(), 
multistatusElement);
  +            
  +            resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
  +            resp.setContentType(TEXT_XML_UTF_8);
  +            new XMLOutputter().output(multistatusElement, resp.getWriter());
           }
           catch (Exception e) {
               e.printStackTrace();
               resp.setStatus( getErrorCode(e) );  // special handling needed
               throw new WebdavException( WebdavStatus.SC_ACCEPTED, false ); // abort 
the TA
           }
  +    }
  +    
  +    /**
  +     * Updates the resource identified by <code>resourcePath</code>
  +     * with the properties and the content either of the resource identified
  +     * <code>updateSourcePath</code> or the version with the label
  +     * <code>updateLabelName</code> (only one of these parameters is set).
  +     * If <code>depth</code> is > 0, the operation is applied recursivly
  +     * to all children of the destination resource.
  +     *
  +     * @param      updateSourcePath    the URI of update source.
  +     * @param      updateLabelName     the label of the version used for the update.
  +     * @param      resourcePath        the URI of update destination.
  +     * @param      depth               the depth to use. If > 0, the update is
  +     *                                 applied recursivly.
  +     * @param      multistatusElement  the <code>&lt;multistatus&gt;</code> element
  +     *                                 to append the <code>&lt;response&gt;</code>
  +     *                                 elements to.
  +     */
  +    protected void update(String updateSourcePath, String updateLabelName, String 
resourcePath, int depth, Element multistatusElement) {
  +        
  +        Element responseElement = new Element(E_RESPONSE, 
Namespace.getNamespace(DEFAULT_NAMESPACE));
  +        multistatusElement.addContent(responseElement);
  +        Element hrefElement = new Element(E_HREF, 
Namespace.getNamespace(DEFAULT_NAMESPACE));
  +        hrefElement.setText(PropertyHelper.getAbsoluteURL(serverUri, 
req.getContextPath(), resourcePath));
  +        responseElement.addContent(hrefElement);
  +        Element statusElement = new Element(E_STATUS, 
Namespace.getNamespace(DEFAULT_NAMESPACE));
  +        responseElement.addContent(statusElement);
  +        
  +        Enumeration childrenEnum = null;
  +        try {
  +            if ( isCollection(resourcePath) && (depth > 0) ) {
  +                ObjectNode currentNode = structure.retrieve(slideToken, 
resourcePath);
  +                childrenEnum = structure.getChildren(slideToken, currentNode);
  +    }
  +            
  +            checkPreconditions(updateSourcePath, updateLabelName, resourcePath);
  +            
  +            if (updateLabelName != null) {
  +                updateSourcePath = 
versioningHelper.getLabeledResourceUri(resourcePath,
  +                                                                          
updateLabelName);
  +            }
  +            
  +            versioningHelper.update( resourcePath, updateSourcePath );
  +            statusElement.setText(HTTP_VERSION + " " +
  +                                      WebdavStatus.SC_OK  + " " +
  +                                      
WebdavStatus.getStatusText(WebdavStatus.SC_OK));
  +            
  +            appendRequestedProps(resourcePath, responseElement);
  +        }
  +        catch (Exception e) {
  +            handleException(e, statusElement, responseElement);
  +        }
           
  +        // process children recursivly
  +        if (childrenEnum != null) {
  +            while (childrenEnum.hasMoreElements()) {
  +                update(updateSourcePath,
  +                       updateLabelName,
  +                           ((ObjectNode)childrenEnum.nextElement()).getUri(),
  +                       depth-1,
  +                       multistatusElement);
  +            }
  +        }
       }
  +
  +    /**
  +     * Appends the &lt;propstat&gt; elements for the requested properties to
  +     * the given <code>responseElement</code>.
  +     *
  +     * @param      resourcePath     the path of the resource for which to retrieve
  +     *                              the properties.
  +     * @param      responseElement  the &lt;reponse&gt; element to add the 
&lt;propstat&gt;
  +     *                              elements to.
  +     *
  +     * @throws     SlideException
  +     * @throws     JDOMException
  +     */
  +    private void appendRequestedProps(String resourcePath, Element responseElement) 
throws SlideException, JDOMException {
  +
  +        if (requestedProps != null) {
  +            List propStatList = 
propertyRetriever.getPropertiesOfObject(requestedProps,
  +                                                                        
resourcePath,
  +                                                                        
req.getContextPath(),
  +                                                                        serverUri,
  +                                                                        true);
  +            Iterator iterator = propStatList.iterator();
  +            while (iterator.hasNext()) {
  +                responseElement.addContent((Element)iterator.next());
  +            }
  +        }
  +    }
  +
  +    
  +    /**
  +     * Checks the preconditions of the Update method.
  +     *
  +     * @param      updateSourcePath    the URI of update source.
  +     * @param      updateLabelName     the label of the version used for the update.
  +     * @param      resourcePath        the URI of update destination.
  +     *
  +     * @throws     SlideException
  +     * @throws     PreconditionViolationException  if any precondition has been 
violated.
  +     */
  +    private void checkPreconditions(String updateSourcePath, String 
updateLabelName, String resourcePath) throws SlideException, 
PreconditionViolationException {
  +
  +        ViolatedPrecondition violatedPrecondition = 
getPreconditionViolation(updateSourcePath,
  +                                                                             
updateLabelName,
  +                                                                             
resourcePath);
  +        if (violatedPrecondition != null) {
  +            throw new PreconditionViolationException(violatedPrecondition, 
resourcePath);
  +        }
  +    }
  +
  +    
  +    /**
  +     * Sets the appropriate status text and appends a &lt;responsedescription&gt;
  +     * element if a precondition has been violated.
  +     *
  +     * @param      exception        the Exception that occurred.
  +     * @param      statusElement    the &lt;status&gt; element.
  +     * @param      responseElement  the &lt;response&gt; element.
  +     */
  +    private void handleException(Exception exception, Element statusElement, 
Element responseElement) {
  +
  +        int errorCode = getErrorCode(exception);
  +        statusElement.setText(HTTP_VERSION + " " + errorCode  + " " +
  +                                  WebdavStatus.getStatusText(errorCode));
  +        if (exception instanceof PreconditionViolationException) {
  +            Element responseDescriptionElement = new Element(E_RESPONSEDESCRIPTION,
  +                                                             
Namespace.getNamespace(DEFAULT_NAMESPACE));
  +            responseElement.addContent(responseDescriptionElement);
  +            Element errorElement = 
getPreconditionViolationError(((PreconditionViolationException)exception).getViolatedPrecondition());
  +            responseDescriptionElement.addContent(errorElement);
  +        }
  +    }
  +    
  +    
  +    /**
  +     * Checks the (DeltaV) preconditions
  +     * <ul>
  +     * <li>&lt;DAV:must-be-checked-in-version-controlled-resource&gt;</li>
  +     * <li>&lt;DAV:must-select-version-in-history&gt;</li>
  +     * </ul>
  +     *
  +     * @param      updateSourcePath  the URI of update source.
  +     * @param      updateLabelName   the label of the version used for the update.
  +     * @param      resourcePath      the URI of update destination.
  +     *
  +     * @return     the precondition that has been violated (if any).
  +     *
  +     * @throws     SlideException
  +     */
  +    protected ViolatedPrecondition getPreconditionViolation(String 
updateSourcePath, String updateSourceLabel, String resourcePath) throws SlideException 
{
  +        
  +        ViolatedPrecondition violatedPrecondition = null;
  +        
  +        NodeRevisionDescriptors revisionDescriptors =
  +            versioningHelper.retrieveRevisionDescriptors(resourcePath);
  +        NodeRevisionDescriptor revisionDescriptor =
  +            versioningHelper.retrieveLatestRevisionDescriptor(resourcePath, 
revisionDescriptors);
  +        ResourceKind resourceKind = 
AbstractResourceKind.determineResourceKind(token,
  +                                                                               
revisionDescriptors,
  +                                                                               
revisionDescriptor);
  +        if ( ! (resourceKind instanceof CheckedInVersionControlled) ) {
  +            return new 
ViolatedPrecondition(DeltavConstants.C_MUST_BE_CHECKED_IN_VERSION_CONTROLLED_RESOURCE,
  +                                            WebdavStatus.SC_CONFLICT);
  +        }
  +        
  +        if (updateSourceLabel != null) {
  +            try {
  +                updateSourcePath = 
versioningHelper.getLabeledResourceUri(resourcePath, updateLabelName);
  +            }
  +            catch (LabeledRevisionNotFoundException e) {
  +                return new 
ViolatedPrecondition(DeltavConstants.C_MUST_SELECT_VERSION_IN_HISTORY,
  +                                                WebdavStatus.SC_CONFLICT);
  +            }
  +        }
  +        
  +        String associatedVrUri = 
versioningHelper.getUriOfAssociatedVR(resourcePath);
  +        String vcrHistoryUri = UriHandler.getUriHandler(token, 
associatedVrUri).getAssociatedHistoryUri();
  +        String vrHistoryUri = UriHandler.getUriHandler(token, 
updateSourcePath).getAssociatedHistoryUri();
  +        if ( ! vcrHistoryUri.equals(vrHistoryUri) ) {
  +            return new 
ViolatedPrecondition(DeltavConstants.C_MUST_SELECT_VERSION_IN_HISTORY,
  +                                            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;
  +    }
  +    
  +    
   }
   
   
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to