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 <remove>
+ * operation, or of type {@link DavProperty}, indicating a <set>
+ * 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 <remove>
+ * operation, or of type {@link DavProperty}, indicating a <set>
+ * 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
}
}
}
|