commit - 557565a3485f3bceaaedfceaed9c90915eb457d4
commit + 17f2d4cbb747e0c9349d8500acf02d15a620c00f
blob - 4d645e1afa7c6fd288e8da760d89064436692577
blob + 514a1b9f2955d0a9825b8c0d0ddbb9a1d0a3e359
--- modules/vfs.s3/pom.xml
+++ modules/vfs.s3/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>moxo</artifactId>
- <groupId>com.thinkberg.moxo</groupId>
- <version>1.0-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
<modelVersion>4.0.0</modelVersion>
+ <groupId>com.thinkberg</groupId>
<artifactId>vfs.s3</artifactId>
<version>1.0-SNAPSHOT</version>
<name>thinkberg.com S3 VFS provider</name>
</resources>
<plugins>
<plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <verbose>true</verbose>
+ <fork>true</fork>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
- <include>**/tests/*.java</include>
+ <include>**/tests/S3FileNameTest.java</include>
+ <include>**/tests/S3FileProviderTest.java</include>
</includes>
</configuration>
</plugin>
blob - ff8178919c5992604e3c2cd499dda4b4f2804614
blob + 3353936723407d8aaf9b55fb8cc0cec4601cf2e3
--- modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/jets3t/Jets3tFileObject.java
+++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/jets3t/Jets3tFileObject.java
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.FileName;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileType;
+import org.apache.commons.vfs.*;
import org.apache.commons.vfs.provider.AbstractFileObject;
import org.apache.commons.vfs.util.MonitorOutputStream;
import org.jets3t.service.Constants;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
+import java.util.Arrays;
import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
/**
attached = false;
}
- protected void doRename(FileObject newfile) throws Exception {
- super.doRename(newfile);
+ protected void doRename(FileObject targetFileObject) throws Exception {
+ String bucketId = bucket.getName();
+ S3Object targetObject = ((Jets3tFileObject) targetFileObject).object;
+
+ LOG.debug(String.format("move object '%s' to '%s'", getS3Key(), targetObject.getKey()));
+
+ // if this is a folder, then rename all children of the current folder too
+ if (FileType.FOLDER.equals(getType())) {
+ String path = object.getKey();
+ // make sure we add a '/' slash at the end to find children
+ if (!"".equals(path)) {
+ path = path + "/";
+ }
+
+ try {
+ S3Object[] children = service.listObjects(bucket, path, null);
+ LOG.debug(children);
+ String targetName = targetObject.getKey();
+ for (S3Object child : children) {
+ String targetChildName = child.getKey();
+ targetChildName = targetName + targetChildName.substring(object.getKey().length());
+ service.renameObject(bucketId, child.getKey(), new S3Object(bucket, targetChildName));
+ }
+ } catch (S3ServiceException e) {
+ throw new FileSystemException(String.format("can't move children of '%s' to '%s'", object.getKey(), targetObject.getKey()), e);
+ }
+ }
+
+ try {
+ service.renameObject(bucket.getName(), object.getKey(), ((Jets3tFileObject) targetFileObject).object);
+ } catch (S3ServiceException e) {
+ throw new FileSystemException("can't rename object", e);
+ }
}
+ @Override
+ public void copyFrom(FileObject file, FileSelector selector) throws FileSystemException {
+ super.copyFrom(file, selector);
+ }
+
protected void doCreateFolder() throws Exception {
if (!Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(object.getContentType())) {
object.setContentType(Mimetypes.MIMETYPE_JETS3T_DIRECTORY);
protected void doSetLastModifiedTime(final long modtime) throws Exception {
object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, modtime);
+ service.updateObjectMetadata(bucket.getName(), object);
}
protected InputStream doGetInputStream() throws Exception {
protected void onClose() throws IOException {
try {
LOG.debug(String.format("sending '%s' to storage (cached=%b)", object.getKey(), cacheFile));
+ LOG.debug(object);
if (cacheFile != null) {
FileChannel cacheFc = getCacheFile().getChannel();
object.setContentLength(cacheFc.size());
return FileType.FILE;
}
- protected String[] doListChildren() throws Exception {
+ protected String[] doListChildren() throws FileSystemException {
String path = object.getKey();
// make sure we add a '/' slash at the end to find children
if (!"".equals(path)) {
path = path + "/";
}
- S3Object[] children = service.listObjects(bucket, path, "/");
- String[] childrenNames = new String[children.length];
- for (int i = 0; i < children.length; i++) {
- if (!children[i].getKey().equals(path)) {
- // strip path from name (leave only base name)
- childrenNames[i] = children[i].getKey().replaceAll("[^/]*//*", "");
+ try {
+ S3Object[] children = service.listObjects(bucket, path, "/");
+ LOG.debug(Arrays.asList(children));
+ LOG.debug(Arrays.asList(children));
+ String[] childrenNames = new String[children.length];
+ for (int i = 0; i < children.length; i++) {
+ if (!children[i].getKey().equals(path)) {
+ // strip path from name (leave only base name)
+ childrenNames[i] = children[i].getKey().replaceAll("[^/]*//*", "");
+ }
}
- }
- return childrenNames;
+ return childrenNames;
+ } catch (S3ServiceException e) {
+ throw new FileSystemException(String.format("can't list children of '%s'", path), e);
+ }
}
protected long doGetContentSize() throws Exception {
return object.getContentLength();
}
+ @SuppressWarnings("unchecked")
+ protected Map doGetAttributes() throws Exception {
+ Map metaData = object.getModifiableMetadata();
+ Map attributes = new HashMap<Object, Object>(metaData.size());
+ for (Object key : metaData.keySet()) {
+ if (((String) key).startsWith(Constants.REST_METADATA_PREFIX)) {
+ attributes.put(((String) key).substring(Constants.REST_METADATA_PREFIX.length()), metaData.get(key));
+ } else {
+ attributes.put(key, metaData.get(key));
+ }
+ }
+ LOG.debug(String.format("%s[%s]", object.getKey(), attributes));
+ return attributes;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void doSetAttribute(String attrName, Object value) throws Exception {
+ object.addMetadata(Constants.REST_METADATA_PREFIX + attrName, value);
+ service.updateObjectMetadata(bucket.getName(), object);
+ }
+
// Utility methods
/**
* Create an S3 key from a commons-vfs path. This simply
blob - 4ab104f040636ab7b267aed201ad98af0049f444
blob + 9e5648fcc4e4e7515289b475da7bb2992a230de9
--- modules/vfs.s3/src/test/java/com/thinkberg/vfs/s3/tests/S3FileProviderTest.java
+++ modules/vfs.s3/src/test/java/com/thinkberg/vfs/s3/tests/S3FileProviderTest.java
};
private static final String FOLDER = "/directory";
private static final String FILE = FOLDER + "/newfile.txt";
+ private static final String FILE_NON_EXISTING = "/nonexisting.txt";
+ private static final String ATTR_TESTKEY = "TESTKEY";
+ protected static final String ATTR_TESTVALUE = "TESTVALUE";
static {
LogFactory.getLog(S3FileProviderTest.class).debug("initializing ...");
public void testGetFolderListing() throws FileSystemException {
FileObject object = ROOT.resolveFile(FOLDER);
- FileObject[] files = object.findFiles(new DepthFileSelector(1));
- assertEquals(3, files.length);
+ assertEquals(2, object.getChildren().length);
}
+ public void testGetFolderListingIsShallow() throws FileSystemException {
+ FileObject object = ROOT.resolveFile(FOLDER);
+ FileObject subFolder = object.resolveFile("subdir");
+ subFolder.createFolder();
+ subFolder.resolveFile("subfile.0").createFile();
+ subFolder.resolveFile("subfile.1").createFile();
+ subFolder.resolveFile("subfile.2").createFile();
+
+ assertEquals(3, object.getChildren().length);
+ }
+
public void testMissingFile() throws FileSystemException {
- FileObject object = ROOT.resolveFile("/nonexisting.txt");
+ FileObject object = ROOT.resolveFile(FILE_NON_EXISTING);
assertFalse(object.exists());
}
assertFalse(object.exists());
}
- public void testCopyFolder() throws FileSystemException {
+ public void testCopyFile() throws FileSystemException {
+ FileObject srcObject = ROOT.resolveFile(FILE);
+ srcObject.createFile();
+ assertTrue("source object should exist", srcObject.exists());
+ FileObject dstObject = ROOT.resolveFile(FILE + ".dst");
+ assertFalse("destination should not exist", dstObject.exists());
+ dstObject.copyFrom(srcObject, ALL_FILE_SELECTOR);
+ assertTrue("destination should exist after copy", dstObject.exists());
+
+ srcObject.delete();
+ dstObject.delete();
+ }
+
+ public void testCopyFileWithAttribute() throws FileSystemException {
+ if (!BUCKETID.startsWith("s3:")) {
+ FileObject srcObject = ROOT.resolveFile(FILE);
+ srcObject.createFile();
+ srcObject.getContent().setAttribute(ATTR_TESTKEY, ATTR_TESTVALUE);
+ assertTrue("source object should exist", srcObject.exists());
+ assertEquals("source object attribute missing",
+ ATTR_TESTVALUE, srcObject.getContent().getAttribute(ATTR_TESTKEY));
+ FileObject dstObject = ROOT.resolveFile(FILE + ".dst");
+ assertFalse("destination should not exist", dstObject.exists());
+ dstObject.copyFrom(srcObject, ALL_FILE_SELECTOR);
+ assertTrue("destination should exist after copy", dstObject.exists());
+ assertEquals("destination object attribute missing",
+ ATTR_TESTVALUE, dstObject.getContent().getAttribute(ATTR_TESTKEY));
+
+ srcObject.delete();
+ dstObject.delete();
+ } else {
+ LogFactory.getLog(S3FileProviderTest.class).info(String.format("ignoring property test for '%s'", ROOT));
+ }
+ }
+
+ public void testCopyShallowFolder() throws FileSystemException {
FileObject origFolder = ROOT.resolveFile(FOLDER);
origFolder.createFolder();
origFolder.resolveFile("file.1").createFile();
origFolder.resolveFile("file.2").createFile();
- FileObject[] origFiles = origFolder.findFiles(new DepthFileSelector(1));
- assertEquals(4, origFiles.length);
+ assertEquals(3, origFolder.getChildren().length);
FileObject destFolder = ROOT.resolveFile(FOLDER + "_dest");
assertFalse(destFolder.exists());
destFolder.copyFrom(origFolder, new DepthFileSelector(1));
assertTrue(destFolder.exists());
+ assertEquals(3, destFolder.getChildren().length);
+
+ FileObject[] origFiles = origFolder.findFiles(new DepthFileSelector(1));
FileObject[] destFiles = destFolder.findFiles(new DepthFileSelector(1));
- assertEquals(4, destFiles.length);
-
for (int i = 0; i < origFiles.length; i++) {
assertEquals(origFiles[i].getName().getRelativeName(origFolder.getName()),
destFiles[i].getName().getRelativeName(destFolder.getName()));
assertFalse(destFolder.exists());
}
-// public void testMoveFolder() throws FileSystemException {
-//
-// }
+ public void testMoveShallowFolder() throws FileSystemException {
+ FileObject origFolder = ROOT.resolveFile(FOLDER);
+ origFolder.delete(ALL_FILE_SELECTOR);
+ origFolder.createFolder();
+ origFolder.resolveFile("file.0").createFile();
+ origFolder.resolveFile("file.1").createFile();
+ origFolder.resolveFile("file.2").createFile();
+
+ assertEquals(3, origFolder.getChildren().length);
+
+ FileObject destFolder = ROOT.resolveFile(FOLDER + "_dest");
+ destFolder.delete(ALL_FILE_SELECTOR);
+ assertFalse(destFolder.exists());
+
+ origFolder.moveTo(destFolder);
+ assertFalse(origFolder.exists());
+ assertTrue(destFolder.exists());
+
+ assertEquals(3, destFolder.getChildren().length);
+
+ destFolder.delete(ALL_FILE_SELECTOR);
+
+ assertFalse(origFolder.exists());
+ assertFalse(destFolder.exists());
+ }
+
+ public void testMoveDeepFolder() throws FileSystemException {
+ FileObject origFolder = ROOT.resolveFile(FOLDER);
+ origFolder.delete(ALL_FILE_SELECTOR);
+ origFolder.createFolder();
+
+ origFolder.resolveFile("file.0").createFile();
+ origFolder.resolveFile("file.1").createFile();
+ origFolder.resolveFile("file.2").createFile();
+ origFolder.resolveFile("subfolder").createFolder();
+ origFolder.resolveFile("subfolder").resolveFile("subfile.0").createFile();
+ origFolder.resolveFile("subfolder").resolveFile("subfile.1").createFile();
+ origFolder.resolveFile("subfolder").resolveFile("subfile.2").createFile();
+
+
+ FileObject[] origFiles = origFolder.findFiles(ALL_FILE_SELECTOR);
+ assertEquals(8, origFiles.length);
+
+ FileObject destFolder = ROOT.resolveFile(FOLDER + "_dest");
+ destFolder.delete(ALL_FILE_SELECTOR);
+ assertFalse(destFolder.exists());
+
+ origFolder.moveTo(destFolder);
+ assertFalse(origFolder.exists());
+ assertTrue(destFolder.exists());
+
+ FileObject[] destFiles = destFolder.findFiles(ALL_FILE_SELECTOR);
+ assertEquals(8, destFiles.length);
+
+ destFolder.delete(ALL_FILE_SELECTOR);
+
+ assertFalse(origFolder.exists());
+ assertFalse(destFolder.exists());
+ }
+
public void testCloseFileSystem() throws FileSystemException {
VFS.getManager().closeFileSystem(ROOT.getFileSystem());
}
blob - c592b4c0538d04698f16be3c7f792e4cf706d0f8
blob + ab1a74fa06b6c50787d3d4de5596e04bba672562
--- modules/webdav/pom.xml
+++ modules/webdav/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>moxo</artifactId>
- <groupId>com.thinkberg.moxo</groupId>
- <version>1.0-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
<modelVersion>4.0.0</modelVersion>
+ <groupId>com.thinkberg</groupId>
<artifactId>webdav</artifactId>
<version>1.0-SNAPSHOT</version>
<name>thinkberg.com WebDAV</name>
<artifactId>commons-codec</artifactId>
<version>1.3</version>
</dependency>
-
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6.1</version>
+ </dependency>
+ <dependency>
+ <groupId>jaxen</groupId>
+ <artifactId>jaxen</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ </dependency>
</dependencies>
<build>
<resources>
</resources>
<plugins>
<plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <verbose>true</verbose>
+ <fork>true</fork>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
blob - 09b60a7b33e721815fda022a1e7167429e306ca8
blob + bc0c6eff3013f0bb36bc5e4f530ddb7d5d520ba1
--- modules/webdav/src/main/java/com/thinkberg/webdav/DeleteHandler.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/DeleteHandler.java
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSelectInfo;
import org.apache.commons.vfs.FileSelector;
-import org.mortbay.jetty.Request;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.text.ParseException;
/**
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
FileObject object = VFSBackend.resolveFile(request.getPathInfo());
- if (request instanceof Request) {
- String fragment = ((Request) request).getUri().getFragment();
+
+ try {
+ String fragment = new URI(request.getRequestURI()).getFragment();
if (fragment != null) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
+ } catch (URISyntaxException e) {
+ throw new IOException(e.getMessage());
}
try {
blob - 204d06d06be8367f5bb86da172606b16b3c525ab
blob + c47185b358b6ad5571018d737169ae5e2aa40ad1
--- modules/webdav/src/main/java/com/thinkberg/webdav/LockHandler.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/LockHandler.java
logXml(propDoc);
}
- private void logXml(Node element) {
+ protected void logXml(Node element) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
XMLWriter xmlWriter = new XMLWriter(bos, OutputFormat.createPrettyPrint());
blob - 21fb7f4fd07568da5160aadb3563b7b18d3ed5f1
blob + 5635c52c1fce56d483cbf7f66f81e52dad5c6c75
--- modules/webdav/src/main/java/com/thinkberg/webdav/MoveHandler.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/MoveHandler.java
package com.thinkberg.webdav;
-import com.thinkberg.webdav.vfs.DepthFileSelector;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
*/
public class MoveHandler extends CopyMoveBase {
protected void copyOrMove(FileObject object, FileObject target, int depth) throws FileSystemException {
- target.copyFrom(object, new DepthFileSelector(depth));
- object.delete(new DepthFileSelector());
+ object.moveTo(target);
}
}
blob - 00a7383b8d339f22c7242ad22205a99bfaec87cf
blob + d7233be643552cc949f8535d2bdc4aade8257493
--- modules/webdav/src/main/java/com/thinkberg/webdav/PropFindHandler.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/PropFindHandler.java
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
-import org.dom4j.*;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
* @version $Id$
*/
public class PropFindHandler extends WebdavHandler {
- private static final String TAG_PROP = "prop";
- private static final String TAG_ALLPROP = "allprop";
- private static final String TAG_PROPNAMES = "propnames";
private static final String TAG_MULTISTATUS = "multistatus";
private static final String TAG_HREF = "href";
private static final String TAG_RESPONSE = "response";
+
+ private static final String TAG_ALLPROP = "allprop";
+ private static final String TAG_PROPNAMES = "propnames";
+ private static final String TAG_PROP = "prop";
+
+ private static final List<String> VALID_PROPFIND_TAGS = Arrays.asList(
+ TAG_ALLPROP, TAG_PROPNAMES, TAG_PROP
+ );
private static final Log LOG = LogFactory.getLog(PropFindHandler.class);
- void logXml(Node element) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- try {
- XMLWriter xmlWriter = new XMLWriter(bos, OutputFormat.createPrettyPrint());
- xmlWriter.write(element);
- LOG.debug(bos.toString());
- } catch (IOException e) {
- LOG.error(e.getMessage());
- }
- }
-
-
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
SAXReader saxReader = new SAXReader();
try {
logXml(propDoc);
Element propFindEl = propDoc.getRootElement();
- Element propEl = (Element) propFindEl.elementIterator().next();
- String propElName = propEl.getName();
+ for (Object propElObject : propFindEl.elements()) {
+ Element propEl = (Element) propElObject;
+ if (VALID_PROPFIND_TAGS.contains(propEl.getName())) {
+ FileObject object = VFSBackend.resolveFile(request.getPathInfo());
+ if (object.exists()) {
+ // respond as XML encoded multi status
+ response.setContentType("text/xml");
+ response.setCharacterEncoding("UTF-8");
+ response.setStatus(SC_MULTI_STATUS);
- List<String> requestedProperties = new ArrayList<String>();
- boolean ignoreValues = false;
- if (TAG_PROP.equals(propElName)) {
- for (Object id : propEl.elements()) {
- requestedProperties.add(((Element) id).getName());
+ Document multiStatusResponse =
+ getMultiStatusResponse(object,
+ propEl,
+ getBaseUrl(request),
+ getDepth(request));
+ logXml(multiStatusResponse);
+
+ // write the actual response
+ XMLWriter writer = new XMLWriter(response.getWriter(), OutputFormat.createCompactFormat());
+ writer.write(multiStatusResponse);
+ writer.flush();
+ writer.close();
+
+ } else {
+ LOG.error(object.getName().getPath() + " NOT FOUND");
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ break;
}
- } else if (TAG_ALLPROP.equals(propElName)) {
- requestedProperties = DavResource.ALL_PROPERTIES;
- } else if (TAG_PROPNAMES.equals(propElName)) {
- requestedProperties = DavResource.ALL_PROPERTIES;
- ignoreValues = true;
}
-
- FileObject object = VFSBackend.resolveFile(request.getPathInfo());
- if (object.exists()) {
- // respond as XML encoded multi status
- response.setContentType("text/xml");
- response.setCharacterEncoding("UTF-8");
- response.setStatus(SC_MULTI_STATUS);
-
- Document multiStatusResponse =
- getMultiStatusRespons(object,
- requestedProperties,
- getBaseUrl(request),
- getDepth(request),
- ignoreValues);
- logXml(multiStatusResponse);
-
- // write the actual response
- XMLWriter writer = new XMLWriter(response.getWriter(), OutputFormat.createCompactFormat());
- writer.write(multiStatusResponse);
- writer.flush();
- writer.close();
-
- } else {
- LOG.error(object.getName().getPath() + " NOT FOUND");
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- }
} catch (DocumentException e) {
LOG.error("invalid request: " + e.getMessage());
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
}
- @SuppressWarnings({"ConstantConditions"})
- private Document getMultiStatusRespons(FileObject object,
- List<String> requestedProperties,
- URL baseUrl,
- int depth,
- boolean ignoreValues) throws FileSystemException {
+ private Document getMultiStatusResponse(FileObject object,
+ Element propEl,
+ URL baseUrl,
+ int depth) throws FileSystemException {
Document propDoc = DocumentHelper.createDocument();
propDoc.setXMLEncoding("UTF-8");
Element responseEl = multiStatus.addElement(TAG_RESPONSE);
try {
URL url = new URL(baseUrl, URLEncoder.encode(child.getName().getPath(), "UTF-8"));
- LOG.debug(url);
responseEl.addElement(TAG_HREF).addText(url.toExternalForm());
} catch (Exception e) {
- e.printStackTrace();
+ LOG.error("can't set href in response", e);
}
DavResource resource = DavResourceFactory.getInstance().getDavResource(child);
- resource.setIgnoreValues(ignoreValues);
- resource.serializeToXml(responseEl, requestedProperties);
+ resource.getPropertyValues(responseEl, propEl);
}
return propDoc;
}
blob - 07ffae65a4113a2f5526d060bb9abd511fc50a5a
blob + 50f915eb7b1c5158cd909b49560628c9b14048a8
--- modules/webdav/src/main/java/com/thinkberg/webdav/PropPatchHandler.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/PropPatchHandler.java
package com.thinkberg.webdav;
+import com.thinkberg.webdav.data.AbstractDavResource;
import com.thinkberg.webdav.data.DavResource;
+import com.thinkberg.webdav.data.DavResourceFactory;
import com.thinkberg.webdav.lock.LockException;
import com.thinkberg.webdav.lock.LockManager;
import com.thinkberg.webdav.vfs.VFSBackend;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import java.io.IOException;
import java.net.URL;
import java.text.ParseException;
+import java.util.ArrayList;
import java.util.List;
/**
public class PropPatchHandler extends WebdavHandler {
private static final Log LOG = LogFactory.getLog(PropPatchHandler.class);
+ private static final String TAG_MULTISTATUS = "multistatus";
+ private static final String TAG_HREF = "href";
+ private static final String TAG_RESPONSE = "response";
+
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
FileObject object = VFSBackend.resolveFile(request.getPathInfo());
return;
}
- SAXReader saxReader = new SAXReader();
- try {
- Document propDoc = saxReader.read(request.getInputStream());
-// log(propDoc);
+ if (object.exists()) {
+ SAXReader saxReader = new SAXReader();
+ try {
+ Document propDoc = saxReader.read(request.getInputStream());
+ logXml(propDoc);
- response.setContentType("text/xml");
- response.setCharacterEncoding("UTF-8");
- response.setStatus(SC_MULTI_STATUS);
-
- if (object.exists()) {
- Document resultDoc = DocumentHelper.createDocument();
- Element multiStatusResponse = resultDoc.addElement("multistatus", "DAV:");
- Element responseEl = multiStatusResponse.addElement("response");
- try {
- URL url = new URL(getBaseUrl(request), URLEncoder.encode(object.getName().getPath(), "UTF-8"));
- LOG.debug(url);
- responseEl.addElement("href").addText(url.toExternalForm());
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- Element propstatEl = responseEl.addElement("propstat");
- Element propEl = propstatEl.addElement("prop");
-
- Element propertyUpdateEl = propDoc.getRootElement();
- for (Object elObject : propertyUpdateEl.elements()) {
+ Element propUpdateEl = propDoc.getRootElement();
+ List<Element> requestedProperties = new ArrayList<Element>();
+ for (Object elObject : propUpdateEl.elements()) {
Element el = (Element) elObject;
- if ("set".equals(el.getName())) {
- for (Object propObject : el.elements()) {
- setProperty(propEl, object, (Element) propObject);
+ String command = el.getName();
+ if (AbstractDavResource.TAG_PROP_SET.equals(command) || AbstractDavResource.TAG_PROP_REMOVE.equals(command)) {
+ for (Object propElObject : el.elements()) {
+ for (Object propNameElObject : ((Element) propElObject).elements()) {
+ Element propNameEl = (Element) propNameElObject;
+ requestedProperties.add(propNameEl);
+ }
}
- } else if ("remove".equals(el.getName())) {
- for (Object propObject : el.elements()) {
- removeProperty(propEl, object, (Element) propObject);
- }
}
}
- propstatEl.addElement("status").addText(DavResource.STATUS_403);
-// log(resultDoc);
+ // respond as XML encoded multi status
+ response.setContentType("text/xml");
+ response.setCharacterEncoding("UTF-8");
+ response.setStatus(SC_MULTI_STATUS);
+ Document multiStatusResponse = getMultiStatusResponse(object, requestedProperties, getBaseUrl(request));
+
+ logXml(multiStatusResponse);
+
// write the actual response
XMLWriter writer = new XMLWriter(response.getWriter(), OutputFormat.createCompactFormat());
- writer.write(resultDoc);
+ writer.write(multiStatusResponse);
writer.flush();
writer.close();
- } else {
- LOG.error(object.getName().getPath() + " NOT FOUND");
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- }
- } catch (DocumentException e) {
- LOG.error("invalid request: " + e.getMessage());
- response.sendError(HttpServletResponse.SC_BAD_REQUEST);
- }
- }
- private void setProperty(Element root, FileObject object, Element el) {
- List propList = el.elements();
- for (Object propElObject : propList) {
- Element propEl = (Element) propElObject;
- for (int i = 0; i < propEl.nodeCount(); i++) {
- propEl.node(i).detach();
+ } catch (DocumentException e) {
+ LOG.error("invalid request: " + e.getMessage());
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
- root.add(propEl.detach());
+ } else {
+ LOG.error(object.getName().getPath() + " NOT FOUND");
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
- private void removeProperty(Element root, FileObject object, Element el) {
- setProperty(root, object, el);
- }
+ private Document getMultiStatusResponse(FileObject object, List<Element> requestedProperties, URL baseUrl) throws FileSystemException {
+ Document propDoc = DocumentHelper.createDocument();
+ propDoc.setXMLEncoding("UTF-8");
-
+ Element multiStatus = propDoc.addElement(TAG_MULTISTATUS, "DAV:");
+ Element responseEl = multiStatus.addElement(TAG_RESPONSE);
+ try {
+ URL url = new URL(baseUrl, URLEncoder.encode(object.getName().getPath(), "UTF-8"));
+ responseEl.addElement(TAG_HREF).addText(url.toExternalForm());
+ } catch (Exception e) {
+ LOG.error("can't set HREF tag in response", e);
+ }
+ DavResource resource = DavResourceFactory.getInstance().getDavResource(object);
+ resource.setPropertyValues(responseEl, requestedProperties);
+ return propDoc;
+ }
}
blob - bca6db1498389193b487c1a5c50753dda989f4c5
blob + c4c58177f10fdcc3fa24ad733291fa87a7f918e5
--- modules/webdav/src/main/java/com/thinkberg/webdav/WebdavHandler.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/WebdavHandler.java
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
+import org.dom4j.Node;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
}
return -1;
}
+
+ void logXml(Node element) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try {
+ XMLWriter xmlWriter = new XMLWriter(bos, OutputFormat.createPrettyPrint());
+ xmlWriter.write(element);
+ LogFactory.getLog(this.getClass()).debug(bos.toString());
+ } catch (IOException e) {
+ LogFactory.getLog(this.getClass()).error(e.getMessage());
+ }
+ }
}
blob - 953b5f534b2c224ad5eb65cd370f36d6232bca2d
blob + 693bd57dff62a318333b2d882a4f4668698b55d2
--- modules/webdav/src/main/java/com/thinkberg/webdav/data/AbstractDavResource.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/data/AbstractDavResource.java
package com.thinkberg.webdav.data;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.FileContent;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemException;
import org.dom4j.Element;
+import org.dom4j.Node;
-import java.util.HashSet;
+import java.util.Arrays;
import java.util.List;
-import java.util.Set;
/**
* @author Matthias L. Jugel
* @version $Id$
*/
public abstract class AbstractDavResource {
- private static final String STATUS_200 = "HTTP/1.1 200 OK";
- private static final String STATUS_404 = "HTTP/1.1 404 Not Found";
+ public static final String STATUS_200 = "HTTP/1.1 200 OK";
+ public static final String STATUS_404 = "HTTP/1.1 404 Not Found";
public static final String STATUS_403 = "HTTP/1.1 403 Forbidden";
+ public static final String STATUS_422 = "HTTP/1.1 422 Unprocessable Entity";
- private static final String TAG_PROPSTAT = "propstat";
- private static final String TAG_PROP = "prop";
- private static final String TAG_STATUS = "status";
+ public static final String TAG_ALLPROP = "allprop";
+ public static final String TAG_PROPNAMES = "propnames";
- public Element serializeToXml(Element root, List<String> requestedProperties) {
- Element propStatEl = root.addElement(TAG_PROPSTAT);
- Element propEl = propStatEl.addElement(TAG_PROP);
+ public static final String TAG_PROPSTAT = "propstat";
+ public static final String TAG_PROP = "prop";
+ public static final String TAG_STATUS = "status";
+ public static final String TAG_PROP_SET = "set";
+ public static final String TAG_PROP_REMOVE = "remove";
- Set<String> missingProperties = new HashSet<String>();
- for (String propertyName : requestedProperties) {
- if (!addPropertyValue(propEl, propertyName)) {
- missingProperties.add(propertyName);
+ // @see http://www.webdav.org/specs/rfc2518.html#dav.properties
+ public static final String PROP_CREATION_DATE = "creationdate";
+ public static final String PROP_DISPLAY_NAME = "displayname";
+ public static final String PROP_GET_CONTENT_LANGUAGE = "getcontentlanguage";
+ public static final String PROP_GET_CONTENT_LENGTH = "getcontentlength";
+ public static final String PROP_GET_CONTENT_TYPE = "getcontenttype";
+ public static final String PROP_GET_ETAG = "getetag";
+ public static final String PROP_GET_LAST_MODIFIED = "getlastmodified";
+ public static final String PROP_LOCK_DISCOVERY = "lockdiscovery";
+ public static final String PROP_RESOURCETYPE = "resourcetype";
+ public static final String PROP_SOURCE = "source";
+ public static final String PROP_SUPPORTED_LOCK = "supportedlock";
+
+ // non-standard properties
+ static final String PROP_QUOTA = "quota";
+ static final String PROP_QUOTA_USED = "quotaused";
+ static final String PROP_QUOTA_AVAILABLE_BYTES = "quota-available-bytes";
+ static final String PROP_QUOTA_USED_BYTES = "quota-used-bytes";
+
+ // list of standard supported properties (for allprop/propname)
+ public static final List<String> ALL_PROPERTIES = Arrays.asList(
+ PROP_CREATION_DATE,
+ PROP_DISPLAY_NAME,
+ PROP_GET_CONTENT_LANGUAGE,
+ PROP_GET_CONTENT_LENGTH,
+ PROP_GET_CONTENT_TYPE,
+ PROP_GET_ETAG,
+ PROP_GET_LAST_MODIFIED,
+ PROP_LOCK_DISCOVERY,
+ PROP_RESOURCETYPE,
+ PROP_SOURCE,
+ PROP_SUPPORTED_LOCK
+ );
+
+ protected final FileObject object;
+
+ public AbstractDavResource(FileObject object) {
+ this.object = object;
+ }
+
+ public Element setPropertyValues(Element root, List<Element> requestedProperties) {
+ // initialize the <propstat> element for 200
+ Element okPropStatEl = root.addElement(TAG_PROPSTAT);
+ Element okPropEl = okPropStatEl.addElement(TAG_PROP);
+
+ // initialize the <propstat> element for 422
+ Element failPropStatEl = root.addElement(TAG_PROPSTAT);
+ Element failPropEl = failPropStatEl.addElement(TAG_PROP);
+
+ // go through the properties and try to set/remove them,
+ // if it fails, add to the failed list
+ for (Node propertyEl : requestedProperties) {
+ if (!setPropertyValue(okPropEl, (Element) propertyEl)) {
+ failPropEl.addElement(((Element) propertyEl).getQName());
}
}
- propStatEl.addElement(TAG_STATUS).addText(STATUS_200);
- // add missing properties status
- if (missingProperties.size() > 0) {
- propStatEl = root.addElement(TAG_PROPSTAT);
- propEl = propStatEl.addElement(TAG_PROP);
- for (String el : missingProperties) {
- propEl.addElement(el);
+ // only add the OK section, if there is content
+ if (okPropEl.elements().size() > 0) {
+ okPropStatEl.addElement(TAG_STATUS).addText(STATUS_200);
+ } else {
+ okPropStatEl.detach();
+ }
+
+ // only add the failed section, if there is content
+ if (failPropEl.elements().size() > 0) {
+ failPropStatEl.addElement(TAG_STATUS).addText(STATUS_422);
+ } else {
+ failPropStatEl.detach();
+ }
+
+ return root;
+ }
+
+ public Element getPropertyValues(Element root, Element propertyEl) {
+ // initialize the <propstat> for 200
+ Element okPropStatEl = root.addElement(TAG_PROPSTAT);
+ Element okPropEl = okPropStatEl.addElement(TAG_PROP);
+
+ // initialize the <propstat> element for 404
+ Element failPropStatEl = root.addElement(TAG_PROPSTAT);
+ Element failPropEl = failPropStatEl.addElement(TAG_PROP);
+
+ if (TAG_ALLPROP.equalsIgnoreCase(propertyEl.getName()) ||
+ TAG_PROPNAMES.equalsIgnoreCase(propertyEl.getName())) {
+ boolean ignoreValue = TAG_PROPNAMES.equalsIgnoreCase(propertyEl.getName());
+
+ // get all known standard properties
+ for (String propName : ALL_PROPERTIES) {
+ if (!getPropertyValue(okPropEl, propName, ignoreValue)) {
+ failPropEl.addElement(propName);
+ }
}
- propStatEl.addElement(TAG_STATUS).addText(STATUS_404);
+
+ // additionally try to add all the custom properties
+ try {
+ FileContent objectContent = object.getContent();
+ for (String attributeName : objectContent.getAttributeNames()) {
+ if (!getPropertyValue(okPropEl, attributeName, ignoreValue)) {
+ failPropEl.addElement(attributeName);
+ }
+ }
+ } catch (FileSystemException e) {
+ LogFactory.getLog(getClass()).error(String.format("can't read attribute properties from '%s'",
+ object.getName()), e);
+ }
+ } else {
+ List requestedProperties = propertyEl.elements();
+ for (Object propertyElObject : requestedProperties) {
+ Element propEl = (Element) propertyElObject;
+ final String nameSpace = propEl.getNamespaceURI();
+ if (!getPropertyValue(okPropEl, getFQName(nameSpace, propEl.getQualifiedName()), false)) {
+ failPropEl.addElement(propEl.getQName());
+ }
+ }
}
+ // only add the OK section, if there is content
+ if (okPropEl.elements().size() > 0) {
+ okPropStatEl.addElement(TAG_STATUS).addText(STATUS_200);
+ } else {
+ okPropStatEl.detach();
+ }
+
+ // only add the failed section, if there is content
+ if (failPropEl.elements().size() > 0) {
+ failPropStatEl.addElement(TAG_STATUS).addText(STATUS_404);
+ } else {
+ failPropStatEl.detach();
+ }
+
+
return root;
}
- @SuppressWarnings({"BooleanMethodIsAlwaysInverted"})
- protected abstract boolean addPropertyValue(Element root, String propertyName);
+ protected String getFQName(String nameSpace, String name) {
+ String prefix = "";
+ if (!"DAV:".equals(nameSpace) && null != nameSpace && !"".equals(nameSpace)) {
+ prefix = new String(Base64.encodeBase64(nameSpace.getBytes()));
+ }
+ return String.format("%s%s", prefix, name);
+ }
+
+ /**
+ * Set the property and its value. Returns false if the property cannot be processed.
+ *
+ * @param root the response stat element
+ * @param propertyEl the property element to set
+ * @return false if this property cannot be set
+ */
+ protected abstract boolean setPropertyValue(Element root, Element propertyEl);
+
+ /**
+ * Get the property value and append it to the xml document (root). If this method
+ * returns false, the property does not exist.
+ *
+ * @param root the root element to add the property name (and possible value to)
+ * @param propertyName the property name to read
+ * @param ignoreValue ignore the value and just add the name
+ * @return whether the property exists
+ */
+ protected abstract boolean getPropertyValue(Element root, String propertyName, boolean ignoreValue);
}
blob - 0e47f326c1df304cd650f3a542497617366517b4
blob + 809b8be1ec0c49b3121f5f5ed7b841cd070a4543
--- modules/webdav/src/main/java/com/thinkberg/webdav/data/DavCollection.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavCollection.java
super(object);
}
-
- public DavCollection(FileObject object, boolean ignoreValues) {
- super(object, ignoreValues);
- }
-
- protected boolean addResourceTypeProperty(Element root) {
+ protected boolean addResourceTypeProperty(Element root, boolean ignoreValue) {
root.addElement(PROP_RESOURCETYPE).addElement(COLLECTION);
return true;
}
* @param root the prop element to add to
* @return true, even though nothing is added
*/
- protected boolean addGetContentLanguageProperty(Element root) {
+ protected boolean addGetContentLanguageProperty(Element root, boolean ignoreValue) {
return true;
}
* @param root the prop element to add to
* @return true, even though nothing is added
*/
- protected boolean addGetContentLengthProperty(Element root) {
+ protected boolean addGetContentLengthProperty(Element root, boolean ignoreValue) {
return true;
}
* @param root the prop element to add to
* @return true, even though nothing is added
*/
- protected boolean addGetContentTypeProperty(Element root) {
+ protected boolean addGetContentTypeProperty(Element root, boolean ignoreValue) {
return true;
}
- protected boolean addQuotaProperty(Element root) {
+ protected boolean addQuotaProperty(Element root, boolean ignoreValue) {
root.addElement(PROP_QUOTA).addText("" + Long.MAX_VALUE);
return true;
}
- protected boolean addQuotaUsedProperty(Element root) {
+ protected boolean addQuotaUsedProperty(Element root, boolean ignoreValue) {
// TODO add correct handling of used quota
root.addElement(PROP_QUOTA_USED).addText("0");
return true;
}
- protected boolean addQuotaAvailableBytesProperty(Element root) {
+ protected boolean addQuotaAvailableBytesProperty(Element root, boolean ignoreValue) {
root.addElement(PROP_QUOTA_AVAILABLE_BYTES).addText(Long.toHexString(Long.MAX_VALUE));
return true;
}
- protected boolean addQuotaUsedBytesProperty(Element root) {
+ protected boolean addQuotaUsedBytesProperty(Element root, boolean ignoreValue) {
// TODO add correct handling of used quota
root.addElement(PROP_QUOTA_USED_BYTES).addText("0");
return true;
blob - 3d01502a97a50c6eb672345d40fd43c6eee5b1e7
blob + cca7886e245ede67ecb82ca0d3dfb3bde4a06852
--- modules/webdav/src/main/java/com/thinkberg/webdav/data/DavResource.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavResource.java
import com.thinkberg.webdav.Util;
import com.thinkberg.webdav.lock.Lock;
import com.thinkberg.webdav.lock.LockManager;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.FileContent;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
import org.dom4j.Element;
-import java.util.Arrays;
+import java.io.IOException;
+import java.io.StringWriter;
import java.util.List;
/**
*/
public class DavResource extends AbstractDavResource {
- // @see http://www.webdav.org/specs/rfc2518.html#dav.properties
- public static final String PROP_CREATION_DATE = "creationdate";
- public static final String PROP_DISPLAY_NAME = "displayname";
- private static final String PROP_GET_CONTENT_LANGUAGE = "getcontentlanguage";
- private static final String PROP_GET_CONTENT_LENGTH = "getcontentlength";
- private static final String PROP_GET_CONTENT_TYPE = "getcontenttype";
- private static final String PROP_GET_ETAG = "getetag";
- private static final String PROP_GET_LAST_MODIFIED = "getlastmodified";
- private static final String PROP_LOCK_DISCOVERY = "lockdiscovery";
- public static final String PROP_RESOURCETYPE = "resourcetype";
- private static final String PROP_SOURCE = "source";
- private static final String PROP_SUPPORTED_LOCK = "supportedlock";
-
- // non-standard properties
- static final String PROP_QUOTA = "quota";
- static final String PROP_QUOTA_USED = "quotaused";
- static final String PROP_QUOTA_AVAILABLE_BYTES = "quota-available-bytes";
- static final String PROP_QUOTA_USED_BYTES = "quota-used-bytes";
-
- // list of standard supported properties (for allprop/propname)
- public static final List<String> ALL_PROPERTIES = Arrays.asList(
- PROP_CREATION_DATE,
- PROP_DISPLAY_NAME,
- PROP_GET_CONTENT_LANGUAGE,
- PROP_GET_CONTENT_LENGTH,
- PROP_GET_CONTENT_TYPE,
- PROP_GET_ETAG,
- PROP_GET_LAST_MODIFIED,
- PROP_LOCK_DISCOVERY,
- PROP_RESOURCETYPE,
- PROP_SOURCE,
- PROP_SUPPORTED_LOCK
- );
-
- protected final FileObject object;
- protected boolean ignoreValues = false;
-
public DavResource(FileObject object) {
- this(object, false);
+ super(object);
}
+ protected boolean setPropertyValue(Element root, Element propertyEl) {
+ LogFactory.getLog(getClass()).debug(String.format("[%s].set('%s')", object.getName(), propertyEl.asXML()));
- public DavResource(FileObject object, boolean ignoreValues) {
- this.object = object;
- this.ignoreValues = ignoreValues;
-
+ if (!ALL_PROPERTIES.contains(propertyEl.getName())) {
+ final String nameSpace = propertyEl.getNamespaceURI();
+ final String attributeName = getFQName(nameSpace, propertyEl.getQualifiedName());
+ try {
+ FileContent objectContent = object.getContent();
+ final String command = propertyEl.getParent().getParent().getName();
+ if (TAG_PROP_SET.equals(command)) {
+ StringWriter propertyValueWriter = new StringWriter();
+ propertyEl.write(propertyValueWriter);
+ propertyValueWriter.close();
+ objectContent.setAttribute(attributeName, propertyValueWriter.getBuffer().toString());
+ } else if (TAG_PROP_REMOVE.equals(command)) {
+ objectContent.setAttribute(attributeName, null);
+ }
+ root.addElement(propertyEl.getQName());
+ return true;
+ } catch (IOException e) {
+ LogFactory.getLog(getClass()).error(String.format("can't store attribute property '%s' = '%s'",
+ attributeName,
+ propertyEl.asXML()), e);
+ }
+ }
+ return false;
}
/**
- * Ignore values
- *
- * @param ignoreValues true if the serialized xml should not contain values
- */
- public void setIgnoreValues(boolean ignoreValues) {
- this.ignoreValues = ignoreValues;
- }
-
- /**
* Add the value for a given property to the result document. If the value
* is missing or can not be added for some reason it will return false to
* indicate a missing property.
*
* @param root the root element for the result document fragment
- * @param propertyName the property name to add
+ * @param propertyName the property name to query
* @return true for successful addition and false for missing data
*/
- protected boolean addPropertyValue(Element root, String propertyName) {
+ protected boolean getPropertyValue(Element root, String propertyName, boolean ignoreValue) {
+ LogFactory.getLog(getClass()).debug(String.format("[%s].get('%s')", object.getName(), propertyName));
if (PROP_CREATION_DATE.equals(propertyName)) {
- return addCreationDateProperty(root);
+ return addCreationDateProperty(root, ignoreValue);
} else if (PROP_DISPLAY_NAME.equals(propertyName)) {
- return addGetDisplayNameProperty(root);
+ return addGetDisplayNameProperty(root, ignoreValue);
} else if (PROP_GET_CONTENT_LANGUAGE.equals(propertyName)) {
- return addGetContentLanguageProperty(root);
+ return addGetContentLanguageProperty(root, ignoreValue);
} else if (PROP_GET_CONTENT_LENGTH.equals(propertyName)) {
- return addGetContentLengthProperty(root);
+ return addGetContentLengthProperty(root, ignoreValue);
} else if (PROP_GET_CONTENT_TYPE.equals(propertyName)) {
- return addGetContentTypeProperty(root);
+ return addGetContentTypeProperty(root, ignoreValue);
} else if (PROP_GET_ETAG.equals(propertyName)) {
- return addGetETagProperty(root);
+ return addGetETagProperty(root, ignoreValue);
} else if (PROP_GET_LAST_MODIFIED.equals(propertyName)) {
- return addGetLastModifiedProperty(root);
+ return addGetLastModifiedProperty(root, ignoreValue);
} else if (PROP_LOCK_DISCOVERY.equals(propertyName)) {
- return addLockDiscoveryProperty(root);
+ return addLockDiscoveryProperty(root, ignoreValue);
} else if (PROP_RESOURCETYPE.equals(propertyName)) {
- return addResourceTypeProperty(root);
+ return addResourceTypeProperty(root, ignoreValue);
} else if (PROP_SOURCE.equals(propertyName)) {
- return addSourceProperty(root);
+ return addSourceProperty(root, ignoreValue);
} else if (PROP_SUPPORTED_LOCK.equals(propertyName)) {
- return addSupportedLockProperty(root);
+ return addSupportedLockProperty(root, ignoreValue);
} else {
// handle non-standard properties (keep a little separate)
if (PROP_QUOTA.equals(propertyName)) {
- return addQuotaProperty(root);
+ return addQuotaProperty(root, ignoreValue);
} else if (PROP_QUOTA_USED.equals(propertyName)) {
- return addQuotaUsedProperty(root);
+ return addQuotaUsedProperty(root, ignoreValue);
} else if (PROP_QUOTA_AVAILABLE_BYTES.equals(propertyName)) {
- return addQuotaAvailableBytesProperty(root);
+ return addQuotaAvailableBytesProperty(root, ignoreValue);
} else if (PROP_QUOTA_USED_BYTES.equals(propertyName)) {
- return addQuotaUsedBytesProperty(root);
+ return addQuotaUsedBytesProperty(root, ignoreValue);
+ } else {
+ try {
+ Object propertyValue = object.getContent().getAttribute(propertyName);
+ if (null != propertyValue) {
+ if (((String) propertyValue).startsWith("<")) {
+ try {
+ Document property = DocumentHelper.parseText((String) propertyValue);
+ if (ignoreValue) {
+ property.clearContent();
+ }
+ root.add(property.getRootElement().detach());
+ return true;
+ } catch (DocumentException e) {
+ LogFactory.getLog(getClass()).error("property value unparsable", e);
+ return false;
+ }
+ } else {
+ Element el = root.addElement(propertyName);
+ if (!ignoreValue) {
+ el.addText((String) propertyValue);
+ }
+ return true;
+ }
+
+ }
+ } catch (FileSystemException e) {
+ LogFactory.getLog(this.getClass()).error(String.format("property '%s' is not supported", propertyName), e);
+ }
}
}
return false;
}
- protected boolean addCreationDateProperty(Element root) {
+ protected boolean addCreationDateProperty(Element root, boolean ignoreValue) {
return false;
}
- protected boolean addGetDisplayNameProperty(Element root) {
+ protected boolean addGetDisplayNameProperty(Element root, boolean ignoreValue) {
Element el = root.addElement(PROP_DISPLAY_NAME);
- if (!ignoreValues) {
+ if (!ignoreValue) {
el.addCDATA(object.getName().getBaseName());
}
return true;
}
- protected boolean addGetContentLanguageProperty(Element root) {
+ protected boolean addGetContentLanguageProperty(Element root, boolean ignoreValue) {
return false;
}
- protected boolean addGetContentLengthProperty(Element root) {
+ protected boolean addGetContentLengthProperty(Element root, boolean ignoreValue) {
try {
Element el = root.addElement(PROP_GET_CONTENT_LENGTH);
- if (!ignoreValues) {
+ if (!ignoreValue) {
el.addText("" + object.getContent().getSize());
}
return true;
}
}
- protected boolean addGetContentTypeProperty(Element root) {
+ protected boolean addGetContentTypeProperty(Element root, boolean ignoreValue) {
try {
String contentType = object.getContent().getContentInfo().getContentType();
if (null == contentType || "".equals(contentType)) {
}
Element el = root.addElement(PROP_GET_CONTENT_TYPE);
- if (!ignoreValues) {
+ if (!ignoreValue) {
el.addText(contentType);
}
return true;
}
}
- protected boolean addGetETagProperty(Element root) {
+ protected boolean addGetETagProperty(Element root, boolean ignoreValue) {
return false;
}
- protected boolean addGetLastModifiedProperty(Element root) {
+ protected boolean addGetLastModifiedProperty(Element root, boolean ignoreValue) {
try {
Element el = root.addElement(PROP_GET_LAST_MODIFIED);
- if (!ignoreValues) {
+ if (!ignoreValue) {
el.addText(Util.getDateString(object.getContent().getLastModifiedTime()));
}
return true;
}
}
- protected boolean addLockDiscoveryProperty(Element root) {
+ protected boolean addLockDiscoveryProperty(Element root, boolean ignoreValue) {
Element lockdiscoveryEl = root.addElement(PROP_LOCK_DISCOVERY);
try {
List<Lock> locks = LockManager.getInstance().discoverLock(object);
if (locks != null && !locks.isEmpty()) {
for (Lock lock : locks) {
- if (lock != null && !ignoreValues) {
+ if (lock != null && !ignoreValue) {
lock.serializeToXml(lockdiscoveryEl);
}
}
}
return true;
} catch (FileSystemException e) {
- e.printStackTrace();
root.remove(lockdiscoveryEl);
+ e.printStackTrace();
return false;
}
}
- protected boolean addResourceTypeProperty(Element root) {
+ protected boolean addResourceTypeProperty(Element root, boolean ignoreValue) {
root.addElement(PROP_RESOURCETYPE);
return true;
}
- protected boolean addSourceProperty(Element root) {
+ protected boolean addSourceProperty(Element root, boolean ignoreValue) {
return false;
}
- protected boolean addSupportedLockProperty(Element root) {
+ protected boolean addSupportedLockProperty(Element root, boolean ignoreValue) {
Element supportedlockEl = root.addElement(PROP_SUPPORTED_LOCK);
- if (!ignoreValues) {
+ if (!ignoreValue) {
Element exclLockentryEl = supportedlockEl.addElement("lockentry");
exclLockentryEl.addElement("lockscope").addElement("exclusive");
exclLockentryEl.addElement("locktype").addElement("write");
return true;
}
- protected boolean addQuotaProperty(Element root) {
+ protected boolean addQuotaProperty(Element root, boolean ignoreValue) {
return false;
}
- protected boolean addQuotaUsedProperty(Element root) {
+ protected boolean addQuotaUsedProperty(Element root, boolean ignoreValue) {
return false;
}
- protected boolean addQuotaAvailableBytesProperty(Element root) {
+ protected boolean addQuotaAvailableBytesProperty(Element root, boolean ignoreValue) {
return false;
}
- protected boolean addQuotaUsedBytesProperty(Element root) {
+ protected boolean addQuotaUsedBytesProperty(Element root, boolean ignoreValue) {
return false;
}
}
blob - 0bd27718adde8f76ebb9bf18691ac0317fb46631
blob + 93266e8ffdd305cc0bad778b0ea41e45055fa1b7
--- modules/webdav/src/main/java/com/thinkberg/webdav/servlet/MoxoWebDAVServlet.java
+++ modules/webdav/src/main/java/com/thinkberg/webdav/servlet/MoxoWebDAVServlet.java
import org.apache.commons.vfs.FileSystemOptions;
import org.apache.commons.vfs.auth.StaticUserAuthenticator;
import org.apache.commons.vfs.impl.DefaultFileSystemConfigBuilder;
-import org.mortbay.jetty.Response;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
} else {
response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
}
- Response jettyResponse = ((Response) response);
- String reason = jettyResponse.getReason();
- LOG.debug(String.format("<< %s (%d%s)", request.getMethod(), jettyResponse.getStatus(), reason != null ? ": " + reason : ""));
+ LOG.debug(String.format("<< %s (%s)", request.getMethod(), response.toString().replaceAll("[\\r\\n]+", "")));
}
}
blob - 2389b60f777cec922576a63c3d4ad792dd4073da
blob + 8f0bdb3b66beb18d36e1200ac5a043a0182ada4f
--- modules/webdav/src/test/java/com/thinkberg/webdav/DavTestCase.java
+++ modules/webdav/src/test/java/com/thinkberg/webdav/DavTestCase.java
import org.dom4j.Element;
import org.dom4j.Node;
-import java.util.Arrays;
-
/**
* Helper class for DAV tests.
*
Element root = DocumentHelper.createElement("root");
DavResourceFactory factory = DavResourceFactory.getInstance();
DavResource davResource = factory.getDavResource(object);
- davResource.setIgnoreValues(ignoreValues);
- davResource.serializeToXml(root, Arrays.asList(propertyName));
+
+ Element testPropertyEl = (Element) root.addElement("prop").detach();
+ testPropertyEl.addElement(propertyName);
+
+ davResource.getPropertyValues(root, testPropertyEl);
+
return root;
}
blob - 06c1c46a60a4facb13fe413c6195580c5b6a3282
blob + 3a0fa1b9ecede2c113b5c0fca9111d6041b9e615
--- pom.xml
+++ pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
- <groupId>com.thinkberg.moxo</groupId>
+ <groupId>com.thinkberg</groupId>
<artifactId>moxo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
+ <name>Moxo S3 DAV Proxy</name>
<modules>
<module>modules/webdav</module>
<module>modules/vfs.s3</module>
</modules>
- <name>Moxo S3 DAV Proxy</name>
<url>http://thinkberg.com</url>
<dependencies>
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.1</version>
</dependency>
<dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- <version>1.6.1</version>
+ <groupId>com.thinkberg</groupId>
+ <artifactId>webdav</artifactId>
+ <version>1.0-SNAPSHOT</version>
</dependency>
- <!--<dependency>-->
- <!--<groupId>jaxen</groupId>-->
- <!--<artifactId>jaxen</artifactId>-->
- <!--<version>1.1</version>-->
- <!--</dependency>-->
+ <dependency>
+ <groupId>com.thinkberg</groupId>
+ <artifactId>vfs.s3</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
</dependencies>
<build>
<resources>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifest>
- <mainClass>com.thinkberg.moxo.Main</mainClass>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>com.thinkberg.moxo.Main</mainClass>
+ <addClasspath>true</addClasspath>
+ </manifest>
+ </archive>
+ <includes>
+ <include>**/moxo/*</include>
+ </includes>
+ </configuration>
+ </execution>
+ </executions>
</plugin>
</plugins>
</build>
blob - 5b43b0aee4de7daf1be61d57c1bd4be286fef0fd
blob + 3048290ec50e533b9e6bc29c272b59405f156dad
--- src/main/resources/simplelog.properties
+++ src/main/resources/simplelog.properties
#
org.apache.commons.logging.simplelog.defaultlog=error
-org.apache.commons.logging.simplelog.log.com.thinkberg.moxo=debug
\ No newline at end of file
+org.apache.commons.logging.simplelog.log.com.thinkberg.vfs.s3=debug
+org.apache.commons.logging.simplelog.log.com.thinkberg.webdav=debug
\ No newline at end of file