Commit Diff


commit - c69f66ef9a0647aa8c88102bf4d4ff9eaa4c2d65
commit + 1939c62d29abc7a7d42c831f096b5cc27f4c1182
blob - 7ab330241c049a148fc7a2505e2460890c3acc73
blob + c14c5ba8b42a4c77c7dda6a647481be6ab4f0ce3
--- pom.xml
+++ pom.xml
@@ -3,22 +3,14 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.thinkberg.moxo</groupId>
     <artifactId>moxo</artifactId>
-    <packaging>jar</packaging>
+    <packaging>pom</packaging>
     <version>1.0-SNAPSHOT</version>
+    <modules>
+        <module>modules/webdav</module>
+        <module>modules/vfs.s3</module>
+    </modules>
     <name>Moxo S3 DAV Proxy</name>
     <url>http://thinkberg.com</url>
-    <repositories>
-        <repository>
-            <id>codehaus-m2-repository</id>
-            <name>Codehaus Maven 2.x Repository</name>
-            <url>http://repository.codehaus.org</url>
-        </repository>
-        <repository>
-            <name>jets3t</name>
-            <id>jets3t</id>
-            <url>http://jets3t.s3.amazonaws.com/maven2</url>
-        </repository>
-    </repositories>
     <dependencies>
         <dependency>
             <groupId>junit</groupId>
@@ -27,21 +19,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>net.java.dev.jets3t</groupId>
-            <artifactId>jets3t</artifactId>
-            <version>0.6.1</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-httpclient</groupId>
-            <artifactId>commons-httpclient</artifactId>
-            <version>3.0.1</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-vfs</groupId>
-            <artifactId>commons-vfs</artifactId>
-            <version>1.0</version>
-        </dependency>
-        <dependency>
             <groupId>org.mortbay.jetty</groupId>
             <artifactId>jetty</artifactId>
             <version>6.1.1</version>
@@ -122,7 +99,7 @@
                 <configuration>
                     <archive>
                         <manifest>
-                            <mainClass>com.thinkberg.moxo.MoxoJettyRunner</mainClass>
+                            <mainClass>com.thinkberg.moxo.Main</mainClass>
                             <addClasspath>true</addClasspath>
                         </manifest>
                     </archive>
blob - /dev/null
blob + 4d645e1afa7c6fd288e8da760d89064436692577 (mode 644)
--- /dev/null
+++ modules/vfs.s3/pom.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2009 Matthias L. Jugel.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~        http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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>
+    <artifactId>vfs.s3</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>thinkberg.com S3 VFS provider</name>
+    <repositories>
+        <repository>
+            <id>codehaus-m2-repository</id>
+            <name>Codehaus Maven 2.x Repository</name>
+            <url>http://repository.codehaus.org</url>
+        </repository>
+        <repository>
+            <name>jets3t</name>
+            <id>jets3t</id>
+            <url>http://jets3t.s3.amazonaws.com/maven2</url>
+        </repository>
+    </repositories>
+    <dependencies>
+        <dependency>
+            <groupId>net.java.dev.jets3t</groupId>
+            <artifactId>jets3t</artifactId>
+            <version>0.6.1</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-vfs</groupId>
+            <artifactId>commons-vfs</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.1</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <includes>
+                        <include>**/tests/*.java</include>
+                    </includes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
blob - /dev/null
blob + ff8178919c5992604e3c2cd499dda4b4f2804614 (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/jets3t/Jets3tFileObject.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.vfs.s3.jets3t;
+
+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.provider.AbstractFileObject;
+import org.apache.commons.vfs.util.MonitorOutputStream;
+import org.jets3t.service.Constants;
+import org.jets3t.service.S3Service;
+import org.jets3t.service.S3ServiceException;
+import org.jets3t.service.model.S3Bucket;
+import org.jets3t.service.model.S3Object;
+import org.jets3t.service.utils.Mimetypes;
+
+import java.io.*;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.util.Date;
+
+
+/**
+ * Implementation of the virtual S3 file system object using the Jets3t library.
+ *
+ * @author Matthias L. Jugel
+ */
+public class Jets3tFileObject extends AbstractFileObject {
+  private static final Log LOG = LogFactory.getLog(Jets3tFileObject.class);
+
+  private static final String VFS_LAST_MODIFIED_TIME = "vfs-last-modified-time";
+
+  private final S3Service service;
+  private final S3Bucket bucket;
+
+  private boolean attached = false;
+  private boolean contentCached = false;
+
+  private S3Object object;
+  private File cacheFile;
+
+  public Jets3tFileObject(FileName fileName,
+                          Jets3tFileSystem fileSystem,
+                          S3Service service, S3Bucket bucket) {
+    super(fileName, fileSystem);
+    this.service = service;
+    this.bucket = bucket;
+  }
+
+  /**
+   * Attach S3 Object to VFS object.
+   * This method only downloads the meta-data without the actual content.
+   * If the object does not exist, it will be created locally.
+   *
+   * @throws Exception if the S3 access fails for some reason
+   */
+  protected void doAttach() throws Exception {
+    if (!attached) {
+      try {
+        object = service.getObjectDetails(bucket, getS3Key());
+        if (object.getMetadata(VFS_LAST_MODIFIED_TIME) == null) {
+          // it is possible the bucket has no last-modified data, use the S3 data then
+          object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + object.getLastModifiedDate().getTime());
+        }
+        contentCached = false;
+        LOG.debug(String.format("attaching (existing) '%s'", object.getKey()));
+      } catch (S3ServiceException e) {
+        object = new S3Object(bucket, getS3Key());
+        object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + new Date().getTime());
+        contentCached = true;
+        LOG.debug(String.format("attaching (new) '%s'", object.getKey()));
+      }
+
+      attached = true;
+    }
+  }
+
+  protected void doDetach() throws Exception {
+    if (attached) {
+      LOG.debug(String.format("detaching '%s' (cached=%b)", object.getKey(), (cacheFile != null)));
+      object = null;
+      if (cacheFile != null) {
+        cacheFile.delete();
+        cacheFile = null;
+        contentCached = false;
+      }
+      attached = false;
+    }
+  }
+
+  protected void doDelete() throws Exception {
+    // do not delete the root folder
+    if ("".equals(object.getKey())) {
+      LOG.warn(String.format("ignored attempt to delete root folder '%s' ", bucket.getName()));
+      return;
+    }
+    LOG.debug(String.format("deleting '%s'", object.getKey()));
+    service.deleteObject(bucket, object.getKey());
+    if (cacheFile != null) {
+      cacheFile.delete();
+      cacheFile = null;
+      contentCached = false;
+    }
+    attached = false;
+  }
+
+  protected void doRename(FileObject newfile) throws Exception {
+    super.doRename(newfile);
+  }
+
+  protected void doCreateFolder() throws Exception {
+    if (!Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(object.getContentType())) {
+      object.setContentType(Mimetypes.MIMETYPE_JETS3T_DIRECTORY);
+
+      LOG.debug(String.format("creating folder '%s'", object.getKey()));
+      service.putObject(bucket, object);
+    }
+  }
+
+  protected long doGetLastModifiedTime() throws Exception {
+    String timeStamp = (String) object.getMetadata(VFS_LAST_MODIFIED_TIME);
+    if (null != timeStamp) {
+      return Long.parseLong(timeStamp);
+    }
+    return 0;
+  }
+
+  protected void doSetLastModifiedTime(final long modtime) throws Exception {
+    object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, modtime);
+  }
+
+  protected InputStream doGetInputStream() throws Exception {
+    if (!contentCached) {
+      object = service.getObject(bucket, getS3Key());
+      LOG.debug(String.format("caching content of '%s'", object.getKey()));
+
+      InputStream objectInputStream = object.getDataInputStream();
+      if (object.getContentLength() > 0) {
+        ReadableByteChannel rbc = Channels.newChannel(objectInputStream);
+        FileChannel cacheFc = getCacheFile().getChannel();
+        cacheFc.transferFrom(rbc, 0, object.getContentLength());
+        cacheFc.close();
+        rbc.close();
+      } else {
+        objectInputStream.close();
+      }
+      contentCached = true;
+    }
+
+    return Channels.newInputStream(getCacheFile().getChannel());
+  }
+
+  protected OutputStream doGetOutputStream(boolean bAppend) throws Exception {
+    return new MonitorOutputStream(Channels.newOutputStream(getCacheFile().getChannel())) {
+      protected void onClose() throws IOException {
+        try {
+          LOG.debug(String.format("sending '%s' to storage (cached=%b)", object.getKey(), cacheFile));
+          if (cacheFile != null) {
+            FileChannel cacheFc = getCacheFile().getChannel();
+            object.setContentLength(cacheFc.size());
+            object.setDataInputStream(Channels.newInputStream(cacheFc));
+          }
+          service.putObject(bucket, object);
+        } catch (S3ServiceException e) {
+          LOG.error(String.format("can't send object '%s' to storage", object), e);
+        }
+      }
+    };
+  }
+
+  protected FileType doGetType() throws Exception {
+    if (null == object.getContentType()) {
+      return FileType.IMAGINARY;
+    }
+
+    String contentType = object.getContentType();
+    if ("".equals(object.getKey()) || Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(contentType)) {
+      return FileType.FOLDER;
+    }
+
+    return FileType.FILE;
+  }
+
+  protected String[] doListChildren() throws Exception {
+    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("[^/]*//*", "");
+      }
+    }
+
+    return childrenNames;
+  }
+
+  protected long doGetContentSize() throws Exception {
+    return object.getContentLength();
+  }
+
+  // Utility methods
+  /**
+   * Create an S3 key from a commons-vfs path. This simply
+   * strips the slash from the beginning if it exists.
+   *
+   * @return the S3 object key
+   */
+  private String getS3Key() {
+    String path = getName().getPath();
+    if ("".equals(path)) {
+      return path;
+    } else {
+      return path.substring(1);
+    }
+  }
+
+  private RandomAccessFile getCacheFile() throws IOException, S3ServiceException {
+    if (cacheFile == null) {
+      cacheFile = File.createTempFile("moxo.", ".s3f");
+      cacheFile.deleteOnExit();
+    }
+    return new RandomAccessFile(cacheFile, "rw");
+  }
+}
blob - /dev/null
blob + 3028150c6ba92a3e89fd9cfe4c3cca98ad17b8ec (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/jets3t/Jets3tFileSystem.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.vfs.s3.jets3t;
+
+import com.thinkberg.vfs.s3.S3FileName;
+import com.thinkberg.vfs.s3.S3FileProvider;
+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.FileSystemException;
+import org.apache.commons.vfs.FileSystemOptions;
+import org.apache.commons.vfs.provider.AbstractFileSystem;
+import org.jets3t.service.S3Service;
+import org.jets3t.service.S3ServiceException;
+import org.jets3t.service.model.S3Bucket;
+
+import java.util.Collection;
+
+/**
+ * An S3 file system.
+ *
+ * @author Matthias L. Jugel
+ */
+public class Jets3tFileSystem extends AbstractFileSystem {
+  private static final Log LOG = LogFactory.getLog(Jets3tFileSystem.class);
+
+  private S3Service service;
+  private S3Bucket bucket;
+
+
+  public Jets3tFileSystem(S3Service service, S3FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException {
+    super(fileName, null, fileSystemOptions);
+    this.service = service;
+
+    try {
+      String bucketId = fileName.getRootFile();
+      if (!service.isBucketAccessible(bucketId)) {
+        LOG.info(String.format("creating new S3 bucket '%s' for file system root", bucketId));
+        bucket = service.createBucket(bucketId);
+      } else {
+        LOG.info(String.format("using existing S3 bucket '%s' for file system root", bucketId));
+        bucket = new S3Bucket(bucketId);
+      }
+    } catch (S3ServiceException e) {
+      throw new FileSystemException(e);
+    }
+  }
+
+  public void destroyFileSystem() throws FileSystemException {
+    try {
+      service.deleteBucket(bucket);
+    } catch (S3ServiceException e) {
+      throw new FileSystemException("can't delete file system root", e);
+    }
+  }
+
+
+  @SuppressWarnings({"unchecked"})
+  protected void addCapabilities(Collection caps) {
+    caps.addAll(S3FileProvider.capabilities);
+  }
+
+  protected FileObject createFile(FileName fileName) throws Exception {
+    return new Jets3tFileObject(fileName, this, service, bucket);
+  }
+
+
+}
blob - /dev/null
blob + ee8611fc7310c54462bf8672a9ff9845cbab912a (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/logging/commons-logging.properties
@@ -0,0 +1,17 @@
+#
+# Copyright 2007 Matthias L. Jugel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
+org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
\ No newline at end of file
blob - /dev/null
blob + 874378181b065e1f421ce9f4f6a618611f87ebff (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/main/logging/simplelog.properties
@@ -0,0 +1,19 @@
+#
+# Copyright 2007 Matthias L. Jugel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.commons.logging.simplelog.defaultlog=error
+#org.apache.commons.logging.simplelog.log.org.jets3t.service=debug
+org.apache.commons.logging.simplelog.log.com.thinkberg.vfs.s3=debug
\ No newline at end of file
blob - /dev/null
blob + 4bbefdfa1eb5476726874d8421dbebb283cd0107 (mode 644)
--- /dev/null
+++ modules/vfs.s3/src/test/resources/s3.auth.properties.template
@@ -0,0 +1,19 @@
+#
+# Copyright 2009 Matthias L. Jugel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Template for testing AWS S3 VFS provider
+#
+s3.access.key=<AWS Access Key>
+s3.secret.key=<AWS Secret Key>
\ No newline at end of file
blob - /dev/null
blob + 5a4955869bb76ae6fb2001027f0da01cdb40a9bf (mode 644)
--- /dev/null
+++ modules/webdav/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2009 Matthias L. Jugel.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~        http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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>
+    <artifactId>webdav</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>thinkberg.com WebDAV</name>
+    <dependencies>
+        <dependency>
+            <groupId>commons-vfs</groupId>
+            <artifactId>commons-vfs</artifactId>
+            <version>1.0</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <includes>
+                        <include>**/tests/*.java</include>
+                    </includes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
blob - /dev/null
blob + 953b5f534b2c224ad5eb65cd370f36d6232bca2d (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/data/AbstractDavResource.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.data;
+
+import org.dom4j.Element;
+
+import java.util.HashSet;
+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_403 = "HTTP/1.1 403 Forbidden";
+
+  private static final String TAG_PROPSTAT = "propstat";
+  private static final String TAG_PROP = "prop";
+  private static final String TAG_STATUS = "status";
+
+  public Element serializeToXml(Element root, List<String> requestedProperties) {
+    Element propStatEl = root.addElement(TAG_PROPSTAT);
+    Element propEl = propStatEl.addElement(TAG_PROP);
+
+    Set<String> missingProperties = new HashSet<String>();
+    for (String propertyName : requestedProperties) {
+      if (!addPropertyValue(propEl, propertyName)) {
+        missingProperties.add(propertyName);
+      }
+    }
+    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);
+      }
+      propStatEl.addElement(TAG_STATUS).addText(STATUS_404);
+    }
+
+    return root;
+  }
+
+  @SuppressWarnings({"BooleanMethodIsAlwaysInverted"})
+  protected abstract boolean addPropertyValue(Element root, String propertyName);
+}
blob - /dev/null
blob + c6b7846fe350a342bb47de0c2709a27ae7c1b23e (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavCollection.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.data;
+
+import org.apache.commons.vfs.FileObject;
+import org.dom4j.Element;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class DavCollection extends DavResource {
+  public static final String COLLECTION = "collection";
+
+  public DavCollection(FileObject object) {
+    super(object);
+  }
+
+
+  public DavCollection(FileObject object, boolean ignoreValues) {
+    super(object, ignoreValues);
+  }
+
+  protected boolean addResourceTypeProperty(Element root) {
+    root.addElement(PROP_RESOURCETYPE).addElement(COLLECTION);
+    return true;
+  }
+
+  /**
+   * Ignore content language for collections.
+   *
+   * @param root the prop element to add to
+   * @return true, even though nothing is added
+   */
+  protected boolean addGetContentLanguageProperty(Element root) {
+    return true;
+  }
+
+  /**
+   * Ignore content length for collections.
+   *
+   * @param root the prop element to add to
+   * @return true, even though nothing is added
+   */
+  protected boolean addGetContentLengthProperty(Element root) {
+    return true;
+  }
+
+  /**
+   * Ignore content type for collections.
+   *
+   * @param root the prop element to add to
+   * @return true, even though nothing is added
+   */
+  protected boolean addGetContentTypeProperty(Element root) {
+    return true;
+  }
+
+  protected boolean addQuotaProperty(Element root) {
+    root.addElement(PROP_QUOTA).addText("" + Long.MAX_VALUE);
+    return true;
+  }
+
+  protected boolean addQuotaUsedProperty(Element root) {
+    // TODO add correct handling of used quota
+    root.addElement(PROP_QUOTA_USED).addText("0");
+    return true;
+  }
+
+  protected boolean addQuotaAvailableBytesProperty(Element root) {
+    root.addElement(PROP_QUOTA_AVAILABLE_BYTES).addText("" + Long.MAX_VALUE);
+    return true;
+  }
+
+  protected boolean addQuotaUsedBytesProperty(Element root) {
+    // TODO add correct handling of used quota
+    root.addElement(PROP_QUOTA_USED_BYTES).addText("0");
+    return true;
+  }
+}
blob - /dev/null
blob + 3d01502a97a50c6eb672345d40fd43c6eee5b1e7 (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavResource.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.data;
+
+import com.thinkberg.webdav.Util;
+import com.thinkberg.webdav.lock.Lock;
+import com.thinkberg.webdav.lock.LockManager;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemException;
+import org.dom4j.Element;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+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);
+  }
+
+
+  public DavResource(FileObject object, boolean ignoreValues) {
+    this.object = object;
+    this.ignoreValues = ignoreValues;
+
+  }
+
+  /**
+   * 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
+   * @return true for successful addition and false for missing data
+   */
+  protected boolean addPropertyValue(Element root, String propertyName) {
+    if (PROP_CREATION_DATE.equals(propertyName)) {
+      return addCreationDateProperty(root);
+    } else if (PROP_DISPLAY_NAME.equals(propertyName)) {
+      return addGetDisplayNameProperty(root);
+    } else if (PROP_GET_CONTENT_LANGUAGE.equals(propertyName)) {
+      return addGetContentLanguageProperty(root);
+    } else if (PROP_GET_CONTENT_LENGTH.equals(propertyName)) {
+      return addGetContentLengthProperty(root);
+    } else if (PROP_GET_CONTENT_TYPE.equals(propertyName)) {
+      return addGetContentTypeProperty(root);
+    } else if (PROP_GET_ETAG.equals(propertyName)) {
+      return addGetETagProperty(root);
+    } else if (PROP_GET_LAST_MODIFIED.equals(propertyName)) {
+      return addGetLastModifiedProperty(root);
+    } else if (PROP_LOCK_DISCOVERY.equals(propertyName)) {
+      return addLockDiscoveryProperty(root);
+    } else if (PROP_RESOURCETYPE.equals(propertyName)) {
+      return addResourceTypeProperty(root);
+    } else if (PROP_SOURCE.equals(propertyName)) {
+      return addSourceProperty(root);
+    } else if (PROP_SUPPORTED_LOCK.equals(propertyName)) {
+      return addSupportedLockProperty(root);
+    } else {
+      // handle non-standard properties (keep a little separate)
+      if (PROP_QUOTA.equals(propertyName)) {
+        return addQuotaProperty(root);
+      } else if (PROP_QUOTA_USED.equals(propertyName)) {
+        return addQuotaUsedProperty(root);
+      } else if (PROP_QUOTA_AVAILABLE_BYTES.equals(propertyName)) {
+        return addQuotaAvailableBytesProperty(root);
+      } else if (PROP_QUOTA_USED_BYTES.equals(propertyName)) {
+        return addQuotaUsedBytesProperty(root);
+      }
+    }
+
+    return false;
+  }
+
+  protected boolean addCreationDateProperty(Element root) {
+    return false;
+  }
+
+  protected boolean addGetDisplayNameProperty(Element root) {
+    Element el = root.addElement(PROP_DISPLAY_NAME);
+    if (!ignoreValues) {
+      el.addCDATA(object.getName().getBaseName());
+    }
+    return true;
+  }
+
+  protected boolean addGetContentLanguageProperty(Element root) {
+    return false;
+  }
+
+  protected boolean addGetContentLengthProperty(Element root) {
+    try {
+      Element el = root.addElement(PROP_GET_CONTENT_LENGTH);
+      if (!ignoreValues) {
+        el.addText("" + object.getContent().getSize());
+      }
+      return true;
+    } catch (FileSystemException e) {
+      e.printStackTrace();
+      return false;
+    }
+  }
+
+  protected boolean addGetContentTypeProperty(Element root) {
+    try {
+      String contentType = object.getContent().getContentInfo().getContentType();
+      if (null == contentType || "".equals(contentType)) {
+        return false;
+      }
+
+      Element el = root.addElement(PROP_GET_CONTENT_TYPE);
+      if (!ignoreValues) {
+        el.addText(contentType);
+      }
+      return true;
+    } catch (FileSystemException e) {
+      e.printStackTrace();
+      return false;
+    }
+  }
+
+  protected boolean addGetETagProperty(Element root) {
+    return false;
+  }
+
+  protected boolean addGetLastModifiedProperty(Element root) {
+    try {
+      Element el = root.addElement(PROP_GET_LAST_MODIFIED);
+      if (!ignoreValues) {
+        el.addText(Util.getDateString(object.getContent().getLastModifiedTime()));
+      }
+      return true;
+    } catch (FileSystemException e) {
+      e.printStackTrace();
+      return false;
+    }
+  }
+
+  protected boolean addLockDiscoveryProperty(Element root) {
+    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) {
+            lock.serializeToXml(lockdiscoveryEl);
+          }
+        }
+      }
+      return true;
+    } catch (FileSystemException e) {
+      e.printStackTrace();
+      root.remove(lockdiscoveryEl);
+      return false;
+    }
+  }
+
+  protected boolean addResourceTypeProperty(Element root) {
+    root.addElement(PROP_RESOURCETYPE);
+    return true;
+  }
+
+  protected boolean addSourceProperty(Element root) {
+    return false;
+  }
+
+  protected boolean addSupportedLockProperty(Element root) {
+    Element supportedlockEl = root.addElement(PROP_SUPPORTED_LOCK);
+    if (!ignoreValues) {
+      Element exclLockentryEl = supportedlockEl.addElement("lockentry");
+      exclLockentryEl.addElement("lockscope").addElement("exclusive");
+      exclLockentryEl.addElement("locktype").addElement("write");
+      Element sharedLockentryEl = supportedlockEl.addElement("lockentry");
+      sharedLockentryEl.addElement("lockscope").addElement("shared");
+      sharedLockentryEl.addElement("locktype").addElement("write");
+    }
+
+    return true;
+  }
+
+  protected boolean addQuotaProperty(Element root) {
+    return false;
+  }
+
+  protected boolean addQuotaUsedProperty(Element root) {
+    return false;
+  }
+
+  protected boolean addQuotaAvailableBytesProperty(Element root) {
+    return false;
+  }
+
+  protected boolean addQuotaUsedBytesProperty(Element root) {
+    return false;
+  }
+}
blob - /dev/null
blob + 21a6eb3fafa39e8b0e6290c24fb7ab4ad2df4972 (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavResourceFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.data;
+
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileType;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class DavResourceFactory {
+  private static DavResourceFactory instance;
+
+  public static DavResourceFactory getInstance() {
+    if (null == instance) {
+      instance = new DavResourceFactory();
+    }
+    return instance;
+  }
+
+  private DavResourceFactory() {
+
+  }
+
+  public DavResource getDavResource(FileObject object) throws FileSystemException {
+    if (FileType.FOLDER.equals(object.getType())) {
+      return new DavCollection(object);
+    } else {
+      return new DavResource(object);
+    }
+  }
+}
blob - /dev/null
blob + 21cc82179b26c678e0a701189ad0451c27474c7d (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/Lock.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.lock;
+
+import org.apache.commons.vfs.FileObject;
+import org.dom4j.Element;
+
+import java.net.URL;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class Lock {
+  public final static String SHARED = "shared";
+  public final static String EXCLUSIVE = "exclusive";
+
+  public final static String WRITE = "write";
+
+  private final FileObject object;
+  private final String type;
+  private final String scope;
+  private final Object owner;
+  private final int depth;
+  private final long timeout;
+  private final String token;
+
+
+  public Lock(FileObject object, String type, String scope, Object owner,
+              int depth, long timeout) {
+    this.object = object;
+    this.type = type;
+    this.scope = scope;
+    this.owner = owner;
+    this.depth = depth;
+    this.timeout = timeout;
+
+    this.token = "opaquelocktoken:" + Integer.toHexString(object.hashCode());
+  }
+
+  public FileObject getObject() {
+    return object;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public String getScope() {
+    return scope;
+  }
+
+  public Object getOwner() {
+    return owner;
+  }
+
+  public int getDepth() {
+    return depth;
+  }
+
+  public String getDepthValue() {
+    switch (depth) {
+      case 0:
+        return "0";
+      case 1:
+        return "1";
+      default:
+        return "Infinity";
+    }
+  }
+
+  public String getTimeout() {
+    if (timeout == -1) {
+      return "Infinity";
+    }
+    return "Second-" + timeout;
+  }
+
+  public String getToken() {
+    return this.token;
+  }
+
+  /**
+   * Create an XML serialized version of the lock by adding an activelock tag
+   * with the locks properties to the root element provided.
+   *
+   * @param root the root element to add the activelock to
+   * @return the root element
+   */
+  public Element serializeToXml(Element root) {
+    Element activelockEl = root.addElement("activelock");
+    activelockEl.addElement("locktype").addElement(getType());
+    activelockEl.addElement("lockscope").addElement(getScope());
+    activelockEl.addElement("depth").addText(getDepthValue());
+    // TODO handle owner correctly
+    if (getOwner() instanceof URL) {
+      activelockEl.addElement("owner").addElement("href")
+              .addText(((URL) getOwner()).toExternalForm());
+    } else {
+      activelockEl.addElement("owner").addText((String) getOwner());
+    }
+    activelockEl.addElement("timeout").addText(getTimeout());
+    activelockEl.addElement("locktoken")
+            .addElement("href").addText(getToken());
+
+    return root;
+  }
+
+  /**
+   * There can only be one lock per object, thus compare the file objects.
+   *
+   * @param other the other lock to compare to
+   * @return whether this lock is for the same file object
+   */
+  public boolean equals(Object other) {
+    return other instanceof Lock && object.equals(((Lock) other).object);
+  }
+
+
+  public String toString() {
+    return String.format("Lock[%s,%s,%s,%s]", object, type, scope, token);
+  }
+}
+
blob - /dev/null
blob + 351b4579632318ff0c4ef04636aec1f35d338b1c (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockConditionFailedException.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.lock;
+
+import java.util.List;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class LockConditionFailedException extends LockException {
+  private String condition = null;
+
+  public LockConditionFailedException(List<Lock> locks) {
+    super(locks);
+  }
+
+  public LockConditionFailedException(List<Lock> locks, String condition) {
+    super(locks);
+    this.condition = condition;
+
+  }
+
+  public String getCondition() {
+    return condition;
+  }
+}
blob - /dev/null
blob + cdad610efc8345cef8a5737d51b239897a2d0f7d (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockConditionRequiredException.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2009 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.lock;
+
+import java.util.List;
+
+public class LockConditionRequiredException extends LockException {
+  public LockConditionRequiredException(List<Lock> locks) {
+    super(locks);
+  }
+}
blob - /dev/null
blob + ed8c50a998c9956e34fb8de8bc053640169bd31b (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockConflictException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.lock;
+
+import java.util.List;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class LockConflictException extends LockException {
+  public LockConflictException(List<Lock> locks) {
+    super(locks);
+  }
+}
blob - /dev/null
blob + 85a2220f0526dd0c79b6e3ac49cb88ceb9bdb94d (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.lock;
+
+import java.util.List;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class LockException extends Exception {
+  private final List<Lock> locks;
+
+  public LockException(List<Lock> locks) {
+    super();
+    this.locks = locks;
+  }
+
+  public List<Lock> getLocks() {
+    return locks;
+  }
+
+  public String toString() {
+    return String.format("[%s: %s]", this.getClass(), locks);
+  }
+}
blob - /dev/null
blob + 6940fa3250eafb941b27dc63fdd39cceff20ea8d (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockManager.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.lock;
+
+import com.thinkberg.webdav.vfs.DepthFileSelector;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSelectInfo;
+import org.apache.commons.vfs.FileSystemException;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The lock manager is responsible for exclusive and shared write locks on the
+ * DAV server. It is used to acquire a lock, release a lock, discover existing
+ * locks or check conditions. The lock manager is a singleton.
+ *
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class LockManager {
+  private static LockManager instance = null;
+  private static final Log LOG = LogFactory.getLog(LockManager.class);
+
+  // condition parser patterns and tokens
+  private static final Pattern IF_PATTERN = Pattern.compile("(<[^>]+>)|(\\([^)]+\\))");
+  private static final Pattern CONDITION_PATTERN = Pattern.compile("([Nn][Oo][Tt])|(<[^>]+>)|(\\[[^]]+\\])");
+  private static final char TOKEN_LOWER_THAN = '<';
+  private static final char TOKEN_LEFT_BRACE = '(';
+  private static final char TOKEN_LEFT_BRACKET = '[';
+
+  /**
+   * Get an instance of the lock manager.
+   *
+   * @return the lock manager
+   */
+  public static LockManager getInstance() {
+    if (null == instance) {
+      instance = new LockManager();
+    }
+
+    return instance;
+  }
+
+  private final Map<FileObject, List<Lock>> lockMap;
+
+  /**
+   * The lock manager is a singleton and cannot be instantiated directly.
+   */
+  private LockManager() {
+    lockMap = new HashMap<FileObject, List<Lock>>();
+  }
+
+  /**
+   * Acquire a lock. This will first check for conflicts and throws exceptions if
+   * there are existing locks or for some reason the lock could not be acquired.
+   *
+   * @param lock the lock to acquire
+   * @throws LockConflictException if an existing lock has priority
+   * @throws FileSystemException   if the file object and its path cannot be accessed
+   */
+  public void acquireLock(Lock lock) throws LockConflictException, FileSystemException {
+    checkConflicts(lock);
+    addLock(lock);
+  }
+
+  /**
+   * Release a lock on a file object with a given lock token. Releeases the lock if
+   * if one exists and if the lock token is valid for the found lock.
+   *
+   * @param object the file object we want to unlock
+   * @param token  the lock token associated with the file object
+   * @return true if the lock has been released, false if not
+   */
+  public boolean releaseLock(FileObject object, String token) {
+    List<Lock> locks = lockMap.get(object);
+    if (null != locks) {
+      for (Lock lock : locks) {
+        if (lock.getToken().equals(token)) {
+          locks.remove(lock);
+          return true;
+        }
+      }
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Discover locks for a given file object. This will find locks for the object
+   * itself and parent path locks with a depth that reaches the file object.
+   *
+   * @param object the file object to find locks for
+   * @return the locks that are found for this file object
+   * @throws FileSystemException if the file object or its parents cannot be accessed
+   */
+  public List<Lock> discoverLock(FileObject object) throws FileSystemException {
+    FileObject parent = object;
+    while (parent != null) {
+      List<Lock> parentLocks = lockMap.get(parent);
+      if (parentLocks != null && !parentLocks.isEmpty()) {
+        return parentLocks;
+      }
+      parent = parent.getParent();
+    }
+
+    return null;
+  }
+
+  /**
+   * Evaluate an 'If:' header condition.
+   * The condition may be a tagged list or an untagged list. Tagged lists define the resource, the condition
+   * applies to in front of the condition (ex. 1, 2, 5, 6). Conditions may be inverted by using 'Not' at the
+   * beginning of the condition (ex. 3, 4, 6). The list constitutes an OR expression while the list of
+   * conditions within braces () constitutes an AND expression.
+   * <p/>
+   * Evaluate example 2:<br/>
+   * <code>
+   * URI(/resource1) { (
+   * is-locked-with(urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2)
+   * AND matches-etag(W/"A weak ETag") )
+   * OR ( matches-etag("strong ETag") ) }
+   * </code>
+   * <p/>
+   * Examples:
+   * <ol>
+   * <li> &lt;http://cid:8080/litmus/unmapped_url&gt; (&lt;opaquelocktoken:cd6798&gt;)</li>
+   * <li> &lt;/resource1&gt; (&lt;urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2&gt; [W/"A weak ETag"]) (["strong ETag"])</li>
+   * <li> (&lt;urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2&gt;) (Not &lt;DAV:no-lock&gt;)</li>
+   * <li> (Not &lt;urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2&gt; &lt;urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092&gt;)</li>
+   * <li> &lt;/specs/rfc2518.doc&gt; (["4217"])</li>
+   * <li> &lt;/specs/rfc2518.doc&gt; (Not ["4217"])</li>
+   * </ol>
+   *
+   * @param contextObject the contextual resource (needed when the If: condition is not tagged)
+   * @param ifCondition   the string of the condition as sent by the If: header
+   * @return evaluation of the condition expression
+   * @throws ParseException        if the condition does not meet the syntax requirements
+   * @throws LockConflictException
+   * @throws FileSystemException
+   */
+  public EvaluationResult evaluateCondition(FileObject contextObject, String ifCondition)
+          throws FileSystemException, LockConflictException, ParseException {
+    List<Lock> locks = discoverLock(contextObject);
+    EvaluationResult evaluation = new EvaluationResult();
+
+    if (ifCondition == null || "".equals(ifCondition)) {
+      if (locks != null) {
+        throw new LockConflictException(locks);
+      }
+      evaluation.result = true;
+      return evaluation;
+    }
+
+    Matcher matcher = IF_PATTERN.matcher(ifCondition);
+    FileObject resource = contextObject;
+    while (matcher.find()) {
+      String token = matcher.group();
+      switch (token.charAt(0)) {
+        case TOKEN_LOWER_THAN:
+          String resourceUri = token.substring(1, token.length() - 1);
+          try {
+            resource = contextObject.getFileSystem().resolveFile(new URI(resourceUri).getPath());
+            locks = discoverLock(resource);
+          } catch (URISyntaxException e) {
+            throw new ParseException(ifCondition, matcher.start());
+          }
+          break;
+        case TOKEN_LEFT_BRACE:
+          LOG.debug(String.format("URI(%s) {", resource));
+          Matcher condMatcher = CONDITION_PATTERN.matcher(token.substring(1, token.length() - 1));
+          boolean expressionResult = true;
+          while (condMatcher.find()) {
+            String condToken = condMatcher.group();
+            boolean negate = false;
+            if (condToken.matches("[Nn][Oo][Tt]")) {
+              negate = true;
+              condMatcher.find();
+              condToken = condMatcher.group();
+            }
+            switch (condToken.charAt(0)) {
+              case TOKEN_LOWER_THAN:
+                String lockToken = condToken.substring(1, condToken.length() - 1);
+
+                boolean foundLock = false;
+                if (locks != null) {
+                  for (Lock lock : locks) {
+                    if (lockToken.equals(lock.getToken())) {
+                      evaluation.locks.add(lock);
+                      foundLock = true;
+                      break;
+                    }
+                  }
+                }
+                final boolean foundLockResult = negate ? !foundLock : foundLock;
+                LOG.debug(String.format("  %sis-locked-with(%s) = %b",
+                                        negate ? "NOT " : "", lockToken, foundLockResult));
+                expressionResult = expressionResult && foundLockResult;
+                break;
+              case TOKEN_LEFT_BRACKET:
+                String eTag = condToken.substring(1, condToken.length() - 1);
+                String resourceETag = String.format("%x", resource.hashCode());
+                boolean resourceTagMatches = resourceETag.equals(eTag);
+                final boolean matchesEtagResult = negate ? !resourceTagMatches : resourceTagMatches;
+                LOG.debug(String.format("  %smatches-etag(%s) = %b",
+                                        negate ? "NOT " : "", eTag, matchesEtagResult));
+                expressionResult = expressionResult && matchesEtagResult;
+                break;
+              default:
+                throw new ParseException(String.format("syntax error in condition '%s' at %d",
+                                                       ifCondition, matcher.start() + condMatcher.start()),
+                                         matcher.start() + condMatcher.start());
+            }
+          }
+
+          evaluation.result = evaluation.result || expressionResult;
+          LOG.debug("} => " + evaluation.result);
+          break;
+        default:
+          throw new ParseException(String.format("syntax error in condition '%s' at %d", ifCondition, matcher.start()),
+                                   matcher.start());
+      }
+    }
+
+    // regardless of the evaluation, if the object is locked but there is no valed lock token in the
+    // conditions we must fail with a lock conflict too
+    if (evaluation.result && (locks != null && !locks.isEmpty()) && evaluation.locks.isEmpty()) {
+      throw new LockConflictException(locks);
+    }
+    return evaluation;
+  }
+
+  public class EvaluationResult {
+    public List<Lock> locks = new ArrayList<Lock>();
+    public boolean result = false;
+
+    public String toString() {
+      return String.format("EvaluationResult[%b,%s]", result, locks);
+    }
+  }
+
+  /**
+   * Add a lock to the list of shared locks of a given object.
+   *
+   * @param lock the lock to add
+   */
+  private void addLock(Lock lock) {
+    FileObject object = lock.getObject();
+    List<Lock> locks = lockMap.get(object);
+    if (null == locks) {
+      locks = new ArrayList<Lock>();
+      lockMap.put(object, locks);
+    }
+    locks.add(lock);
+  }
+
+  /**
+   * Check whether a lock conflicts with already existing locks up and down the path.
+   * First we go up the path to check for parent locks that may include the file object
+   * and the go down the directory tree (if depth requires it) to check locks that
+   * will conflict.
+   *
+   * @param requestedLock the lock requested
+   * @throws LockConflictException if a conflicting lock was found
+   * @throws FileSystemException   if the file object or path cannot be accessed
+   */
+  private void checkConflicts(final Lock requestedLock) throws LockConflictException, FileSystemException {
+    // find locks in the parent path
+    FileObject parent = requestedLock.getObject();
+    while (parent != null) {
+      List<Lock> parentLocks = lockMap.get(parent);
+      if (parentLocks != null && !parentLocks.isEmpty()) {
+        for (Lock parentLock : parentLocks) {
+          if (Lock.EXCLUSIVE.equals(requestedLock.getScope()) || Lock.EXCLUSIVE.equals(parentLock.getScope())) {
+            throw new LockConflictException(parentLocks);
+          }
+        }
+      }
+      parent = parent.getParent();
+    }
+
+    // look for locks down the path (if depth requests it)
+    if (requestedLock.getDepth() != 0 && requestedLock.getObject().getChildren().length > 0) {
+      requestedLock.getObject().findFiles(new DepthFileSelector(1, requestedLock.getDepth()) {
+        public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception {
+          List<Lock> childLocks = lockMap.get(fileSelectInfo.getFile());
+          for (Lock childLock : childLocks) {
+            if (Lock.EXCLUSIVE.equals(requestedLock.getScope()) || Lock.EXCLUSIVE.equals(childLock.getScope())) {
+              throw new LockConflictException(childLocks);
+            }
+          }
+          return false;
+        }
+      }, false, new ArrayList());
+    }
+  }
+
+}
blob - /dev/null
blob + 0bd27718adde8f76ebb9bf18691ac0317fb46631 (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/servlet/MoxoWebDAVServlet.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2007 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.servlet;
+
+import com.thinkberg.webdav.*;
+import com.thinkberg.webdav.vfs.VFSBackend;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.FileSystemException;
+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;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class MoxoWebDAVServlet extends HttpServlet {
+  private static final Log LOG = LogFactory.getLog(MoxoWebDAVServlet.class);
+
+  private final Map<String, WebdavHandler> handlers = new HashMap<String, WebdavHandler>();
+
+  public MoxoWebDAVServlet() {
+    handlers.put("COPY", new CopyHandler());
+    handlers.put("DELETE", new DeleteHandler());
+    handlers.put("GET", new GetHandler());
+    handlers.put("HEAD", new HeadHandler());
+    handlers.put("LOCK", new LockHandler());
+    handlers.put("MKCOL", new MkColHandler());
+    handlers.put("MOVE", new MoveHandler());
+    handlers.put("OPTIONS", new OptionsHandler());
+    handlers.put("POST", new PostHandler());
+    handlers.put("PROPFIND", new PropFindHandler());
+    handlers.put("PROPPATCH", new PropPatchHandler());
+    handlers.put("PUT", new PutHandler());
+    handlers.put("UNLOCK", new UnlockHandler());
+
+  }
+
+  public void init(ServletConfig servletConfig) throws ServletException {
+    super.init(servletConfig);
+    String rootUri = servletConfig.getInitParameter("vfs.uri");
+    String authDomain = servletConfig.getInitParameter("vfs.auth.domain");
+    String authUser = servletConfig.getInitParameter("vfs.auth.user");
+    String authPass = servletConfig.getInitParameter("vfs.auth.password");
+    try {
+      StaticUserAuthenticator userAuthenticator =
+              new StaticUserAuthenticator(authDomain, authUser, authPass);
+      FileSystemOptions options = new FileSystemOptions();
+      DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(options, userAuthenticator);
+
+      VFSBackend.initialize(rootUri, options);
+    } catch (FileSystemException e) {
+      LOG.error(String.format("can't create file system backend for '%s'", rootUri));
+    }
+  }
+
+  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+//    String auth = request.getHeader("Authorization");
+//    String login = "", password = "";
+//
+//    if (auth != null) {
+//      auth = new String(Base64.decodeBase64(auth.substring(auth.indexOf(' ') + 1).getBytes()));
+//      login = auth.substring(0, auth.indexOf(':'));
+//      password = auth.substring(auth.indexOf(':') + 1);
+//    }
+//
+//    AWSCredentials credentials = AWSCredentials.load(password,  ))
+//    if (user == null) {
+//      response.setHeader("WWW-Authenticate", "Basic realm=\"Moxo\"");
+//      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+//      return;
+//    }
+
+
+    // show we are doing the litmus test
+    String litmusTest = request.getHeader("X-Litmus");
+    if (null == litmusTest) {
+      litmusTest = request.getHeader("X-Litmus-Second");
+    }
+    if (litmusTest != null) {
+      LOG.info(String.format("WebDAV Litmus Test: %s", litmusTest));
+    }
+
+    String method = request.getMethod();
+    LOG.debug(String.format(">> %s %s", request.getMethod(), request.getPathInfo()));
+    if (handlers.containsKey(method)) {
+      handlers.get(method).service(request, response);
+    } 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 : ""));
+  }
+}
blob - /dev/null
blob + 79745966960b3bcf835f5e6f13cbf1aa0f68c869 (mode 644)
--- /dev/null
+++ modules/webdav/src/main/java/com/thinkberg/webdav/vfs/VFSBackend.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 Matthias L. Jugel.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.thinkberg.webdav.vfs;
+
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileSystemOptions;
+import org.apache.commons.vfs.VFS;
+
+/**
+ * @author Matthias L. Jugel
+ * @version $Id$
+ */
+public class VFSBackend {
+  private static VFSBackend instance;
+
+  private final FileObject fileSystemRoot;
+
+  public static void initialize(String rootUri, FileSystemOptions options) throws FileSystemException {
+    if (null == instance) {
+      instance = new VFSBackend(rootUri, options);
+    }
+  }
+
+  private VFSBackend(String rootUri, FileSystemOptions options) throws FileSystemException {
+    fileSystemRoot = VFS.getManager().resolveFile(rootUri, options);
+  }
+
+  public static FileObject resolveFile(String path) throws FileSystemException {
+    if (null == instance) {
+      throw new IllegalStateException("VFS backend not initialized");
+    }
+    return instance.fileSystemRoot.resolveFile(path);
+  }
+}
blob - /dev/null
blob + ee8611fc7310c54462bf8672a9ff9845cbab912a (mode 644)
--- /dev/null
+++ modules/webdav/src/main/logging/commons-logging.properties
@@ -0,0 +1,17 @@
+#
+# Copyright 2007 Matthias L. Jugel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
+org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
\ No newline at end of file
blob - /dev/null
blob + 17a37d029897fd962f98dd3e7b370914ea0e3a69 (mode 644)
--- /dev/null
+++ modules/webdav/src/main/logging/simplelog.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2007 Matthias L. Jugel.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.commons.logging.simplelog.defaultlog=error
+org.apache.commons.logging.simplelog.log.com.thinkberg.webdav=debug
\ No newline at end of file
blob - /dev/null
blob + 69501658828ef0ef55a5ee90f4c3512ecc313e1b (mode 755)
--- /dev/null
+++ modules/webdav/src/test/java/com/thinkberg/webdav/tests/DavResourceTest.java
@@ -0,0 +1,55 @@
+package com.thinkberg.webdav.tests;
+
+import com.thinkberg.webdav.DavTestCase;
+import com.thinkberg.webdav.data.DavCollection;
+import com.thinkberg.webdav.data.DavResource;
+import org.apache.commons.vfs.FileSystemException;
+import org.dom4j.Element;
+
+import java.io.IOException;
+
+/**
+ * Test case for the DAV resource wrapper. Checks that resources are serialized
+ * correctly.
+ *
+ * @author Matthias L. Jugel
+ */
+public class DavResourceTest extends DavTestCase {
+  public void testFileCreationDateIsNull() throws FileSystemException {
+    Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE);
+    assertNull(selectExistingProperty(root, DavResource.PROP_CREATION_DATE));
+  }
+
+  public void testFileCreationDateIsMissing() throws IOException {
+    Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE);
+    assertEquals(DavResource.PROP_CREATION_DATE,
+                 selectMissingPropertyName(root, DavResource.PROP_CREATION_DATE));
+  }
+
+  public void testFileDisplayNameWithValue() throws FileSystemException {
+    testPropertyValue(aFile, DavResource.PROP_DISPLAY_NAME, aFile.getName().getBaseName());
+  }
+
+  public void testFileDisplayNameWithoutValue() throws FileSystemException {
+    testPropertyNoValue(aFile, DavResource.PROP_DISPLAY_NAME);
+  }
+
+  public void testFileResourceTypeNotMissing() throws FileSystemException {
+    Element root = serializeDavResource(aFile, DavResource.PROP_RESOURCETYPE);
+    assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE));
+  }
+
+  public void testDirectoryResourceTypeNotMissing() throws FileSystemException {
+    Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE);
+    assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE));
+  }
+
+  public void testFileResourceType() throws FileSystemException {
+    testPropertyNoValue(aFile, DavResource.PROP_RESOURCETYPE);
+  }
+
+  public void testDirectoryResourceType() throws FileSystemException {
+    Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE);
+    assertNotNull(selectExistingProperty(root, DavResource.PROP_RESOURCETYPE).selectSingleNode(DavCollection.COLLECTION));
+  }
+}
blob - fad5566e89f5e3a1e30cdf358aff899558c340ff
blob + 81fa814c760d3f3302548ef451f1fcad06157e6d
--- src/main/java/com/thinkberg/moxo/MoxoJettyRunner.java
+++ src/main/java/com/thinkberg/moxo/MoxoJettyRunner.java
@@ -29,7 +29,7 @@ import java.net.URL;
  * @author Matthias L. Jugel
  */
 public class MoxoJettyRunner {
-  private static final String CONF_JETTY_XML = "jetty.xml";
+  private static final String CONF_JETTY_XML = "/jetty.xml";
 
   public static void main(String[] args) {
     System.out.println("Moxo S3 DAV Proxy (c) 2007 Matthias L. Jugel");
@@ -51,10 +51,11 @@ public class MoxoJettyRunner {
   }
 
   private static URL getXmlConfigurationUrl() {
-    URL url = MoxoJettyRunner.class.getResource("/" + MoxoJettyRunner.CONF_JETTY_XML);
+    String configFile = System.getProperty("jetty.xml", CONF_JETTY_XML);
+    URL url = MoxoJettyRunner.class.getResource(configFile);
     if (null == url) {
       try {
-        url = new File(MoxoJettyRunner.CONF_JETTY_XML).toURL();
+        url = new File(configFile).toURL();
         System.err.println("Loading configuration from file: " + url.toExternalForm());
       } catch (MalformedURLException e) {
         // ignore ...
blob - 34da23d2a591b3326dc3d78d18ae9a335ad6b4ca (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/CopyHandler.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.vfs.DepthFileSelector;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class CopyHandler extends CopyMoveBase {
-  protected void copyOrMove(FileObject object, FileObject target, int depth) throws FileSystemException {
-    target.copyFrom(object, new DepthFileSelector(depth));
-  }
-}
blob - 3e03b367c7a948895653aafa48ac0d07ee118c5f (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/CopyMoveBase.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.lock.LockException;
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileType;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.text.ParseException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public abstract class CopyMoveBase extends WebdavHandler {
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    boolean overwrite = getOverwrite(request);
-    FileObject object = getVFSObject(request.getPathInfo());
-    FileObject targetObject = getDestination(request);
-
-
-    try {
-      final LockManager lockManager = LockManager.getInstance();
-      LockManager.EvaluationResult evaluation = lockManager.evaluateCondition(targetObject, getIf(request));
-      if (!evaluation.result) {
-        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-        return;
-      }
-      if ("MOVE".equals(request.getMethod())) {
-        evaluation = lockManager.evaluateCondition(object, getIf(request));
-        if (!evaluation.result) {
-          response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-          return;
-        }
-      }
-    } catch (LockException e) {
-      response.sendError(SC_LOCKED);
-      return;
-    } catch (ParseException e) {
-      response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-      return;
-    }
-
-
-    if (null == targetObject) {
-      response.sendError(HttpServletResponse.SC_BAD_REQUEST);
-      return;
-    }
-
-    if (object.equals(targetObject)) {
-      response.sendError(HttpServletResponse.SC_FORBIDDEN);
-      return;
-    }
-
-    if (targetObject.exists()) {
-      if (!overwrite) {
-        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-        return;
-      }
-      response.setStatus(HttpServletResponse.SC_NO_CONTENT);
-    } else {
-      FileObject targetParent = targetObject.getParent();
-      if (!targetParent.exists() ||
-              !FileType.FOLDER.equals(targetParent.getType())) {
-        response.sendError(HttpServletResponse.SC_CONFLICT);
-      }
-      response.setStatus(HttpServletResponse.SC_CREATED);
-    }
-
-    copyOrMove(object, targetObject, getDepth(request));
-  }
-
-  protected abstract void copyOrMove(FileObject object, FileObject target, int depth) throws FileSystemException;
-
-}
blob - 1cd9fda42df8a35bd14e6be5cd93938a0344a9ce (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/DeleteHandler.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.lock.LockException;
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-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.text.ParseException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class DeleteHandler extends WebdavHandler {
-  private static final Log LOG = LogFactory.getLog(DeleteHandler.class);
-
-  private final static FileSelector ALL_FILES_SELECTOR = new FileSelector() {
-    public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception {
-      return true;
-    }
-
-    public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws Exception {
-      return true;
-    }
-  };
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    FileObject object = getVFSObject(request.getPathInfo());
-    if (request instanceof Request) {
-      String fragment = ((Request) request).getUri().getFragment();
-      if (fragment != null) {
-        response.sendError(HttpServletResponse.SC_FORBIDDEN);
-        return;
-      }
-    }
-
-    try {
-      if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) {
-        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-        return;
-      }
-    } catch (LockException e) {
-      response.sendError(WebdavHandler.SC_LOCKED);
-      return;
-    } catch (ParseException e) {
-      response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-      return;
-    }
-
-    if (object.exists()) {
-      int deletedObjects = object.delete(ALL_FILES_SELECTOR);
-      LOG.debug("deleted " + deletedObjects + " objects");
-      if (deletedObjects > 0) {
-        response.setStatus(HttpServletResponse.SC_OK);
-      } else {
-        response.sendError(HttpServletResponse.SC_FORBIDDEN);
-      }
-    } else {
-      response.sendError(HttpServletResponse.SC_NOT_FOUND);
-    }
-  }
-}
blob - 2a0d7c02a9d33230c3492d40a0a444e5c8d0efb1 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/GetHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import org.apache.commons.vfs.FileContent;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileType;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class GetHandler extends WebdavHandler {
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    FileObject object = getVFSObject(request.getPathInfo());
-
-    if (object.exists()) {
-      if (FileType.FOLDER.equals(object.getType())) {
-        response.sendError(HttpServletResponse.SC_FORBIDDEN);
-        return;
-      }
-
-      setHeader(response, object.getContent());
-
-      InputStream is = object.getContent().getInputStream();
-      OutputStream os = response.getOutputStream();
-      Util.copyStream(is, os);
-      is.close();
-    } else {
-      response.sendError(HttpServletResponse.SC_NOT_FOUND);
-    }
-  }
-
-  void setHeader(HttpServletResponse response, FileContent content) throws FileSystemException {
-    response.setHeader("Last-Modified", Util.getDateString(content.getLastModifiedTime()));
-    response.setHeader("Content-Type", content.getContentInfo().getContentType());
-    response.setHeader("ETag", String.format("%x", content.getFile().hashCode()));
-  }
-
-
-}
blob - 214793924ede616c96a919382f76715c89613a58 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/HeadHandler.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileType;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class HeadHandler extends GetHandler {
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    FileObject object = getVFSObject(request.getPathInfo());
-
-    if (object.exists()) {
-      if (FileType.FOLDER.equals(object.getType())) {
-        response.sendError(HttpServletResponse.SC_FORBIDDEN);
-      } else {
-        setHeader(response, object.getContent());
-      }
-    } else {
-      response.sendError(HttpServletResponse.SC_NOT_FOUND);
-    }
-  }
-}
blob - 2cf6621edb3bdded57a86109a03ee75a17d97cfc (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/LockHandler.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.lock.Lock;
-import com.thinkberg.moxo.dav.lock.LockConflictException;
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.FileObject;
-import org.dom4j.*;
-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.text.ParseException;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Handle WebDAV LOCK requests.
- *
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class LockHandler extends WebdavHandler {
-  private static final Log LOG = LogFactory.getLog(LockHandler.class);
-
-  private static final String TAG_LOCKSCOPE = "lockscope";
-  private static final String TAG_LOCKTYPE = "locktype";
-  private static final String TAG_OWNER = "owner";
-  private static final String TAG_HREF = "href";
-  private static final String TAG_PROP = "prop";
-  private static final String TAG_LOCKDISCOVERY = "lockdiscovery";
-
-  private static final String HEADER_LOCK_TOKEN = "Lock-Token";
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    FileObject object = getVFSObject(request.getPathInfo());
-
-    try {
-      final LockManager manager = LockManager.getInstance();
-      final LockManager.EvaluationResult evaluation = manager.evaluateCondition(object, getIf(request));
-      if (!evaluation.result) {
-        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-        return;
-      } else {
-        if (!evaluation.locks.isEmpty()) {
-          LOG.debug(String.format("discovered locks: %s", evaluation.locks));
-          sendLockAcquiredResponse(response, evaluation.locks.get(0));
-          return;
-        }
-      }
-    } catch (LockConflictException e) {
-      List<Lock> locks = e.getLocks();
-      for (Lock lock : locks) {
-        if (Lock.EXCLUSIVE.equals(lock.getType())) {
-          response.sendError(WebdavHandler.SC_LOCKED);
-          return;
-        }
-      }
-    } catch (ParseException e) {
-      response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-      return;
-    }
-
-    try {
-      SAXReader saxReader = new SAXReader();
-      Document lockInfo = saxReader.read(request.getInputStream());
-      //log(lockInfo);
-
-      Element rootEl = lockInfo.getRootElement();
-      String lockScope = null, lockType = null;
-      Object owner = null;
-      Iterator elIt = rootEl.elementIterator();
-      while (elIt.hasNext()) {
-        Element el = (Element) elIt.next();
-        if (TAG_LOCKSCOPE.equals(el.getName())) {
-          lockScope = el.selectSingleNode("*").getName();
-        } else if (TAG_LOCKTYPE.equals(el.getName())) {
-          lockType = el.selectSingleNode("*").getName();
-        } else if (TAG_OWNER.equals(el.getName())) {
-          // TODO correctly handle owner
-          Node subEl = el.selectSingleNode("*");
-          if (subEl != null && TAG_HREF.equals(subEl.getName())) {
-            owner = new URL(el.selectSingleNode("*").getText());
-          } else {
-            owner = el.getText();
-          }
-        }
-      }
-
-      LOG.debug("LOCK(" + lockType + ", " + lockScope + ", " + owner + ")");
-
-      Lock requestedLock = new Lock(object, lockType, lockScope, owner, getDepth(request), getTimeout(request));
-      try {
-        LockManager.getInstance().acquireLock(requestedLock);
-        sendLockAcquiredResponse(response, requestedLock);
-      } catch (LockConflictException e) {
-        response.sendError(SC_LOCKED);
-      } catch (IllegalArgumentException e) {
-        response.sendError(HttpServletResponse.SC_BAD_REQUEST);
-      }
-    } catch (DocumentException e) {
-      e.printStackTrace();
-      response.sendError(HttpServletResponse.SC_BAD_REQUEST);
-    }
-  }
-
-  private void sendLockAcquiredResponse(HttpServletResponse response, Lock lock) throws IOException {
-    if (!lock.getObject().exists()) {
-      response.setStatus(SC_CREATED);
-    }
-    response.setContentType("text/xml");
-    response.setCharacterEncoding("UTF-8");
-    response.setHeader(HEADER_LOCK_TOKEN, "<" + lock.getToken() + ">");
-
-    Document propDoc = DocumentHelper.createDocument();
-    Element propEl = propDoc.addElement(TAG_PROP, "DAV:");
-    Element lockdiscoveryEl = propEl.addElement(TAG_LOCKDISCOVERY);
-
-    lock.serializeToXml(lockdiscoveryEl);
-
-    XMLWriter xmlWriter = new XMLWriter(response.getWriter());
-    xmlWriter.write(propDoc);
-
-    logXml(propDoc);
-  }
-
-  private 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.debug("ERROR writing XML log: " + e.getMessage());
-    }
-  }
-}
blob - 3edc720043d1911ec3a98cd4b63e24554884e6a9 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/MkColHandler.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.lock.LockException;
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileType;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.text.ParseException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class MkColHandler extends WebdavHandler {
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    BufferedReader bufferedReader = request.getReader();
-    String line = bufferedReader.readLine();
-    if (line != null) {
-      response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
-      return;
-    }
-
-    FileObject object = getVFSObject(request.getPathInfo());
-
-    try {
-      if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) {
-        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-        return;
-      }
-    } catch (LockException e) {
-      response.sendError(WebdavHandler.SC_LOCKED);
-      return;
-    } catch (ParseException e) {
-      response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-      return;
-    }
-
-    if (object.exists()) {
-      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
-      return;
-    }
-
-    if (!object.getParent().exists() || !FileType.FOLDER.equals(object.getParent().getType())) {
-      response.sendError(HttpServletResponse.SC_CONFLICT);
-      return;
-    }
-
-    try {
-      object.createFolder();
-      response.setStatus(HttpServletResponse.SC_CREATED);
-    } catch (FileSystemException e) {
-      response.sendError(HttpServletResponse.SC_FORBIDDEN);
-    }
-  }
-}
blob - 5cb1a045ff6f0fc46e8991898548660850d8a10a (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/MoveHandler.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.vfs.DepthFileSelector;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-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());
-  }
-}
blob - 105b947a18e598dc34be32c8564a80e80f7fa409 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/OptionsHandler.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileType;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class OptionsHandler extends WebdavHandler {
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    response.setHeader("DAV", "1, 2");
-
-    String path = request.getPathInfo();
-    StringBuffer options = new StringBuffer();
-    FileObject object = getVFSObject(path);
-    if (object.exists()) {
-      options.append("OPTIONS, GET, HEAD, POST, DELETE, TRACE, COPY, MOVE, LOCK, UNLOCK, PROPFIND");
-      if (FileType.FOLDER.equals(object.getType())) {
-        options.append(", PUT");
-      }
-    } else {
-      options.append("OPTIONS, MKCOL, PUT, LOCK");
-    }
-    response.setHeader("Allow", options.toString());
-
-    // see: http://www-128.ibm.com/developerworks/rational/library/2089.html
-    response.setHeader("MS-Author-Via", "DAV");
-  }
-}
blob - e0038189d0aaef0103b1f32ab0a53ea3a228e09e (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/PostHandler.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class PostHandler extends WebdavHandler {
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
-  }
-}
blob - 9f8b33f2d2f8c952a1dba98b56c888dad88670b3 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/PropFindHandler.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.data.DavResource;
-import com.thinkberg.moxo.dav.data.DavResourceFactory;
-import com.thinkberg.moxo.vfs.DepthFileSelector;
-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.*;
-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.List;
-
-/**
- * @author Matthias L. Jugel
- * @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 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 {
-      Document propDoc = saxReader.read(request.getInputStream());
-      logXml(propDoc);
-
-      Element propFindEl = propDoc.getRootElement();
-      Element propEl = (Element) propFindEl.elementIterator().next();
-      String propElName = propEl.getName();
-
-      List<String> requestedProperties = new ArrayList<String>();
-      boolean ignoreValues = false;
-      if (TAG_PROP.equals(propElName)) {
-        for (Object id : propEl.elements()) {
-          requestedProperties.add(((Element) id).getName());
-        }
-      } else if (TAG_ALLPROP.equals(propElName)) {
-        requestedProperties = DavResource.ALL_PROPERTIES;
-      } else if (TAG_PROPNAMES.equals(propElName)) {
-        requestedProperties = DavResource.ALL_PROPERTIES;
-        ignoreValues = true;
-      }
-
-      FileObject object = getVFSObject(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 {
-    Document propDoc = DocumentHelper.createDocument();
-    propDoc.setXMLEncoding("UTF-8");
-
-    Element multiStatus = propDoc.addElement(TAG_MULTISTATUS, "DAV:");
-    FileObject[] children = object.findFiles(new DepthFileSelector(depth));
-    for (FileObject child : children) {
-      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();
-      }
-      DavResource resource = DavResourceFactory.getInstance().getDavResource(child);
-      resource.setIgnoreValues(ignoreValues);
-      resource.serializeToXml(responseEl, requestedProperties);
-    }
-    return propDoc;
-  }
-}
blob - 029e0da28dec7284d703d42725af8549d2f49ae5 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/PropPatchHandler.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.data.DavResource;
-import com.thinkberg.moxo.dav.lock.LockException;
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.FileObject;
-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.IOException;
-import java.net.URL;
-import java.text.ParseException;
-import java.util.List;
-
-/**
- * Handle PROPPATCH requests. This currently a dummy only and will return a
- * forbidden status for any attempt to modify or remove a property.
- *
- * @author Matthias L. Jugel
- */
-public class PropPatchHandler extends WebdavHandler {
-  private static final Log LOG = LogFactory.getLog(PropPatchHandler.class);
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    FileObject object = getVFSObject(request.getPathInfo());
-
-    try {
-      if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) {
-        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-        return;
-      }
-    } catch (LockException e) {
-      response.sendError(WebdavHandler.SC_LOCKED);
-      return;
-    } catch (ParseException e) {
-      response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-      return;
-    }
-
-    SAXReader saxReader = new SAXReader();
-    try {
-      Document propDoc = saxReader.read(request.getInputStream());
-//      log(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 el = (Element) elObject;
-          if ("set".equals(el.getName())) {
-            for (Object propObject : el.elements()) {
-              setProperty(propEl, object, (Element) propObject);
-            }
-          } 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);
-
-        // write the actual response
-        XMLWriter writer = new XMLWriter(response.getWriter(), OutputFormat.createCompactFormat());
-        writer.write(resultDoc);
-        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();
-      }
-      root.add(propEl.detach());
-    }
-  }
-
-  private void removeProperty(Element root, FileObject object, Element el) {
-    setProperty(root, object, el);
-  }
-
-
-}
blob - ed879c915a369d9649cbba45551e983960a733ad (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/PutHandler.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.lock.LockException;
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileType;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.ParseException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class PutHandler extends WebdavHandler {
-  private static final Log LOG = LogFactory.getLog(PutHandler.class);
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    FileObject object = getVFSObject(request.getPathInfo());
-
-    try {
-      if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) {
-        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-        return;
-      }
-    } catch (LockException e) {
-      response.sendError(WebdavHandler.SC_LOCKED);
-      return;
-    } catch (ParseException e) {
-      response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
-      return;
-    }
-    // it is forbidden to write data on a folder
-    if (object.exists() && FileType.FOLDER.equals(object.getType())) {
-      response.sendError(HttpServletResponse.SC_FORBIDDEN);
-      return;
-    }
-
-    FileObject parent = object.getParent();
-    if (!parent.exists()) {
-      response.sendError(HttpServletResponse.SC_FORBIDDEN);
-      return;
-    }
-
-    if (!FileType.FOLDER.equals(parent.getType())) {
-      response.sendError(HttpServletResponse.SC_CONFLICT);
-      return;
-    }
-
-    InputStream is = request.getInputStream();
-    OutputStream os = object.getContent().getOutputStream();
-    long bytesCopied = Util.copyStream(is, os);
-    String contentLengthHeader = request.getHeader("Content-length");
-    LOG.debug(String.format("sent %d/%s bytes", bytesCopied, contentLengthHeader == null ? "unknown" : contentLengthHeader));
-    os.flush();
-    object.close();
-
-    response.setStatus(HttpServletResponse.SC_CREATED);
-  }
-}
blob - cdf9f6df05dd32310e05a5e0ab104c03779b15ea (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/URLEncoder.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import java.io.UnsupportedEncodingException;
-import java.util.BitSet;
-
-/**
- * Encode a URL but leave some special characters in plain text.
- *
- * @author Matthias L. Jugel
- */
-class URLEncoder {
-
-  private static final BitSet keepPlain;
-
-  static {
-    keepPlain = new BitSet(256);
-    int i;
-    for (i = 'a'; i <= 'z'; i++) {
-      keepPlain.set(i);
-    }
-    for (i = 'A'; i <= 'Z'; i++) {
-      keepPlain.set(i);
-    }
-    for (i = '0'; i <= '9'; i++) {
-      keepPlain.set(i);
-    }
-    keepPlain.set('+');
-    keepPlain.set('-');
-    keepPlain.set('_');
-    keepPlain.set('.');
-    keepPlain.set('*');
-    keepPlain.set('/');
-    keepPlain.set(':');
-  }
-
-
-  public static String encode(String s, String enc) throws UnsupportedEncodingException {
-    byte[] buf = s.getBytes(enc);
-    StringBuffer result = new StringBuffer();
-    for (byte aBuf : buf) {
-      int c = (int) aBuf;
-      if (keepPlain.get(c & 0xFF)) {
-        result.append((char) c);
-      } else {
-        result.append('%').append(Integer.toHexString(c & 0xFF).toUpperCase());
-      }
-    }
-    return result.toString();
-  }
-}
blob - e9810818ac9e79873202dae184ec9ad09b813804 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/UnlockHandler.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.FileObject;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class UnlockHandler extends WebdavHandler {
-  private static final Log LOG = LogFactory.getLog(UnlockHandler.class);
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
-    FileObject object = getVFSObject(request.getPathInfo());
-    String lockTokenHeader = request.getHeader("Lock-Token");
-    String lockToken = lockTokenHeader.substring(1, lockTokenHeader.length() - 1);
-    LOG.debug("UNLOCK(" + lockToken + ")");
-
-    if (LockManager.getInstance().releaseLock(object, lockToken)) {
-      response.setStatus(HttpServletResponse.SC_NO_CONTENT);
-    } else {
-      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-    }
-  }
-}
blob - 9b6e71d63c5a52df24c66a3d45ff9da5b93a6115 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/Util.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class Util {
-
-  private static final SimpleDateFormat httpDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
-
-  public static String getDateString(long time) {
-    return httpDateFormat.format(new Date(time));
-  }
-
-//  public static String getISODateString(long time) {
-//    return "";    4
-//  }
-
-
-  public static long copyStream(final InputStream is, final OutputStream os) throws IOException {
-    ReadableByteChannel rbc = Channels.newChannel(is);
-    WritableByteChannel wbc = Channels.newChannel(os);
-
-    int bytesWritten = 0;
-    final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
-    while (rbc.read(buffer) != -1) {
-      buffer.flip();
-      bytesWritten += wbc.write(buffer);
-      buffer.compact();
-    }
-    buffer.flip();
-    while (buffer.hasRemaining()) {
-      bytesWritten += wbc.write(buffer);
-    }
-
-    rbc.close();
-    wbc.close();
-
-    return bytesWritten;
-  }
-}
blob - b52d655c1ac100625581cb02aba7e7f923b502b6 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/WebdavHandler.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav;
-
-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.apache.commons.vfs.FileSystemManager;
-import org.apache.commons.vfs.VFS;
-import org.jets3t.service.Jets3tProperties;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Arrays;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public abstract class WebdavHandler {
-  private static final Log LOG = LogFactory.getLog(WebdavHandler.class);
-
-  static final int SC_CREATED = 201;
-  static final int SC_LOCKED = 423;
-  static final int SC_MULTI_STATUS = 207;
-
-  private static FileObject fileSystemRoot;
-
-  static {
-    try {
-      String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties");
-      Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName);
-      FileSystemManager fsm = VFS.getManager();
-
-      // create a virtual filesystemusing the url provided or fall back to RAM
-      fileSystemRoot = fsm.resolveFile(properties.getStringProperty("vfs.uri", "ram:/"));
-
-      LOG.info("created virtual file system: " + fileSystemRoot);
-    } catch (FileSystemException e) {
-      LOG.error("can't create virtual file system: " + e.getMessage());
-      e.printStackTrace();
-    }
-  }
-
-  protected static FileObject getVFSObject(String path) throws FileSystemException {
-    return fileSystemRoot.resolveFile(path);
-  }
-
-  protected static URL getBaseUrl(HttpServletRequest request) {
-    try {
-      String requestUrl = request.getRequestURL().toString();
-      String requestUri = request.getRequestURI();
-      String requestUrlBase = requestUrl.substring(0, requestUrl.length() - requestUri.length());
-      return new URL(requestUrlBase);
-    } catch (MalformedURLException e) {
-      // ignore ...
-    }
-    return null;
-  }
-
-  public abstract void service(HttpServletRequest request, HttpServletResponse response) throws IOException;
-
-  /**
-   * Get the depth header value. This value defines how operations
-   * like propfind, move, copy etc. handle collections. A depth value
-   * of 0 will only return the current collection, 1 will return
-   * children too and infinity will recursively operate.
-   *
-   * @param request the servlet request
-   * @return the depth value as 0, 1 or Integer.MAX_VALUE;
-   */
-  int getDepth(HttpServletRequest request) {
-    String depth = request.getHeader("Depth");
-    int depthValue;
-
-    if (null == depth || "infinity".equalsIgnoreCase(depth)) {
-      depthValue = Integer.MAX_VALUE;
-    } else {
-      depthValue = Integer.parseInt(depth);
-    }
-
-    LOG.debug(String.format("request header: Depth: %s", (depthValue == Integer.MAX_VALUE ? "infinity" : depthValue)));
-    return depthValue;
-  }
-
-  /**
-   * Get the overwrite header value, whether to overwrite destination
-   * objects or collections or not.
-   *
-   * @param request the servlet request
-   * @return true or false
-   */
-  boolean getOverwrite(HttpServletRequest request) {
-    String overwrite = request.getHeader("Overwrite");
-    boolean overwriteValue = overwrite == null || "T".equals(overwrite);
-
-    LOG.debug(String.format("request header: Overwrite: %s", overwriteValue));
-    return overwriteValue;
-  }
-
-  /**
-   * Get the destination object or collection. The destination header contains
-   * a URL to the destination which is returned as a file object.
-   *
-   * @param request the servlet request
-   * @return the file object of the destination
-   * @throws FileSystemException   if the file system cannot create a file object
-   * @throws MalformedURLException if the url is misformatted
-   */
-  FileObject getDestination(HttpServletRequest request) throws FileSystemException, MalformedURLException {
-    String targetUrlStr = request.getHeader("Destination");
-    FileObject targetObject = null;
-    if (null != targetUrlStr) {
-      URL target = new URL(targetUrlStr);
-      targetObject = getVFSObject(target.getPath());
-      LOG.debug(String.format("request header: Destination: %s", targetObject.getName().getPath()));
-    }
-
-    return targetObject;
-  }
-
-  /**
-   * Get the if header.
-   *
-   * @param request the request
-   * @return the value if the If: header.
-   */
-  String getIf(HttpServletRequest request) {
-    String getIfHeader = request.getHeader("If");
-
-    if (null != getIfHeader) {
-      LOG.debug(String.format("request header: If: '%s'", getIfHeader));
-    }
-    return getIfHeader;
-  }
-
-  /**
-   * Get and parse the timeout header value.
-   *
-   * @param request the request
-   * @return the timeout
-   */
-  long getTimeout(HttpServletRequest request) {
-    String timeout = request.getHeader("Timeout");
-    if (null != timeout) {
-      String[] timeoutValues = timeout.split(",[ ]*");
-      LOG.debug(String.format("request header: Timeout: %s", Arrays.asList(timeoutValues).toString()));
-      if ("infinity".equalsIgnoreCase(timeoutValues[0])) {
-        return -1;
-      } else {
-        return Integer.parseInt(timeoutValues[0].replaceAll("Second-", ""));
-      }
-    }
-    return -1;
-  }
-}
blob - 82ec809f38ec9a22f32b81ba769787173ef5df2d (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/data/AbstractDavResource.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.data;
-
-import org.dom4j.Element;
-
-import java.util.HashSet;
-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_403 = "HTTP/1.1 403 Forbidden";
-
-  private static final String TAG_PROPSTAT = "propstat";
-  private static final String TAG_PROP = "prop";
-  private static final String TAG_STATUS = "status";
-
-  public Element serializeToXml(Element root, List<String> requestedProperties) {
-    Element propStatEl = root.addElement(TAG_PROPSTAT);
-    Element propEl = propStatEl.addElement(TAG_PROP);
-
-    Set<String> missingProperties = new HashSet<String>();
-    for (String propertyName : requestedProperties) {
-      if (!addPropertyValue(propEl, propertyName)) {
-        missingProperties.add(propertyName);
-      }
-    }
-    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);
-      }
-      propStatEl.addElement(TAG_STATUS).addText(STATUS_404);
-    }
-
-    return root;
-  }
-
-  @SuppressWarnings({"BooleanMethodIsAlwaysInverted"})
-  protected abstract boolean addPropertyValue(Element root, String propertyName);
-}
blob - fcd185c553c3e877a601f195e39e4d1687e16c32 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/data/DavCollection.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.data;
-
-import org.apache.commons.vfs.FileObject;
-import org.dom4j.Element;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class DavCollection extends DavResource {
-  public static final String COLLECTION = "collection";
-
-  public DavCollection(FileObject object) {
-    super(object);
-  }
-
-
-  public DavCollection(FileObject object, boolean ignoreValues) {
-    super(object, ignoreValues);
-  }
-
-  protected boolean addResourceTypeProperty(Element root) {
-    root.addElement(PROP_RESOURCETYPE).addElement(COLLECTION);
-    return true;
-  }
-
-  /**
-   * Ignore content language for collections.
-   *
-   * @param root the prop element to add to
-   * @return true, even though nothing is added
-   */
-  protected boolean addGetContentLanguageProperty(Element root) {
-    return true;
-  }
-
-  /**
-   * Ignore content length for collections.
-   *
-   * @param root the prop element to add to
-   * @return true, even though nothing is added
-   */
-  protected boolean addGetContentLengthProperty(Element root) {
-    return true;
-  }
-
-  /**
-   * Ignore content type for collections.
-   *
-   * @param root the prop element to add to
-   * @return true, even though nothing is added
-   */
-  protected boolean addGetContentTypeProperty(Element root) {
-    return true;
-  }
-
-  protected boolean addQuotaProperty(Element root) {
-    root.addElement(PROP_QUOTA).addText("" + Long.MAX_VALUE);
-    return true;
-  }
-
-  protected boolean addQuotaUsedProperty(Element root) {
-    // TODO add correct handling of used quota
-    root.addElement(PROP_QUOTA_USED).addText("0");
-    return true;
-  }
-
-  protected boolean addQuotaAvailableBytesProperty(Element root) {
-    root.addElement(PROP_QUOTA_AVAILABLE_BYTES).addText("" + Long.MAX_VALUE);
-    return true;
-  }
-
-  protected boolean addQuotaUsedBytesProperty(Element root) {
-    // TODO add correct handling of used quota
-    root.addElement(PROP_QUOTA_USED_BYTES).addText("0");
-    return true;
-  }
-}
blob - 7b8460688401f8da61a40a80db7fe85b44f0b4c3 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/data/DavResource.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.data;
-
-import com.thinkberg.moxo.dav.Util;
-import com.thinkberg.moxo.dav.lock.Lock;
-import com.thinkberg.moxo.dav.lock.LockManager;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-import org.dom4j.Element;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-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);
-  }
-
-
-  public DavResource(FileObject object, boolean ignoreValues) {
-    this.object = object;
-    this.ignoreValues = ignoreValues;
-
-  }
-
-  /**
-   * 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
-   * @return true for successful addition and false for missing data
-   */
-  protected boolean addPropertyValue(Element root, String propertyName) {
-    if (PROP_CREATION_DATE.equals(propertyName)) {
-      return addCreationDateProperty(root);
-    } else if (PROP_DISPLAY_NAME.equals(propertyName)) {
-      return addGetDisplayNameProperty(root);
-    } else if (PROP_GET_CONTENT_LANGUAGE.equals(propertyName)) {
-      return addGetContentLanguageProperty(root);
-    } else if (PROP_GET_CONTENT_LENGTH.equals(propertyName)) {
-      return addGetContentLengthProperty(root);
-    } else if (PROP_GET_CONTENT_TYPE.equals(propertyName)) {
-      return addGetContentTypeProperty(root);
-    } else if (PROP_GET_ETAG.equals(propertyName)) {
-      return addGetETagProperty(root);
-    } else if (PROP_GET_LAST_MODIFIED.equals(propertyName)) {
-      return addGetLastModifiedProperty(root);
-    } else if (PROP_LOCK_DISCOVERY.equals(propertyName)) {
-      return addLockDiscoveryProperty(root);
-    } else if (PROP_RESOURCETYPE.equals(propertyName)) {
-      return addResourceTypeProperty(root);
-    } else if (PROP_SOURCE.equals(propertyName)) {
-      return addSourceProperty(root);
-    } else if (PROP_SUPPORTED_LOCK.equals(propertyName)) {
-      return addSupportedLockProperty(root);
-    } else {
-      // handle non-standard properties (keep a little separate)
-      if (PROP_QUOTA.equals(propertyName)) {
-        return addQuotaProperty(root);
-      } else if (PROP_QUOTA_USED.equals(propertyName)) {
-        return addQuotaUsedProperty(root);
-      } else if (PROP_QUOTA_AVAILABLE_BYTES.equals(propertyName)) {
-        return addQuotaAvailableBytesProperty(root);
-      } else if (PROP_QUOTA_USED_BYTES.equals(propertyName)) {
-        return addQuotaUsedBytesProperty(root);
-      }
-    }
-
-    return false;
-  }
-
-  protected boolean addCreationDateProperty(Element root) {
-    return false;
-  }
-
-  protected boolean addGetDisplayNameProperty(Element root) {
-    Element el = root.addElement(PROP_DISPLAY_NAME);
-    if (!ignoreValues) {
-      el.addCDATA(object.getName().getBaseName());
-    }
-    return true;
-  }
-
-  protected boolean addGetContentLanguageProperty(Element root) {
-    return false;
-  }
-
-  protected boolean addGetContentLengthProperty(Element root) {
-    try {
-      Element el = root.addElement(PROP_GET_CONTENT_LENGTH);
-      if (!ignoreValues) {
-        el.addText("" + object.getContent().getSize());
-      }
-      return true;
-    } catch (FileSystemException e) {
-      e.printStackTrace();
-      return false;
-    }
-  }
-
-  protected boolean addGetContentTypeProperty(Element root) {
-    try {
-      String contentType = object.getContent().getContentInfo().getContentType();
-      if (null == contentType || "".equals(contentType)) {
-        return false;
-      }
-
-      Element el = root.addElement(PROP_GET_CONTENT_TYPE);
-      if (!ignoreValues) {
-        el.addText(contentType);
-      }
-      return true;
-    } catch (FileSystemException e) {
-      e.printStackTrace();
-      return false;
-    }
-  }
-
-  protected boolean addGetETagProperty(Element root) {
-    return false;
-  }
-
-  protected boolean addGetLastModifiedProperty(Element root) {
-    try {
-      Element el = root.addElement(PROP_GET_LAST_MODIFIED);
-      if (!ignoreValues) {
-        el.addText(Util.getDateString(object.getContent().getLastModifiedTime()));
-      }
-      return true;
-    } catch (FileSystemException e) {
-      e.printStackTrace();
-      return false;
-    }
-  }
-
-  protected boolean addLockDiscoveryProperty(Element root) {
-    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) {
-            lock.serializeToXml(lockdiscoveryEl);
-          }
-        }
-      }
-      return true;
-    } catch (FileSystemException e) {
-      e.printStackTrace();
-      root.remove(lockdiscoveryEl);
-      return false;
-    }
-  }
-
-  protected boolean addResourceTypeProperty(Element root) {
-    root.addElement(PROP_RESOURCETYPE);
-    return true;
-  }
-
-  protected boolean addSourceProperty(Element root) {
-    return false;
-  }
-
-  protected boolean addSupportedLockProperty(Element root) {
-    Element supportedlockEl = root.addElement(PROP_SUPPORTED_LOCK);
-    if (!ignoreValues) {
-      Element exclLockentryEl = supportedlockEl.addElement("lockentry");
-      exclLockentryEl.addElement("lockscope").addElement("exclusive");
-      exclLockentryEl.addElement("locktype").addElement("write");
-      Element sharedLockentryEl = supportedlockEl.addElement("lockentry");
-      sharedLockentryEl.addElement("lockscope").addElement("shared");
-      sharedLockentryEl.addElement("locktype").addElement("write");
-    }
-
-    return true;
-  }
-
-  protected boolean addQuotaProperty(Element root) {
-    return false;
-  }
-
-  protected boolean addQuotaUsedProperty(Element root) {
-    return false;
-  }
-
-  protected boolean addQuotaAvailableBytesProperty(Element root) {
-    return false;
-  }
-
-  protected boolean addQuotaUsedBytesProperty(Element root) {
-    return false;
-  }
-}
blob - 8d66d4881885922677820797ffae246c27b96ef9 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/data/DavResourceFactory.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.data;
-
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileType;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class DavResourceFactory {
-  private static DavResourceFactory instance;
-
-  public static DavResourceFactory getInstance() {
-    if (null == instance) {
-      instance = new DavResourceFactory();
-    }
-    return instance;
-  }
-
-  private DavResourceFactory() {
-
-  }
-
-  public DavResource getDavResource(FileObject object) throws FileSystemException {
-    if (FileType.FOLDER.equals(object.getType())) {
-      return new DavCollection(object);
-    } else {
-      return new DavResource(object);
-    }
-  }
-}
blob - 1e07eee9313edf1cf95329fbec218d5878378116 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/lock/Lock.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.lock;
-
-import org.apache.commons.vfs.FileObject;
-import org.dom4j.Element;
-
-import java.net.URL;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class Lock {
-  public final static String SHARED = "shared";
-  public final static String EXCLUSIVE = "exclusive";
-
-  public final static String WRITE = "write";
-
-  private final FileObject object;
-  private final String type;
-  private final String scope;
-  private final Object owner;
-  private final int depth;
-  private final long timeout;
-  private final String token;
-
-
-  public Lock(FileObject object, String type, String scope, Object owner,
-              int depth, long timeout) {
-    this.object = object;
-    this.type = type;
-    this.scope = scope;
-    this.owner = owner;
-    this.depth = depth;
-    this.timeout = timeout;
-
-    this.token = "opaquelocktoken:" + Integer.toHexString(object.hashCode());
-  }
-
-  public FileObject getObject() {
-    return object;
-  }
-
-  public String getType() {
-    return type;
-  }
-
-  public String getScope() {
-    return scope;
-  }
-
-  public Object getOwner() {
-    return owner;
-  }
-
-  public int getDepth() {
-    return depth;
-  }
-
-  public String getDepthValue() {
-    switch (depth) {
-      case 0:
-        return "0";
-      case 1:
-        return "1";
-      default:
-        return "Infinity";
-    }
-  }
-
-  public String getTimeout() {
-    if (timeout == -1) {
-      return "Infinity";
-    }
-    return "Second-" + timeout;
-  }
-
-  public String getToken() {
-    return this.token;
-  }
-
-  /**
-   * Create an XML serialized version of the lock by adding an activelock tag
-   * with the locks properties to the root element provided.
-   *
-   * @param root the root element to add the activelock to
-   * @return the root element
-   */
-  public Element serializeToXml(Element root) {
-    Element activelockEl = root.addElement("activelock");
-    activelockEl.addElement("locktype").addElement(getType());
-    activelockEl.addElement("lockscope").addElement(getScope());
-    activelockEl.addElement("depth").addText(getDepthValue());
-    // TODO handle owner correctly
-    if (getOwner() instanceof URL) {
-      activelockEl.addElement("owner").addElement("href")
-              .addText(((URL) getOwner()).toExternalForm());
-    } else {
-      activelockEl.addElement("owner").addText((String) getOwner());
-    }
-    activelockEl.addElement("timeout").addText(getTimeout());
-    activelockEl.addElement("locktoken")
-            .addElement("href").addText(getToken());
-
-    return root;
-  }
-
-  /**
-   * There can only be one lock per object, thus compare the file objects.
-   *
-   * @param other the other lock to compare to
-   * @return whether this lock is for the same file object
-   */
-  public boolean equals(Object other) {
-    return other instanceof Lock && object.equals(((Lock) other).object);
-  }
-
-
-  public String toString() {
-    return String.format("Lock[%s,%s,%s,%s]", object, type, scope, token);
-  }
-}
-
blob - 0944f6914361ef87067e9e0739796e73448509e2 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/lock/LockConditionFailedException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.lock;
-
-import java.util.List;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class LockConditionFailedException extends LockException {
-  private String condition = null;
-
-  public LockConditionFailedException(List<Lock> locks) {
-    super(locks);
-  }
-
-  public LockConditionFailedException(List<Lock> locks, String condition) {
-    super(locks);
-    this.condition = condition;
-
-  }
-
-  public String getCondition() {
-    return condition;
-  }
-}
blob - 217437da42098d75357b98160f381a27ba1e4c95 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/lock/LockConditionRequiredException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2009 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.lock;
-
-import java.util.List;
-
-public class LockConditionRequiredException extends LockException {
-  public LockConditionRequiredException(List<Lock> locks) {
-    super(locks);
-  }
-}
blob - bc0d2328671d1f91e7b57dc24d33acd8d01e849f (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/lock/LockConflictException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.lock;
-
-import java.util.List;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class LockConflictException extends LockException {
-  public LockConflictException(List<Lock> locks) {
-    super(locks);
-  }
-}
blob - 1ca6c2f973c038a647cd769743a77a78708243bc (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/lock/LockException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.lock;
-
-import java.util.List;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class LockException extends Exception {
-  private final List<Lock> locks;
-
-  public LockException(List<Lock> locks) {
-    super();
-    this.locks = locks;
-  }
-
-  public List<Lock> getLocks() {
-    return locks;
-  }
-
-  public String toString() {
-    return String.format("[%s: %s]", this.getClass(), locks);
-  }
-}
blob - ffac2fafb4c81fc700c4686ab276f1625eebe709 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/dav/lock/LockManager.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.dav.lock;
-
-import com.thinkberg.moxo.vfs.DepthFileSelector;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSelectInfo;
-import org.apache.commons.vfs.FileSystemException;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * The lock manager is responsible for exclusive and shared write locks on the
- * DAV server. It is used to acquire a lock, release a lock, discover existing
- * locks or check conditions. The lock manager is a singleton.
- *
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class LockManager {
-  private static LockManager instance = null;
-  private static final Log LOG = LogFactory.getLog(LockManager.class);
-
-  // condition parser patterns and tokens
-  private static final Pattern IF_PATTERN = Pattern.compile("(<[^>]+>)|(\\([^)]+\\))");
-  private static final Pattern CONDITION_PATTERN = Pattern.compile("([Nn][Oo][Tt])|(<[^>]+>)|(\\[[^]]+\\])");
-  private static final char TOKEN_LOWER_THAN = '<';
-  private static final char TOKEN_LEFT_BRACE = '(';
-  private static final char TOKEN_LEFT_BRACKET = '[';
-
-  /**
-   * Get an instance of the lock manager.
-   *
-   * @return the lock manager
-   */
-  public static LockManager getInstance() {
-    if (null == instance) {
-      instance = new LockManager();
-    }
-
-    return instance;
-  }
-
-  private final Map<FileObject, List<Lock>> lockMap;
-
-  /**
-   * The lock manager is a singleton and cannot be instantiated directly.
-   */
-  private LockManager() {
-    lockMap = new HashMap<FileObject, List<Lock>>();
-  }
-
-  /**
-   * Acquire a lock. This will first check for conflicts and throws exceptions if
-   * there are existing locks or for some reason the lock could not be acquired.
-   *
-   * @param lock the lock to acquire
-   * @throws LockConflictException if an existing lock has priority
-   * @throws FileSystemException   if the file object and its path cannot be accessed
-   */
-  public void acquireLock(Lock lock) throws LockConflictException, FileSystemException {
-    checkConflicts(lock);
-    addLock(lock);
-  }
-
-  /**
-   * Release a lock on a file object with a given lock token. Releeases the lock if
-   * if one exists and if the lock token is valid for the found lock.
-   *
-   * @param object the file object we want to unlock
-   * @param token  the lock token associated with the file object
-   * @return true if the lock has been released, false if not
-   */
-  public boolean releaseLock(FileObject object, String token) {
-    List<Lock> locks = lockMap.get(object);
-    if (null != locks) {
-      for (Lock lock : locks) {
-        if (lock.getToken().equals(token)) {
-          locks.remove(lock);
-          return true;
-        }
-      }
-      return false;
-    }
-
-    return true;
-  }
-
-  /**
-   * Discover locks for a given file object. This will find locks for the object
-   * itself and parent path locks with a depth that reaches the file object.
-   *
-   * @param object the file object to find locks for
-   * @return the locks that are found for this file object
-   * @throws FileSystemException if the file object or its parents cannot be accessed
-   */
-  public List<Lock> discoverLock(FileObject object) throws FileSystemException {
-    FileObject parent = object;
-    while (parent != null) {
-      List<Lock> parentLocks = lockMap.get(parent);
-      if (parentLocks != null && !parentLocks.isEmpty()) {
-        return parentLocks;
-      }
-      parent = parent.getParent();
-    }
-
-    return null;
-  }
-
-  /**
-   * Evaluate an 'If:' header condition.
-   * The condition may be a tagged list or an untagged list. Tagged lists define the resource, the condition
-   * applies to in front of the condition (ex. 1, 2, 5, 6). Conditions may be inverted by using 'Not' at the
-   * beginning of the condition (ex. 3, 4, 6). The list constitutes an OR expression while the list of
-   * conditions within braces () constitutes an AND expression.
-   * <p/>
-   * Evaluate example 2:<br/>
-   * <code>
-   * URI(/resource1) { (
-   * is-locked-with(urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2)
-   * AND matches-etag(W/"A weak ETag") )
-   * OR ( matches-etag("strong ETag") ) }
-   * </code>
-   * <p/>
-   * Examples:
-   * <ol>
-   * <li> &lt;http://cid:8080/litmus/unmapped_url&gt; (&lt;opaquelocktoken:cd6798&gt;)</li>
-   * <li> &lt;/resource1&gt; (&lt;urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2&gt; [W/"A weak ETag"]) (["strong ETag"])</li>
-   * <li> (&lt;urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2&gt;) (Not &lt;DAV:no-lock&gt;)</li>
-   * <li> (Not &lt;urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2&gt; &lt;urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092&gt;)</li>
-   * <li> &lt;/specs/rfc2518.doc&gt; (["4217"])</li>
-   * <li> &lt;/specs/rfc2518.doc&gt; (Not ["4217"])</li>
-   * </ol>
-   *
-   * @param contextObject the contextual resource (needed when the If: condition is not tagged)
-   * @param ifCondition   the string of the condition as sent by the If: header
-   * @return evaluation of the condition expression
-   * @throws ParseException        if the condition does not meet the syntax requirements
-   * @throws LockConflictException
-   * @throws FileSystemException
-   */
-  public EvaluationResult evaluateCondition(FileObject contextObject, String ifCondition)
-          throws FileSystemException, LockConflictException, ParseException {
-    List<Lock> locks = discoverLock(contextObject);
-    EvaluationResult evaluation = new EvaluationResult();
-
-    if (ifCondition == null || "".equals(ifCondition)) {
-      if (locks != null) {
-        throw new LockConflictException(locks);
-      }
-      evaluation.result = true;
-      return evaluation;
-    }
-
-    Matcher matcher = IF_PATTERN.matcher(ifCondition);
-    FileObject resource = contextObject;
-    while (matcher.find()) {
-      String token = matcher.group();
-      switch (token.charAt(0)) {
-        case TOKEN_LOWER_THAN:
-          String resourceUri = token.substring(1, token.length() - 1);
-          try {
-            resource = contextObject.getFileSystem().resolveFile(new URI(resourceUri).getPath());
-            locks = discoverLock(resource);
-          } catch (URISyntaxException e) {
-            throw new ParseException(ifCondition, matcher.start());
-          }
-          break;
-        case TOKEN_LEFT_BRACE:
-          LOG.debug(String.format("URI(%s) {", resource));
-          Matcher condMatcher = CONDITION_PATTERN.matcher(token.substring(1, token.length() - 1));
-          boolean expressionResult = true;
-          while (condMatcher.find()) {
-            String condToken = condMatcher.group();
-            boolean negate = false;
-            if (condToken.matches("[Nn][Oo][Tt]")) {
-              negate = true;
-              condMatcher.find();
-              condToken = condMatcher.group();
-            }
-            switch (condToken.charAt(0)) {
-              case TOKEN_LOWER_THAN:
-                String lockToken = condToken.substring(1, condToken.length() - 1);
-
-                boolean foundLock = false;
-                if (locks != null) {
-                  for (Lock lock : locks) {
-                    if (lockToken.equals(lock.getToken())) {
-                      evaluation.locks.add(lock);
-                      foundLock = true;
-                      break;
-                    }
-                  }
-                }
-                final boolean foundLockResult = negate ? !foundLock : foundLock;
-                LOG.debug(String.format("  %sis-locked-with(%s) = %b",
-                                        negate ? "NOT " : "", lockToken, foundLockResult));
-                expressionResult = expressionResult && foundLockResult;
-                break;
-              case TOKEN_LEFT_BRACKET:
-                String eTag = condToken.substring(1, condToken.length() - 1);
-                String resourceETag = String.format("%x", resource.hashCode());
-                boolean resourceTagMatches = resourceETag.equals(eTag);
-                final boolean matchesEtagResult = negate ? !resourceTagMatches : resourceTagMatches;
-                LOG.debug(String.format("  %smatches-etag(%s) = %b",
-                                        negate ? "NOT " : "", eTag, matchesEtagResult));
-                expressionResult = expressionResult && matchesEtagResult;
-                break;
-              default:
-                throw new ParseException(String.format("syntax error in condition '%s' at %d",
-                                                       ifCondition, matcher.start() + condMatcher.start()),
-                                         matcher.start() + condMatcher.start());
-            }
-          }
-
-          evaluation.result = evaluation.result || expressionResult;
-          LOG.debug("} => " + evaluation.result);
-          break;
-        default:
-          throw new ParseException(String.format("syntax error in condition '%s' at %d", ifCondition, matcher.start()),
-                                   matcher.start());
-      }
-    }
-
-    // regardless of the evaluation, if the object is locked but there is no valed lock token in the
-    // conditions we must fail with a lock conflict too
-    if (evaluation.result && (locks != null && !locks.isEmpty()) && evaluation.locks.isEmpty()) {
-      throw new LockConflictException(locks);
-    }
-    return evaluation;
-  }
-
-  public class EvaluationResult {
-    public List<Lock> locks = new ArrayList<Lock>();
-    public boolean result = false;
-
-    public String toString() {
-      return String.format("EvaluationResult[%b,%s]", result, locks);
-    }
-  }
-
-  /**
-   * Add a lock to the list of shared locks of a given object.
-   *
-   * @param lock the lock to add
-   */
-  private void addLock(Lock lock) {
-    FileObject object = lock.getObject();
-    List<Lock> locks = lockMap.get(object);
-    if (null == locks) {
-      locks = new ArrayList<Lock>();
-      lockMap.put(object, locks);
-    }
-    locks.add(lock);
-  }
-
-  /**
-   * Check whether a lock conflicts with already existing locks up and down the path.
-   * First we go up the path to check for parent locks that may include the file object
-   * and the go down the directory tree (if depth requires it) to check locks that
-   * will conflict.
-   *
-   * @param requestedLock the lock requested
-   * @throws LockConflictException if a conflicting lock was found
-   * @throws FileSystemException   if the file object or path cannot be accessed
-   */
-  private void checkConflicts(final Lock requestedLock) throws LockConflictException, FileSystemException {
-    // find locks in the parent path
-    FileObject parent = requestedLock.getObject();
-    while (parent != null) {
-      List<Lock> parentLocks = lockMap.get(parent);
-      if (parentLocks != null && !parentLocks.isEmpty()) {
-        for (Lock parentLock : parentLocks) {
-          if (Lock.EXCLUSIVE.equals(requestedLock.getScope()) || Lock.EXCLUSIVE.equals(parentLock.getScope())) {
-            throw new LockConflictException(parentLocks);
-          }
-        }
-      }
-      parent = parent.getParent();
-    }
-
-    // look for locks down the path (if depth requests it)
-    if (requestedLock.getDepth() != 0 && requestedLock.getObject().getChildren().length > 0) {
-      requestedLock.getObject().findFiles(new DepthFileSelector(1, requestedLock.getDepth()) {
-        public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception {
-          List<Lock> childLocks = lockMap.get(fileSelectInfo.getFile());
-          for (Lock childLock : childLocks) {
-            if (Lock.EXCLUSIVE.equals(requestedLock.getScope()) || Lock.EXCLUSIVE.equals(childLock.getScope())) {
-              throw new LockConflictException(childLocks);
-            }
-          }
-          return false;
-        }
-      }, false, new ArrayList());
-    }
-  }
-
-}
blob - 094aa76addd911ee350612557694b1c5fecd0879 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/servlet/MoxoWebDAVServlet.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.servlet;
-
-import com.thinkberg.moxo.dav.*;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.FileObject;
-import org.mortbay.jetty.Response;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class MoxoWebDAVServlet extends HttpServlet {
-  private static final Log LOG = LogFactory.getLog(MoxoWebDAVServlet.class);
-
-  private final Map<String, WebdavHandler> handlers = new HashMap<String, WebdavHandler>();
-  private FileObject fileSystemRoot = null;
-
-  public MoxoWebDAVServlet() {
-    handlers.put("COPY", new CopyHandler());
-    handlers.put("DELETE", new DeleteHandler());
-    handlers.put("GET", new GetHandler());
-    handlers.put("HEAD", new HeadHandler());
-    handlers.put("LOCK", new LockHandler());
-    handlers.put("MKCOL", new MkColHandler());
-    handlers.put("MOVE", new MoveHandler());
-    handlers.put("OPTIONS", new OptionsHandler());
-    handlers.put("POST", new PostHandler());
-    handlers.put("PROPFIND", new PropFindHandler());
-    handlers.put("PROPPATCH", new PropPatchHandler());
-    handlers.put("PUT", new PutHandler());
-    handlers.put("UNLOCK", new UnlockHandler());
-  }
-
-  protected FileObject getFileSystemRoot() {
-    return fileSystemRoot;
-  }
-
-  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-//    String auth = request.getHeader("Authorization");
-//    String login = "", password = "";
-//
-//    if (auth != null) {
-//      auth = new String(Base64.decodeBase64(auth.substring(auth.indexOf(' ') + 1).getBytes()));
-//      login = auth.substring(0, auth.indexOf(':'));
-//      password = auth.substring(auth.indexOf(':') + 1);
-//    }
-//
-//    AWSCredentials credentials = AWSCredentials.load(password,  ))
-//    if (user == null) {
-//      response.setHeader("WWW-Authenticate", "Basic realm=\"Moxo\"");
-//      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-//      return;
-//    }
-
-
-    // show we are doing the litmus test
-    String litmusTest = request.getHeader("X-Litmus");
-    if (null == litmusTest) {
-      litmusTest = request.getHeader("X-Litmus-Second");
-    }
-    if (litmusTest != null) {
-      LOG.info(String.format("WebDAV Litmus Test: %s", litmusTest));
-    }
-
-    String method = request.getMethod();
-    LOG.debug(String.format(">> %s %s", request.getMethod(), request.getPathInfo()));
-    if (handlers.containsKey(method)) {
-      handlers.get(method).service(request, response);
-    } 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 : ""));
-  }
-}
blob - 6e622e49ceb530d686040b60ba8b310b252b7d62 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/DepthFileSelector.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import org.apache.commons.vfs.FileSelectInfo;
-import org.apache.commons.vfs.FileSelector;
-
-/**
- * A file selector that operates depth of the directory structure and will
- * select all files up to and including the depth given in the constructor.
- *
- * @author Matthias L. Jugel
- * @version $Id$
- */
-public class DepthFileSelector implements FileSelector {
-  private final int maxDepth;
-  private final int minDepth;
-
-  /**
-   * Create a file selector that will select ALL files.
-   */
-  public DepthFileSelector() {
-    this(0, Integer.MAX_VALUE);
-  }
-
-  /**
-   * Create a file selector that will select all files up to and including
-   * the directory depth.
-   *
-   * @param depth the maximum depth
-   */
-  public DepthFileSelector(int depth) {
-    this(0, depth);
-  }
-
-  public DepthFileSelector(int min, int max) {
-    minDepth = min;
-    maxDepth = max;
-  }
-
-  public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception {
-    int depth = fileSelectInfo.getDepth();
-    return depth >= minDepth && depth <= maxDepth;
-  }
-
-  public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws Exception {
-    return fileSelectInfo.getDepth() < maxDepth;
-  }
-}
blob - 1dd702d68b6fbe36e2acde95debb98faa1b29a0f (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/S3FileName.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import org.apache.commons.vfs.FileType;
-import org.apache.commons.vfs.provider.local.LocalFileName;
-
-/**
- * @author Matthias L. Jugel
- */
-public class S3FileName extends LocalFileName {
-  protected S3FileName(final String scheme, final String rootFile, final String path, final FileType type) {
-    super(scheme, rootFile, path, type);
-  }
-}
blob - 34a5d56d0239c568932ce009f30c10cda2b451c7 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/S3FileNameParser.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import org.apache.commons.vfs.FileName;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileType;
-import org.apache.commons.vfs.provider.AbstractFileNameParser;
-import org.apache.commons.vfs.provider.UriParser;
-import org.apache.commons.vfs.provider.VfsComponentContext;
-
-/**
- * @author Matthias L. Jugel
- */
-public class S3FileNameParser extends AbstractFileNameParser {
-  private static final S3FileNameParser instance = new S3FileNameParser();
-
-  public static S3FileNameParser getInstance() {
-    return instance;
-  }
-
-  private S3FileNameParser() {
-
-  }
-
-  public FileName parseUri(final VfsComponentContext context, final FileName base, final String filename) throws FileSystemException {
-    StringBuffer name = new StringBuffer();
-
-    String scheme = UriParser.extractScheme(filename, name);
-    UriParser.canonicalizePath(name, 0, name.length(), this);
-
-    UriParser.fixSeparators(name);
-
-    // Normalise the path
-    FileType fileType = UriParser.normalisePath(name);
-
-    // Extract the root prefix
-    final String bucketName = UriParser.extractFirstElement(name);
-
-
-    return new S3FileName(scheme, bucketName, name.toString(), fileType);
-  }
-
-}
blob - 8caafbfd75cd2ba1fa4dbd73d893b8cd3df66fd1 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/S3FileProvider.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import org.apache.commons.vfs.*;
-import org.apache.commons.vfs.provider.AbstractOriginatingFileProvider;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * An S3 file provider. Create an S3 file system out of an S3 file name.
- * Also defines the capabilities of the file system.
- *
- * @author Matthias L. Jugel
- */
-public class S3FileProvider extends AbstractOriginatingFileProvider {
-
-  public final static Collection<Capability> capabilities = Collections.unmodifiableCollection(Arrays.asList(
-          Capability.CREATE,
-          Capability.DELETE,
-          Capability.RENAME,
-          Capability.GET_TYPE,
-          Capability.GET_LAST_MODIFIED,
-          Capability.SET_LAST_MODIFIED_FILE,
-          Capability.SET_LAST_MODIFIED_FOLDER,
-          Capability.LIST_CHILDREN,
-          Capability.READ_CONTENT,
-          Capability.URI,
-          Capability.WRITE_CONTENT,
-          Capability.APPEND_CONTENT/*,
-          Capability.RANDOM_ACCESS_READ,
-          Capability.RANDOM_ACCESS_WRITE*/
-
-  ));
-
-  public S3FileProvider() {
-    super();
-    setFileNameParser(S3FileNameParser.getInstance());
-  }
-
-  /**
-   * Create a file system with the S3 root provided.
-   *
-   * @param fileName          the S3 file name that defines the root (bucket)
-   * @param fileSystemOptions file system options
-   * @return an S3 file system
-   * @throws FileSystemException if te file system cannot be created
-   */
-  protected FileSystem doCreateFileSystem(FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException {
-    return S3FileSystemFactory.getFileSystem((S3FileName) fileName, fileSystemOptions);
-  }
-
-  /**
-   * Get the capabilities of the file system provider.
-   *
-   * @return the file system capabilities
-   */
-  public Collection getCapabilities() {
-    return capabilities;
-  }
-}
blob - 27fc92eae78c75b11491a79b35cad2fdb8444ed9 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/S3FileSystemFactory.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import com.thinkberg.moxo.vfs.jets3t.Jets3tFileSystem;
-import org.apache.commons.vfs.FileSystem;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileSystemOptions;
-
-/**
- * @author Matthias L. Jugel
- */
-public class S3FileSystemFactory {
-  public static FileSystem getFileSystem(S3FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException {
-    // TODO load dynamically
-    return new Jets3tFileSystem(fileName, fileSystemOptions);
-  }
-}
blob - 1f080072887e8f54191f85b14ae1e3d922de11bc (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/jets3t/Jets3tConnector.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs.jets3t;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jets3t.service.Jets3tProperties;
-import org.jets3t.service.S3Service;
-import org.jets3t.service.S3ServiceException;
-import org.jets3t.service.impl.rest.httpclient.RestS3Service;
-import org.jets3t.service.security.AWSCredentials;
-
-/**
- * @author Matthias L. Jugel
- */
-public class Jets3tConnector {
-  private static final Log LOG = LogFactory.getLog(Jets3tConnector.class);
-
-  private static final String APPLICATION_DESCRIPTION = "S3 VFS Connector/1.0";
-
-  private static Jets3tConnector instance;
-
-  /**
-   * Get an instance of the Jets3tConnector which is initialized and authenticated to the
-   * Amazon S3 Service.
-   *
-   * @return a Jets3t S3 connector
-   * @throws org.jets3t.service.S3ServiceException
-   *          if connection or authentication fails
-   */
-  public static Jets3tConnector getInstance() throws S3ServiceException {
-    if (null == instance) {
-      instance = new Jets3tConnector();
-    }
-    return instance;
-  }
-
-  private S3Service service;
-
-  /**
-   * Initialize Amazon S3.
-   *
-   * @throws org.jets3t.service.S3ServiceException
-   *          if the service cannot be accessed
-   */
-  private Jets3tConnector() throws S3ServiceException {
-    String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties");
-    Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName);
-
-    if (!properties.isLoaded()) {
-      throw new S3ServiceException("can't find S3 configuration: " + propertiesFileName);
-    }
-
-
-    AWSCredentials awsCredentials = new AWSCredentials(
-            properties.getStringProperty("accesskey", null),
-            properties.getStringProperty("secretkey", null));
-
-
-    service = new RestS3Service(awsCredentials, APPLICATION_DESCRIPTION, null);
-    LOG.info("S3 authentication succeeded");
-  }
-
-  public S3Service getService() {
-    return service;
-  }
-}
blob - e5e4ff824521e982ee015ee38c6ab14d746cbc0a (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/jets3t/Jets3tFileObject.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs.jets3t;
-
-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.provider.AbstractFileObject;
-import org.apache.commons.vfs.util.MonitorOutputStream;
-import org.jets3t.service.Constants;
-import org.jets3t.service.S3Service;
-import org.jets3t.service.S3ServiceException;
-import org.jets3t.service.model.S3Bucket;
-import org.jets3t.service.model.S3Object;
-import org.jets3t.service.utils.Mimetypes;
-
-import java.io.*;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.nio.channels.ReadableByteChannel;
-import java.util.Date;
-
-
-/**
- * Implementation of the virtual S3 file system object using the Jets3t library.
- *
- * @author Matthias L. Jugel
- */
-public class Jets3tFileObject extends AbstractFileObject {
-  private static final Log LOG = LogFactory.getLog(Jets3tFileObject.class);
-
-  private static final String VFS_LAST_MODIFIED_TIME = "vfs-last-modified-time";
-
-  private final S3Service service;
-  private final S3Bucket bucket;
-
-  private boolean attached = false;
-  private boolean dirty = false;
-  private boolean contentCached = false;
-
-  private S3Object object;
-  private File cacheFile;
-
-  public Jets3tFileObject(FileName fileName,
-                          Jets3tFileSystem fileSystem,
-                          S3Service service, S3Bucket bucket) {
-    super(fileName, fileSystem);
-    this.service = service;
-    this.bucket = bucket;
-  }
-
-  /**
-   * Attach S3 Object to VFS object.
-   * This method only downloads the meta-data without the actual content.
-   * If the object does not exist, it will be created locally.
-   *
-   * @throws Exception if the S3 access fails for some reason
-   */
-  protected void doAttach() throws Exception {
-    if (!attached) {
-      try {
-        object = service.getObjectDetails(bucket, getS3Key());
-        if (object.getMetadata(VFS_LAST_MODIFIED_TIME) == null) {
-          // it is possible the bucket has no last-modified data, use the S3 data then
-          object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + object.getLastModifiedDate().getTime());
-        }
-        contentCached = false;
-        dirty = false;
-
-        LOG.debug(String.format("attaching (existing) '%s'", object.getKey()));
-      } catch (S3ServiceException e) {
-        object = new S3Object(bucket, getS3Key());
-        object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + new Date().getTime());
-        contentCached = true;
-        dirty = true;
-
-        LOG.debug(String.format("attaching (new) '%s'", object.getKey()));
-      }
-
-      attached = true;
-    }
-  }
-
-  protected void doDetach() throws Exception {
-    if (attached) {
-      LOG.debug(String.format("detaching '%s' (dirty=%b, cached=%b)", object.getKey(), dirty, (cacheFile != null)));
-      object = null;
-      if (cacheFile != null) {
-        cacheFile.delete();
-        cacheFile = null;
-        contentCached = false;
-      }
-      dirty = false;
-      attached = false;
-    }
-  }
-
-  protected void doDelete() throws Exception {
-    // do not delete the root folder
-    if ("".equals(object.getKey())) {
-      LOG.warn(String.format("ignored attempt to delete root folder '%s' ", bucket.getName()));
-      return;
-    }
-    LOG.debug(String.format("deleting '%s'", object.getKey()));
-    service.deleteObject(bucket, object.getKey());
-    if (cacheFile != null) {
-      cacheFile.delete();
-      cacheFile = null;
-      contentCached = false;
-    }
-    dirty = false;
-    attached = false;
-  }
-
-  protected void doRename(FileObject newfile) throws Exception {
-    super.doRename(newfile);
-  }
-
-  protected void doCreateFolder() throws Exception {
-    if (!Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(object.getContentType())) {
-      object.setContentType(Mimetypes.MIMETYPE_JETS3T_DIRECTORY);
-
-      LOG.debug(String.format("creating folder '%s'", object.getKey()));
-      service.putObject(bucket, object);
-    }
-  }
-
-  protected long doGetLastModifiedTime() throws Exception {
-    String timeStamp = (String) object.getMetadata(VFS_LAST_MODIFIED_TIME);
-    if (null != timeStamp) {
-      return Long.parseLong(timeStamp);
-    }
-    return 0;
-  }
-
-  protected void doSetLastModifiedTime(final long modtime) throws Exception {
-    object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, modtime);
-    dirty = true;
-  }
-
-  protected InputStream doGetInputStream() throws Exception {
-    if (!contentCached) {
-      object = service.getObject(bucket, getS3Key());
-      LOG.debug(String.format("caching content of '%s'", object.getKey()));
-
-      InputStream objectInputStream = object.getDataInputStream();
-      if (object.getContentLength() > 0) {
-        ReadableByteChannel rbc = Channels.newChannel(objectInputStream);
-        FileChannel cacheFc = getCacheFile().getChannel();
-        cacheFc.transferFrom(rbc, 0, object.getContentLength());
-        cacheFc.close();
-        rbc.close();
-      } else {
-        objectInputStream.close();
-      }
-      contentCached = true;
-    }
-
-    return Channels.newInputStream(getCacheFile().getChannel());
-  }
-
-  protected OutputStream doGetOutputStream(boolean bAppend) throws Exception {
-    dirty = true;
-    return new MonitorOutputStream(Channels.newOutputStream(getCacheFile().getChannel())) {
-      protected void onClose() throws IOException {
-        try {
-          LOG.debug(String.format("sending '%s' to storage (dirty=%b, cached=%b)", object.getKey(), dirty, cacheFile));
-          if (cacheFile != null) {
-            FileChannel cacheFc = getCacheFile().getChannel();
-            object.setContentLength(cacheFc.size());
-            object.setDataInputStream(Channels.newInputStream(cacheFc));
-          }
-          service.putObject(bucket, object);
-        } catch (S3ServiceException e) {
-          LOG.error(String.format("can't send object '%s' to storage", object.getKey()), e);
-        }
-      }
-    };
-  }
-
-  protected FileType doGetType() throws Exception {
-    if (null == object.getContentType()) {
-      return FileType.IMAGINARY;
-    }
-
-    String contentType = object.getContentType();
-    if ("".equals(object.getKey()) || Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(contentType)) {
-      return FileType.FOLDER;
-    }
-
-    return FileType.FILE;
-  }
-
-  protected String[] doListChildren() throws Exception {
-    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("[^/]*//*", "");
-      }
-    }
-
-    return childrenNames;
-  }
-
-  protected long doGetContentSize() throws Exception {
-    return object.getContentLength();
-  }
-
-  // Utility methods
-  /**
-   * Create an S3 key from a commons-vfs path. This simply
-   * strips the slash from the beginning if it exists.
-   *
-   * @return the S3 object key
-   */
-  private String getS3Key() {
-    String path = getName().getPath();
-    if ("".equals(path)) {
-      return path;
-    } else {
-      return path.substring(1);
-    }
-  }
-
-  private RandomAccessFile getCacheFile() throws IOException, S3ServiceException {
-    if (cacheFile == null) {
-      cacheFile = File.createTempFile("moxo.", ".s3");
-    }
-    return new RandomAccessFile(cacheFile, "rw");
-  }
-}
blob - 1c80a615bbd89066c8f4fccfe435b9b490d829b9 (mode 644)
blob + /dev/null
--- src/main/java/com/thinkberg/moxo/vfs/jets3t/Jets3tFileSystem.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs.jets3t;
-
-import com.thinkberg.moxo.vfs.S3FileName;
-import com.thinkberg.moxo.vfs.S3FileProvider;
-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.FileSystemException;
-import org.apache.commons.vfs.FileSystemOptions;
-import org.apache.commons.vfs.provider.AbstractFileSystem;
-import org.jets3t.service.S3Service;
-import org.jets3t.service.S3ServiceException;
-import org.jets3t.service.model.S3Bucket;
-
-import java.util.Collection;
-
-/**
- * An S3 file system.
- *
- * @author Matthias L. Jugel
- */
-public class Jets3tFileSystem extends AbstractFileSystem {
-  private static final Log LOG = LogFactory.getLog(Jets3tFileSystem.class);
-
-  private S3Service service;
-  private S3Bucket bucket;
-
-  public Jets3tFileSystem(S3FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException {
-    super(fileName, null, fileSystemOptions);
-    String bucketId = fileName.getRootFile();
-    try {
-      service = Jets3tConnector.getInstance().getService();
-      if (!service.isBucketAccessible(bucketId)) {
-        LOG.info(String.format("creating new S3 bucket '%s' for file system root", bucketId));
-        bucket = service.createBucket(bucketId);
-      } else {
-        LOG.info(String.format("using existing S3 bucket '%s' for file system root", bucketId));
-        bucket = new S3Bucket(bucketId);
-      }
-    } catch (S3ServiceException e) {
-      throw new FileSystemException(e);
-    }
-  }
-
-  public void destroyFileSystem() throws FileSystemException {
-    try {
-      service.deleteBucket(bucket);
-    } catch (S3ServiceException e) {
-      throw new FileSystemException("can't delete file system root", e);
-    }
-
-
-  }
-
-  @SuppressWarnings({"unchecked"})
-  protected void addCapabilities(Collection caps) {
-    caps.addAll(S3FileProvider.capabilities);
-  }
-
-  protected FileObject createFile(FileName fileName) throws Exception {
-    return new Jets3tFileObject(fileName, this, service, bucket);
-  }
-
-
-}
blob - 686c14998f8bbad319b7f2e07f193ecb66f3cbb8 (mode 644)
blob + /dev/null
--- src/main/resources/META-INF/vfs-providers.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  ~ Copyright 2007 Matthias L. Jugel.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~        http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<providers>
-
-  <provider class-name="com.thinkberg.moxo.vfs.S3FileProvider">
-    <scheme name="s3"/>
-    <if-available class-name="org.jets3t.service.S3Service"/>
-  </provider>
-
-</providers>
blob - 3067e4fa327fbd14e218e7adccae96656857cc6b
blob + 71c406fc4d38c233930be39548d9d3767b2a5d3b
--- src/main/resources/jetty.xml
+++ src/main/resources/jetty.xml
@@ -130,9 +130,26 @@
                 <SystemProperty name="jetty.docroot" default="."/>
             </Set>
             <Call name="addServlet">
-                <Arg>com.thinkberg.moxo.servlet.MoxoWebDAVServlet</Arg>
+                <Arg>com.thinkberg.webdav.servlet.MoxoWebDAVServlet</Arg>
                 <Arg>/*</Arg>
+                <Call name="setInitParameter">
+                    <Arg>vfs.uri</Arg>
+                    <Arg>ram:/</Arg>
+                </Call>
+                <Call name="setInitParameter">
+                    <Arg>vfs.auth.domain</Arg>
+                    <Arg></Arg>
+                </Call>
+                <Call name="setInitParameter">
+                    <Arg>vfs.auth.user</Arg>
+                    <Arg>theuser</Arg>
+                </Call>
+                <Call name="setInitParameter">
+                    <Arg>vfs.auth.password</Arg>
+                    <Arg>thepassword</Arg>
+                </Call>
             </Call>
+
         </New>
     </Set>
 
blob - 2431b8fe9d36132a3fa0f91baef89bc9df06ccc6 (mode 644)
blob + /dev/null
--- src/main/resources/moxo.template.properties
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright 2007 Matthias L. Jugel.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-#####################################
-# VFS provider application properties
-#
-# This file must be available on the 
-# classpath when the VFS is used
-####################################
-
-# AWS Access Key (required)
-accesskey=<your AWS access key here>
-
-# AWS Secret Key (required)
-secretkey=<your AWS secret key here>
-
-# Access Control List setting to apply to uploads, must be one of: PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE
-# The ACL setting defaults to PRIVATE if this setting is missing.
-acl=PRIVATE
-
-# Password used when encrypting/decrypting files. Only required when the --crypto setting is used.
-password=<some encryption password here>
-
-# the bucket that contains the file system
-s3.url=s3://TESTBUCKET/
-#s3.url=ram:/
\ No newline at end of file
blob - 674ed457589717c031e07eeae6ec32eea0b1deb7 (mode 644)
blob + /dev/null
--- src/test/java/com/thinkberg/moxo/MoxoTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.thinkberg.moxo;
-
-import com.thinkberg.moxo.dav.DavLockManagerTest;
-import com.thinkberg.moxo.dav.DavResourceTest;
-import com.thinkberg.moxo.vfs.S3FileNameTest;
-import com.thinkberg.moxo.vfs.S3FileProviderTest;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-import org.jets3t.service.Jets3tProperties;
-
-/**
- * Unit tests for the Moxo S3 Amazon Proxy server.
- *
- * @author Matthias L. Jugel
- */
-public class MoxoTest extends TestCase {
-  /**
-   * The complete Moxo Test suite.
-   *
-   * @param name name of the test case
-   */
-  public MoxoTest(String name) {
-    super(name);
-  }
-
-  /**
-   * Add all known tests to the suite.
-   *
-   * @return the suite of tests being tested
-   */
-  public static Test suite() {
-    TestSuite s = new TestSuite();
-
-    s.addTestSuite(DavResourceTest.class);
-    s.addTestSuite(DavLockManagerTest.class);
-
-    String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties");
-    Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName);
-
-    String vfsUrl = properties.getStringProperty("vfs.uri", null);
-    if (null != vfsUrl && vfsUrl.startsWith("s3:")) {
-      s.addTestSuite(S3FileNameTest.class);
-      s.addTestSuite(S3FileProviderTest.class);
-    }
-
-    return s;
-  }
-
-
-}
blob - df58a524ec201431dcad1cd542b86f58aed5384d (mode 644)
blob + /dev/null
--- src/test/java/com/thinkberg/moxo/dav/DavLockManagerTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.lock.Lock;
-import com.thinkberg.moxo.dav.lock.LockConflictException;
-import com.thinkberg.moxo.dav.lock.LockManager;
-
-/**
- * @author Matthias L. Jugel
- */
-public class DavLockManagerTest extends DavTestCase {
-  private final String OWNER_STR = "testowner";
-
-  public DavLockManagerTest() {
-    super();
-  }
-
-  public void testAcquireSingleSharedFileLock() {
-    Lock sharedLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    try {
-      LockManager.getInstance().acquireLock(sharedLock);
-    } catch (Exception e) {
-      assertNull(e.getMessage(), e);
-    }
-  }
-
-  public void testAcquireDoubleSharedFileLock() {
-    Lock sharedLock1 = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    Lock sharedLock2 = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR + "1", 0, 3600);
-    try {
-      LockManager.getInstance().acquireLock(sharedLock1);
-      LockManager.getInstance().acquireLock(sharedLock2);
-    } catch (Exception e) {
-      assertNull(e.getMessage(), e);
-    }
-  }
-
-  public void testFailToAcquireExclusiveLockOverSharedLock() {
-    Lock sharedLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    Lock exclusiveLock = new Lock(aFile, Lock.WRITE, Lock.EXCLUSIVE, OWNER_STR, 0, 3600);
-    try {
-      LockManager.getInstance().acquireLock(sharedLock);
-      LockManager.getInstance().acquireLock(exclusiveLock);
-      assertTrue("acquireLock() should fail", false);
-    } catch (Exception e) {
-      assertEquals(LockConflictException.class, e.getClass());
-    }
-  }
-
-  public void testConditionUnmappedFails() throws Exception {
-    final String condition = "<http://cid:8080/litmus/unmapped_url> (<opaquelocktoken:cd6798>)";
-    assertFalse("condition for unmapped resource must fail",
-                LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-  public void testConditionSimpleLockToken() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String condition = "(<" + aLock.getToken() + ">)";
-    LockManager.getInstance().acquireLock(aLock);
-    assertTrue("condition with existing lock token should not fail",
-               LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-  public void testConditionSimpleLockLokenWrong() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String condition = "(<" + aLock.getToken() + "x>)";
-    LockManager.getInstance().acquireLock(aLock);
-    try {
-      LockManager.getInstance().evaluateCondition(aFile, condition);
-    } catch (LockConflictException e) {
-      assertFalse("condition with wrong lock token must fail on locked resource", e.getLocks().isEmpty());
-    }
-  }
-
-  public void testConditionSimpleLockTokenAndETag() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String condition = "(<" + aLock.getToken() + "> [" + Integer.toHexString(aFile.hashCode()) + "])";
-    LockManager.getInstance().acquireLock(aLock);
-    assertTrue("condition with existing lock token and correct ETag should not fail",
-               LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-  public void testConditionSimpleLockTokenWrongAndETag() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String condition = "(<" + aLock.getToken() + "x> [" + Integer.toHexString(aFile.hashCode()) + "])";
-    LockManager.getInstance().acquireLock(aLock);
-    try {
-      LockManager.getInstance().evaluateCondition(aFile, condition);
-    } catch (LockConflictException e) {
-      assertFalse("condition with non-existing lock token and correct ETag should fail",
-                  e.getLocks().isEmpty());
-    }
-  }
-
-  public void testConditionSimpleLockTokenAndETagWrong() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String condition = "(<" + aLock.getToken() + "> [" + Integer.toHexString(aFile.hashCode()) + "x])";
-    LockManager.getInstance().acquireLock(aLock);
-    assertFalse("condition with existing lock token and incorrect ETag should fail",
-                LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-  public void testConditionSimpleLockTokenWrongAndETagWrong() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String condition = "(<" + aLock.getToken() + "x> [" + Integer.toHexString(aFile.hashCode()) + "x])";
-    LockManager.getInstance().acquireLock(aLock);
-    assertFalse("condition with non-existing lock token and incorrect ETag should fail",
-                LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-  public void testConditionSimpleLockTokenWrongAndETagOrSimpleETag() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String eTag = Integer.toHexString(aFile.hashCode());
-    final String condition = "(<" + aLock.getToken() + "x> [" + eTag + "]) ([" + eTag + "])";
-    LockManager.getInstance().acquireLock(aLock);
-    try {
-      LockManager.getInstance().evaluateCondition(aFile, condition);
-    } catch (LockConflictException e) {
-      assertFalse("condition with one correct ETag in list should not fail on locked resource",
-                  e.getLocks().isEmpty());
-    }
-  }
-
-  public void testConditionSimpleNegatedLockTokenWrongAndETag() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String eTag = Integer.toHexString(aFile.hashCode());
-    final String condition = "(Not <" + aLock.getToken() + "x> [" + eTag + "])";
-    assertTrue("condition with negated wrong lock token and correct ETag should not fail on unlocked resource",
-               LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-
-  public void testConditionMustNotFail() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String condition = "(<" + aLock.getToken() + "x>) (Not <DAV:no-lock>)";
-    assertTrue("using (Not <DAV:no-lock>) in condition list must not fail on unlocked resource",
-               LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-
-  public void testComplexConditionWithBogusLockToken() throws Exception {
-    Lock aLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-    final String eTag = Integer.toHexString(aFile.hashCode());
-    final String condition = "(<" + aLock.getToken() + "> [" + eTag + "x]) (Not <DAV:no-lock> [" + eTag + "x])";
-    LockManager.getInstance().acquireLock(aLock);
-    assertFalse("complex condition with bogus eTag should fail",
-                LockManager.getInstance().evaluateCondition(aFile, condition).result);
-  }
-
-
-//  assertFalse(lockManager.evaluateCondition(aFile, "</resource1> (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> [W/\"A weak ETag\"]) ([\"strong ETag\"])");
-//  lockManager.evaluateCondition(aFile, "(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>) (Not <DAV:no-lock>)");
-//  lockManager.evaluateCondition(aFile, "(Not <urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> <urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092>)");
-//  lockManager.evaluateCondition(aFile, "</specs/rfc2518.doc> ([\"4217\"])");
-//  lockManager.evaluateCondition(aFile, "</specs/rfc2518.doc> (Not [\"4217\"])");
-//  lockManager.evaluateCondition(aFile, "(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>) (Not <DAV:no-lock>) </specs/rfc2518.doc> (Not [\"4217\"])");
-//  lockManager.evaluateCondition(aFile, "(<opaquelocktoken:10a098> [10a198]) (Not <DAV:no-lock> [10a198])");
-
-//  public void testLockConditionRequiredException() {
-//    Lock sharedLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600);
-//    try {
-//      LockManager.getInstance().acquireLock(sharedLock);
-//      LockManager.getInstance().checkCondition(aFile, null);
-//      assertTrue("checkCondition() should fail", false);
-//    } catch (Exception e) {
-//      assertEquals(LockConditionRequiredException.class, e.getClass());
-//    }
-//  }
-}
blob - 66f3e2ed8c1495e69dd6a684bf30ad748976367b (mode 644)
blob + /dev/null
--- src/test/java/com/thinkberg/moxo/dav/DavResourceTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.data.DavCollection;
-import com.thinkberg.moxo.dav.data.DavResource;
-import org.apache.commons.vfs.FileSystemException;
-import org.dom4j.Element;
-
-import java.io.IOException;
-
-/**
- * Test case for the DAV resource wrapper. Checks that resources are serialized
- * correctly.
- *
- * @author Matthias L. Jugel
- */
-public class DavResourceTest extends DavTestCase {
-  public void testFileCreationDateIsNull() throws FileSystemException {
-    Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE);
-    assertNull(selectExistingProperty(root, DavResource.PROP_CREATION_DATE));
-  }
-
-  public void testFileCreationDateIsMissing() throws IOException {
-    Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE);
-    assertEquals(DavResource.PROP_CREATION_DATE,
-                 selectMissingPropertyName(root, DavResource.PROP_CREATION_DATE));
-  }
-
-  public void testFileDisplayNameWithValue() throws FileSystemException {
-    testPropertyValue(aFile, DavResource.PROP_DISPLAY_NAME, aFile.getName().getBaseName());
-  }
-
-  public void testFileDisplayNameWithoutValue() throws FileSystemException {
-    testPropertyNoValue(aFile, DavResource.PROP_DISPLAY_NAME);
-  }
-
-  public void testFileResourceTypeNotMissing() throws FileSystemException {
-    Element root = serializeDavResource(aFile, DavResource.PROP_RESOURCETYPE);
-    assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE));
-  }
-
-  public void testDirectoryResourceTypeNotMissing() throws FileSystemException {
-    Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE);
-    assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE));
-  }
-
-  public void testFileResourceType() throws FileSystemException {
-    testPropertyNoValue(aFile, DavResource.PROP_RESOURCETYPE);
-  }
-
-  public void testDirectoryResourceType() throws FileSystemException {
-    Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE);
-    assertNotNull(selectExistingProperty(root, DavResource.PROP_RESOURCETYPE).selectSingleNode(DavCollection.COLLECTION));
-  }
-}
blob - c348a78e06fa4feda0222993ce6a971a7d0994fa (mode 644)
blob + /dev/null
--- src/test/java/com/thinkberg/moxo/dav/DavTestCase.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.thinkberg.moxo.dav;
-
-import com.thinkberg.moxo.dav.data.DavResource;
-import com.thinkberg.moxo.dav.data.DavResourceFactory;
-import junit.framework.TestCase;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileSystemManager;
-import org.apache.commons.vfs.VFS;
-import org.dom4j.DocumentHelper;
-import org.dom4j.Element;
-import org.dom4j.Node;
-
-import java.util.Arrays;
-
-/**
- * Helper class for DAV tests.
- *
- * @author Matthias L. Jugel
- */
-public class DavTestCase extends TestCase {
-  private static final String PROP_EXISTS = "propstat[status='HTTP/1.1 200 OK']/prop/";
-  private static final String PROP_MISSING = "propstat[status='HTTP/1.1 404 Not Found']/prop/";
-  private static final String EMPTY = "";
-
-  FileObject aFile;
-  FileObject aDirectory;
-
-
-  protected void setUp() throws Exception {
-    super.setUp();
-    FileSystemManager fsm = VFS.getManager();
-    FileObject fsRoot = fsm.createVirtualFileSystem(fsm.resolveFile("ram:/"));
-    aFile = fsRoot.resolveFile("/file.txt");
-    aFile.delete();
-    aFile.createFile();
-    aDirectory = fsRoot.resolveFile("/folder");
-    aDirectory.delete();
-    aDirectory.createFolder();
-  }
-
-  protected void testPropertyValue(FileObject object, String propertyName, String propertyValue) throws FileSystemException {
-    Element root = serializeDavResource(object, propertyName);
-    assertEquals(propertyValue, selectExistingPropertyValue(root, propertyName));
-  }
-
-  protected void testPropertyNoValue(FileObject object, String propertyName) throws FileSystemException {
-    Element root = serializeDavResource(object, propertyName, true);
-    assertEquals(EMPTY, selectExistingPropertyValue(root, propertyName));
-  }
-
-  Node selectExistingProperty(Element root, String propertyName) {
-    return root.selectSingleNode(PROP_EXISTS + propertyName);
-  }
-
-  Node selectMissingProperty(Element root, String propertyName) {
-    return root.selectSingleNode(PROP_MISSING + propertyName);
-  }
-
-  String selectMissingPropertyName(Element root, String propertyName) {
-    return selectMissingProperty(root, propertyName).getName();
-  }
-
-  private String selectExistingPropertyValue(Element root, String propertyName) {
-    return selectExistingProperty(root, propertyName).getText();
-  }
-
-  Element serializeDavResource(FileObject object, String propertyName) throws FileSystemException {
-    return serializeDavResource(object, propertyName, false);
-  }
-
-  private Element serializeDavResource(FileObject object, String propertyName, boolean ignoreValues) throws FileSystemException {
-    Element root = DocumentHelper.createElement("root");
-    DavResourceFactory factory = DavResourceFactory.getInstance();
-    DavResource davResource = factory.getDavResource(object);
-    davResource.setIgnoreValues(ignoreValues);
-    davResource.serializeToXml(root, Arrays.asList(propertyName));
-    return root;
-  }
-
-}
blob - cad1af21c05c18a65efeb78b403be26e71fca272 (mode 644)
blob + /dev/null
--- src/test/java/com/thinkberg/moxo/vfs/S3FileNameTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import org.apache.commons.vfs.FileName;
-import org.apache.commons.vfs.FileSystemException;
-
-import java.net.URI;
-
-/**
- * @author Matthias L. Jugel
- */
-public class S3FileNameTest extends S3TestCase {
-  public void testGetBucketFromUri() throws FileSystemException {
-    String uriString = ROOT + "/junk.txt";
-    String bucketId = URI.create(uriString).getHost();
-    FileName fileName = S3FileNameParser.getInstance().parseUri(null, null, uriString);
-    assertEquals(bucketId, ((S3FileName) fileName).getRootFile());
-  }
-
-  public void testGetRootFolderFromUri() throws FileSystemException {
-    String path = "/myfolder";
-    String uri = ROOT + path;
-    FileName fileName = S3FileNameParser.getInstance().parseUri(null, null, uri);
-    assertEquals(path, fileName.getPath());
-  }
-}
blob - 5b2ab9887bbf9efd98ff97084bc3b832cb1ed6ef (mode 644)
blob + /dev/null
--- src/test/java/com/thinkberg/moxo/vfs/S3FileProviderTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import com.thinkberg.moxo.vfs.jets3t.Jets3tFileSystem;
-import org.apache.commons.vfs.*;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.URI;
-import java.util.Arrays;
-
-/**
- * @author Matthias L. Jugel
- */
-public class S3FileProviderTest extends S3TestCase {
-  private static final FileSelector ALL_FILE_SELECTOR = new FileSelector() {
-
-    public boolean includeFile(FileSelectInfo fileInfo) throws Exception {
-      return true;
-    }
-
-    public boolean traverseDescendents(FileSelectInfo fileInfo) throws Exception {
-      return true;
-    }
-  };
-  private static final String FOLDER = "/directory";
-  private static final String FILE = FOLDER + "/newfile.txt";
-
-  static {
-    try {
-      FileObject rootFs = VFS.getManager().resolveFile(ROOT);
-      rootFs.delete(ALL_FILE_SELECTOR);
-    } catch (FileSystemException e) {
-      // just delete, ignore the rest
-    }
-  }
-
-  public void testDoCreateFileSystem() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT);
-    String bucketId = URI.create(ROOT).getHost();
-    assertEquals(bucketId, ((S3FileName) object.getName()).getRootFile());
-  }
-
-
-  public void testFileSystemIsEmpty() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT);
-    assertEquals(1, object.findFiles(ALL_FILE_SELECTOR).length);
-  }
-
-  public void testRootDirectoryIsFolder() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT);
-    assertEquals(FileType.FOLDER, object.getType());
-  }
-
-  public void testCreateFolder() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER);
-    assertFalse(object.exists());
-    object.createFolder();
-    assertTrue(object.exists());
-    assertEquals(FileType.FOLDER, object.getType());
-  }
-
-  public void testGetFolder() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER);
-    assertTrue(object.exists());
-    assertEquals(FileType.FOLDER, object.getType());
-  }
-
-  public void testCreateFile() throws IOException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FILE);
-    assertFalse(object.exists());
-    OutputStream os = object.getContent().getOutputStream();
-    os.write(0xfc);
-    os.close();
-    assertTrue(object.exists());
-    assertEquals(FileType.FILE, object.getType());
-  }
-
-  public void testCreateEmptyFile() throws IOException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FILE + ".empty");
-    assertFalse(object.exists());
-    object.createFile();
-    assertTrue(object.exists());
-    assertEquals(FileType.FILE, object.getType());
-  }
-
-  public void testFileHasLastModifiedTimestamp() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FILE);
-    object.getContent().getLastModifiedTime();
-  }
-
-  public void testGetFolderListing() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER);
-    FileObject[] files = object.findFiles(new DepthFileSelector(1));
-    assertEquals(3, files.length);
-  }
-
-  public void testMissingFile() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + "/nonexisting.txt");
-    assertFalse(object.exists());
-  }
-
-  public void testGetLastModifiedTimeFolder() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER);
-    object.getContent().getLastModifiedTime();
-  }
-
-  public void testGetLastModifiedTimeFile() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FILE);
-    object.getContent().getLastModifiedTime();
-  }
-
-  public void testDeleteFile() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FILE);
-    object.delete();
-    assertFalse(object.exists());
-  }
-
-  public void testDeleteFolder() throws FileSystemException {
-    FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER);
-    object.delete(ALL_FILE_SELECTOR);
-    assertFalse(object.exists());
-  }
-
-  public void testCopyFolder() throws FileSystemException {
-    FileObject origFolder = VFS.getManager().resolveFile(ROOT + FOLDER);
-    origFolder.createFolder();
-
-    origFolder.resolveFile("file.0").createFile();
-    origFolder.resolveFile("file.1").createFile();
-    origFolder.resolveFile("file.2").createFile();
-
-    FileObject[] origFiles = origFolder.findFiles(new DepthFileSelector(1));
-    assertEquals(4, origFiles.length);
-
-    FileObject destFolder = VFS.getManager().resolveFile(ROOT + FOLDER + "_dest");
-    assertFalse(destFolder.exists());
-    destFolder.copyFrom(origFolder, new DepthFileSelector(1));
-    assertTrue(destFolder.exists());
-
-    FileObject[] destFiles = destFolder.findFiles(new DepthFileSelector(1));
-    System.err.println(Arrays.asList(destFiles));
-    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()));
-    }
-
-    origFolder.delete(ALL_FILE_SELECTOR);
-    destFolder.delete(ALL_FILE_SELECTOR);
-
-    assertFalse(origFolder.exists());
-    assertFalse(destFolder.exists());
-  }
-
-//  public void testMoveFolder() throws FileSystemException {
-//
-//  }
-
-  public void testCloseFileSystem() throws FileSystemException {
-    FileSystem fs = VFS.getManager().resolveFile(ROOT).getFileSystem();
-    VFS.getManager().closeFileSystem(fs);
-  }
-
-  public void testDestroyFileSystem() throws FileSystemException {
-    FileSystem fs = VFS.getManager().resolveFile(ROOT).getFileSystem();
-    assertTrue(fs instanceof Jets3tFileSystem);
-    ((Jets3tFileSystem) fs).destroyFileSystem();
-  }
-}
blob - 76282b1a08134826075cca2b0d02c7972257af5c (mode 644)
blob + /dev/null
--- src/test/java/com/thinkberg/moxo/vfs/S3TestCase.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2007 Matthias L. Jugel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.thinkberg.moxo.vfs;
-
-import junit.framework.TestCase;
-import org.jets3t.service.Jets3tProperties;
-
-import java.util.Random;
-
-/**
- * @author Matthias L. Jugel
- */
-public class S3TestCase extends TestCase {
-  protected static final String ROOT;
-
-  static {
-    String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties");
-    Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName);
-    System.out.println("ignoring original vfs.url settings for test: " + properties.getStringProperty("vfs.uri", "ram:/"));
-    ROOT = "s3://MOXOTEST" + String.format("%X", new Random(System.currentTimeMillis()).nextLong()) + "/";
-    System.out.println("using " + ROOT);
-  }
-}