commit - c69f66ef9a0647aa8c88102bf4d4ff9eaa4c2d65
commit + 1939c62d29abc7a7d42c831f096b5cc27f4c1182
blob - 7ab330241c049a148fc7a2505e2460890c3acc73
blob + c14c5ba8b42a4c77c7dda6a647481be6ab4f0ce3
--- pom.xml
+++ pom.xml
<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>
<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>
<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
+<?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
+/*
+ * 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
+/*
+ * 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
+#
+# 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
+#
+# 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
+#
+# 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
+<?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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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> <http://cid:8080/litmus/unmapped_url> (<opaquelocktoken:cd6798>)</li>
+ * <li> </resource1> (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> [W/"A weak ETag"]) (["strong ETag"])</li>
+ * <li> (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>) (Not <DAV:no-lock>)</li>
+ * <li> (Not <urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> <urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092>)</li>
+ * <li> </specs/rfc2518.doc> (["4217"])</li>
+ * <li> </specs/rfc2518.doc> (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
+/*
+ * 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
+/*
+ * 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
+#
+# 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
+#
+# 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
+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
* @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");
}
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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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> <http://cid:8080/litmus/unmapped_url> (<opaquelocktoken:cd6798>)</li>
- * <li> </resource1> (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> [W/"A weak ETag"]) (["strong ETag"])</li>
- * <li> (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>) (Not <DAV:no-lock>)</li>
- * <li> (Not <urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> <urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092>)</li>
- * <li> </specs/rfc2518.doc> (["4217"])</li>
- * <li> </specs/rfc2518.doc> (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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-/*
- * 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
-<!--
- ~ 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
<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
-#
-# 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
-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
-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
-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
-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
-/*
- * 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
-/*
- * 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
-/*
- * 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);
- }
-}