commit 1939c62d29abc7a7d42c831f096b5cc27f4c1182 from: leo date: Mon Jan 26 20:25:04 2009 UTC refactored to separate dav and vfs into modules commit - c69f66ef9a0647aa8c88102bf4d4ff9eaa4c2d65 commit + 1939c62d29abc7a7d42c831f096b5cc27f4c1182 blob - 7ab330241c049a148fc7a2505e2460890c3acc73 blob + c14c5ba8b42a4c77c7dda6a647481be6ab4f0ce3 --- pom.xml +++ pom.xml @@ -3,22 +3,14 @@ 4.0.0 com.thinkberg.moxo moxo - jar + pom 1.0-SNAPSHOT + + modules/webdav + modules/vfs.s3 + Moxo S3 DAV Proxy http://thinkberg.com - - - codehaus-m2-repository - Codehaus Maven 2.x Repository - http://repository.codehaus.org - - - jets3t - jets3t - http://jets3t.s3.amazonaws.com/maven2 - - junit @@ -27,21 +19,6 @@ test - net.java.dev.jets3t - jets3t - 0.6.1 - - - commons-httpclient - commons-httpclient - 3.0.1 - - - commons-vfs - commons-vfs - 1.0 - - org.mortbay.jetty jetty 6.1.1 @@ -122,7 +99,7 @@ - com.thinkberg.moxo.MoxoJettyRunner + com.thinkberg.moxo.Main true blob - /dev/null blob + 4d645e1afa7c6fd288e8da760d89064436692577 (mode 644) --- /dev/null +++ modules/vfs.s3/pom.xml @@ -0,0 +1,82 @@ + + + + + + moxo + com.thinkberg.moxo + 1.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + vfs.s3 + 1.0-SNAPSHOT + thinkberg.com S3 VFS provider + + + codehaus-m2-repository + Codehaus Maven 2.x Repository + http://repository.codehaus.org + + + jets3t + jets3t + http://jets3t.s3.amazonaws.com/maven2 + + + + + net.java.dev.jets3t + jets3t + 0.6.1 + + + commons-httpclient + commons-httpclient + 3.0.1 + + + commons-vfs + commons-vfs + 1.0 + + + commons-collections + commons-collections + 3.2.1 + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/tests/*.java + + + + + + \ No newline at end of file blob - /dev/null blob + ff8178919c5992604e3c2cd499dda4b4f2804614 (mode 644) --- /dev/null +++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/jets3t/Jets3tFileObject.java @@ -0,0 +1,247 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.vfs.s3.jets3t; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs.FileName; +import org.apache.commons.vfs.FileObject; +import org.apache.commons.vfs.FileType; +import org.apache.commons.vfs.provider.AbstractFileObject; +import org.apache.commons.vfs.util.MonitorOutputStream; +import org.jets3t.service.Constants; +import org.jets3t.service.S3Service; +import org.jets3t.service.S3ServiceException; +import org.jets3t.service.model.S3Bucket; +import org.jets3t.service.model.S3Object; +import org.jets3t.service.utils.Mimetypes; + +import java.io.*; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.util.Date; + + +/** + * Implementation of the virtual S3 file system object using the Jets3t library. + * + * @author Matthias L. Jugel + */ +public class Jets3tFileObject extends AbstractFileObject { + private static final Log LOG = LogFactory.getLog(Jets3tFileObject.class); + + private static final String VFS_LAST_MODIFIED_TIME = "vfs-last-modified-time"; + + private final S3Service service; + private final S3Bucket bucket; + + private boolean attached = false; + private boolean contentCached = false; + + private S3Object object; + private File cacheFile; + + public Jets3tFileObject(FileName fileName, + Jets3tFileSystem fileSystem, + S3Service service, S3Bucket bucket) { + super(fileName, fileSystem); + this.service = service; + this.bucket = bucket; + } + + /** + * Attach S3 Object to VFS object. + * This method only downloads the meta-data without the actual content. + * If the object does not exist, it will be created locally. + * + * @throws Exception if the S3 access fails for some reason + */ + protected void doAttach() throws Exception { + if (!attached) { + try { + object = service.getObjectDetails(bucket, getS3Key()); + if (object.getMetadata(VFS_LAST_MODIFIED_TIME) == null) { + // it is possible the bucket has no last-modified data, use the S3 data then + object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + object.getLastModifiedDate().getTime()); + } + contentCached = false; + LOG.debug(String.format("attaching (existing) '%s'", object.getKey())); + } catch (S3ServiceException e) { + object = new S3Object(bucket, getS3Key()); + object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + new Date().getTime()); + contentCached = true; + LOG.debug(String.format("attaching (new) '%s'", object.getKey())); + } + + attached = true; + } + } + + protected void doDetach() throws Exception { + if (attached) { + LOG.debug(String.format("detaching '%s' (cached=%b)", object.getKey(), (cacheFile != null))); + object = null; + if (cacheFile != null) { + cacheFile.delete(); + cacheFile = null; + contentCached = false; + } + attached = false; + } + } + + protected void doDelete() throws Exception { + // do not delete the root folder + if ("".equals(object.getKey())) { + LOG.warn(String.format("ignored attempt to delete root folder '%s' ", bucket.getName())); + return; + } + LOG.debug(String.format("deleting '%s'", object.getKey())); + service.deleteObject(bucket, object.getKey()); + if (cacheFile != null) { + cacheFile.delete(); + cacheFile = null; + contentCached = false; + } + attached = false; + } + + protected void doRename(FileObject newfile) throws Exception { + super.doRename(newfile); + } + + protected void doCreateFolder() throws Exception { + if (!Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(object.getContentType())) { + object.setContentType(Mimetypes.MIMETYPE_JETS3T_DIRECTORY); + + LOG.debug(String.format("creating folder '%s'", object.getKey())); + service.putObject(bucket, object); + } + } + + protected long doGetLastModifiedTime() throws Exception { + String timeStamp = (String) object.getMetadata(VFS_LAST_MODIFIED_TIME); + if (null != timeStamp) { + return Long.parseLong(timeStamp); + } + return 0; + } + + protected void doSetLastModifiedTime(final long modtime) throws Exception { + object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, modtime); + } + + protected InputStream doGetInputStream() throws Exception { + if (!contentCached) { + object = service.getObject(bucket, getS3Key()); + LOG.debug(String.format("caching content of '%s'", object.getKey())); + + InputStream objectInputStream = object.getDataInputStream(); + if (object.getContentLength() > 0) { + ReadableByteChannel rbc = Channels.newChannel(objectInputStream); + FileChannel cacheFc = getCacheFile().getChannel(); + cacheFc.transferFrom(rbc, 0, object.getContentLength()); + cacheFc.close(); + rbc.close(); + } else { + objectInputStream.close(); + } + contentCached = true; + } + + return Channels.newInputStream(getCacheFile().getChannel()); + } + + protected OutputStream doGetOutputStream(boolean bAppend) throws Exception { + return new MonitorOutputStream(Channels.newOutputStream(getCacheFile().getChannel())) { + protected void onClose() throws IOException { + try { + LOG.debug(String.format("sending '%s' to storage (cached=%b)", object.getKey(), cacheFile)); + if (cacheFile != null) { + FileChannel cacheFc = getCacheFile().getChannel(); + object.setContentLength(cacheFc.size()); + object.setDataInputStream(Channels.newInputStream(cacheFc)); + } + service.putObject(bucket, object); + } catch (S3ServiceException e) { + LOG.error(String.format("can't send object '%s' to storage", object), e); + } + } + }; + } + + protected FileType doGetType() throws Exception { + if (null == object.getContentType()) { + return FileType.IMAGINARY; + } + + String contentType = object.getContentType(); + if ("".equals(object.getKey()) || Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(contentType)) { + return FileType.FOLDER; + } + + return FileType.FILE; + } + + protected String[] doListChildren() throws Exception { + String path = object.getKey(); + // make sure we add a '/' slash at the end to find children + if (!"".equals(path)) { + path = path + "/"; + } + + S3Object[] children = service.listObjects(bucket, path, "/"); + String[] childrenNames = new String[children.length]; + for (int i = 0; i < children.length; i++) { + if (!children[i].getKey().equals(path)) { + // strip path from name (leave only base name) + childrenNames[i] = children[i].getKey().replaceAll("[^/]*//*", ""); + } + } + + return childrenNames; + } + + protected long doGetContentSize() throws Exception { + return object.getContentLength(); + } + + // Utility methods + /** + * Create an S3 key from a commons-vfs path. This simply + * strips the slash from the beginning if it exists. + * + * @return the S3 object key + */ + private String getS3Key() { + String path = getName().getPath(); + if ("".equals(path)) { + return path; + } else { + return path.substring(1); + } + } + + private RandomAccessFile getCacheFile() throws IOException, S3ServiceException { + if (cacheFile == null) { + cacheFile = File.createTempFile("moxo.", ".s3f"); + cacheFile.deleteOnExit(); + } + return new RandomAccessFile(cacheFile, "rw"); + } +} blob - /dev/null blob + 3028150c6ba92a3e89fd9cfe4c3cca98ad17b8ec (mode 644) --- /dev/null +++ modules/vfs.s3/src/main/java/com/thinkberg/vfs/s3/jets3t/Jets3tFileSystem.java @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.vfs.s3.jets3t; + +import com.thinkberg.vfs.s3.S3FileName; +import com.thinkberg.vfs.s3.S3FileProvider; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs.FileName; +import org.apache.commons.vfs.FileObject; +import org.apache.commons.vfs.FileSystemException; +import org.apache.commons.vfs.FileSystemOptions; +import org.apache.commons.vfs.provider.AbstractFileSystem; +import org.jets3t.service.S3Service; +import org.jets3t.service.S3ServiceException; +import org.jets3t.service.model.S3Bucket; + +import java.util.Collection; + +/** + * An S3 file system. + * + * @author Matthias L. Jugel + */ +public class Jets3tFileSystem extends AbstractFileSystem { + private static final Log LOG = LogFactory.getLog(Jets3tFileSystem.class); + + private S3Service service; + private S3Bucket bucket; + + + public Jets3tFileSystem(S3Service service, S3FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException { + super(fileName, null, fileSystemOptions); + this.service = service; + + try { + String bucketId = fileName.getRootFile(); + if (!service.isBucketAccessible(bucketId)) { + LOG.info(String.format("creating new S3 bucket '%s' for file system root", bucketId)); + bucket = service.createBucket(bucketId); + } else { + LOG.info(String.format("using existing S3 bucket '%s' for file system root", bucketId)); + bucket = new S3Bucket(bucketId); + } + } catch (S3ServiceException e) { + throw new FileSystemException(e); + } + } + + public void destroyFileSystem() throws FileSystemException { + try { + service.deleteBucket(bucket); + } catch (S3ServiceException e) { + throw new FileSystemException("can't delete file system root", e); + } + } + + + @SuppressWarnings({"unchecked"}) + protected void addCapabilities(Collection caps) { + caps.addAll(S3FileProvider.capabilities); + } + + protected FileObject createFile(FileName fileName) throws Exception { + return new Jets3tFileObject(fileName, this, service, bucket); + } + + +} blob - /dev/null blob + ee8611fc7310c54462bf8672a9ff9845cbab912a (mode 644) --- /dev/null +++ modules/vfs.s3/src/main/logging/commons-logging.properties @@ -0,0 +1,17 @@ +# +# Copyright 2007 Matthias L. Jugel. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger +org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog \ No newline at end of file blob - /dev/null blob + 874378181b065e1f421ce9f4f6a618611f87ebff (mode 644) --- /dev/null +++ modules/vfs.s3/src/main/logging/simplelog.properties @@ -0,0 +1,19 @@ +# +# Copyright 2007 Matthias L. Jugel. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.commons.logging.simplelog.defaultlog=error +#org.apache.commons.logging.simplelog.log.org.jets3t.service=debug +org.apache.commons.logging.simplelog.log.com.thinkberg.vfs.s3=debug \ No newline at end of file blob - /dev/null blob + 4bbefdfa1eb5476726874d8421dbebb283cd0107 (mode 644) --- /dev/null +++ modules/vfs.s3/src/test/resources/s3.auth.properties.template @@ -0,0 +1,19 @@ +# +# Copyright 2009 Matthias L. Jugel. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Template for testing AWS S3 VFS provider +# +s3.access.key= +s3.secret.key= \ No newline at end of file blob - /dev/null blob + 5a4955869bb76ae6fb2001027f0da01cdb40a9bf (mode 644) --- /dev/null +++ modules/webdav/pom.xml @@ -0,0 +1,55 @@ + + + + + + moxo + com.thinkberg.moxo + 1.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + webdav + 1.0-SNAPSHOT + thinkberg.com WebDAV + + + commons-vfs + commons-vfs + 1.0 + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/tests/*.java + + + + + + \ No newline at end of file blob - /dev/null blob + 953b5f534b2c224ad5eb65cd370f36d6232bca2d (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/data/AbstractDavResource.java @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.data; + +import org.dom4j.Element; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public abstract class AbstractDavResource { + private static final String STATUS_200 = "HTTP/1.1 200 OK"; + private static final String STATUS_404 = "HTTP/1.1 404 Not Found"; + public static final String STATUS_403 = "HTTP/1.1 403 Forbidden"; + + private static final String TAG_PROPSTAT = "propstat"; + private static final String TAG_PROP = "prop"; + private static final String TAG_STATUS = "status"; + + public Element serializeToXml(Element root, List requestedProperties) { + Element propStatEl = root.addElement(TAG_PROPSTAT); + Element propEl = propStatEl.addElement(TAG_PROP); + + Set missingProperties = new HashSet(); + for (String propertyName : requestedProperties) { + if (!addPropertyValue(propEl, propertyName)) { + missingProperties.add(propertyName); + } + } + propStatEl.addElement(TAG_STATUS).addText(STATUS_200); + + // add missing properties status + if (missingProperties.size() > 0) { + propStatEl = root.addElement(TAG_PROPSTAT); + propEl = propStatEl.addElement(TAG_PROP); + for (String el : missingProperties) { + propEl.addElement(el); + } + propStatEl.addElement(TAG_STATUS).addText(STATUS_404); + } + + return root; + } + + @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) + protected abstract boolean addPropertyValue(Element root, String propertyName); +} blob - /dev/null blob + c6b7846fe350a342bb47de0c2709a27ae7c1b23e (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavCollection.java @@ -0,0 +1,94 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.data; + +import org.apache.commons.vfs.FileObject; +import org.dom4j.Element; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class DavCollection extends DavResource { + public static final String COLLECTION = "collection"; + + public DavCollection(FileObject object) { + super(object); + } + + + public DavCollection(FileObject object, boolean ignoreValues) { + super(object, ignoreValues); + } + + protected boolean addResourceTypeProperty(Element root) { + root.addElement(PROP_RESOURCETYPE).addElement(COLLECTION); + return true; + } + + /** + * Ignore content language for collections. + * + * @param root the prop element to add to + * @return true, even though nothing is added + */ + protected boolean addGetContentLanguageProperty(Element root) { + return true; + } + + /** + * Ignore content length for collections. + * + * @param root the prop element to add to + * @return true, even though nothing is added + */ + protected boolean addGetContentLengthProperty(Element root) { + return true; + } + + /** + * Ignore content type for collections. + * + * @param root the prop element to add to + * @return true, even though nothing is added + */ + protected boolean addGetContentTypeProperty(Element root) { + return true; + } + + protected boolean addQuotaProperty(Element root) { + root.addElement(PROP_QUOTA).addText("" + Long.MAX_VALUE); + return true; + } + + protected boolean addQuotaUsedProperty(Element root) { + // TODO add correct handling of used quota + root.addElement(PROP_QUOTA_USED).addText("0"); + return true; + } + + protected boolean addQuotaAvailableBytesProperty(Element root) { + root.addElement(PROP_QUOTA_AVAILABLE_BYTES).addText("" + Long.MAX_VALUE); + return true; + } + + protected boolean addQuotaUsedBytesProperty(Element root) { + // TODO add correct handling of used quota + root.addElement(PROP_QUOTA_USED_BYTES).addText("0"); + return true; + } +} blob - /dev/null blob + 3d01502a97a50c6eb672345d40fd43c6eee5b1e7 (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavResource.java @@ -0,0 +1,261 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.data; + +import com.thinkberg.webdav.Util; +import com.thinkberg.webdav.lock.Lock; +import com.thinkberg.webdav.lock.LockManager; +import org.apache.commons.vfs.FileObject; +import org.apache.commons.vfs.FileSystemException; +import org.dom4j.Element; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class DavResource extends AbstractDavResource { + + // @see http://www.webdav.org/specs/rfc2518.html#dav.properties + public static final String PROP_CREATION_DATE = "creationdate"; + public static final String PROP_DISPLAY_NAME = "displayname"; + private static final String PROP_GET_CONTENT_LANGUAGE = "getcontentlanguage"; + private static final String PROP_GET_CONTENT_LENGTH = "getcontentlength"; + private static final String PROP_GET_CONTENT_TYPE = "getcontenttype"; + private static final String PROP_GET_ETAG = "getetag"; + private static final String PROP_GET_LAST_MODIFIED = "getlastmodified"; + private static final String PROP_LOCK_DISCOVERY = "lockdiscovery"; + public static final String PROP_RESOURCETYPE = "resourcetype"; + private static final String PROP_SOURCE = "source"; + private static final String PROP_SUPPORTED_LOCK = "supportedlock"; + + // non-standard properties + static final String PROP_QUOTA = "quota"; + static final String PROP_QUOTA_USED = "quotaused"; + static final String PROP_QUOTA_AVAILABLE_BYTES = "quota-available-bytes"; + static final String PROP_QUOTA_USED_BYTES = "quota-used-bytes"; + + // list of standard supported properties (for allprop/propname) + public static final List 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 locks = LockManager.getInstance().discoverLock(object); + if (locks != null && !locks.isEmpty()) { + for (Lock lock : locks) { + if (lock != null && !ignoreValues) { + lock.serializeToXml(lockdiscoveryEl); + } + } + } + return true; + } catch (FileSystemException e) { + e.printStackTrace(); + root.remove(lockdiscoveryEl); + return false; + } + } + + protected boolean addResourceTypeProperty(Element root) { + root.addElement(PROP_RESOURCETYPE); + return true; + } + + protected boolean addSourceProperty(Element root) { + return false; + } + + protected boolean addSupportedLockProperty(Element root) { + Element supportedlockEl = root.addElement(PROP_SUPPORTED_LOCK); + if (!ignoreValues) { + Element exclLockentryEl = supportedlockEl.addElement("lockentry"); + exclLockentryEl.addElement("lockscope").addElement("exclusive"); + exclLockentryEl.addElement("locktype").addElement("write"); + Element sharedLockentryEl = supportedlockEl.addElement("lockentry"); + sharedLockentryEl.addElement("lockscope").addElement("shared"); + sharedLockentryEl.addElement("locktype").addElement("write"); + } + + return true; + } + + protected boolean addQuotaProperty(Element root) { + return false; + } + + protected boolean addQuotaUsedProperty(Element root) { + return false; + } + + protected boolean addQuotaAvailableBytesProperty(Element root) { + return false; + } + + protected boolean addQuotaUsedBytesProperty(Element root) { + return false; + } +} blob - /dev/null blob + 21a6eb3fafa39e8b0e6290c24fb7ab4ad2df4972 (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/data/DavResourceFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.data; + +import org.apache.commons.vfs.FileObject; +import org.apache.commons.vfs.FileSystemException; +import org.apache.commons.vfs.FileType; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class DavResourceFactory { + private static DavResourceFactory instance; + + public static DavResourceFactory getInstance() { + if (null == instance) { + instance = new DavResourceFactory(); + } + return instance; + } + + private DavResourceFactory() { + + } + + public DavResource getDavResource(FileObject object) throws FileSystemException { + if (FileType.FOLDER.equals(object.getType())) { + return new DavCollection(object); + } else { + return new DavResource(object); + } + } +} blob - /dev/null blob + 21cc82179b26c678e0a701189ad0451c27474c7d (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/Lock.java @@ -0,0 +1,138 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.lock; + +import org.apache.commons.vfs.FileObject; +import org.dom4j.Element; + +import java.net.URL; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class Lock { + public final static String SHARED = "shared"; + public final static String EXCLUSIVE = "exclusive"; + + public final static String WRITE = "write"; + + private final FileObject object; + private final String type; + private final String scope; + private final Object owner; + private final int depth; + private final long timeout; + private final String token; + + + public Lock(FileObject object, String type, String scope, Object owner, + int depth, long timeout) { + this.object = object; + this.type = type; + this.scope = scope; + this.owner = owner; + this.depth = depth; + this.timeout = timeout; + + this.token = "opaquelocktoken:" + Integer.toHexString(object.hashCode()); + } + + public FileObject getObject() { + return object; + } + + public String getType() { + return type; + } + + public String getScope() { + return scope; + } + + public Object getOwner() { + return owner; + } + + public int getDepth() { + return depth; + } + + public String getDepthValue() { + switch (depth) { + case 0: + return "0"; + case 1: + return "1"; + default: + return "Infinity"; + } + } + + public String getTimeout() { + if (timeout == -1) { + return "Infinity"; + } + return "Second-" + timeout; + } + + public String getToken() { + return this.token; + } + + /** + * Create an XML serialized version of the lock by adding an activelock tag + * with the locks properties to the root element provided. + * + * @param root the root element to add the activelock to + * @return the root element + */ + public Element serializeToXml(Element root) { + Element activelockEl = root.addElement("activelock"); + activelockEl.addElement("locktype").addElement(getType()); + activelockEl.addElement("lockscope").addElement(getScope()); + activelockEl.addElement("depth").addText(getDepthValue()); + // TODO handle owner correctly + if (getOwner() instanceof URL) { + activelockEl.addElement("owner").addElement("href") + .addText(((URL) getOwner()).toExternalForm()); + } else { + activelockEl.addElement("owner").addText((String) getOwner()); + } + activelockEl.addElement("timeout").addText(getTimeout()); + activelockEl.addElement("locktoken") + .addElement("href").addText(getToken()); + + return root; + } + + /** + * There can only be one lock per object, thus compare the file objects. + * + * @param other the other lock to compare to + * @return whether this lock is for the same file object + */ + public boolean equals(Object other) { + return other instanceof Lock && object.equals(((Lock) other).object); + } + + + public String toString() { + return String.format("Lock[%s,%s,%s,%s]", object, type, scope, token); + } +} + blob - /dev/null blob + 351b4579632318ff0c4ef04636aec1f35d338b1c (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockConditionFailedException.java @@ -0,0 +1,41 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.lock; + +import java.util.List; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class LockConditionFailedException extends LockException { + private String condition = null; + + public LockConditionFailedException(List locks) { + super(locks); + } + + public LockConditionFailedException(List locks, String condition) { + super(locks); + this.condition = condition; + + } + + public String getCondition() { + return condition; + } +} blob - /dev/null blob + cdad610efc8345cef8a5737d51b239897a2d0f7d (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockConditionRequiredException.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.lock; + +import java.util.List; + +public class LockConditionRequiredException extends LockException { + public LockConditionRequiredException(List locks) { + super(locks); + } +} blob - /dev/null blob + ed8c50a998c9956e34fb8de8bc053640169bd31b (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockConflictException.java @@ -0,0 +1,29 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.lock; + +import java.util.List; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class LockConflictException extends LockException { + public LockConflictException(List locks) { + super(locks); + } +} blob - /dev/null blob + 85a2220f0526dd0c79b6e3ac49cb88ceb9bdb94d (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockException.java @@ -0,0 +1,40 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.lock; + +import java.util.List; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class LockException extends Exception { + private final List locks; + + public LockException(List locks) { + super(); + this.locks = locks; + } + + public List getLocks() { + return locks; + } + + public String toString() { + return String.format("[%s: %s]", this.getClass(), locks); + } +} blob - /dev/null blob + 6940fa3250eafb941b27dc63fdd39cceff20ea8d (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/lock/LockManager.java @@ -0,0 +1,322 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.lock; + +import com.thinkberg.webdav.vfs.DepthFileSelector; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs.FileObject; +import org.apache.commons.vfs.FileSelectInfo; +import org.apache.commons.vfs.FileSystemException; + +import java.net.URI; +import java.net.URISyntaxException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * The lock manager is responsible for exclusive and shared write locks on the + * DAV server. It is used to acquire a lock, release a lock, discover existing + * locks or check conditions. The lock manager is a singleton. + * + * @author Matthias L. Jugel + * @version $Id$ + */ +public class LockManager { + private static LockManager instance = null; + private static final Log LOG = LogFactory.getLog(LockManager.class); + + // condition parser patterns and tokens + private static final Pattern IF_PATTERN = Pattern.compile("(<[^>]+>)|(\\([^)]+\\))"); + private static final Pattern CONDITION_PATTERN = Pattern.compile("([Nn][Oo][Tt])|(<[^>]+>)|(\\[[^]]+\\])"); + private static final char TOKEN_LOWER_THAN = '<'; + private static final char TOKEN_LEFT_BRACE = '('; + private static final char TOKEN_LEFT_BRACKET = '['; + + /** + * Get an instance of the lock manager. + * + * @return the lock manager + */ + public static LockManager getInstance() { + if (null == instance) { + instance = new LockManager(); + } + + return instance; + } + + private final Map> lockMap; + + /** + * The lock manager is a singleton and cannot be instantiated directly. + */ + private LockManager() { + lockMap = new HashMap>(); + } + + /** + * 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 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 discoverLock(FileObject object) throws FileSystemException { + FileObject parent = object; + while (parent != null) { + List 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. + *

+ * Evaluate example 2:
+ * + * URI(/resource1) { ( + * is-locked-with(urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2) + * AND matches-etag(W/"A weak ETag") ) + * OR ( matches-etag("strong ETag") ) } + * + *

+ * Examples: + *

    + *
  1. <http://cid:8080/litmus/unmapped_url> (<opaquelocktoken:cd6798>)
  2. + *
  3. </resource1> (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> [W/"A weak ETag"]) (["strong ETag"])
  4. + *
  5. (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>) (Not <DAV:no-lock>)
  6. + *
  7. (Not <urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> <urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092>)
  8. + *
  9. </specs/rfc2518.doc> (["4217"])
  10. + *
  11. </specs/rfc2518.doc> (Not ["4217"])
  12. + *
+ * + * @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 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 locks = new ArrayList(); + 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 locks = lockMap.get(object); + if (null == locks) { + locks = new ArrayList(); + 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 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 childLocks = lockMap.get(fileSelectInfo.getFile()); + for (Lock childLock : childLocks) { + if (Lock.EXCLUSIVE.equals(requestedLock.getScope()) || Lock.EXCLUSIVE.equals(childLock.getScope())) { + throw new LockConflictException(childLocks); + } + } + return false; + } + }, false, new ArrayList()); + } + } + +} blob - /dev/null blob + 0bd27718adde8f76ebb9bf18691ac0317fb46631 (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/servlet/MoxoWebDAVServlet.java @@ -0,0 +1,120 @@ +/* + * Copyright 2007 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.servlet; + +import com.thinkberg.webdav.*; +import com.thinkberg.webdav.vfs.VFSBackend; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs.FileSystemException; +import org.apache.commons.vfs.FileSystemOptions; +import org.apache.commons.vfs.auth.StaticUserAuthenticator; +import org.apache.commons.vfs.impl.DefaultFileSystemConfigBuilder; +import org.mortbay.jetty.Response; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class MoxoWebDAVServlet extends HttpServlet { + private static final Log LOG = LogFactory.getLog(MoxoWebDAVServlet.class); + + private final Map handlers = new HashMap(); + + public MoxoWebDAVServlet() { + handlers.put("COPY", new CopyHandler()); + handlers.put("DELETE", new DeleteHandler()); + handlers.put("GET", new GetHandler()); + handlers.put("HEAD", new HeadHandler()); + handlers.put("LOCK", new LockHandler()); + handlers.put("MKCOL", new MkColHandler()); + handlers.put("MOVE", new MoveHandler()); + handlers.put("OPTIONS", new OptionsHandler()); + handlers.put("POST", new PostHandler()); + handlers.put("PROPFIND", new PropFindHandler()); + handlers.put("PROPPATCH", new PropPatchHandler()); + handlers.put("PUT", new PutHandler()); + handlers.put("UNLOCK", new UnlockHandler()); + + } + + public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); + String rootUri = servletConfig.getInitParameter("vfs.uri"); + String authDomain = servletConfig.getInitParameter("vfs.auth.domain"); + String authUser = servletConfig.getInitParameter("vfs.auth.user"); + String authPass = servletConfig.getInitParameter("vfs.auth.password"); + try { + StaticUserAuthenticator userAuthenticator = + new StaticUserAuthenticator(authDomain, authUser, authPass); + FileSystemOptions options = new FileSystemOptions(); + DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(options, userAuthenticator); + + VFSBackend.initialize(rootUri, options); + } catch (FileSystemException e) { + LOG.error(String.format("can't create file system backend for '%s'", rootUri)); + } + } + + public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { +// String auth = request.getHeader("Authorization"); +// String login = "", password = ""; +// +// if (auth != null) { +// auth = new String(Base64.decodeBase64(auth.substring(auth.indexOf(' ') + 1).getBytes())); +// login = auth.substring(0, auth.indexOf(':')); +// password = auth.substring(auth.indexOf(':') + 1); +// } +// +// AWSCredentials credentials = AWSCredentials.load(password, )) +// if (user == null) { +// response.setHeader("WWW-Authenticate", "Basic realm=\"Moxo\""); +// response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); +// return; +// } + + + // show we are doing the litmus test + String litmusTest = request.getHeader("X-Litmus"); + if (null == litmusTest) { + litmusTest = request.getHeader("X-Litmus-Second"); + } + if (litmusTest != null) { + LOG.info(String.format("WebDAV Litmus Test: %s", litmusTest)); + } + + String method = request.getMethod(); + LOG.debug(String.format(">> %s %s", request.getMethod(), request.getPathInfo())); + if (handlers.containsKey(method)) { + handlers.get(method).service(request, response); + } else { + response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); + } + Response jettyResponse = ((Response) response); + String reason = jettyResponse.getReason(); + LOG.debug(String.format("<< %s (%d%s)", request.getMethod(), jettyResponse.getStatus(), reason != null ? ": " + reason : "")); + } +} blob - /dev/null blob + 79745966960b3bcf835f5e6f13cbf1aa0f68c869 (mode 644) --- /dev/null +++ modules/webdav/src/main/java/com/thinkberg/webdav/vfs/VFSBackend.java @@ -0,0 +1,49 @@ +/* + * Copyright 2009 Matthias L. Jugel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.thinkberg.webdav.vfs; + +import org.apache.commons.vfs.FileObject; +import org.apache.commons.vfs.FileSystemException; +import org.apache.commons.vfs.FileSystemOptions; +import org.apache.commons.vfs.VFS; + +/** + * @author Matthias L. Jugel + * @version $Id$ + */ +public class VFSBackend { + private static VFSBackend instance; + + private final FileObject fileSystemRoot; + + public static void initialize(String rootUri, FileSystemOptions options) throws FileSystemException { + if (null == instance) { + instance = new VFSBackend(rootUri, options); + } + } + + private VFSBackend(String rootUri, FileSystemOptions options) throws FileSystemException { + fileSystemRoot = VFS.getManager().resolveFile(rootUri, options); + } + + public static FileObject resolveFile(String path) throws FileSystemException { + if (null == instance) { + throw new IllegalStateException("VFS backend not initialized"); + } + return instance.fileSystemRoot.resolveFile(path); + } +} blob - /dev/null blob + ee8611fc7310c54462bf8672a9ff9845cbab912a (mode 644) --- /dev/null +++ modules/webdav/src/main/logging/commons-logging.properties @@ -0,0 +1,17 @@ +# +# Copyright 2007 Matthias L. Jugel. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger +org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog \ No newline at end of file blob - /dev/null blob + 17a37d029897fd962f98dd3e7b370914ea0e3a69 (mode 644) --- /dev/null +++ modules/webdav/src/main/logging/simplelog.properties @@ -0,0 +1,18 @@ +# +# Copyright 2007 Matthias L. Jugel. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.commons.logging.simplelog.defaultlog=error +org.apache.commons.logging.simplelog.log.com.thinkberg.webdav=debug \ No newline at end of file blob - /dev/null blob + 69501658828ef0ef55a5ee90f4c3512ecc313e1b (mode 755) --- /dev/null +++ modules/webdav/src/test/java/com/thinkberg/webdav/tests/DavResourceTest.java @@ -0,0 +1,55 @@ +package com.thinkberg.webdav.tests; + +import com.thinkberg.webdav.DavTestCase; +import com.thinkberg.webdav.data.DavCollection; +import com.thinkberg.webdav.data.DavResource; +import org.apache.commons.vfs.FileSystemException; +import org.dom4j.Element; + +import java.io.IOException; + +/** + * Test case for the DAV resource wrapper. Checks that resources are serialized + * correctly. + * + * @author Matthias L. Jugel + */ +public class DavResourceTest extends DavTestCase { + public void testFileCreationDateIsNull() throws FileSystemException { + Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE); + assertNull(selectExistingProperty(root, DavResource.PROP_CREATION_DATE)); + } + + public void testFileCreationDateIsMissing() throws IOException { + Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE); + assertEquals(DavResource.PROP_CREATION_DATE, + selectMissingPropertyName(root, DavResource.PROP_CREATION_DATE)); + } + + public void testFileDisplayNameWithValue() throws FileSystemException { + testPropertyValue(aFile, DavResource.PROP_DISPLAY_NAME, aFile.getName().getBaseName()); + } + + public void testFileDisplayNameWithoutValue() throws FileSystemException { + testPropertyNoValue(aFile, DavResource.PROP_DISPLAY_NAME); + } + + public void testFileResourceTypeNotMissing() throws FileSystemException { + Element root = serializeDavResource(aFile, DavResource.PROP_RESOURCETYPE); + assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE)); + } + + public void testDirectoryResourceTypeNotMissing() throws FileSystemException { + Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE); + assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE)); + } + + public void testFileResourceType() throws FileSystemException { + testPropertyNoValue(aFile, DavResource.PROP_RESOURCETYPE); + } + + public void testDirectoryResourceType() throws FileSystemException { + Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE); + assertNotNull(selectExistingProperty(root, DavResource.PROP_RESOURCETYPE).selectSingleNode(DavCollection.COLLECTION)); + } +} blob - fad5566e89f5e3a1e30cdf358aff899558c340ff blob + 81fa814c760d3f3302548ef451f1fcad06157e6d --- src/main/java/com/thinkberg/moxo/MoxoJettyRunner.java +++ src/main/java/com/thinkberg/moxo/MoxoJettyRunner.java @@ -29,7 +29,7 @@ import java.net.URL; * @author Matthias L. Jugel */ public class MoxoJettyRunner { - private static final String CONF_JETTY_XML = "jetty.xml"; + private static final String CONF_JETTY_XML = "/jetty.xml"; public static void main(String[] args) { System.out.println("Moxo S3 DAV Proxy (c) 2007 Matthias L. Jugel"); @@ -51,10 +51,11 @@ public class MoxoJettyRunner { } private static URL getXmlConfigurationUrl() { - URL url = MoxoJettyRunner.class.getResource("/" + MoxoJettyRunner.CONF_JETTY_XML); + String configFile = System.getProperty("jetty.xml", CONF_JETTY_XML); + URL url = MoxoJettyRunner.class.getResource(configFile); if (null == url) { try { - url = new File(MoxoJettyRunner.CONF_JETTY_XML).toURL(); + url = new File(configFile).toURL(); System.err.println("Loading configuration from file: " + url.toExternalForm()); } catch (MalformedURLException e) { // ignore ... blob - 34da23d2a591b3326dc3d78d18ae9a335ad6b4ca (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/CopyHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.vfs.DepthFileSelector; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class CopyHandler extends CopyMoveBase { - protected void copyOrMove(FileObject object, FileObject target, int depth) throws FileSystemException { - target.copyFrom(object, new DepthFileSelector(depth)); - } -} blob - 3e03b367c7a948895653aafa48ac0d07ee118c5f (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/CopyMoveBase.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.lock.LockException; -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileType; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.text.ParseException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public abstract class CopyMoveBase extends WebdavHandler { - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - boolean overwrite = getOverwrite(request); - FileObject object = getVFSObject(request.getPathInfo()); - FileObject targetObject = getDestination(request); - - - try { - final LockManager lockManager = LockManager.getInstance(); - LockManager.EvaluationResult evaluation = lockManager.evaluateCondition(targetObject, getIf(request)); - if (!evaluation.result) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - if ("MOVE".equals(request.getMethod())) { - evaluation = lockManager.evaluateCondition(object, getIf(request)); - if (!evaluation.result) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - } - } catch (LockException e) { - response.sendError(SC_LOCKED); - return; - } catch (ParseException e) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - - - if (null == targetObject) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - if (object.equals(targetObject)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - if (targetObject.exists()) { - if (!overwrite) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - response.setStatus(HttpServletResponse.SC_NO_CONTENT); - } else { - FileObject targetParent = targetObject.getParent(); - if (!targetParent.exists() || - !FileType.FOLDER.equals(targetParent.getType())) { - response.sendError(HttpServletResponse.SC_CONFLICT); - } - response.setStatus(HttpServletResponse.SC_CREATED); - } - - copyOrMove(object, targetObject, getDepth(request)); - } - - protected abstract void copyOrMove(FileObject object, FileObject target, int depth) throws FileSystemException; - -} blob - 1cd9fda42df8a35bd14e6be5cd93938a0344a9ce (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/DeleteHandler.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.lock.LockException; -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSelectInfo; -import org.apache.commons.vfs.FileSelector; -import org.mortbay.jetty.Request; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.text.ParseException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class DeleteHandler extends WebdavHandler { - private static final Log LOG = LogFactory.getLog(DeleteHandler.class); - - private final static FileSelector ALL_FILES_SELECTOR = new FileSelector() { - public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception { - return true; - } - - public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws Exception { - return true; - } - }; - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - FileObject object = getVFSObject(request.getPathInfo()); - if (request instanceof Request) { - String fragment = ((Request) request).getUri().getFragment(); - if (fragment != null) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - } - - try { - if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - } catch (LockException e) { - response.sendError(WebdavHandler.SC_LOCKED); - return; - } catch (ParseException e) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - - if (object.exists()) { - int deletedObjects = object.delete(ALL_FILES_SELECTOR); - LOG.debug("deleted " + deletedObjects + " objects"); - if (deletedObjects > 0) { - response.setStatus(HttpServletResponse.SC_OK); - } else { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - } - } else { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - } - } -} blob - 2a0d7c02a9d33230c3492d40a0a444e5c8d0efb1 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/GetHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import org.apache.commons.vfs.FileContent; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileType; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class GetHandler extends WebdavHandler { - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - FileObject object = getVFSObject(request.getPathInfo()); - - if (object.exists()) { - if (FileType.FOLDER.equals(object.getType())) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - setHeader(response, object.getContent()); - - InputStream is = object.getContent().getInputStream(); - OutputStream os = response.getOutputStream(); - Util.copyStream(is, os); - is.close(); - } else { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - } - } - - void setHeader(HttpServletResponse response, FileContent content) throws FileSystemException { - response.setHeader("Last-Modified", Util.getDateString(content.getLastModifiedTime())); - response.setHeader("Content-Type", content.getContentInfo().getContentType()); - response.setHeader("ETag", String.format("%x", content.getFile().hashCode())); - } - - -} blob - 214793924ede616c96a919382f76715c89613a58 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/HeadHandler.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileType; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class HeadHandler extends GetHandler { - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - FileObject object = getVFSObject(request.getPathInfo()); - - if (object.exists()) { - if (FileType.FOLDER.equals(object.getType())) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - } else { - setHeader(response, object.getContent()); - } - } else { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - } - } -} blob - 2cf6621edb3bdded57a86109a03ee75a17d97cfc (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/LockHandler.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.lock.Lock; -import com.thinkberg.moxo.dav.lock.LockConflictException; -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.dom4j.*; -import org.dom4j.io.OutputFormat; -import org.dom4j.io.SAXReader; -import org.dom4j.io.XMLWriter; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.URL; -import java.text.ParseException; -import java.util.Iterator; -import java.util.List; - -/** - * Handle WebDAV LOCK requests. - * - * @author Matthias L. Jugel - * @version $Id$ - */ -public class LockHandler extends WebdavHandler { - private static final Log LOG = LogFactory.getLog(LockHandler.class); - - private static final String TAG_LOCKSCOPE = "lockscope"; - private static final String TAG_LOCKTYPE = "locktype"; - private static final String TAG_OWNER = "owner"; - private static final String TAG_HREF = "href"; - private static final String TAG_PROP = "prop"; - private static final String TAG_LOCKDISCOVERY = "lockdiscovery"; - - private static final String HEADER_LOCK_TOKEN = "Lock-Token"; - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - FileObject object = getVFSObject(request.getPathInfo()); - - try { - final LockManager manager = LockManager.getInstance(); - final LockManager.EvaluationResult evaluation = manager.evaluateCondition(object, getIf(request)); - if (!evaluation.result) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } else { - if (!evaluation.locks.isEmpty()) { - LOG.debug(String.format("discovered locks: %s", evaluation.locks)); - sendLockAcquiredResponse(response, evaluation.locks.get(0)); - return; - } - } - } catch (LockConflictException e) { - List locks = e.getLocks(); - for (Lock lock : locks) { - if (Lock.EXCLUSIVE.equals(lock.getType())) { - response.sendError(WebdavHandler.SC_LOCKED); - return; - } - } - } catch (ParseException e) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - - try { - SAXReader saxReader = new SAXReader(); - Document lockInfo = saxReader.read(request.getInputStream()); - //log(lockInfo); - - Element rootEl = lockInfo.getRootElement(); - String lockScope = null, lockType = null; - Object owner = null; - Iterator elIt = rootEl.elementIterator(); - while (elIt.hasNext()) { - Element el = (Element) elIt.next(); - if (TAG_LOCKSCOPE.equals(el.getName())) { - lockScope = el.selectSingleNode("*").getName(); - } else if (TAG_LOCKTYPE.equals(el.getName())) { - lockType = el.selectSingleNode("*").getName(); - } else if (TAG_OWNER.equals(el.getName())) { - // TODO correctly handle owner - Node subEl = el.selectSingleNode("*"); - if (subEl != null && TAG_HREF.equals(subEl.getName())) { - owner = new URL(el.selectSingleNode("*").getText()); - } else { - owner = el.getText(); - } - } - } - - LOG.debug("LOCK(" + lockType + ", " + lockScope + ", " + owner + ")"); - - Lock requestedLock = new Lock(object, lockType, lockScope, owner, getDepth(request), getTimeout(request)); - try { - LockManager.getInstance().acquireLock(requestedLock); - sendLockAcquiredResponse(response, requestedLock); - } catch (LockConflictException e) { - response.sendError(SC_LOCKED); - } catch (IllegalArgumentException e) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - } - } catch (DocumentException e) { - e.printStackTrace(); - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - } - } - - private void sendLockAcquiredResponse(HttpServletResponse response, Lock lock) throws IOException { - if (!lock.getObject().exists()) { - response.setStatus(SC_CREATED); - } - response.setContentType("text/xml"); - response.setCharacterEncoding("UTF-8"); - response.setHeader(HEADER_LOCK_TOKEN, "<" + lock.getToken() + ">"); - - Document propDoc = DocumentHelper.createDocument(); - Element propEl = propDoc.addElement(TAG_PROP, "DAV:"); - Element lockdiscoveryEl = propEl.addElement(TAG_LOCKDISCOVERY); - - lock.serializeToXml(lockdiscoveryEl); - - XMLWriter xmlWriter = new XMLWriter(response.getWriter()); - xmlWriter.write(propDoc); - - logXml(propDoc); - } - - private void logXml(Node element) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try { - XMLWriter xmlWriter = new XMLWriter(bos, OutputFormat.createPrettyPrint()); - xmlWriter.write(element); - LOG.debug(bos.toString()); - } catch (IOException e) { - LOG.debug("ERROR writing XML log: " + e.getMessage()); - } - } -} blob - 3edc720043d1911ec3a98cd4b63e24554884e6a9 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/MkColHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.lock.LockException; -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileType; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.BufferedReader; -import java.io.IOException; -import java.text.ParseException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class MkColHandler extends WebdavHandler { - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - BufferedReader bufferedReader = request.getReader(); - String line = bufferedReader.readLine(); - if (line != null) { - response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); - return; - } - - FileObject object = getVFSObject(request.getPathInfo()); - - try { - if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - } catch (LockException e) { - response.sendError(WebdavHandler.SC_LOCKED); - return; - } catch (ParseException e) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - - if (object.exists()) { - response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); - return; - } - - if (!object.getParent().exists() || !FileType.FOLDER.equals(object.getParent().getType())) { - response.sendError(HttpServletResponse.SC_CONFLICT); - return; - } - - try { - object.createFolder(); - response.setStatus(HttpServletResponse.SC_CREATED); - } catch (FileSystemException e) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - } - } -} blob - 5cb1a045ff6f0fc46e8991898548660850d8a10a (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/MoveHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.vfs.DepthFileSelector; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class MoveHandler extends CopyMoveBase { - protected void copyOrMove(FileObject object, FileObject target, int depth) throws FileSystemException { - target.copyFrom(object, new DepthFileSelector(depth)); - object.delete(new DepthFileSelector()); - } -} blob - 105b947a18e598dc34be32c8564a80e80f7fa409 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/OptionsHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileType; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class OptionsHandler extends WebdavHandler { - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.setHeader("DAV", "1, 2"); - - String path = request.getPathInfo(); - StringBuffer options = new StringBuffer(); - FileObject object = getVFSObject(path); - if (object.exists()) { - options.append("OPTIONS, GET, HEAD, POST, DELETE, TRACE, COPY, MOVE, LOCK, UNLOCK, PROPFIND"); - if (FileType.FOLDER.equals(object.getType())) { - options.append(", PUT"); - } - } else { - options.append("OPTIONS, MKCOL, PUT, LOCK"); - } - response.setHeader("Allow", options.toString()); - - // see: http://www-128.ibm.com/developerworks/rational/library/2089.html - response.setHeader("MS-Author-Via", "DAV"); - } -} blob - e0038189d0aaef0103b1f32ab0a53ea3a228e09e (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/PostHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class PostHandler extends WebdavHandler { - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - } -} blob - 9f8b33f2d2f8c952a1dba98b56c888dad88670b3 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/PropFindHandler.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.data.DavResource; -import com.thinkberg.moxo.dav.data.DavResourceFactory; -import com.thinkberg.moxo.vfs.DepthFileSelector; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.dom4j.*; -import org.dom4j.io.OutputFormat; -import org.dom4j.io.SAXReader; -import org.dom4j.io.XMLWriter; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class PropFindHandler extends WebdavHandler { - private static final String TAG_PROP = "prop"; - private static final String TAG_ALLPROP = "allprop"; - private static final String TAG_PROPNAMES = "propnames"; - private static final String TAG_MULTISTATUS = "multistatus"; - private static final String TAG_HREF = "href"; - private static final String TAG_RESPONSE = "response"; - private static final Log LOG = LogFactory.getLog(PropFindHandler.class); - - void logXml(Node element) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try { - XMLWriter xmlWriter = new XMLWriter(bos, OutputFormat.createPrettyPrint()); - xmlWriter.write(element); - LOG.debug(bos.toString()); - } catch (IOException e) { - LOG.error(e.getMessage()); - } - } - - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - SAXReader saxReader = new SAXReader(); - try { - Document propDoc = saxReader.read(request.getInputStream()); - logXml(propDoc); - - Element propFindEl = propDoc.getRootElement(); - Element propEl = (Element) propFindEl.elementIterator().next(); - String propElName = propEl.getName(); - - List requestedProperties = new ArrayList(); - 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 requestedProperties, - URL baseUrl, - int depth, - boolean ignoreValues) throws FileSystemException { - Document propDoc = DocumentHelper.createDocument(); - propDoc.setXMLEncoding("UTF-8"); - - Element multiStatus = propDoc.addElement(TAG_MULTISTATUS, "DAV:"); - FileObject[] children = object.findFiles(new DepthFileSelector(depth)); - for (FileObject child : children) { - Element responseEl = multiStatus.addElement(TAG_RESPONSE); - try { - URL url = new URL(baseUrl, URLEncoder.encode(child.getName().getPath(), "UTF-8")); - LOG.debug(url); - responseEl.addElement(TAG_HREF).addText(url.toExternalForm()); - } catch (Exception e) { - e.printStackTrace(); - } - DavResource resource = DavResourceFactory.getInstance().getDavResource(child); - resource.setIgnoreValues(ignoreValues); - resource.serializeToXml(responseEl, requestedProperties); - } - return propDoc; - } -} blob - 029e0da28dec7284d703d42725af8549d2f49ae5 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/PropPatchHandler.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.data.DavResource; -import com.thinkberg.moxo.dav.lock.LockException; -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.DocumentHelper; -import org.dom4j.Element; -import org.dom4j.io.OutputFormat; -import org.dom4j.io.SAXReader; -import org.dom4j.io.XMLWriter; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.URL; -import java.text.ParseException; -import java.util.List; - -/** - * Handle PROPPATCH requests. This currently a dummy only and will return a - * forbidden status for any attempt to modify or remove a property. - * - * @author Matthias L. Jugel - */ -public class PropPatchHandler extends WebdavHandler { - private static final Log LOG = LogFactory.getLog(PropPatchHandler.class); - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - FileObject object = getVFSObject(request.getPathInfo()); - - try { - if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - } catch (LockException e) { - response.sendError(WebdavHandler.SC_LOCKED); - return; - } catch (ParseException e) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - - SAXReader saxReader = new SAXReader(); - try { - Document propDoc = saxReader.read(request.getInputStream()); -// log(propDoc); - - response.setContentType("text/xml"); - response.setCharacterEncoding("UTF-8"); - response.setStatus(SC_MULTI_STATUS); - - if (object.exists()) { - Document resultDoc = DocumentHelper.createDocument(); - Element multiStatusResponse = resultDoc.addElement("multistatus", "DAV:"); - Element responseEl = multiStatusResponse.addElement("response"); - try { - URL url = new URL(getBaseUrl(request), URLEncoder.encode(object.getName().getPath(), "UTF-8")); - LOG.debug(url); - responseEl.addElement("href").addText(url.toExternalForm()); - } catch (Exception e) { - e.printStackTrace(); - } - - Element propstatEl = responseEl.addElement("propstat"); - Element propEl = propstatEl.addElement("prop"); - - Element propertyUpdateEl = propDoc.getRootElement(); - for (Object elObject : propertyUpdateEl.elements()) { - Element el = (Element) elObject; - if ("set".equals(el.getName())) { - for (Object propObject : el.elements()) { - setProperty(propEl, object, (Element) propObject); - } - } else if ("remove".equals(el.getName())) { - for (Object propObject : el.elements()) { - removeProperty(propEl, object, (Element) propObject); - } - } - } - propstatEl.addElement("status").addText(DavResource.STATUS_403); - -// log(resultDoc); - - // write the actual response - XMLWriter writer = new XMLWriter(response.getWriter(), OutputFormat.createCompactFormat()); - writer.write(resultDoc); - writer.flush(); - writer.close(); - } else { - LOG.error(object.getName().getPath() + " NOT FOUND"); - response.sendError(HttpServletResponse.SC_NOT_FOUND); - } - } catch (DocumentException e) { - LOG.error("invalid request: " + e.getMessage()); - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - } - } - - private void setProperty(Element root, FileObject object, Element el) { - List propList = el.elements(); - for (Object propElObject : propList) { - Element propEl = (Element) propElObject; - for (int i = 0; i < propEl.nodeCount(); i++) { - propEl.node(i).detach(); - } - root.add(propEl.detach()); - } - } - - private void removeProperty(Element root, FileObject object, Element el) { - setProperty(root, object, el); - } - - -} blob - ed879c915a369d9649cbba45551e983960a733ad (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/PutHandler.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.lock.LockException; -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileType; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.ParseException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class PutHandler extends WebdavHandler { - private static final Log LOG = LogFactory.getLog(PutHandler.class); - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - FileObject object = getVFSObject(request.getPathInfo()); - - try { - if (!LockManager.getInstance().evaluateCondition(object, getIf(request)).result) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - } catch (LockException e) { - response.sendError(WebdavHandler.SC_LOCKED); - return; - } catch (ParseException e) { - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return; - } - // it is forbidden to write data on a folder - if (object.exists() && FileType.FOLDER.equals(object.getType())) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - FileObject parent = object.getParent(); - if (!parent.exists()) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - if (!FileType.FOLDER.equals(parent.getType())) { - response.sendError(HttpServletResponse.SC_CONFLICT); - return; - } - - InputStream is = request.getInputStream(); - OutputStream os = object.getContent().getOutputStream(); - long bytesCopied = Util.copyStream(is, os); - String contentLengthHeader = request.getHeader("Content-length"); - LOG.debug(String.format("sent %d/%s bytes", bytesCopied, contentLengthHeader == null ? "unknown" : contentLengthHeader)); - os.flush(); - object.close(); - - response.setStatus(HttpServletResponse.SC_CREATED); - } -} blob - cdf9f6df05dd32310e05a5e0ab104c03779b15ea (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/URLEncoder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import java.io.UnsupportedEncodingException; -import java.util.BitSet; - -/** - * Encode a URL but leave some special characters in plain text. - * - * @author Matthias L. Jugel - */ -class URLEncoder { - - private static final BitSet keepPlain; - - static { - keepPlain = new BitSet(256); - int i; - for (i = 'a'; i <= 'z'; i++) { - keepPlain.set(i); - } - for (i = 'A'; i <= 'Z'; i++) { - keepPlain.set(i); - } - for (i = '0'; i <= '9'; i++) { - keepPlain.set(i); - } - keepPlain.set('+'); - keepPlain.set('-'); - keepPlain.set('_'); - keepPlain.set('.'); - keepPlain.set('*'); - keepPlain.set('/'); - keepPlain.set(':'); - } - - - public static String encode(String s, String enc) throws UnsupportedEncodingException { - byte[] buf = s.getBytes(enc); - StringBuffer result = new StringBuffer(); - for (byte aBuf : buf) { - int c = (int) aBuf; - if (keepPlain.get(c & 0xFF)) { - result.append((char) c); - } else { - result.append('%').append(Integer.toHexString(c & 0xFF).toUpperCase()); - } - } - return result.toString(); - } -} blob - e9810818ac9e79873202dae184ec9ad09b813804 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/UnlockHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class UnlockHandler extends WebdavHandler { - private static final Log LOG = LogFactory.getLog(UnlockHandler.class); - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - FileObject object = getVFSObject(request.getPathInfo()); - String lockTokenHeader = request.getHeader("Lock-Token"); - String lockToken = lockTokenHeader.substring(1, lockTokenHeader.length() - 1); - LOG.debug("UNLOCK(" + lockToken + ")"); - - if (LockManager.getInstance().releaseLock(object, lockToken)) { - response.setStatus(HttpServletResponse.SC_NO_CONTENT); - } else { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - } - } -} blob - 9b6e71d63c5a52df24c66a3d45ff9da5b93a6115 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/Util.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class Util { - - private static final SimpleDateFormat httpDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); - - public static String getDateString(long time) { - return httpDateFormat.format(new Date(time)); - } - -// public static String getISODateString(long time) { -// return ""; 4 -// } - - - public static long copyStream(final InputStream is, final OutputStream os) throws IOException { - ReadableByteChannel rbc = Channels.newChannel(is); - WritableByteChannel wbc = Channels.newChannel(os); - - int bytesWritten = 0; - final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024); - while (rbc.read(buffer) != -1) { - buffer.flip(); - bytesWritten += wbc.write(buffer); - buffer.compact(); - } - buffer.flip(); - while (buffer.hasRemaining()) { - bytesWritten += wbc.write(buffer); - } - - rbc.close(); - wbc.close(); - - return bytesWritten; - } -} blob - b52d655c1ac100625581cb02aba7e7f923b502b6 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/WebdavHandler.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileSystemManager; -import org.apache.commons.vfs.VFS; -import org.jets3t.service.Jets3tProperties; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public abstract class WebdavHandler { - private static final Log LOG = LogFactory.getLog(WebdavHandler.class); - - static final int SC_CREATED = 201; - static final int SC_LOCKED = 423; - static final int SC_MULTI_STATUS = 207; - - private static FileObject fileSystemRoot; - - static { - try { - String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties"); - Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName); - FileSystemManager fsm = VFS.getManager(); - - // create a virtual filesystemusing the url provided or fall back to RAM - fileSystemRoot = fsm.resolveFile(properties.getStringProperty("vfs.uri", "ram:/")); - - LOG.info("created virtual file system: " + fileSystemRoot); - } catch (FileSystemException e) { - LOG.error("can't create virtual file system: " + e.getMessage()); - e.printStackTrace(); - } - } - - protected static FileObject getVFSObject(String path) throws FileSystemException { - return fileSystemRoot.resolveFile(path); - } - - protected static URL getBaseUrl(HttpServletRequest request) { - try { - String requestUrl = request.getRequestURL().toString(); - String requestUri = request.getRequestURI(); - String requestUrlBase = requestUrl.substring(0, requestUrl.length() - requestUri.length()); - return new URL(requestUrlBase); - } catch (MalformedURLException e) { - // ignore ... - } - return null; - } - - public abstract void service(HttpServletRequest request, HttpServletResponse response) throws IOException; - - /** - * Get the depth header value. This value defines how operations - * like propfind, move, copy etc. handle collections. A depth value - * of 0 will only return the current collection, 1 will return - * children too and infinity will recursively operate. - * - * @param request the servlet request - * @return the depth value as 0, 1 or Integer.MAX_VALUE; - */ - int getDepth(HttpServletRequest request) { - String depth = request.getHeader("Depth"); - int depthValue; - - if (null == depth || "infinity".equalsIgnoreCase(depth)) { - depthValue = Integer.MAX_VALUE; - } else { - depthValue = Integer.parseInt(depth); - } - - LOG.debug(String.format("request header: Depth: %s", (depthValue == Integer.MAX_VALUE ? "infinity" : depthValue))); - return depthValue; - } - - /** - * Get the overwrite header value, whether to overwrite destination - * objects or collections or not. - * - * @param request the servlet request - * @return true or false - */ - boolean getOverwrite(HttpServletRequest request) { - String overwrite = request.getHeader("Overwrite"); - boolean overwriteValue = overwrite == null || "T".equals(overwrite); - - LOG.debug(String.format("request header: Overwrite: %s", overwriteValue)); - return overwriteValue; - } - - /** - * Get the destination object or collection. The destination header contains - * a URL to the destination which is returned as a file object. - * - * @param request the servlet request - * @return the file object of the destination - * @throws FileSystemException if the file system cannot create a file object - * @throws MalformedURLException if the url is misformatted - */ - FileObject getDestination(HttpServletRequest request) throws FileSystemException, MalformedURLException { - String targetUrlStr = request.getHeader("Destination"); - FileObject targetObject = null; - if (null != targetUrlStr) { - URL target = new URL(targetUrlStr); - targetObject = getVFSObject(target.getPath()); - LOG.debug(String.format("request header: Destination: %s", targetObject.getName().getPath())); - } - - return targetObject; - } - - /** - * Get the if header. - * - * @param request the request - * @return the value if the If: header. - */ - String getIf(HttpServletRequest request) { - String getIfHeader = request.getHeader("If"); - - if (null != getIfHeader) { - LOG.debug(String.format("request header: If: '%s'", getIfHeader)); - } - return getIfHeader; - } - - /** - * Get and parse the timeout header value. - * - * @param request the request - * @return the timeout - */ - long getTimeout(HttpServletRequest request) { - String timeout = request.getHeader("Timeout"); - if (null != timeout) { - String[] timeoutValues = timeout.split(",[ ]*"); - LOG.debug(String.format("request header: Timeout: %s", Arrays.asList(timeoutValues).toString())); - if ("infinity".equalsIgnoreCase(timeoutValues[0])) { - return -1; - } else { - return Integer.parseInt(timeoutValues[0].replaceAll("Second-", "")); - } - } - return -1; - } -} blob - 82ec809f38ec9a22f32b81ba769787173ef5df2d (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/data/AbstractDavResource.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.data; - -import org.dom4j.Element; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public abstract class AbstractDavResource { - private static final String STATUS_200 = "HTTP/1.1 200 OK"; - private static final String STATUS_404 = "HTTP/1.1 404 Not Found"; - public static final String STATUS_403 = "HTTP/1.1 403 Forbidden"; - - private static final String TAG_PROPSTAT = "propstat"; - private static final String TAG_PROP = "prop"; - private static final String TAG_STATUS = "status"; - - public Element serializeToXml(Element root, List requestedProperties) { - Element propStatEl = root.addElement(TAG_PROPSTAT); - Element propEl = propStatEl.addElement(TAG_PROP); - - Set missingProperties = new HashSet(); - for (String propertyName : requestedProperties) { - if (!addPropertyValue(propEl, propertyName)) { - missingProperties.add(propertyName); - } - } - propStatEl.addElement(TAG_STATUS).addText(STATUS_200); - - // add missing properties status - if (missingProperties.size() > 0) { - propStatEl = root.addElement(TAG_PROPSTAT); - propEl = propStatEl.addElement(TAG_PROP); - for (String el : missingProperties) { - propEl.addElement(el); - } - propStatEl.addElement(TAG_STATUS).addText(STATUS_404); - } - - return root; - } - - @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) - protected abstract boolean addPropertyValue(Element root, String propertyName); -} blob - fcd185c553c3e877a601f195e39e4d1687e16c32 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/data/DavCollection.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.data; - -import org.apache.commons.vfs.FileObject; -import org.dom4j.Element; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class DavCollection extends DavResource { - public static final String COLLECTION = "collection"; - - public DavCollection(FileObject object) { - super(object); - } - - - public DavCollection(FileObject object, boolean ignoreValues) { - super(object, ignoreValues); - } - - protected boolean addResourceTypeProperty(Element root) { - root.addElement(PROP_RESOURCETYPE).addElement(COLLECTION); - return true; - } - - /** - * Ignore content language for collections. - * - * @param root the prop element to add to - * @return true, even though nothing is added - */ - protected boolean addGetContentLanguageProperty(Element root) { - return true; - } - - /** - * Ignore content length for collections. - * - * @param root the prop element to add to - * @return true, even though nothing is added - */ - protected boolean addGetContentLengthProperty(Element root) { - return true; - } - - /** - * Ignore content type for collections. - * - * @param root the prop element to add to - * @return true, even though nothing is added - */ - protected boolean addGetContentTypeProperty(Element root) { - return true; - } - - protected boolean addQuotaProperty(Element root) { - root.addElement(PROP_QUOTA).addText("" + Long.MAX_VALUE); - return true; - } - - protected boolean addQuotaUsedProperty(Element root) { - // TODO add correct handling of used quota - root.addElement(PROP_QUOTA_USED).addText("0"); - return true; - } - - protected boolean addQuotaAvailableBytesProperty(Element root) { - root.addElement(PROP_QUOTA_AVAILABLE_BYTES).addText("" + Long.MAX_VALUE); - return true; - } - - protected boolean addQuotaUsedBytesProperty(Element root) { - // TODO add correct handling of used quota - root.addElement(PROP_QUOTA_USED_BYTES).addText("0"); - return true; - } -} blob - 7b8460688401f8da61a40a80db7fe85b44f0b4c3 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/data/DavResource.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.data; - -import com.thinkberg.moxo.dav.Util; -import com.thinkberg.moxo.dav.lock.Lock; -import com.thinkberg.moxo.dav.lock.LockManager; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.dom4j.Element; - -import java.util.Arrays; -import java.util.List; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class DavResource extends AbstractDavResource { - - // @see http://www.webdav.org/specs/rfc2518.html#dav.properties - public static final String PROP_CREATION_DATE = "creationdate"; - public static final String PROP_DISPLAY_NAME = "displayname"; - private static final String PROP_GET_CONTENT_LANGUAGE = "getcontentlanguage"; - private static final String PROP_GET_CONTENT_LENGTH = "getcontentlength"; - private static final String PROP_GET_CONTENT_TYPE = "getcontenttype"; - private static final String PROP_GET_ETAG = "getetag"; - private static final String PROP_GET_LAST_MODIFIED = "getlastmodified"; - private static final String PROP_LOCK_DISCOVERY = "lockdiscovery"; - public static final String PROP_RESOURCETYPE = "resourcetype"; - private static final String PROP_SOURCE = "source"; - private static final String PROP_SUPPORTED_LOCK = "supportedlock"; - - // non-standard properties - static final String PROP_QUOTA = "quota"; - static final String PROP_QUOTA_USED = "quotaused"; - static final String PROP_QUOTA_AVAILABLE_BYTES = "quota-available-bytes"; - static final String PROP_QUOTA_USED_BYTES = "quota-used-bytes"; - - // list of standard supported properties (for allprop/propname) - public static final List 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 locks = LockManager.getInstance().discoverLock(object); - if (locks != null && !locks.isEmpty()) { - for (Lock lock : locks) { - if (lock != null && !ignoreValues) { - lock.serializeToXml(lockdiscoveryEl); - } - } - } - return true; - } catch (FileSystemException e) { - e.printStackTrace(); - root.remove(lockdiscoveryEl); - return false; - } - } - - protected boolean addResourceTypeProperty(Element root) { - root.addElement(PROP_RESOURCETYPE); - return true; - } - - protected boolean addSourceProperty(Element root) { - return false; - } - - protected boolean addSupportedLockProperty(Element root) { - Element supportedlockEl = root.addElement(PROP_SUPPORTED_LOCK); - if (!ignoreValues) { - Element exclLockentryEl = supportedlockEl.addElement("lockentry"); - exclLockentryEl.addElement("lockscope").addElement("exclusive"); - exclLockentryEl.addElement("locktype").addElement("write"); - Element sharedLockentryEl = supportedlockEl.addElement("lockentry"); - sharedLockentryEl.addElement("lockscope").addElement("shared"); - sharedLockentryEl.addElement("locktype").addElement("write"); - } - - return true; - } - - protected boolean addQuotaProperty(Element root) { - return false; - } - - protected boolean addQuotaUsedProperty(Element root) { - return false; - } - - protected boolean addQuotaAvailableBytesProperty(Element root) { - return false; - } - - protected boolean addQuotaUsedBytesProperty(Element root) { - return false; - } -} blob - 8d66d4881885922677820797ffae246c27b96ef9 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/data/DavResourceFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.data; - -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileType; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class DavResourceFactory { - private static DavResourceFactory instance; - - public static DavResourceFactory getInstance() { - if (null == instance) { - instance = new DavResourceFactory(); - } - return instance; - } - - private DavResourceFactory() { - - } - - public DavResource getDavResource(FileObject object) throws FileSystemException { - if (FileType.FOLDER.equals(object.getType())) { - return new DavCollection(object); - } else { - return new DavResource(object); - } - } -} blob - 1e07eee9313edf1cf95329fbec218d5878378116 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/lock/Lock.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.lock; - -import org.apache.commons.vfs.FileObject; -import org.dom4j.Element; - -import java.net.URL; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class Lock { - public final static String SHARED = "shared"; - public final static String EXCLUSIVE = "exclusive"; - - public final static String WRITE = "write"; - - private final FileObject object; - private final String type; - private final String scope; - private final Object owner; - private final int depth; - private final long timeout; - private final String token; - - - public Lock(FileObject object, String type, String scope, Object owner, - int depth, long timeout) { - this.object = object; - this.type = type; - this.scope = scope; - this.owner = owner; - this.depth = depth; - this.timeout = timeout; - - this.token = "opaquelocktoken:" + Integer.toHexString(object.hashCode()); - } - - public FileObject getObject() { - return object; - } - - public String getType() { - return type; - } - - public String getScope() { - return scope; - } - - public Object getOwner() { - return owner; - } - - public int getDepth() { - return depth; - } - - public String getDepthValue() { - switch (depth) { - case 0: - return "0"; - case 1: - return "1"; - default: - return "Infinity"; - } - } - - public String getTimeout() { - if (timeout == -1) { - return "Infinity"; - } - return "Second-" + timeout; - } - - public String getToken() { - return this.token; - } - - /** - * Create an XML serialized version of the lock by adding an activelock tag - * with the locks properties to the root element provided. - * - * @param root the root element to add the activelock to - * @return the root element - */ - public Element serializeToXml(Element root) { - Element activelockEl = root.addElement("activelock"); - activelockEl.addElement("locktype").addElement(getType()); - activelockEl.addElement("lockscope").addElement(getScope()); - activelockEl.addElement("depth").addText(getDepthValue()); - // TODO handle owner correctly - if (getOwner() instanceof URL) { - activelockEl.addElement("owner").addElement("href") - .addText(((URL) getOwner()).toExternalForm()); - } else { - activelockEl.addElement("owner").addText((String) getOwner()); - } - activelockEl.addElement("timeout").addText(getTimeout()); - activelockEl.addElement("locktoken") - .addElement("href").addText(getToken()); - - return root; - } - - /** - * There can only be one lock per object, thus compare the file objects. - * - * @param other the other lock to compare to - * @return whether this lock is for the same file object - */ - public boolean equals(Object other) { - return other instanceof Lock && object.equals(((Lock) other).object); - } - - - public String toString() { - return String.format("Lock[%s,%s,%s,%s]", object, type, scope, token); - } -} - blob - 0944f6914361ef87067e9e0739796e73448509e2 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/lock/LockConditionFailedException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.lock; - -import java.util.List; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class LockConditionFailedException extends LockException { - private String condition = null; - - public LockConditionFailedException(List locks) { - super(locks); - } - - public LockConditionFailedException(List locks, String condition) { - super(locks); - this.condition = condition; - - } - - public String getCondition() { - return condition; - } -} blob - 217437da42098d75357b98160f381a27ba1e4c95 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/lock/LockConditionRequiredException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2009 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.lock; - -import java.util.List; - -public class LockConditionRequiredException extends LockException { - public LockConditionRequiredException(List locks) { - super(locks); - } -} blob - bc0d2328671d1f91e7b57dc24d33acd8d01e849f (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/lock/LockConflictException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.lock; - -import java.util.List; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class LockConflictException extends LockException { - public LockConflictException(List locks) { - super(locks); - } -} blob - 1ca6c2f973c038a647cd769743a77a78708243bc (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/lock/LockException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.lock; - -import java.util.List; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class LockException extends Exception { - private final List locks; - - public LockException(List locks) { - super(); - this.locks = locks; - } - - public List getLocks() { - return locks; - } - - public String toString() { - return String.format("[%s: %s]", this.getClass(), locks); - } -} blob - ffac2fafb4c81fc700c4686ab276f1625eebe709 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/dav/lock/LockManager.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.dav.lock; - -import com.thinkberg.moxo.vfs.DepthFileSelector; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSelectInfo; -import org.apache.commons.vfs.FileSystemException; - -import java.net.URI; -import java.net.URISyntaxException; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The lock manager is responsible for exclusive and shared write locks on the - * DAV server. It is used to acquire a lock, release a lock, discover existing - * locks or check conditions. The lock manager is a singleton. - * - * @author Matthias L. Jugel - * @version $Id$ - */ -public class LockManager { - private static LockManager instance = null; - private static final Log LOG = LogFactory.getLog(LockManager.class); - - // condition parser patterns and tokens - private static final Pattern IF_PATTERN = Pattern.compile("(<[^>]+>)|(\\([^)]+\\))"); - private static final Pattern CONDITION_PATTERN = Pattern.compile("([Nn][Oo][Tt])|(<[^>]+>)|(\\[[^]]+\\])"); - private static final char TOKEN_LOWER_THAN = '<'; - private static final char TOKEN_LEFT_BRACE = '('; - private static final char TOKEN_LEFT_BRACKET = '['; - - /** - * Get an instance of the lock manager. - * - * @return the lock manager - */ - public static LockManager getInstance() { - if (null == instance) { - instance = new LockManager(); - } - - return instance; - } - - private final Map> lockMap; - - /** - * The lock manager is a singleton and cannot be instantiated directly. - */ - private LockManager() { - lockMap = new HashMap>(); - } - - /** - * 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 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 discoverLock(FileObject object) throws FileSystemException { - FileObject parent = object; - while (parent != null) { - List 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. - *

- * Evaluate example 2:
- * - * URI(/resource1) { ( - * is-locked-with(urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2) - * AND matches-etag(W/"A weak ETag") ) - * OR ( matches-etag("strong ETag") ) } - * - *

- * Examples: - *

    - *
  1. <http://cid:8080/litmus/unmapped_url> (<opaquelocktoken:cd6798>)
  2. - *
  3. </resource1> (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> [W/"A weak ETag"]) (["strong ETag"])
  4. - *
  5. (<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>) (Not <DAV:no-lock>)
  6. - *
  7. (Not <urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> <urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092>)
  8. - *
  9. </specs/rfc2518.doc> (["4217"])
  10. - *
  11. </specs/rfc2518.doc> (Not ["4217"])
  12. - *
- * - * @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 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 locks = new ArrayList(); - 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 locks = lockMap.get(object); - if (null == locks) { - locks = new ArrayList(); - 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 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 childLocks = lockMap.get(fileSelectInfo.getFile()); - for (Lock childLock : childLocks) { - if (Lock.EXCLUSIVE.equals(requestedLock.getScope()) || Lock.EXCLUSIVE.equals(childLock.getScope())) { - throw new LockConflictException(childLocks); - } - } - return false; - } - }, false, new ArrayList()); - } - } - -} blob - 094aa76addd911ee350612557694b1c5fecd0879 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/servlet/MoxoWebDAVServlet.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.servlet; - -import com.thinkberg.moxo.dav.*; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileObject; -import org.mortbay.jetty.Response; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Matthias L. Jugel - * @version $Id$ - */ -public class MoxoWebDAVServlet extends HttpServlet { - private static final Log LOG = LogFactory.getLog(MoxoWebDAVServlet.class); - - private final Map handlers = new HashMap(); - private FileObject fileSystemRoot = null; - - public MoxoWebDAVServlet() { - handlers.put("COPY", new CopyHandler()); - handlers.put("DELETE", new DeleteHandler()); - handlers.put("GET", new GetHandler()); - handlers.put("HEAD", new HeadHandler()); - handlers.put("LOCK", new LockHandler()); - handlers.put("MKCOL", new MkColHandler()); - handlers.put("MOVE", new MoveHandler()); - handlers.put("OPTIONS", new OptionsHandler()); - handlers.put("POST", new PostHandler()); - handlers.put("PROPFIND", new PropFindHandler()); - handlers.put("PROPPATCH", new PropPatchHandler()); - handlers.put("PUT", new PutHandler()); - handlers.put("UNLOCK", new UnlockHandler()); - } - - protected FileObject getFileSystemRoot() { - return fileSystemRoot; - } - - public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { -// String auth = request.getHeader("Authorization"); -// String login = "", password = ""; -// -// if (auth != null) { -// auth = new String(Base64.decodeBase64(auth.substring(auth.indexOf(' ') + 1).getBytes())); -// login = auth.substring(0, auth.indexOf(':')); -// password = auth.substring(auth.indexOf(':') + 1); -// } -// -// AWSCredentials credentials = AWSCredentials.load(password, )) -// if (user == null) { -// response.setHeader("WWW-Authenticate", "Basic realm=\"Moxo\""); -// response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); -// return; -// } - - - // show we are doing the litmus test - String litmusTest = request.getHeader("X-Litmus"); - if (null == litmusTest) { - litmusTest = request.getHeader("X-Litmus-Second"); - } - if (litmusTest != null) { - LOG.info(String.format("WebDAV Litmus Test: %s", litmusTest)); - } - - String method = request.getMethod(); - LOG.debug(String.format(">> %s %s", request.getMethod(), request.getPathInfo())); - if (handlers.containsKey(method)) { - handlers.get(method).service(request, response); - } else { - response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); - } - Response jettyResponse = ((Response) response); - String reason = jettyResponse.getReason(); - LOG.debug(String.format("<< %s (%d%s)", request.getMethod(), jettyResponse.getStatus(), reason != null ? ": " + reason : "")); - } -} blob - 6e622e49ceb530d686040b60ba8b310b252b7d62 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/DepthFileSelector.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import org.apache.commons.vfs.FileSelectInfo; -import org.apache.commons.vfs.FileSelector; - -/** - * A file selector that operates depth of the directory structure and will - * select all files up to and including the depth given in the constructor. - * - * @author Matthias L. Jugel - * @version $Id$ - */ -public class DepthFileSelector implements FileSelector { - private final int maxDepth; - private final int minDepth; - - /** - * Create a file selector that will select ALL files. - */ - public DepthFileSelector() { - this(0, Integer.MAX_VALUE); - } - - /** - * Create a file selector that will select all files up to and including - * the directory depth. - * - * @param depth the maximum depth - */ - public DepthFileSelector(int depth) { - this(0, depth); - } - - public DepthFileSelector(int min, int max) { - minDepth = min; - maxDepth = max; - } - - public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception { - int depth = fileSelectInfo.getDepth(); - return depth >= minDepth && depth <= maxDepth; - } - - public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws Exception { - return fileSelectInfo.getDepth() < maxDepth; - } -} blob - 1dd702d68b6fbe36e2acde95debb98faa1b29a0f (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/S3FileName.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import org.apache.commons.vfs.FileType; -import org.apache.commons.vfs.provider.local.LocalFileName; - -/** - * @author Matthias L. Jugel - */ -public class S3FileName extends LocalFileName { - protected S3FileName(final String scheme, final String rootFile, final String path, final FileType type) { - super(scheme, rootFile, path, type); - } -} blob - 34a5d56d0239c568932ce009f30c10cda2b451c7 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/S3FileNameParser.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import org.apache.commons.vfs.FileName; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileType; -import org.apache.commons.vfs.provider.AbstractFileNameParser; -import org.apache.commons.vfs.provider.UriParser; -import org.apache.commons.vfs.provider.VfsComponentContext; - -/** - * @author Matthias L. Jugel - */ -public class S3FileNameParser extends AbstractFileNameParser { - private static final S3FileNameParser instance = new S3FileNameParser(); - - public static S3FileNameParser getInstance() { - return instance; - } - - private S3FileNameParser() { - - } - - public FileName parseUri(final VfsComponentContext context, final FileName base, final String filename) throws FileSystemException { - StringBuffer name = new StringBuffer(); - - String scheme = UriParser.extractScheme(filename, name); - UriParser.canonicalizePath(name, 0, name.length(), this); - - UriParser.fixSeparators(name); - - // Normalise the path - FileType fileType = UriParser.normalisePath(name); - - // Extract the root prefix - final String bucketName = UriParser.extractFirstElement(name); - - - return new S3FileName(scheme, bucketName, name.toString(), fileType); - } - -} blob - 8caafbfd75cd2ba1fa4dbd73d893b8cd3df66fd1 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/S3FileProvider.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import org.apache.commons.vfs.*; -import org.apache.commons.vfs.provider.AbstractOriginatingFileProvider; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -/** - * An S3 file provider. Create an S3 file system out of an S3 file name. - * Also defines the capabilities of the file system. - * - * @author Matthias L. Jugel - */ -public class S3FileProvider extends AbstractOriginatingFileProvider { - - public final static Collection capabilities = Collections.unmodifiableCollection(Arrays.asList( - Capability.CREATE, - Capability.DELETE, - Capability.RENAME, - Capability.GET_TYPE, - Capability.GET_LAST_MODIFIED, - Capability.SET_LAST_MODIFIED_FILE, - Capability.SET_LAST_MODIFIED_FOLDER, - Capability.LIST_CHILDREN, - Capability.READ_CONTENT, - Capability.URI, - Capability.WRITE_CONTENT, - Capability.APPEND_CONTENT/*, - Capability.RANDOM_ACCESS_READ, - Capability.RANDOM_ACCESS_WRITE*/ - - )); - - public S3FileProvider() { - super(); - setFileNameParser(S3FileNameParser.getInstance()); - } - - /** - * Create a file system with the S3 root provided. - * - * @param fileName the S3 file name that defines the root (bucket) - * @param fileSystemOptions file system options - * @return an S3 file system - * @throws FileSystemException if te file system cannot be created - */ - protected FileSystem doCreateFileSystem(FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException { - return S3FileSystemFactory.getFileSystem((S3FileName) fileName, fileSystemOptions); - } - - /** - * Get the capabilities of the file system provider. - * - * @return the file system capabilities - */ - public Collection getCapabilities() { - return capabilities; - } -} blob - 27fc92eae78c75b11491a79b35cad2fdb8444ed9 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/S3FileSystemFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import com.thinkberg.moxo.vfs.jets3t.Jets3tFileSystem; -import org.apache.commons.vfs.FileSystem; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileSystemOptions; - -/** - * @author Matthias L. Jugel - */ -public class S3FileSystemFactory { - public static FileSystem getFileSystem(S3FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException { - // TODO load dynamically - return new Jets3tFileSystem(fileName, fileSystemOptions); - } -} blob - 1f080072887e8f54191f85b14ae1e3d922de11bc (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/jets3t/Jets3tConnector.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs.jets3t; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jets3t.service.Jets3tProperties; -import org.jets3t.service.S3Service; -import org.jets3t.service.S3ServiceException; -import org.jets3t.service.impl.rest.httpclient.RestS3Service; -import org.jets3t.service.security.AWSCredentials; - -/** - * @author Matthias L. Jugel - */ -public class Jets3tConnector { - private static final Log LOG = LogFactory.getLog(Jets3tConnector.class); - - private static final String APPLICATION_DESCRIPTION = "S3 VFS Connector/1.0"; - - private static Jets3tConnector instance; - - /** - * Get an instance of the Jets3tConnector which is initialized and authenticated to the - * Amazon S3 Service. - * - * @return a Jets3t S3 connector - * @throws org.jets3t.service.S3ServiceException - * if connection or authentication fails - */ - public static Jets3tConnector getInstance() throws S3ServiceException { - if (null == instance) { - instance = new Jets3tConnector(); - } - return instance; - } - - private S3Service service; - - /** - * Initialize Amazon S3. - * - * @throws org.jets3t.service.S3ServiceException - * if the service cannot be accessed - */ - private Jets3tConnector() throws S3ServiceException { - String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties"); - Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName); - - if (!properties.isLoaded()) { - throw new S3ServiceException("can't find S3 configuration: " + propertiesFileName); - } - - - AWSCredentials awsCredentials = new AWSCredentials( - properties.getStringProperty("accesskey", null), - properties.getStringProperty("secretkey", null)); - - - service = new RestS3Service(awsCredentials, APPLICATION_DESCRIPTION, null); - LOG.info("S3 authentication succeeded"); - } - - public S3Service getService() { - return service; - } -} blob - e5e4ff824521e982ee015ee38c6ab14d746cbc0a (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/jets3t/Jets3tFileObject.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs.jets3t; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileName; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileType; -import org.apache.commons.vfs.provider.AbstractFileObject; -import org.apache.commons.vfs.util.MonitorOutputStream; -import org.jets3t.service.Constants; -import org.jets3t.service.S3Service; -import org.jets3t.service.S3ServiceException; -import org.jets3t.service.model.S3Bucket; -import org.jets3t.service.model.S3Object; -import org.jets3t.service.utils.Mimetypes; - -import java.io.*; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.ReadableByteChannel; -import java.util.Date; - - -/** - * Implementation of the virtual S3 file system object using the Jets3t library. - * - * @author Matthias L. Jugel - */ -public class Jets3tFileObject extends AbstractFileObject { - private static final Log LOG = LogFactory.getLog(Jets3tFileObject.class); - - private static final String VFS_LAST_MODIFIED_TIME = "vfs-last-modified-time"; - - private final S3Service service; - private final S3Bucket bucket; - - private boolean attached = false; - private boolean dirty = false; - private boolean contentCached = false; - - private S3Object object; - private File cacheFile; - - public Jets3tFileObject(FileName fileName, - Jets3tFileSystem fileSystem, - S3Service service, S3Bucket bucket) { - super(fileName, fileSystem); - this.service = service; - this.bucket = bucket; - } - - /** - * Attach S3 Object to VFS object. - * This method only downloads the meta-data without the actual content. - * If the object does not exist, it will be created locally. - * - * @throws Exception if the S3 access fails for some reason - */ - protected void doAttach() throws Exception { - if (!attached) { - try { - object = service.getObjectDetails(bucket, getS3Key()); - if (object.getMetadata(VFS_LAST_MODIFIED_TIME) == null) { - // it is possible the bucket has no last-modified data, use the S3 data then - object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + object.getLastModifiedDate().getTime()); - } - contentCached = false; - dirty = false; - - LOG.debug(String.format("attaching (existing) '%s'", object.getKey())); - } catch (S3ServiceException e) { - object = new S3Object(bucket, getS3Key()); - object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, "" + new Date().getTime()); - contentCached = true; - dirty = true; - - LOG.debug(String.format("attaching (new) '%s'", object.getKey())); - } - - attached = true; - } - } - - protected void doDetach() throws Exception { - if (attached) { - LOG.debug(String.format("detaching '%s' (dirty=%b, cached=%b)", object.getKey(), dirty, (cacheFile != null))); - object = null; - if (cacheFile != null) { - cacheFile.delete(); - cacheFile = null; - contentCached = false; - } - dirty = false; - attached = false; - } - } - - protected void doDelete() throws Exception { - // do not delete the root folder - if ("".equals(object.getKey())) { - LOG.warn(String.format("ignored attempt to delete root folder '%s' ", bucket.getName())); - return; - } - LOG.debug(String.format("deleting '%s'", object.getKey())); - service.deleteObject(bucket, object.getKey()); - if (cacheFile != null) { - cacheFile.delete(); - cacheFile = null; - contentCached = false; - } - dirty = false; - attached = false; - } - - protected void doRename(FileObject newfile) throws Exception { - super.doRename(newfile); - } - - protected void doCreateFolder() throws Exception { - if (!Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(object.getContentType())) { - object.setContentType(Mimetypes.MIMETYPE_JETS3T_DIRECTORY); - - LOG.debug(String.format("creating folder '%s'", object.getKey())); - service.putObject(bucket, object); - } - } - - protected long doGetLastModifiedTime() throws Exception { - String timeStamp = (String) object.getMetadata(VFS_LAST_MODIFIED_TIME); - if (null != timeStamp) { - return Long.parseLong(timeStamp); - } - return 0; - } - - protected void doSetLastModifiedTime(final long modtime) throws Exception { - object.addMetadata(Constants.REST_METADATA_PREFIX + VFS_LAST_MODIFIED_TIME, modtime); - dirty = true; - } - - protected InputStream doGetInputStream() throws Exception { - if (!contentCached) { - object = service.getObject(bucket, getS3Key()); - LOG.debug(String.format("caching content of '%s'", object.getKey())); - - InputStream objectInputStream = object.getDataInputStream(); - if (object.getContentLength() > 0) { - ReadableByteChannel rbc = Channels.newChannel(objectInputStream); - FileChannel cacheFc = getCacheFile().getChannel(); - cacheFc.transferFrom(rbc, 0, object.getContentLength()); - cacheFc.close(); - rbc.close(); - } else { - objectInputStream.close(); - } - contentCached = true; - } - - return Channels.newInputStream(getCacheFile().getChannel()); - } - - protected OutputStream doGetOutputStream(boolean bAppend) throws Exception { - dirty = true; - return new MonitorOutputStream(Channels.newOutputStream(getCacheFile().getChannel())) { - protected void onClose() throws IOException { - try { - LOG.debug(String.format("sending '%s' to storage (dirty=%b, cached=%b)", object.getKey(), dirty, cacheFile)); - if (cacheFile != null) { - FileChannel cacheFc = getCacheFile().getChannel(); - object.setContentLength(cacheFc.size()); - object.setDataInputStream(Channels.newInputStream(cacheFc)); - } - service.putObject(bucket, object); - } catch (S3ServiceException e) { - LOG.error(String.format("can't send object '%s' to storage", object.getKey()), e); - } - } - }; - } - - protected FileType doGetType() throws Exception { - if (null == object.getContentType()) { - return FileType.IMAGINARY; - } - - String contentType = object.getContentType(); - if ("".equals(object.getKey()) || Mimetypes.MIMETYPE_JETS3T_DIRECTORY.equals(contentType)) { - return FileType.FOLDER; - } - - return FileType.FILE; - } - - protected String[] doListChildren() throws Exception { - String path = object.getKey(); - // make sure we add a '/' slash at the end to find children - if (!"".equals(path)) { - path = path + "/"; - } - - S3Object[] children = service.listObjects(bucket, path, "/"); - String[] childrenNames = new String[children.length]; - for (int i = 0; i < children.length; i++) { - if (!children[i].getKey().equals(path)) { - // strip path from name (leave only base name) - childrenNames[i] = children[i].getKey().replaceAll("[^/]*//*", ""); - } - } - - return childrenNames; - } - - protected long doGetContentSize() throws Exception { - return object.getContentLength(); - } - - // Utility methods - /** - * Create an S3 key from a commons-vfs path. This simply - * strips the slash from the beginning if it exists. - * - * @return the S3 object key - */ - private String getS3Key() { - String path = getName().getPath(); - if ("".equals(path)) { - return path; - } else { - return path.substring(1); - } - } - - private RandomAccessFile getCacheFile() throws IOException, S3ServiceException { - if (cacheFile == null) { - cacheFile = File.createTempFile("moxo.", ".s3"); - } - return new RandomAccessFile(cacheFile, "rw"); - } -} blob - 1c80a615bbd89066c8f4fccfe435b9b490d829b9 (mode 644) blob + /dev/null --- src/main/java/com/thinkberg/moxo/vfs/jets3t/Jets3tFileSystem.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs.jets3t; - -import com.thinkberg.moxo.vfs.S3FileName; -import com.thinkberg.moxo.vfs.S3FileProvider; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs.FileName; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileSystemOptions; -import org.apache.commons.vfs.provider.AbstractFileSystem; -import org.jets3t.service.S3Service; -import org.jets3t.service.S3ServiceException; -import org.jets3t.service.model.S3Bucket; - -import java.util.Collection; - -/** - * An S3 file system. - * - * @author Matthias L. Jugel - */ -public class Jets3tFileSystem extends AbstractFileSystem { - private static final Log LOG = LogFactory.getLog(Jets3tFileSystem.class); - - private S3Service service; - private S3Bucket bucket; - - public Jets3tFileSystem(S3FileName fileName, FileSystemOptions fileSystemOptions) throws FileSystemException { - super(fileName, null, fileSystemOptions); - String bucketId = fileName.getRootFile(); - try { - service = Jets3tConnector.getInstance().getService(); - if (!service.isBucketAccessible(bucketId)) { - LOG.info(String.format("creating new S3 bucket '%s' for file system root", bucketId)); - bucket = service.createBucket(bucketId); - } else { - LOG.info(String.format("using existing S3 bucket '%s' for file system root", bucketId)); - bucket = new S3Bucket(bucketId); - } - } catch (S3ServiceException e) { - throw new FileSystemException(e); - } - } - - public void destroyFileSystem() throws FileSystemException { - try { - service.deleteBucket(bucket); - } catch (S3ServiceException e) { - throw new FileSystemException("can't delete file system root", e); - } - - - } - - @SuppressWarnings({"unchecked"}) - protected void addCapabilities(Collection caps) { - caps.addAll(S3FileProvider.capabilities); - } - - protected FileObject createFile(FileName fileName) throws Exception { - return new Jets3tFileObject(fileName, this, service, bucket); - } - - -} blob - 686c14998f8bbad319b7f2e07f193ecb66f3cbb8 (mode 644) blob + /dev/null --- src/main/resources/META-INF/vfs-providers.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - blob - 3067e4fa327fbd14e218e7adccae96656857cc6b blob + 71c406fc4d38c233930be39548d9d3767b2a5d3b --- src/main/resources/jetty.xml +++ src/main/resources/jetty.xml @@ -130,9 +130,26 @@ - com.thinkberg.moxo.servlet.MoxoWebDAVServlet + com.thinkberg.webdav.servlet.MoxoWebDAVServlet /* + + vfs.uri + ram:/ + + + vfs.auth.domain + + + + vfs.auth.user + theuser + + + vfs.auth.password + thepassword + + blob - 2431b8fe9d36132a3fa0f91baef89bc9df06ccc6 (mode 644) blob + /dev/null --- src/main/resources/moxo.template.properties +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright 2007 Matthias L. Jugel. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -##################################### -# VFS provider application properties -# -# This file must be available on the -# classpath when the VFS is used -#################################### - -# AWS Access Key (required) -accesskey= - -# AWS Secret Key (required) -secretkey= - -# 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= - -# the bucket that contains the file system -s3.url=s3://TESTBUCKET/ -#s3.url=ram:/ \ No newline at end of file blob - 674ed457589717c031e07eeae6ec32eea0b1deb7 (mode 644) blob + /dev/null --- src/test/java/com/thinkberg/moxo/MoxoTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.thinkberg.moxo; - -import com.thinkberg.moxo.dav.DavLockManagerTest; -import com.thinkberg.moxo.dav.DavResourceTest; -import com.thinkberg.moxo.vfs.S3FileNameTest; -import com.thinkberg.moxo.vfs.S3FileProviderTest; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; -import org.jets3t.service.Jets3tProperties; - -/** - * Unit tests for the Moxo S3 Amazon Proxy server. - * - * @author Matthias L. Jugel - */ -public class MoxoTest extends TestCase { - /** - * The complete Moxo Test suite. - * - * @param name name of the test case - */ - public MoxoTest(String name) { - super(name); - } - - /** - * Add all known tests to the suite. - * - * @return the suite of tests being tested - */ - public static Test suite() { - TestSuite s = new TestSuite(); - - s.addTestSuite(DavResourceTest.class); - s.addTestSuite(DavLockManagerTest.class); - - String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties"); - Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName); - - String vfsUrl = properties.getStringProperty("vfs.uri", null); - if (null != vfsUrl && vfsUrl.startsWith("s3:")) { - s.addTestSuite(S3FileNameTest.class); - s.addTestSuite(S3FileProviderTest.class); - } - - return s; - } - - -} blob - df58a524ec201431dcad1cd542b86f58aed5384d (mode 644) blob + /dev/null --- src/test/java/com/thinkberg/moxo/dav/DavLockManagerTest.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.lock.Lock; -import com.thinkberg.moxo.dav.lock.LockConflictException; -import com.thinkberg.moxo.dav.lock.LockManager; - -/** - * @author Matthias L. Jugel - */ -public class DavLockManagerTest extends DavTestCase { - private final String OWNER_STR = "testowner"; - - public DavLockManagerTest() { - super(); - } - - public void testAcquireSingleSharedFileLock() { - Lock sharedLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600); - try { - LockManager.getInstance().acquireLock(sharedLock); - } catch (Exception e) { - assertNull(e.getMessage(), e); - } - } - - public void testAcquireDoubleSharedFileLock() { - Lock sharedLock1 = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600); - Lock sharedLock2 = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR + "1", 0, 3600); - try { - LockManager.getInstance().acquireLock(sharedLock1); - LockManager.getInstance().acquireLock(sharedLock2); - } catch (Exception e) { - assertNull(e.getMessage(), e); - } - } - - public void testFailToAcquireExclusiveLockOverSharedLock() { - Lock sharedLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600); - Lock exclusiveLock = new Lock(aFile, Lock.WRITE, Lock.EXCLUSIVE, OWNER_STR, 0, 3600); - try { - LockManager.getInstance().acquireLock(sharedLock); - LockManager.getInstance().acquireLock(exclusiveLock); - assertTrue("acquireLock() should fail", false); - } catch (Exception e) { - assertEquals(LockConflictException.class, e.getClass()); - } - } - - public void testConditionUnmappedFails() throws Exception { - final String condition = " ()"; - 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 )"; - assertTrue("using (Not ) 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 [" + eTag + "x])"; - LockManager.getInstance().acquireLock(aLock); - assertFalse("complex condition with bogus eTag should fail", - LockManager.getInstance().evaluateCondition(aFile, condition).result); - } - - -// assertFalse(lockManager.evaluateCondition(aFile, " ( [W/\"A weak ETag\"]) ([\"strong ETag\"])"); -// lockManager.evaluateCondition(aFile, "() (Not )"); -// lockManager.evaluateCondition(aFile, "(Not )"); -// lockManager.evaluateCondition(aFile, " ([\"4217\"])"); -// lockManager.evaluateCondition(aFile, " (Not [\"4217\"])"); -// lockManager.evaluateCondition(aFile, "() (Not ) (Not [\"4217\"])"); -// lockManager.evaluateCondition(aFile, "( [10a198]) (Not [10a198])"); - -// public void testLockConditionRequiredException() { -// Lock sharedLock = new Lock(aFile, Lock.WRITE, Lock.SHARED, OWNER_STR, 0, 3600); -// try { -// LockManager.getInstance().acquireLock(sharedLock); -// LockManager.getInstance().checkCondition(aFile, null); -// assertTrue("checkCondition() should fail", false); -// } catch (Exception e) { -// assertEquals(LockConditionRequiredException.class, e.getClass()); -// } -// } -} blob - 66f3e2ed8c1495e69dd6a684bf30ad748976367b (mode 644) blob + /dev/null --- src/test/java/com/thinkberg/moxo/dav/DavResourceTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.data.DavCollection; -import com.thinkberg.moxo.dav.data.DavResource; -import org.apache.commons.vfs.FileSystemException; -import org.dom4j.Element; - -import java.io.IOException; - -/** - * Test case for the DAV resource wrapper. Checks that resources are serialized - * correctly. - * - * @author Matthias L. Jugel - */ -public class DavResourceTest extends DavTestCase { - public void testFileCreationDateIsNull() throws FileSystemException { - Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE); - assertNull(selectExistingProperty(root, DavResource.PROP_CREATION_DATE)); - } - - public void testFileCreationDateIsMissing() throws IOException { - Element root = serializeDavResource(aFile, DavResource.PROP_CREATION_DATE); - assertEquals(DavResource.PROP_CREATION_DATE, - selectMissingPropertyName(root, DavResource.PROP_CREATION_DATE)); - } - - public void testFileDisplayNameWithValue() throws FileSystemException { - testPropertyValue(aFile, DavResource.PROP_DISPLAY_NAME, aFile.getName().getBaseName()); - } - - public void testFileDisplayNameWithoutValue() throws FileSystemException { - testPropertyNoValue(aFile, DavResource.PROP_DISPLAY_NAME); - } - - public void testFileResourceTypeNotMissing() throws FileSystemException { - Element root = serializeDavResource(aFile, DavResource.PROP_RESOURCETYPE); - assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE)); - } - - public void testDirectoryResourceTypeNotMissing() throws FileSystemException { - Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE); - assertNull(selectMissingProperty(root, DavResource.PROP_RESOURCETYPE)); - } - - public void testFileResourceType() throws FileSystemException { - testPropertyNoValue(aFile, DavResource.PROP_RESOURCETYPE); - } - - public void testDirectoryResourceType() throws FileSystemException { - Element root = serializeDavResource(aDirectory, DavResource.PROP_RESOURCETYPE); - assertNotNull(selectExistingProperty(root, DavResource.PROP_RESOURCETYPE).selectSingleNode(DavCollection.COLLECTION)); - } -} blob - c348a78e06fa4feda0222993ce6a971a7d0994fa (mode 644) blob + /dev/null --- src/test/java/com/thinkberg/moxo/dav/DavTestCase.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.thinkberg.moxo.dav; - -import com.thinkberg.moxo.dav.data.DavResource; -import com.thinkberg.moxo.dav.data.DavResourceFactory; -import junit.framework.TestCase; -import org.apache.commons.vfs.FileObject; -import org.apache.commons.vfs.FileSystemException; -import org.apache.commons.vfs.FileSystemManager; -import org.apache.commons.vfs.VFS; -import org.dom4j.DocumentHelper; -import org.dom4j.Element; -import org.dom4j.Node; - -import java.util.Arrays; - -/** - * Helper class for DAV tests. - * - * @author Matthias L. Jugel - */ -public class DavTestCase extends TestCase { - private static final String PROP_EXISTS = "propstat[status='HTTP/1.1 200 OK']/prop/"; - private static final String PROP_MISSING = "propstat[status='HTTP/1.1 404 Not Found']/prop/"; - private static final String EMPTY = ""; - - FileObject aFile; - FileObject aDirectory; - - - protected void setUp() throws Exception { - super.setUp(); - FileSystemManager fsm = VFS.getManager(); - FileObject fsRoot = fsm.createVirtualFileSystem(fsm.resolveFile("ram:/")); - aFile = fsRoot.resolveFile("/file.txt"); - aFile.delete(); - aFile.createFile(); - aDirectory = fsRoot.resolveFile("/folder"); - aDirectory.delete(); - aDirectory.createFolder(); - } - - protected void testPropertyValue(FileObject object, String propertyName, String propertyValue) throws FileSystemException { - Element root = serializeDavResource(object, propertyName); - assertEquals(propertyValue, selectExistingPropertyValue(root, propertyName)); - } - - protected void testPropertyNoValue(FileObject object, String propertyName) throws FileSystemException { - Element root = serializeDavResource(object, propertyName, true); - assertEquals(EMPTY, selectExistingPropertyValue(root, propertyName)); - } - - Node selectExistingProperty(Element root, String propertyName) { - return root.selectSingleNode(PROP_EXISTS + propertyName); - } - - Node selectMissingProperty(Element root, String propertyName) { - return root.selectSingleNode(PROP_MISSING + propertyName); - } - - String selectMissingPropertyName(Element root, String propertyName) { - return selectMissingProperty(root, propertyName).getName(); - } - - private String selectExistingPropertyValue(Element root, String propertyName) { - return selectExistingProperty(root, propertyName).getText(); - } - - Element serializeDavResource(FileObject object, String propertyName) throws FileSystemException { - return serializeDavResource(object, propertyName, false); - } - - private Element serializeDavResource(FileObject object, String propertyName, boolean ignoreValues) throws FileSystemException { - Element root = DocumentHelper.createElement("root"); - DavResourceFactory factory = DavResourceFactory.getInstance(); - DavResource davResource = factory.getDavResource(object); - davResource.setIgnoreValues(ignoreValues); - davResource.serializeToXml(root, Arrays.asList(propertyName)); - return root; - } - -} blob - cad1af21c05c18a65efeb78b403be26e71fca272 (mode 644) blob + /dev/null --- src/test/java/com/thinkberg/moxo/vfs/S3FileNameTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import org.apache.commons.vfs.FileName; -import org.apache.commons.vfs.FileSystemException; - -import java.net.URI; - -/** - * @author Matthias L. Jugel - */ -public class S3FileNameTest extends S3TestCase { - public void testGetBucketFromUri() throws FileSystemException { - String uriString = ROOT + "/junk.txt"; - String bucketId = URI.create(uriString).getHost(); - FileName fileName = S3FileNameParser.getInstance().parseUri(null, null, uriString); - assertEquals(bucketId, ((S3FileName) fileName).getRootFile()); - } - - public void testGetRootFolderFromUri() throws FileSystemException { - String path = "/myfolder"; - String uri = ROOT + path; - FileName fileName = S3FileNameParser.getInstance().parseUri(null, null, uri); - assertEquals(path, fileName.getPath()); - } -} blob - 5b2ab9887bbf9efd98ff97084bc3b832cb1ed6ef (mode 644) blob + /dev/null --- src/test/java/com/thinkberg/moxo/vfs/S3FileProviderTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import com.thinkberg.moxo.vfs.jets3t.Jets3tFileSystem; -import org.apache.commons.vfs.*; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.URI; -import java.util.Arrays; - -/** - * @author Matthias L. Jugel - */ -public class S3FileProviderTest extends S3TestCase { - private static final FileSelector ALL_FILE_SELECTOR = new FileSelector() { - - public boolean includeFile(FileSelectInfo fileInfo) throws Exception { - return true; - } - - public boolean traverseDescendents(FileSelectInfo fileInfo) throws Exception { - return true; - } - }; - private static final String FOLDER = "/directory"; - private static final String FILE = FOLDER + "/newfile.txt"; - - static { - try { - FileObject rootFs = VFS.getManager().resolveFile(ROOT); - rootFs.delete(ALL_FILE_SELECTOR); - } catch (FileSystemException e) { - // just delete, ignore the rest - } - } - - public void testDoCreateFileSystem() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT); - String bucketId = URI.create(ROOT).getHost(); - assertEquals(bucketId, ((S3FileName) object.getName()).getRootFile()); - } - - - public void testFileSystemIsEmpty() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT); - assertEquals(1, object.findFiles(ALL_FILE_SELECTOR).length); - } - - public void testRootDirectoryIsFolder() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT); - assertEquals(FileType.FOLDER, object.getType()); - } - - public void testCreateFolder() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER); - assertFalse(object.exists()); - object.createFolder(); - assertTrue(object.exists()); - assertEquals(FileType.FOLDER, object.getType()); - } - - public void testGetFolder() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER); - assertTrue(object.exists()); - assertEquals(FileType.FOLDER, object.getType()); - } - - public void testCreateFile() throws IOException { - FileObject object = VFS.getManager().resolveFile(ROOT + FILE); - assertFalse(object.exists()); - OutputStream os = object.getContent().getOutputStream(); - os.write(0xfc); - os.close(); - assertTrue(object.exists()); - assertEquals(FileType.FILE, object.getType()); - } - - public void testCreateEmptyFile() throws IOException { - FileObject object = VFS.getManager().resolveFile(ROOT + FILE + ".empty"); - assertFalse(object.exists()); - object.createFile(); - assertTrue(object.exists()); - assertEquals(FileType.FILE, object.getType()); - } - - public void testFileHasLastModifiedTimestamp() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FILE); - object.getContent().getLastModifiedTime(); - } - - public void testGetFolderListing() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER); - FileObject[] files = object.findFiles(new DepthFileSelector(1)); - assertEquals(3, files.length); - } - - public void testMissingFile() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + "/nonexisting.txt"); - assertFalse(object.exists()); - } - - public void testGetLastModifiedTimeFolder() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER); - object.getContent().getLastModifiedTime(); - } - - public void testGetLastModifiedTimeFile() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FILE); - object.getContent().getLastModifiedTime(); - } - - public void testDeleteFile() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FILE); - object.delete(); - assertFalse(object.exists()); - } - - public void testDeleteFolder() throws FileSystemException { - FileObject object = VFS.getManager().resolveFile(ROOT + FOLDER); - object.delete(ALL_FILE_SELECTOR); - assertFalse(object.exists()); - } - - public void testCopyFolder() throws FileSystemException { - FileObject origFolder = VFS.getManager().resolveFile(ROOT + FOLDER); - origFolder.createFolder(); - - origFolder.resolveFile("file.0").createFile(); - origFolder.resolveFile("file.1").createFile(); - origFolder.resolveFile("file.2").createFile(); - - FileObject[] origFiles = origFolder.findFiles(new DepthFileSelector(1)); - assertEquals(4, origFiles.length); - - FileObject destFolder = VFS.getManager().resolveFile(ROOT + FOLDER + "_dest"); - assertFalse(destFolder.exists()); - destFolder.copyFrom(origFolder, new DepthFileSelector(1)); - assertTrue(destFolder.exists()); - - FileObject[] destFiles = destFolder.findFiles(new DepthFileSelector(1)); - System.err.println(Arrays.asList(destFiles)); - assertEquals(4, destFiles.length); - - for (int i = 0; i < origFiles.length; i++) { - assertEquals(origFiles[i].getName().getRelativeName(origFolder.getName()), - destFiles[i].getName().getRelativeName(destFolder.getName())); - } - - origFolder.delete(ALL_FILE_SELECTOR); - destFolder.delete(ALL_FILE_SELECTOR); - - assertFalse(origFolder.exists()); - assertFalse(destFolder.exists()); - } - -// public void testMoveFolder() throws FileSystemException { -// -// } - - public void testCloseFileSystem() throws FileSystemException { - FileSystem fs = VFS.getManager().resolveFile(ROOT).getFileSystem(); - VFS.getManager().closeFileSystem(fs); - } - - public void testDestroyFileSystem() throws FileSystemException { - FileSystem fs = VFS.getManager().resolveFile(ROOT).getFileSystem(); - assertTrue(fs instanceof Jets3tFileSystem); - ((Jets3tFileSystem) fs).destroyFileSystem(); - } -} blob - 76282b1a08134826075cca2b0d02c7972257af5c (mode 644) blob + /dev/null --- src/test/java/com/thinkberg/moxo/vfs/S3TestCase.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2007 Matthias L. Jugel. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.thinkberg.moxo.vfs; - -import junit.framework.TestCase; -import org.jets3t.service.Jets3tProperties; - -import java.util.Random; - -/** - * @author Matthias L. Jugel - */ -public class S3TestCase extends TestCase { - protected static final String ROOT; - - static { - String propertiesFileName = System.getProperty("moxo.properties", "moxo.properties"); - Jets3tProperties properties = Jets3tProperties.getInstance(propertiesFileName); - System.out.println("ignoring original vfs.url settings for test: " + properties.getStringProperty("vfs.uri", "ram:/")); - ROOT = "s3://MOXOTEST" + String.format("%X", new Random(System.currentTimeMillis()).nextLong()) + "/"; - System.out.println("using " + ROOT); - } -}