jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r397835 - in /jackrabbit/trunk/jcr-server: server/src/java/org/apache/jackrabbit/server/ server/src/java/org/apache/jackrabbit/webdav/jcr/ server/src/java/org/apache/jackrabbit/webdav/simple/ webdav/src/java/org/apache/jackrabbit/webdav/
Date Fri, 28 Apr 2006 09:48:37 GMT
Author: angela
Date: Fri Apr 28 02:48:32 2006
New Revision: 397835

URL: http://svn.apache.org/viewcvs?rev=397835&view=rev
Log:
JCR-405: PROPPATCH doesn't respect document order
minor improvements within 'jcr' package:
- reorder nodes
- fixing creation/replacement of multivalued JCR properties
- contentlength for single value JCR properties
- improve spooling of resource content

Modified:
    jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java
    jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java
    jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java
    jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemResource.java
    jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/RootItemCollection.java
    jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/VersionControlledItemCollection.java
    jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/simple/DavResourceImpl.java
    jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java
    jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java
    jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java

Modified: jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java (original)
+++ jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java Fri Apr 28 02:48:32 2006
@@ -46,7 +46,6 @@
 import org.apache.jackrabbit.webdav.property.DavProperty;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import org.apache.jackrabbit.webdav.search.SearchConstants;
 import org.apache.jackrabbit.webdav.search.SearchInfo;
 import org.apache.jackrabbit.webdav.search.SearchResource;
@@ -440,26 +439,15 @@
                                DavResource resource)
             throws IOException, DavException {
 
-        DavPropertySet setProperties = request.getPropPatchSetProperties();
-        DavPropertyNameSet removeProperties = request.getPropPatchRemoveProperties();
-        if (setProperties.isEmpty() && removeProperties.isEmpty()) {
+        List changeList = request.getPropPatchChangeList();
+        if (changeList.isEmpty()) {
             response.sendError(DavServletResponse.SC_BAD_REQUEST);
             return;
         }
 
         MultiStatus ms = new MultiStatus();
-        try {
-            MultiStatusResponse msr = resource.alterProperties(setProperties, removeProperties);
-            ms.addResponse(msr);
-        } catch (DavException e) {
-            /* NOTE: known bug with litmus, which expects the exception (e.g. 423)
-               to the set instead of the MultiStatus Code. RFC 2518 explicitely
-               expects the errors to be included in the multistatus.
-               Remove the catch if this turns out to be an problem with clients
-               in general. */
-            ms.addResourceStatus(resource, e.getErrorCode(), DEPTH_0);
-        }
-        response.sendMultiStatus(ms);
+        MultiStatusResponse msr = resource.alterProperties(changeList);
+        ms.addResponse(msr);
     }
 
     /**

Modified: jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java (original)
+++ jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/AbstractResource.java Fri Apr 28 02:48:32 2006
@@ -49,6 +49,8 @@
 import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
 import org.apache.jackrabbit.webdav.property.HrefProperty;
 import org.apache.jackrabbit.webdav.property.ResourceType;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameIterator;
+import org.apache.jackrabbit.webdav.property.DavPropertyIterator;
 import org.apache.jackrabbit.webdav.search.QueryGrammerSet;
 import org.apache.jackrabbit.webdav.search.SearchInfo;
 import org.apache.jackrabbit.webdav.search.SearchResource;
@@ -72,8 +74,6 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Iterator;
@@ -169,22 +169,16 @@
     }
 
     /**
-     * Returns <code>null</code>
+     * Spools the properties of this resource to the context. Note that subclasses
+     * are in charge of spooling the data to the output stream provided by the
+     * context.
      *
-     * @return Always returns <code>null</code>
-     */
-    InputStream getStream() {
-        return null;
-    }
-
-    /**
      * @see DavResource#spool(OutputContext)
      */
     public void spool(OutputContext outputContext) throws IOException {
         if (!initedProps) {
             initProperties();
         }
-
         // export properties
         outputContext.setModificationTime(getModificationTime());
         DavProperty etag = getProperty(DavPropertyName.GETETAG);
@@ -210,22 +204,6 @@
         if (contentLanguage != null) {
             outputContext.setContentLanguage(contentLanguage.getValue().toString());
         }
-
-        // spool content
-        InputStream in = getStream();
-        OutputStream out = outputContext.getOutputStream();
-        if (in != null && out != null) {
-            try {
-                IOUtil.spool(in, out);
-            } finally {
-                // also close stream if not sending content
-                try {
-                    in.close();
-                } catch (IOException e) {
-                    // ignore
-                }
-            }
-        }
     }
 
     /**
@@ -275,13 +253,36 @@
     }
 
     /**
-     * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     * Builds a single List from the properties to set and the properties to
+     * remove and delegates the list to {@link #alterProperties(List)};
      *
      * @see DavResource#alterProperties(org.apache.jackrabbit.webdav.property.DavPropertySet, org.apache.jackrabbit.webdav.property.DavPropertyNameSet) 
      */
     public MultiStatusResponse alterProperties(DavPropertySet setProperties,
                                 DavPropertyNameSet removePropertyNames)
         throws DavException {
+        List changeList = new ArrayList();
+        if (removePropertyNames != null) {
+            DavPropertyNameIterator it = removePropertyNames.iterator();
+            while (it.hasNext()) {
+                changeList.add(it.next());
+            }
+        }
+        if (setProperties != null) {
+            DavPropertyIterator it = setProperties.iterator();
+            while (it.hasNext()) {
+                changeList.add(it.next());
+            }
+        }
+        return alterProperties(changeList);
+    }
+
+    /**
+     * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
+     *
+     * @see DavResource#alterProperties(List)
+     */
+    public MultiStatusResponse alterProperties(List changeList) throws DavException {
         throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
     }
 

Modified: jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java (original)
+++ jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java Fri Apr 28 02:48:32 2006
@@ -16,6 +16,7 @@
 package org.apache.jackrabbit.webdav.jcr;
 
 import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.server.io.IOUtil;
 import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.webdav.DavConstants;
 import org.apache.jackrabbit.webdav.DavException;
@@ -26,11 +27,14 @@
 import org.apache.jackrabbit.webdav.DavResourceLocator;
 import org.apache.jackrabbit.webdav.DavServletResponse;
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
 import org.apache.jackrabbit.webdav.io.InputContext;
+import org.apache.jackrabbit.webdav.io.OutputContext;
 import org.apache.jackrabbit.webdav.jcr.lock.JcrActiveLock;
 import org.apache.jackrabbit.webdav.jcr.nodetype.NodeTypeProperty;
 import org.apache.jackrabbit.webdav.jcr.version.report.ExportViewReport;
 import org.apache.jackrabbit.webdav.jcr.version.report.LocateCorrespondingNodeReport;
+import org.apache.jackrabbit.webdav.jcr.property.ValuesProperty;
 import org.apache.jackrabbit.webdav.lock.ActiveLock;
 import org.apache.jackrabbit.webdav.lock.LockInfo;
 import org.apache.jackrabbit.webdav.lock.Scope;
@@ -41,7 +45,6 @@
 import org.apache.jackrabbit.webdav.ordering.OrderingType;
 import org.apache.jackrabbit.webdav.ordering.Position;
 import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.DavPropertyIterator;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
@@ -49,6 +52,8 @@
 import org.apache.jackrabbit.webdav.property.HrefProperty;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.ImportUUIDBehavior;
@@ -63,18 +68,22 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.PathNotFoundException;
 import javax.jcr.lock.Lock;
 import javax.jcr.nodetype.NodeType;
+import javax.xml.parsers.ParserConfigurationException;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
+
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.List;
 
 /**
  * <code>DefaultItemCollection</code> represents a JCR node item.
@@ -83,8 +92,7 @@
         implements OrderingResource {
 
     private static Logger log = LoggerFactory.getLogger(DefaultItemCollection.class);
-
-    private File content;
+    private static final String TMP_PREFIX = "_tmp_";
 
     /**
      * Create a new <code>DefaultItemCollection</code>.
@@ -133,23 +141,28 @@
         return true;
     }
 
-
     /**
-     * Returns an {@link java.io.InputStream} to the content of this collection.
-     */
-    public InputStream getStream() {
-        if (!initedProps)  {
-            initProperties();
-        }
-        if (content != null) {
-            try {
-                return new FileInputStream(content);
-            } catch (FileNotFoundException e) {
-                // should not occur
-                log.error(e.getMessage());
+     * If this resource represents an existing <code>Node</code> the system
+     * view is spooled as resource content.
+     *
+     * @param outputContext
+     * @throws IOException
+     * @see Session#exportSystemView(String, OutputStream, boolean, boolean)
+     */
+    public void spool(OutputContext outputContext) throws IOException {
+        // spool properties
+        super.spool(outputContext);
+        // spool data
+        try {
+            OutputStream out = outputContext.getOutputStream();
+            if (out != null && exists()) {
+                getRepositorySession().exportSystemView(item.getPath(), out, false, true);
             }
+        } catch (PathNotFoundException e) {
+            log.error("Error while spooling resource content: " + e.getMessage());
+        } catch (RepositoryException e) {
+            log.error("Error while spooling resource content: " + e.getMessage());
         }
-        return null;
     }
 
     /**
@@ -260,7 +273,7 @@
     }
 
     /**
-     * Loops over the given <code>Set</code>s and alters the properties accordingly.
+     * Loops over the given <code>List</code>s and alters the properties accordingly.
      * Changes are persisted at the end according to the rules defined with
      * the {@link #complete()} method.<p>
      * Please note: since there is only a single property ({@link #JCR_MIXINNODETYPES}
@@ -268,26 +281,26 @@
      * or throws an exception, even if this violates RFC 2518. Thus no property
      * specific multistatus will be created in case of an error.
      *
-     * @param setProperties
-     * @param removePropertyNames
+     * @param changeList
      * @return
      * @throws DavException
      * @see DavResource#alterProperties(org.apache.jackrabbit.webdav.property.DavPropertySet, org.apache.jackrabbit.webdav.property.DavPropertyNameSet)
      */
-    public MultiStatusResponse alterProperties(DavPropertySet setProperties,
-                                DavPropertyNameSet removePropertyNames)
-        throws DavException {
-        DavPropertyIterator setIter = setProperties.iterator();
-        while (setIter.hasNext()) {
-            DavProperty prop = setIter.nextProperty();
-            // use the internal set method in order to prevent premature 'save'
-            internalSetProperty(prop);
-        }
-        Iterator remNameIter = removePropertyNames.iterator();
-        while (remNameIter.hasNext()) {
-            DavPropertyName propName = (DavPropertyName) remNameIter.next();
-            // use the internal set method in order to prevent premature 'save'
-            internalRemoveProperty(propName);
+    public MultiStatusResponse alterProperties(List changeList) throws DavException {
+        Iterator it = changeList.iterator();
+        while (it.hasNext()) {
+            Object propEntry = it.next();
+            if (propEntry instanceof DavPropertyName) {
+                // use the internal remove method in order to prevent premature 'save'
+                DavPropertyName propName = (DavPropertyName) propEntry;
+                internalRemoveProperty(propName);
+            } else if (propEntry instanceof DavProperty) {
+                // use the internal set method in order to prevent premature 'save'
+                DavProperty prop = (DavProperty) propEntry;
+                internalSetProperty(prop);
+            } else {
+                throw new IllegalArgumentException("unknown object in change list: " + propEntry.getClass().getName());
+            }
         }
         // TODO: missing undo of successful set/remove if subsequent operation fails
         // NOTE, that this is relevant with transactions only.
@@ -327,6 +340,7 @@
             throw new DavException(DavServletResponse.SC_CONFLICT);
         }
 
+        File tmpFile = null;
         try {
             Node n = (Node) item;
             InputStream in = (inputContext != null) ? inputContext.getInputStream() : null;
@@ -350,16 +364,36 @@
                 }
             } else {
                 if (in == null) {
-                    // PUT: not possible
+                    // PUT: not possible without request body
                     throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Cannot create a new non-collection resource without request body.");
                 } else {
-                    // TODO: find a way to create non-binary and multivalue properties
                     // PUT : create new or overwrite existing property.
-                    // NOTE: will fail for multivalue properties.
-                    n.setProperty(memberName, in);
+                    tmpFile = File.createTempFile(TMP_PREFIX + memberName, null, null);
+                    FileOutputStream out = new FileOutputStream(tmpFile);
+                    IOUtil.spool(in, out);
+                    out.close();
+                    // try to parse the request body into a 'values' property.
+                    ValuesProperty vp = buildValuesProperty(new FileInputStream(tmpFile));
+                    if (vp != null) {
+                        if (JCR_VALUE.equals(vp.getName())) {
+                            n.setProperty(memberName, vp.getJcrValue());
+                        } else {
+                            n.setProperty(memberName, vp.getJcrValues());
+                        }
+                    } else {
+                        // request body cannot be parsed into a 'values' property.
+                        // fallback: try to import as single value from stream.
+                        n.setProperty(memberName, new FileInputStream(tmpFile));
+                    }
                 }
             }
-            complete();
+            if (resource.exists() && resource instanceof AbstractItemResource) {
+                // PUT may modify value of existing jcr property. thus, this
+                // node is not modified by the 'addMember' call.
+                ((AbstractItemResource)resource).complete();
+            } else {
+                complete();
+            }
         } catch (ItemExistsException e) {
             // according to RFC 2518: MKCOL only possible on non-existing/deleted resource
             throw new JcrDavException(e, DavServletResponse.SC_METHOD_NOT_ALLOWED);
@@ -367,6 +401,10 @@
             throw new JcrDavException(e);
         } catch (IOException e) {
             throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENTITY, e.getMessage());
+        } finally {
+            if (tmpFile != null) {
+                tmpFile.delete();
+            }
         }
     }
 
@@ -656,12 +694,13 @@
         Node n = (Node)item;
         try {
             for (int i = 0; i < instructions.length; i++) {
-                String srcRelPath = Text.getName(instructions[i].getMemberHandle());
+                String srcRelPath = instructions[i].getMemberHandle();
                 Position pos = instructions[i].getPosition();
                 String destRelPath = getRelDestinationPath(pos, n.getNodes());
                 // preform the reordering
                 n.orderBefore(srcRelPath, destRelPath);
             }
+            complete();
         } catch (RepositoryException e) {
             // UnsupportedRepositoryException should not occur
             throw new JcrDavException(e);
@@ -682,34 +721,36 @@
     private String getRelDestinationPath(Position position, NodeIterator childNodes)
             throws RepositoryException {
 
-        String destPath = null;
+        String destRelPath = null;
         if (OrderingConstants.XML_FIRST.equals(position.getType())) {
             if (childNodes.hasNext()) {
                 Node firstChild = childNodes.nextNode();
-                destPath = firstChild.getPath();
+                // use last segment of node-path instead of name.
+                destRelPath = Text.getName(firstChild.getPath());
             }
             // no child nodes available > reordering to 'first' position fails.
-            if (destPath == null) {
+            if (destRelPath == null) {
                 throw new ItemNotFoundException("No 'first' item found for reordering.");
             }
         } else if (OrderingConstants.XML_AFTER.equals(position.getType())) {
-            String afterRelPath = Text.getName(position.getSegment());
+            String afterRelPath = position.getSegment();
             boolean found = false;
             // jcr only knows order-before > retrieve the node that follows the
             // one incidated by the 'afterRelPath'.
-            while (childNodes.hasNext() && destPath == null) {
-                String childPath = childNodes.nextNode().getPath();
+            while (childNodes.hasNext() && destRelPath == null) {
+                // compare to last segment of node-path instead of name.
+                String childRelPath = Text.getName(childNodes.nextNode().getPath());
                 if (found) {
-                    destPath = childPath;
+                    destRelPath = childRelPath;
                 } else {
-                    found = afterRelPath.equals(Text.getName(childPath));
+                    found = afterRelPath.equals(childRelPath);
                 }
             }
         } else {
-            destPath = position.getSegment();
+            // before or last. in the latter case the segmet is 'null'
+            destRelPath = position.getSegment();
         }
-
-        return (destPath != null) ? Text.getName(destPath) : destPath;
+        return destRelPath;
     }
 
     //--------------------------------------------------------------------------
@@ -758,23 +799,8 @@
     protected void initProperties() {
         super.initProperties();
         if (exists()) {
-            try {
-                String prefix = "_tmp_" + item.getName();
-                // create tmpFile in default system-tmp directory
-                content = File.createTempFile(prefix, null, null);
-                content.deleteOnExit();
-                FileOutputStream out = new FileOutputStream(content);
-                getRepositorySession().exportSystemView(item.getPath(), out, false, true);
-                out.close();
-                properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, new Long(content.length())));
-                properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, "text/xml"));
-
-            } catch (IOException e) {
-                log.error("Error while property initialization: "+e.getMessage());
-            } catch (RepositoryException e) {
-                log.error("Error while property initialization: "+e.getMessage());
-            }
-
+            // resource is serialized as system-view (xml)
+            properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, "text/xml"));
             Node n = (Node)item;
             // overwrite the default modificationtime if possible
             try {
@@ -860,5 +886,35 @@
             l.add(itemIterator.next());
         }
         addHrefProperty(name, (Item[]) l.toArray(new Item[l.size()]), isProtected);
+    }
+
+    /**
+     * Tries to parse the given input stream as xml document and build a
+     * {@link ValuesProperty} out of it.
+     *
+     * @param in
+     * @return values property or 'null' if the given stream cannot be parsed
+     * into an XML document or if build the property fails.
+     */
+    private ValuesProperty buildValuesProperty(InputStream in) {
+        String errorMsg = "Cannot parse stream into a 'ValuesProperty'.";
+        try {
+            Document reqBody = DomUtil.BUILDER_FACTORY.newDocumentBuilder().parse(in);
+            DavProperty defaultProp = DefaultDavProperty.createFromXml(reqBody.getDocumentElement());
+            ValuesProperty vp = new ValuesProperty(defaultProp, PropertyType.STRING);
+            return vp;
+        } catch (IOException e) {
+            log.debug(errorMsg, e);
+        } catch (ParserConfigurationException e) {
+            log.debug(errorMsg, e);
+        } catch (SAXException e) {
+            log.debug(errorMsg, e);
+        } catch (DavException e) {
+            log.debug(errorMsg, e);
+        } catch (RepositoryException e) {
+            log.debug(errorMsg, e);
+        }
+        // cannot parse request body into a 'values' property
+        return null;
     }
 }

Modified: jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemResource.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemResource.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemResource.java (original)
+++ jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/DefaultItemResource.java Fri Apr 28 02:48:32 2006
@@ -23,20 +23,25 @@
 import org.apache.jackrabbit.webdav.DavResourceLocator;
 import org.apache.jackrabbit.webdav.DavServletResponse;
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
 import org.apache.jackrabbit.webdav.io.InputContext;
+import org.apache.jackrabbit.webdav.io.OutputContext;
 import org.apache.jackrabbit.webdav.jcr.property.LengthsProperty;
 import org.apache.jackrabbit.webdav.jcr.property.ValuesProperty;
 import org.apache.jackrabbit.webdav.lock.ActiveLock;
 import org.apache.jackrabbit.webdav.lock.Scope;
 import org.apache.jackrabbit.webdav.lock.Type;
 import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.DavPropertyIterator;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
+import org.apache.jackrabbit.server.io.IOUtil;
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
 
 import javax.jcr.Item;
 import javax.jcr.Property;
@@ -44,9 +49,13 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
+import javax.xml.parsers.ParserConfigurationException;
 import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * <code>DefaultItemResource</code> represents JCR property item.
@@ -81,31 +90,50 @@
 
     /**
      * In case an underlying repository {@link Property property} exists the following
-     * logic is applyed to obtain the stream:<ul>
-     * <li>Property is not multivalue: Return the {@link javax.jcr.Value#getStream()
+     * logic is applyed to spool the property content:
+     * <ul>
+     * <li>Property is not multi valued: Return the {@link javax.jcr.Value#getStream()
      * stream representation} of the property value.</li>
-     * <li>Property is multivalue: Return stream that provides the system view of
-     * that item.</li>
+     * <li>Property is multivalue: Return the xml representation of the values.</li>
      * </ul>
      *
-     * @return
+     * @param outputContext
+     * @see DavResource#spool(OutputContext)
      */
-    InputStream getStream() {
+    public void spool(OutputContext outputContext) throws IOException {
+        // write properties
+        super.spool(outputContext);
+        // spool content
         InputStream in = null;
-        if (exists()) {
-            try {
-                // NOTE: stream cannot be obtained for multivalue properties
-                if (!isMultiple()) {
+        try {
+            OutputStream out = outputContext.getOutputStream();
+            if (out != null && exists()) {
+                if (isMultiple()) {
+                    Document doc = DomUtil.BUILDER_FACTORY.newDocumentBuilder().newDocument();
+                    doc.appendChild(getProperty(JCR_VALUES).toXml(doc));
+                    OutputFormat format = new OutputFormat("xml", "UTF-8", false);
+                    XMLSerializer serializer = new XMLSerializer(out, format);
+                    serializer.setNamespaces(true);
+                    serializer.asDOMSerializer().serialize(doc);
+                } else {
                     in = ((Property)item).getStream();
+                    if (in != null) {
+                        IOUtil.spool(in, out);
+                    }
                 }
-            } catch (ValueFormatException e) {
-                // should not occur
-                log.error("Cannot obtain stream from resource: " + e.getMessage());
-            } catch (RepositoryException e) {
-                log.error("Cannot obtain stream from resource: " + e.getMessage());
+            }
+        } catch (ParserConfigurationException e) {
+            log.error("Error while spooling multivalued resource: " + e.getMessage());
+        } catch (ValueFormatException e) {
+            // should not occur
+            log.error("Cannot obtain stream from resource: " + e.getMessage());
+        } catch (RepositoryException e) {
+            log.error("Cannot obtain stream from resource: " + e.getMessage());
+        } finally {
+            if (in != null) {
+                in.close();
             }
         }
-        return in;
     }
 
     /**
@@ -167,36 +195,32 @@
     }
 
     /**
-     * Loops over the given <code>Set</code>s and alters the properties accordingly.
+     * Loops over the given <code>List</code> and alters the properties accordingly.
      * Changes are persisted at the end only according to the rules defined with
      * the {@link #complete()} method.<p>
      * Please note: since there is only a single property than can be set
      * from a client (i.e. jcr:value OR jcr:values) this method either succeeds
      * or throws an exception, even if this violates RFC 2518.
      *
-     * @param setProperties
-     * @param removePropertyNames
+     * @param changeList
      * @throws DavException
-     * @see DavResource#alterProperties(DavPropertySet, DavPropertyNameSet)
+     * @see DavResource#alterProperties(List)
      */
-    public MultiStatusResponse alterProperties(DavPropertySet setProperties,
-                                DavPropertyNameSet removePropertyNames)
-        throws DavException {
-
-        // altering any properties fails if an attempt is made to remove a property
-        if (removePropertyNames != null && !removePropertyNames.isEmpty()) {
-            Iterator it = removePropertyNames.iterator();
-            while (it.hasNext()) {
+    public MultiStatusResponse alterProperties(List changeList) throws DavException {
+        Iterator it = changeList.iterator();
+        while (it.hasNext()) {
+            Object propEntry = it.next();
+            if (propEntry instanceof DavPropertyName) {
+                // altering any properties fails if an attempt is made to remove
+                // a property
                 throw new DavException(DavServletResponse.SC_FORBIDDEN);
+            } else if (propEntry instanceof DavProperty) {
+                DavProperty prop = (DavProperty) propEntry;
+                internalSetProperty(prop);
+            } else {
+                throw new IllegalArgumentException("unknown object in change list: " + propEntry.getClass().getName());
             }
         }
-
-        // only set/add >> existance of resource is checked inside internal method
-        DavPropertyIterator setIter = setProperties.iterator();
-        while (setIter.hasNext()) {
-            DavProperty prop = setIter.nextProperty();
-            internalSetProperty(prop);
-        }
         complete();
         return new MultiStatusResponse(getHref(), DavServletResponse.SC_OK);
     }
@@ -266,8 +290,11 @@
                 String contentType;
                 if (!isMultiple()) {
                     contentType = (type == PropertyType.BINARY) ? "application/octet-stream" : "text/plain";
-                    properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, contentType));
-                } // else: no contenttype for multivalue properties
+                } else {
+                    contentType = "text/xml";
+                }
+                properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, contentType));
+                
 
                 // add jcr-specific resource properties
                 properties.add(new DefaultDavProperty(JCR_TYPE, PropertyType.nameFromValue(type)));
@@ -276,7 +303,11 @@
                     properties.add(new LengthsProperty(prop.getLengths()));
                 } else {
                     properties.add(new ValuesProperty(prop.getValue()));
-                    properties.add(new DefaultDavProperty(JCR_LENGTH, String.valueOf(prop.getLength()), true));
+                    long length = prop.getLength();
+                    properties.add(new DefaultDavProperty(JCR_LENGTH, String.valueOf(length), true));
+                    if (prop.getLength() > IOUtil.UNDEFINED_LENGTH) {
+                        properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, String.valueOf(length)));
+                    }
                 }
             } catch (RepositoryException e) {
                 log.error("Failed to retrieve resource properties: "+e.getMessage());

Modified: jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/RootItemCollection.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/RootItemCollection.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/RootItemCollection.java (original)
+++ jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/RootItemCollection.java Fri Apr 28 02:48:32 2006
@@ -22,8 +22,6 @@
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
 import org.apache.jackrabbit.webdav.jcr.property.NamespacesProperty;
 import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,6 +30,7 @@
 import javax.jcr.RepositoryException;
 import java.util.Iterator;
 import java.util.Properties;
+import java.util.List;
 
 /**
  * <code>RootItemCollection</code> represents the root node of the underlying
@@ -138,13 +137,23 @@
      * @see #setProperty(DavProperty)
      * @see DefaultItemCollection#alterProperties(org.apache.jackrabbit.webdav.property.DavPropertySet, org.apache.jackrabbit.webdav.property.DavPropertyNameSet)
      */
-    public MultiStatusResponse alterProperties(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames) throws DavException {
+    public MultiStatusResponse alterProperties(List changeList) throws DavException {
         // TODO: respect order of the set and do not persist if super.alterProperties fails
-        if (setProperties.contains(JCR_NAMESPACES)) {
-            setProperty(setProperties.remove(JCR_NAMESPACES));
+        DavProperty namespaceProp = null;
+        Iterator it = changeList.iterator();
+        while (it.hasNext()) {
+            Object propEntry = it.next();
+            if (propEntry instanceof DavProperty && JCR_NAMESPACES.equals(((DavProperty)propEntry).getName())) {
+                namespaceProp = (DavProperty) propEntry;
+                break;
+            }
+        }
+        if (namespaceProp != null) {
+            setProperty(namespaceProp);
+            changeList.remove(namespaceProp);
         }
         // let super-class handle the rest of the properties
-        return super.alterProperties(setProperties, removePropertyNames);
+        return super.alterProperties(changeList);
     }
 
     //--------------------------------------------------------------------------

Modified: jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/VersionControlledItemCollection.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/VersionControlledItemCollection.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/VersionControlledItemCollection.java (original)
+++ jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/jcr/VersionControlledItemCollection.java Fri Apr 28 02:48:32 2006
@@ -26,9 +26,9 @@
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
 import org.apache.jackrabbit.webdav.property.HrefProperty;
+import org.apache.jackrabbit.webdav.property.DavProperty;
 import org.apache.jackrabbit.webdav.version.LabelInfo;
 import org.apache.jackrabbit.webdav.version.MergeInfo;
 import org.apache.jackrabbit.webdav.version.UpdateInfo;
@@ -57,6 +57,7 @@
 import javax.jcr.version.Version;
 import javax.jcr.version.VersionHistory;
 import java.util.List;
+import java.util.ArrayList;
 
 /**
  * <code>VersionControlledItemCollection</code> represents a JCR node item and
@@ -112,14 +113,12 @@
     }
 
     /**
-     *
-     * @param setProperties
-     * @param removePropertyNames
+     * @param changeList
      * @throws DavException
      * @see DefaultItemCollection#alterProperties(org.apache.jackrabbit.webdav.property.DavPropertySet, org.apache.jackrabbit.webdav.property.DavPropertyNameSet)
      * for additional description of non-compliant behaviour.
      */
-    public MultiStatusResponse alterProperties(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames) throws DavException {
+    public MultiStatusResponse alterProperties(List changeList) throws DavException {
         /* first resolve merge conflict since they cannot be handled by
            setting property values in jcr (and are persisted immediately).
            NOTE: this violates RFC 2518 that requires that proppatch
@@ -127,9 +126,9 @@
            required that no changes must be persisted if any set/remove fails.
         */
         // TODO: solve violation of RFC 2518
-        resolveMergeConflict(setProperties, removePropertyNames);
+        resolveMergeConflict(changeList);
         // alter other properties only if merge-conflicts could be handled
-        return super.alterProperties(setProperties, removePropertyNames);
+        return super.alterProperties(changeList);
     }
 
     /**
@@ -143,63 +142,74 @@
      * not allow for a resolution of an existing merge conflict, this method
      * returns silently.
      *
-     * @param setProperties
-     * @param removePropertyNames
+     * @param changeList
      * @throws org.apache.jackrabbit.webdav.DavException
      * @see Node#doneMerge(Version)
      * @see Node#cancelMerge(Version)
      */
-    private void resolveMergeConflict(DavPropertySet setProperties,
-                                     DavPropertyNameSet removePropertyNames)
-        throws DavException {
-
+    private void resolveMergeConflict(List changeList) throws DavException {
         if (!exists()) {
             throw new DavException(DavServletResponse.SC_NOT_FOUND);
         }
-
         try {
             Node n = (Node)item;
-            if (removePropertyNames.contains(AUTO_MERGE_SET)) {
-                // retrieve the current jcr:mergeFailed property values
-                if (!n.hasProperty(JcrConstants.JCR_MERGEFAILED)) {
-                    throw new DavException(DavServletResponse.SC_CONFLICT, "Attempt to resolve non-existing merge conflicts.");
-                }
-                Value[] mergeFailed = n.getProperty(JcrConstants.JCR_MERGEFAILED).getValues();
-
-                // resolve all remaining merge conflicts with 'cancel'
-                for (int i = 0; i < mergeFailed.length; i++) {
-                    n.cancelMerge((Version)getRepositorySession().getNodeByUUID(mergeFailed[i].getString()));
+            DavProperty autoMergeSet = null;
+            DavProperty predecessorSet = null;
+            /* find DAV:auto-merge-set entries. If none exists no attempt is made
+               to resolve merge conflict > return silently */
+            for (int i = 0; i < changeList.size(); i++) {
+                Object propEntry = changeList.get(i);
+                // If DAV:auto-merge-set is DavPropertyName all remaining merge
+                // conflicts are resolved with 'cancel'
+                if (propEntry instanceof DavPropertyName && AUTO_MERGE_SET.equals(propEntry)) {
+                    // retrieve the current jcr:mergeFailed property values
+                    if (!n.hasProperty(JcrConstants.JCR_MERGEFAILED)) {
+                        throw new DavException(DavServletResponse.SC_CONFLICT, "Attempt to resolve non-existing merge conflicts.");
+                    }
+                    Value[] mergeFailed = n.getProperty(JcrConstants.JCR_MERGEFAILED).getValues();
+                    for (int j = 0; j < mergeFailed.length; j++) {
+                        n.cancelMerge((Version)getRepositorySession().getNodeByUUID(mergeFailed[j].getString()));
+                    }
+                    // remove this entry from the changeList
+                    changeList.remove(propEntry);
+                } else if (propEntry instanceof DavProperty) {
+                    if (AUTO_MERGE_SET.equals(((DavProperty)propEntry).getName())) {
+                        autoMergeSet = (DavProperty)propEntry;
+                    } else if (PREDECESSOR_SET.equals(((DavProperty)propEntry).getName())) {
+                        predecessorSet = (DavProperty)propEntry;
+                    }
                 }
-                // adjust removeProperty set
-                removePropertyNames.remove(AUTO_MERGE_SET);
+            }
 
-            } else if (setProperties.contains(AUTO_MERGE_SET) && setProperties.contains(PREDECESSOR_SET)){
+            // If DAV:auto-merge-set is a DavProperty merge conflicts need to be
+            // resolved individually according to the DAV:predecessor-set property.
+            if (autoMergeSet != null) {
                 // retrieve the current jcr:mergeFailed property values
                 if (!n.hasProperty(JcrConstants.JCR_MERGEFAILED)) {
                     throw new DavException(DavServletResponse.SC_CONFLICT, "Attempt to resolve non-existing merge conflicts.");
                 }
-                Value[] mergeFailed = n.getProperty(JcrConstants.JCR_MERGEFAILED).getValues();
-
 
-                // check which mergeFailed entries have been removed from the
-                // auto-merge-set (cancelMerge) and have been moved over to the
-                // predecessor set (doneMerge)
-                List mergeset = new HrefProperty(setProperties.get(AUTO_MERGE_SET)).getHrefs();
-                List predecSet = new HrefProperty(setProperties.get(PREDECESSOR_SET)).getHrefs();
+                List mergeset = new HrefProperty(autoMergeSet).getHrefs();
+                List predecSet = (predecessorSet == null) ? new ArrayList() : new HrefProperty(predecessorSet).getHrefs();
 
                 Session session = getRepositorySession();
+                // loop over the mergeFailed values (versions) and test whether they are
+                // removed from the DAV:auto-merge-set thus indicating resolution.
+                Value[] mergeFailed = n.getProperty(JcrConstants.JCR_MERGEFAILED).getValues();
                 for (int i = 0; i < mergeFailed.length; i++) {
                     // build version-href from each entry in the jcr:mergeFailed property
+                    // in order to be able to compare to the entries in the HrefProperty.
                     Version version = (Version) session.getNodeByUUID(mergeFailed[i].getString());
                     String href = getLocatorFromItem(version).getHref(true);
 
                     // Test if that version has been removed from the merge-set.
-                    // thus indicating that the merge-conflict needs to be resolved.
+                    // thus indicating that this merge conflict needs to be resolved.
                     if (!mergeset.contains(href)) {
-                        // Test if the 'href' has been moved over to the
-                        // predecessor-set (thus 'doneMerge' is appropriate) or
-                        // if it is not present in the predecessor set and the
-                        // the conflict is resolved by 'cancelMerge'.
+                        // If the conflict value has been moved over from DAV:auto-merge-set
+                        // to the predecessor-set, resolution with 'doneMerge' is
+                        // appropriate. If the value has been removed from the
+                        // merge-set but not added to the predecessors 'cancelMerge'
+                        // must be called.
                         if (predecSet.contains(href)) {
                             n.doneMerge(version);
                         } else {
@@ -207,11 +217,14 @@
                         }
                     }
                 }
-                // adjust setProperty set
-                setProperties.remove(AUTO_MERGE_SET);
-                setProperties.remove(PREDECESSOR_SET);
+                // after successful resolution of merge-conflicts according to
+                // DAV:auto-merge-set and DAV:predecessor-set remove these entries
+                // from the changeList.
+                changeList.remove(autoMergeSet);
+                if (predecessorSet != null) {
+                    changeList.remove(predecessorSet);
+                }
             }
-            /* else: no (valid) attempt to resolve merge conflict > return silently */
         } catch (RepositoryException e) {
             throw new JcrDavException(e);
         }

Modified: jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/simple/DavResourceImpl.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/simple/DavResourceImpl.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/simple/DavResourceImpl.java (original)
+++ jackrabbit/trunk/jcr-server/server/src/java/org/apache/jackrabbit/webdav/simple/DavResourceImpl.java Fri Apr 28 02:48:32 2006
@@ -55,6 +55,7 @@
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
 import org.apache.jackrabbit.webdav.property.ResourceType;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameIterator;
 import org.apache.jackrabbit.webdav.xml.Namespace;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -386,45 +387,64 @@
     }
 
     /**
-     * @see DavResource#alterProperties(org.apache.jackrabbit.webdav.property.DavPropertySet, org.apache.jackrabbit.webdav.property.DavPropertyNameSet)
+     * @see DavResource#alterProperties(DavPropertySet, DavPropertyNameSet)
      */
     public MultiStatusResponse alterProperties(DavPropertySet setProperties,
                                                DavPropertyNameSet removePropertyNames)
             throws DavException {
+        List changeList = new ArrayList();
+        if (removePropertyNames != null) {
+            DavPropertyNameIterator it = removePropertyNames.iterator();
+            while (it.hasNext()) {
+                changeList.add(it.next());
+            }
+        }
+        if (setProperties != null) {
+            DavPropertyIterator it = setProperties.iterator();
+            while (it.hasNext()) {
+                changeList.add(it.next());
+            }
+        }
+
+        return alterProperties(changeList);
+    }
+
+    public MultiStatusResponse alterProperties(List changeList) throws DavException {
         if (isLocked(this)) {
             throw new DavException(DavServletResponse.SC_LOCKED);
         }
         if (!exists()) {
             throw new DavException(DavServletResponse.SC_NOT_FOUND);
         }
-
         MultiStatusResponse msr = new MultiStatusResponse(getHref(), null);
         boolean success = true;
 
-        // loop over set and remove Sets and remember all properties and propertyNames
+        // loop over List and remember all properties and propertyNames
         // that have successfully been altered
         List successList = new ArrayList();
-        DavPropertyIterator setIter = setProperties.iterator();
-        while (setIter.hasNext()) {
-            DavProperty prop = setIter.nextProperty();
-            try {
-                setJcrProperty(prop);
-                successList.add(prop);
-            } catch (RepositoryException e) {
-                msr.add(prop.getName(), new JcrDavException(e).getErrorCode());
-                success = false;
-            }
-        }
-
-        Iterator remNameIter = removePropertyNames.iterator();
-        while (remNameIter.hasNext()) {
-            DavPropertyName propName = (DavPropertyName) remNameIter.next();
-            try {
-                removeJcrProperty(propName);
-                successList.add(propName);
-            } catch (RepositoryException e) {
-                msr.add(propName, new JcrDavException(e).getErrorCode());
-                success = false;
+        Iterator it = changeList.iterator();
+        while (it.hasNext()) {
+            Object propEntry = it.next();
+            if (propEntry instanceof DavPropertyName) {
+                DavPropertyName propName = (DavPropertyName)propEntry;
+                try {
+                    removeJcrProperty(propName);
+                    successList.add(propName);
+                } catch (RepositoryException e) {
+                    msr.add(propName, new JcrDavException(e).getErrorCode());
+                    success = false;
+                }
+            } else if (propEntry instanceof DavProperty) {
+                DavProperty prop = (DavProperty)propEntry;
+                try {
+                    setJcrProperty(prop);
+                    successList.add(prop);
+                } catch (RepositoryException e) {
+                    msr.add(prop.getName(), new JcrDavException(e).getErrorCode());
+                    success = false;
+                }
+            } else {
+                throw new IllegalArgumentException("unknown object in change list: " + propEntry.getClass().getName());
             }
         }
 
@@ -441,7 +461,7 @@
                complete action. in case of failure set the status to 'failed-dependency'
                in order to indicate, that altering those names/properties would
                have succeeded, if no other error occured.*/
-            Iterator it = successList.iterator();
+            it = successList.iterator();
             while (it.hasNext()) {
                 Object o = it.next();
                 int status = (success) ? DavServletResponse.SC_OK : DavServletResponse.SC_FAILED_DEPENDENCY;

Modified: jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java (original)
+++ jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java Fri Apr 28 02:48:32 2006
@@ -28,6 +28,7 @@
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
 
 import java.io.IOException;
+import java.util.List;
 
 /**
  * <code>DavResource</code> provides standard WebDAV functionality as specified
@@ -180,8 +181,24 @@
      * @throws DavException if an error occured. This may be the case if the
      * general state of the resource prevents any properties to be set or removed
      * (e.g. due to a lock).
+     * @deprecated use {@link #alterProperties(List)} instead
      */
     public MultiStatusResponse alterProperties(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames) throws DavException;
+
+    /**
+     * Set/add and remove the specified properties from this resource.
+     *
+     * @param changeList list containing {@link DavPropertyName} objects (for
+     * properties to be removed) and {@link DavProperty} objects (for
+     * properties to be added/set).
+     * @return multistatus response listing the status resulting from
+     * setting and/or removing the specified properties, in order to allow a
+     * detailled multistatus response.
+     * @throws DavException if an error occured. This may be the case if the
+     * general state of the resource prevents any properties to be set or removed
+     * (e.g. due to a lock).
+     */
+    public MultiStatusResponse alterProperties(List changeList) throws DavException;
 
     /**
      * Retrieve the resource this resource is internal member of.

Modified: jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java (original)
+++ jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java Fri Apr 28 02:48:32 2006
@@ -18,9 +18,12 @@
 import org.apache.jackrabbit.webdav.lock.LockInfo;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.w3c.dom.Document;
 
 import javax.servlet.http.HttpServletRequest;
+import java.util.List;
 
 /**
  * <code>DavServletRequest</code> extends the HttpServletRequest by Webdav
@@ -155,6 +158,7 @@
      * @return set of properties the client wanted to modify / create with a
      * PROPPATCH request.
      * @throws DavException In case of invalid request body
+     * @deprecated use {@link #getPropPatchChangeList()} instead
      */
     public DavPropertySet getPropPatchSetProperties() throws DavException;
 
@@ -170,8 +174,20 @@
      * @return set of property names the client wanted to remove with a
      * PROPPATCH request.
      * @throws DavException In case of invalid request body
+     * @deprecated use {@link #getPropPatchChangeList()} instead
      */
     public DavPropertyNameSet getPropPatchRemoveProperties() throws DavException;
+
+     /**
+      * Return a {@link List} of property change operations. Each entry
+      * is either of type {@link DavPropertyName}, indicating a &lt;remove&gt;
+      * operation, or of type {@link DavProperty}, indicating a &lt;set&gt;
+      * operation. Note that ordering is significant here.
+      * 
+      * @return {@link List} of property change operations
+      * @throws DavException In case of invalid request body
+      */
+     public List getPropPatchChangeList() throws DavException;
 
     /**
      * Return the parsed 'lockinfo' request body, the {@link DavConstants#HEADER_TIMEOUT

Modified: jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java?rev=397835&r1=397834&r2=397835&view=diff
==============================================================================
--- jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java (original)
+++ jackrabbit/trunk/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java Fri Apr 28 02:48:32 2006
@@ -68,6 +68,8 @@
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * <code>WebdavRequestImpl</code>...
@@ -87,6 +89,7 @@
     private DavPropertyNameSet propfindProps;
     private DavPropertySet proppatchSet;
     private DavPropertyNameSet proppatchRemove;
+    private List proppatchList;
 
     /**
      * Creates a new <code>DavServletRequest</code> with the given parameters.
@@ -355,6 +358,7 @@
      *
      * @return the list of 'set' entries in the PROPPATCH request body
      * @see DavServletRequest#getPropPatchSetProperties()
+     * @deprecated use {@link #getPropPatchChangeList()} instead
      */
     public DavPropertySet getPropPatchSetProperties() throws DavException {
         if (proppatchSet == null) {
@@ -370,6 +374,7 @@
      *
      * @return the list of 'remove' entries in the PROPPATCH request body
      * @see DavServletRequest#getPropPatchRemoveProperties()
+     * @deprecated use {@link #getPropPatchChangeList()} instead
      */
     public DavPropertyNameSet getPropPatchRemoveProperties() throws DavException {
         if (proppatchRemove == null) {
@@ -378,6 +383,22 @@
         return proppatchRemove;
     }
 
+     /**
+      * Return a {@link List} of property change operations. Each entry
+      * is either of type {@link DavPropertyName}, indicating a &lt;remove&gt;
+      * operation, or of type {@link DavProperty}, indicating a &lt;set&gt;
+      * operation. Note that ordering is significant here.
+      *
+      * @return the list of change operations entries in the PROPPATCH request body
+      * @see DavServletRequest#getPropPatchChangeList()
+      */
+     public List getPropPatchChangeList() throws DavException {
+         if (proppatchList == null) {
+             parsePropPatchRequest();
+         }
+         return proppatchList;
+     }
+
     /**
      * Parse the PROPPATCH request body.
      */
@@ -385,6 +406,8 @@
 
         proppatchSet = new DavPropertySet();
         proppatchRemove = new DavPropertyNameSet();
+        proppatchList = new ArrayList();
+
         Document requestDocument = getRequestDocument();
 
         if (requestDocument == null) {
@@ -393,31 +416,36 @@
 
         Element root = requestDocument.getDocumentElement();
         if (!DomUtil.matches(root, XML_PROPERTYUPDATE, NAMESPACE)) {
-            // we should also check for correct namespace
-            log.warn("PropPatch-Request has no <propertyupdate> tag.");
+            log.warn("PropPatch-Request has no <DAV:propertyupdate> tag.");
             throw new DavException(DavServletResponse.SC_BAD_REQUEST, "PropPatch-Request has no <propertyupdate> tag.");
         }
 
-        ElementIterator it = DomUtil.getChildren(root, XML_SET, NAMESPACE);
+        ElementIterator it = DomUtil.getChildren(root);
         while (it.hasNext()) {
-            Element propEl = DomUtil.getChildElement(it.nextElement(), XML_PROP, NAMESPACE);
-            if (propEl != null) {
-                ElementIterator properties = DomUtil.getChildren(propEl);
-                while (properties.hasNext()) {
-                   proppatchSet.add(DefaultDavProperty.createFromXml(properties.nextElement()));
+            Element el = it.nextElement();
+            if (DomUtil.matches(el, XML_SET, NAMESPACE)) {
+                Element propEl = DomUtil.getChildElement(el, XML_PROP, NAMESPACE);
+                if (propEl != null) {
+                    ElementIterator properties = DomUtil.getChildren(propEl);
+                    while (properties.hasNext()) {
+                        DavProperty davProp = DefaultDavProperty.createFromXml(properties.nextElement());
+                        proppatchSet.add(davProp);
+                        proppatchList.add(davProp);
+                    }
                 }
-            }
-        }
-
-        // get <remove> properties
-        it = DomUtil.getChildren(root, XML_REMOVE, NAMESPACE);
-        while (it.hasNext()) {
-            Element propEl = DomUtil.getChildElement(it.nextElement(), XML_PROP, NAMESPACE);
-            if (propEl != null) {
-                ElementIterator names = DomUtil.getChildren(propEl);
-                while (names.hasNext()) {
-                    proppatchRemove.add(DavPropertyName.createFromXml(names.nextElement()));
+            } else if (DomUtil.matches(el, XML_REMOVE, NAMESPACE)) {
+                Element propEl = DomUtil.getChildElement(el, XML_PROP, NAMESPACE);
+                if (propEl != null) {
+                    ElementIterator properties = DomUtil.getChildren(propEl);
+                    while (properties.hasNext()) {
+                        DavProperty davProp = DefaultDavProperty.createFromXml(properties.nextElement());
+                        proppatchSet.add(davProp);
+                        proppatchList.add(davProp.getName());
+                    }
                 }
+            } else {
+                log.debug("Unknown element in DAV:propertyupdate: " + el.getNodeName());
+                // unknown child elements are ignored
             }
         }
     }



Mime
View raw message