diff --git a/extensions/webdav/src/org/exist/webdav/ByteCountOutputStream.java b/extensions/webdav/src/org/exist/webdav/ByteCountOutputStream.java index 6165e9329b5..05349704889 100644 --- a/extensions/webdav/src/org/exist/webdav/ByteCountOutputStream.java +++ b/extensions/webdav/src/org/exist/webdav/ByteCountOutputStream.java @@ -25,7 +25,6 @@ import java.io.OutputStream; /** - * * @author wessels */ public class ByteCountOutputStream extends OutputStream { diff --git a/extensions/webdav/src/org/exist/webdav/ExistCollection.java b/extensions/webdav/src/org/exist/webdav/ExistCollection.java index da564bd30f7..055931d44d7 100644 --- a/extensions/webdav/src/org/exist/webdav/ExistCollection.java +++ b/extensions/webdav/src/org/exist/webdav/ExistCollection.java @@ -21,18 +21,7 @@ */ package org.exist.webdav; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; - import org.apache.commons.io.IOUtils; - import org.exist.EXistException; import org.exist.collections.Collection; import org.exist.collections.IndexInfo; @@ -40,39 +29,43 @@ import org.exist.dom.persistent.DocumentImpl; import org.exist.security.Permission; import org.exist.security.PermissionDeniedException; -import org.exist.storage.txn.TransactionManager; -import org.exist.storage.txn.Txn; import org.exist.storage.BrokerPool; import org.exist.storage.DBBroker; import org.exist.storage.lock.Lock.LockMode; -import org.exist.util.LockException; -import org.exist.util.MimeTable; -import org.exist.util.MimeType; -import org.exist.util.VirtualTempFile; -import org.exist.util.VirtualTempFileInputSource; - +import org.exist.storage.txn.TransactionManager; +import org.exist.storage.txn.Txn; +import org.exist.util.*; import org.exist.webdav.exceptions.CollectionDoesNotExistException; import org.exist.webdav.exceptions.CollectionExistsException; import org.exist.xmldb.XmldbURI; - import org.xml.sax.SAXException; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; + /** * Class for accessing the Collection class of the exist-db native API. * * @author Dannes Wessels (dizzzz_at_exist-db.org) */ public class ExistCollection extends ExistResource { - + /** - * Constructor. - * - * @param uri URI of document - * @param pool Reference to brokerpool + * Constructor. + * + * @param uri URI of document + * @param pool Reference to brokerpool */ public ExistCollection(XmldbURI uri, BrokerPool pool) { - if(LOG.isTraceEnabled()) { + if (LOG.isTraceEnabled()) { LOG.trace(String.format("New collection object for %s", uri)); } @@ -97,7 +90,7 @@ public void initMetadata() { return; } - try(final DBBroker broker = brokerPool.get(Optional.of(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.of(subject))) { // Get access to collection Collection collection = null; try { @@ -139,7 +132,7 @@ public void initMetadata() { public List getCollectionURIs() { final List collectionURIs = new ArrayList<>(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { // Try to read as specified subject Collection collection = null; try { @@ -170,7 +163,7 @@ public void initMetadata() { public List getDocumentURIs() { final List documentURIs = new ArrayList<>(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { Collection collection = null; try { // Try to read as specified subject @@ -201,7 +194,7 @@ public void initMetadata() { */ void delete() { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Deleting '%s'", xmldbUri)); } @@ -209,8 +202,8 @@ void delete() { final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); - final Txn txn = txnManager.beginTransaction()) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); + final Txn txn = txnManager.beginTransaction()) { // Open collection if possible, else abort collection = broker.openCollection(xmldbUri, LockMode.WRITE_LOCK); @@ -225,7 +218,7 @@ void delete() { // Commit change txnManager.commit(txn); - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("Document deleted sucessfully"); } } catch (EXistException | IOException | PermissionDeniedException | TriggerException e) { @@ -237,7 +230,7 @@ void delete() { collection.release(LockMode.WRITE_LOCK); } - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("Finished delete"); } } @@ -245,7 +238,7 @@ void delete() { public XmldbURI createCollection(String name) throws PermissionDeniedException, CollectionExistsException, EXistException { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Create '%s' in '%s'", name, xmldbUri)); } @@ -254,8 +247,8 @@ public XmldbURI createCollection(String name) throws PermissionDeniedException, final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); - final Txn txn = txnManager.beginTransaction()) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); + final Txn txn = txnManager.beginTransaction()) { // Check if collection exists. not likely to happen since availability is // checked by ResourceFactory @@ -264,7 +257,7 @@ public XmldbURI createCollection(String name) throws PermissionDeniedException, final String msg = "Collection already exists"; LOG.debug(msg); - + //XXX: double "abort" is bad thing!!! txnManager.abort(txn); throw new CollectionExistsException(msg); @@ -278,7 +271,7 @@ public XmldbURI createCollection(String name) throws PermissionDeniedException, // Commit change txnManager.commit(txn); - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("Collection created sucessfully"); } } catch (EXistException | PermissionDeniedException e) { @@ -296,7 +289,7 @@ public XmldbURI createCollection(String name) throws PermissionDeniedException, collection.release(LockMode.WRITE_LOCK); } - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("Finished creation"); } } @@ -307,7 +300,7 @@ public XmldbURI createCollection(String name) throws PermissionDeniedException, public XmldbURI createFile(String newName, InputStream is, Long length, String contentType) throws IOException, PermissionDeniedException, CollectionDoesNotExistException { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("Create '%s' in '%s'", newName, xmldbUri)); XmldbURI newNameUri = XmldbURI.create(newName); @@ -323,8 +316,8 @@ public XmldbURI createFile(String newName, InputStream is, Long length, String c // create temp file and store. Existdb needs to read twice from a stream. VirtualTempFile vtf = new VirtualTempFile(); - try(final BufferedInputStream bis = new BufferedInputStream(is); - final BufferedOutputStream bos = new BufferedOutputStream(vtf)) { + try (final BufferedInputStream bis = new BufferedInputStream(is); + final BufferedOutputStream bos = new BufferedOutputStream(vtf)) { // Perform actual copy IOUtils.copy(bis, bos); @@ -335,7 +328,7 @@ public XmldbURI createFile(String newName, InputStream is, Long length, String c // XML documents are not supported a small file will be created. if (mime.isXMLType() && vtf.length() == 0L) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("Creating dummy XML file for null resource lock '%s'", newNameUri)); vtf = new VirtualTempFile(); @@ -345,8 +338,8 @@ public XmldbURI createFile(String newName, InputStream is, Long length, String c final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); - final Txn txn = txnManager.beginTransaction()) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); + final Txn txn = txnManager.beginTransaction()) { // Check if collection exists. not likely to happen since availability is checked // by ResourceFactory @@ -360,11 +353,11 @@ public XmldbURI createFile(String newName, InputStream is, Long length, String c if (mime.isXMLType()) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("Inserting XML document '%s'", mime.getName())); // Stream into database - try(final VirtualTempFileInputSource vtfis = new VirtualTempFileInputSource(vtf)) { + try (final VirtualTempFileInputSource vtfis = new VirtualTempFileInputSource(vtf)) { IndexInfo info = collection.validateXMLResource(txn, broker, newNameUri, vtfis); DocumentImpl doc = info.getDocument(); doc.getMetadata().setMimeType(mime.getName()); @@ -373,12 +366,12 @@ public XmldbURI createFile(String newName, InputStream is, Long length, String c } else { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("Inserting BINARY document '%s'", mime.getName())); // Stream into database - try(final InputStream fis = vtf.getByteStream(); - final InputStream bis = new BufferedInputStream(fis)) { + try (final InputStream fis = vtf.getByteStream(); + final InputStream bis = new BufferedInputStream(fis)) { collection.addBinaryResource(txn, broker, newNameUri, bis, mime.getName(), length); } } @@ -414,7 +407,7 @@ public XmldbURI createFile(String newName, InputStream is, Long length, String c collection.release(LockMode.WRITE_LOCK); } - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("Finished creation"); } } @@ -427,13 +420,13 @@ public XmldbURI createFile(String newName, InputStream is, Long length, String c void resourceCopyMove(XmldbURI destCollectionUri, String newName, Mode mode) throws EXistException { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("%s '%s' to '%s' named '%s'", mode, xmldbUri, destCollectionUri, newName)); XmldbURI newNameUri = null; try { newNameUri = XmldbURI.xmldbUriFor(newName); - + } catch (URISyntaxException ex) { LOG.error(ex); throw new EXistException(ex.getMessage()); @@ -449,8 +442,8 @@ void resourceCopyMove(XmldbURI destCollectionUri, String newName, Mode mode) thr final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); - final Txn txn = txnManager.beginTransaction()) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); + final Txn txn = txnManager.beginTransaction()) { // Open collection if possible, else abort srcCollection = broker.openCollection(srcCollectionUri, srcCollectionLockMode); @@ -479,7 +472,7 @@ void resourceCopyMove(XmldbURI destCollectionUri, String newName, Mode mode) thr // Commit change txnManager.commit(txn); - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Collection %sd successfully", mode)); } diff --git a/extensions/webdav/src/org/exist/webdav/ExistDocument.java b/extensions/webdav/src/org/exist/webdav/ExistDocument.java index 531a8815f5a..11f3bffca24 100644 --- a/extensions/webdav/src/org/exist/webdav/ExistDocument.java +++ b/extensions/webdav/src/org/exist/webdav/ExistDocument.java @@ -21,13 +21,6 @@ */ package org.exist.webdav; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.net.URISyntaxException; -import java.util.Optional; - import org.exist.EXistException; import org.exist.collections.Collection; import org.exist.collections.triggers.TriggerException; @@ -48,9 +41,15 @@ import org.exist.webdav.exceptions.DocumentAlreadyLockedException; import org.exist.webdav.exceptions.DocumentNotLockedException; import org.exist.xmldb.XmldbURI; - import org.xml.sax.SAXException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.URISyntaxException; +import java.util.Optional; + /** * Class for accessing the Collection class of the exist-db native API. * @@ -58,11 +57,15 @@ */ public class ExistDocument extends ExistResource { + private String mimeType; + private long contentLength = 0; + private boolean isXmlDocument = false; + /** - * Constructor. - * - * @param uri URI of document - * @param pool Reference to brokerpool + * Constructor. + * + * @param uri URI of document + * @param pool Reference to brokerpool */ public ExistDocument(XmldbURI uri, BrokerPool pool) { @@ -91,7 +94,7 @@ public void initMetadata() { return; } - try(final DBBroker broker = brokerPool.get(Optional.of(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.of(subject))) { DocumentImpl document = null; try { // If it is not a collection, check if it is a document @@ -118,7 +121,7 @@ public void initMetadata() { // Get (estimated) file size contentLength = document.getContentLength(); - } finally { + } finally { // Cleanup resources if (document != null) { document.getUpdateLock().release(LockMode.READ_LOCK); @@ -130,19 +133,14 @@ public void initMetadata() { isInitialized = true; } - private String mimeType; public String getMimeType() { return mimeType; } - - private long contentLength = 0; public long getContentLength() { return contentLength; } - - private boolean isXmlDocument = false; public boolean isXmlDocument() { return isXmlDocument; @@ -159,7 +157,7 @@ public void stream(OutputStream os) throws IOException, PermissionDeniedExceptio long startTime = System.currentTimeMillis(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { DocumentImpl document = null; try { @@ -171,8 +169,10 @@ public void stream(OutputStream os) throws IOException, PermissionDeniedExceptio Serializer serializer = broker.getSerializer(); serializer.reset(); try { - // Set serialization options - serializer.setProperties(configuration); + // Set custom serialization options when available + if (!configuration.isEmpty()) { + serializer.setProperties(configuration); + } // Serialize document try (Writer w = new OutputStreamWriter(os, "UTF-8")) { @@ -230,8 +230,8 @@ void delete() { final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); - final Txn txn = txnManager.beginTransaction()) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); + final Txn txn = txnManager.beginTransaction()) { // Need to split path into collection and document name XmldbURI collName = xmldbUri.removeLastSegment(); @@ -295,7 +295,7 @@ public LockToken getCurrentLock() { DocumentImpl document = null; - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { // If it is not a collection, check if it is a document document = broker.getXMLResource(xmldbUri, LockMode.READ_LOCK); @@ -361,7 +361,7 @@ public LockToken lock(LockToken inputToken) throws PermissionDeniedException, DocumentImpl document = null; - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { // Try to get document (add catch?) document = broker.getXMLResource(xmldbUri, LockMode.WRITE_LOCK); @@ -385,9 +385,9 @@ public LockToken lock(LockToken inputToken) throws PermissionDeniedException, } } - if ( userLock != null && userLock.getName() != null + if (userLock != null && userLock.getName() != null && !userLock.getName().equals(subject.getName()) - && !subject.hasDbaRole() ) { + && !subject.hasDbaRole()) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Resource is locked by user %s.", userLock.getName())); } @@ -414,7 +414,7 @@ public LockToken lock(LockToken inputToken) throws PermissionDeniedException, // Make token persistant final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final Txn txn = txnManager.beginTransaction()) { + try (final Txn txn = txnManager.beginTransaction()) { broker.storeMetadata(txn, document); txnManager.commit(txn); } @@ -422,7 +422,7 @@ public LockToken lock(LockToken inputToken) throws PermissionDeniedException, if (LOG.isDebugEnabled()) { LOG.debug("Successfully retrieved token"); } - + return inputToken; @@ -433,7 +433,7 @@ public LockToken lock(LockToken inputToken) throws PermissionDeniedException, } catch (TriggerException e) { LOG.error(e); throw new EXistException(e); - } finally { + } finally { // TODO: check if can be done earlier if (document != null) { @@ -459,8 +459,8 @@ void unlock() throws PermissionDeniedException, DocumentNotLockedException, EXis final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); - final Txn txn = txnManager.beginTransaction()) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); + final Txn txn = txnManager.beginTransaction()) { // Try to get document (add catch?) @@ -482,7 +482,7 @@ void unlock() throws PermissionDeniedException, DocumentNotLockedException, EXis } // Check if Resource is from subject - if (!lock.getName().equals(subject.getName()) && !subject.hasDbaRole() ) { + if (!lock.getName().equals(subject.getName()) && !subject.hasDbaRole()) { LOG.debug(String.format("Resource lock is from user %s", lock.getName())); throw new PermissionDeniedException(lock.getName()); } @@ -502,7 +502,7 @@ void unlock() throws PermissionDeniedException, DocumentNotLockedException, EXis } catch (TriggerException e) { LOG.error(e); throw new EXistException(e); - } finally { + } finally { if (document != null) { document.getUpdateLock().release(LockMode.WRITE_LOCK); } @@ -541,8 +541,8 @@ void resourceCopyMove(XmldbURI destCollectionUri, String newName, Mode mode) thr final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); - final Txn txn = txnManager.beginTransaction()) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject)); + final Txn txn = txnManager.beginTransaction()) { // Need to split path into collection and document name XmldbURI srcCollectionUri = xmldbUri.removeLastSegment(); @@ -633,7 +633,7 @@ public LockToken refreshLock(String token) throws PermissionDeniedException, throw new EXistException("token is null"); } - try(final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { + try (final DBBroker broker = brokerPool.get(Optional.ofNullable(subject))) { // Try to get document (add catch?) document = broker.getXMLResource(xmldbUri, LockMode.WRITE_LOCK); @@ -658,7 +658,7 @@ public LockToken refreshLock(String token) throws PermissionDeniedException, throw new DocumentNotLockedException(msg); } - if (userLock.getName() != null && !userLock.getName().equals(subject.getName()) + if (userLock.getName() != null && !userLock.getName().equals(subject.getName()) && !subject.hasDbaRole()) { if (LOG.isDebugEnabled()) { LOG.debug(String.format("Resource is locked by %s", userLock.getName())); @@ -679,7 +679,7 @@ public LockToken refreshLock(String token) throws PermissionDeniedException, // Make token persistant final TransactionManager txnManager = brokerPool.getTransactionManager(); - try(final Txn txn = txnManager.beginTransaction()) { + try (final Txn txn = txnManager.beginTransaction()) { broker.storeXMLResource(txn, document); txnManager.commit(txn); } diff --git a/extensions/webdav/src/org/exist/webdav/ExistResource.java b/extensions/webdav/src/org/exist/webdav/ExistResource.java index 23017592cc6..3c28816fb4e 100644 --- a/extensions/webdav/src/org/exist/webdav/ExistResource.java +++ b/extensions/webdav/src/org/exist/webdav/ExistResource.java @@ -21,21 +21,21 @@ */ package org.exist.webdav; -import java.util.Properties; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; - -import org.exist.security.SecurityManager; import org.exist.security.AuthenticationException; import org.exist.security.Permission; +import org.exist.security.SecurityManager; import org.exist.security.Subject; import org.exist.storage.BrokerPool; import org.exist.xmldb.XmldbURI; +import java.util.Properties; + /** * Generic class representing an eXist Resource. - * - * @author Dannes Wessels + * + * @author Dannes Wessels */ public abstract class ExistResource { @@ -50,16 +50,11 @@ protected boolean readAllowed = false; protected boolean writeAllowed = false; protected boolean executeAllowed = false; -// protected ExistResource existResource; protected String ownerUser; protected String ownerGroup; - - protected Properties configuration = new Properties(); - protected enum Mode { - MOVE, COPY - } + protected Properties configuration = new Properties(); abstract void initMetadata(); @@ -102,12 +97,12 @@ public String getOwnerGroup() { public String getOwnerUser() { return ownerUser; } - - public Properties getConfiguration(){ + + public Properties getSerializationConfiguration() { return configuration; } - - public void setConfiguration(Properties config){ + + public void setSerializationConfiguration(Properties config) { configuration = config; } @@ -130,4 +125,8 @@ protected Subject authenticate(String username, String password) { } return subject; } + + protected enum Mode { + MOVE, COPY + } } diff --git a/extensions/webdav/src/org/exist/webdav/ExistResourceFactory.java b/extensions/webdav/src/org/exist/webdav/ExistResourceFactory.java index ef23e1f5c4c..f8dfa2f9bee 100644 --- a/extensions/webdav/src/org/exist/webdav/ExistResourceFactory.java +++ b/extensions/webdav/src/org/exist/webdav/ExistResourceFactory.java @@ -22,30 +22,26 @@ package org.exist.webdav; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import com.bradmcevoy.http.Resource; import com.bradmcevoy.http.ResourceFactory; - -import java.io.InputStream; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Optional; -import java.util.Properties; -import javax.xml.transform.OutputKeys; - +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.exist.EXistException; import org.exist.collections.Collection; import org.exist.dom.persistent.DocumentImpl; import org.exist.storage.BrokerPool; import org.exist.storage.DBBroker; import org.exist.storage.lock.Lock.LockMode; -import org.exist.storage.serializers.EXistOutputKeys; import org.exist.util.FileUtils; import org.exist.xmldb.XmldbURI; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.Properties; + /** * Class for constructing Milton WebDAV framework resource objects . * @@ -55,27 +51,11 @@ private final static Logger LOG = LogManager.getLogger(ExistResourceFactory.class); private BrokerPool brokerPool = null; - - // default output properties for the XML serialization - public final static Properties DEFAULT_WEBDAV_OPTIONS = new Properties(); - - /** XML serialization options */ - private Properties webDavOptions = new Properties(); /** - * Default serialization options + * XML serialization options */ - static { - DEFAULT_WEBDAV_OPTIONS.setProperty(OutputKeys.INDENT, "yes"); - DEFAULT_WEBDAV_OPTIONS.setProperty(OutputKeys.ENCODING, "UTF-8"); - DEFAULT_WEBDAV_OPTIONS.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); - DEFAULT_WEBDAV_OPTIONS.setProperty(EXistOutputKeys.EXPAND_XINCLUDES, "no"); - DEFAULT_WEBDAV_OPTIONS.setProperty(EXistOutputKeys.PROCESS_XSL_PI, "no"); - } - - private enum ResourceType { - DOCUMENT, COLLECTION, IGNORABLE, NOT_EXISTING - }; + private Properties webDavOptions = new Properties(); /** * Default constructor. Get access to instance of exist-db broker pool. @@ -88,33 +68,32 @@ public ExistResourceFactory() { } catch (EXistException e) { LOG.error("Unable to initialize WebDAV interface.", e); } - - // Set default values - webDavOptions.putAll(DEFAULT_WEBDAV_OPTIONS); - + // load specific options try { // Find right file final Optional eXistHome = brokerPool.getConfiguration().getExistHome(); final Path config = FileUtils.resolve(eXistHome, "webdav.properties"); - + // Read from file if existent - if(Files.isReadable(config)) { + if (Files.isReadable(config)) { LOG.info(String.format("Read WebDAV configuration from %s", config.toAbsolutePath().toString())); try (final InputStream is = Files.newInputStream(config)) { webDavOptions.load(is); } - + } else { - LOG.info("Using WebDAV default serialization options."); + LOG.info("Using eXist-db default serialization options."); } - + } catch (Throwable ex) { LOG.error(ex.getMessage()); } - + } + ; + /* * Construct Resource for path. A Document or Collection resource is returned, NULL if type * could not be detected. @@ -139,7 +118,7 @@ public Resource getResource(String host, String path) { path = path.substring(0, path.lastIndexOf("/")); } - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("host='%s' path='%s'", host, path)); } @@ -155,7 +134,7 @@ public Resource getResource(String host, String path) { switch (getResourceType(brokerPool, xmldbUri)) { case DOCUMENT: MiltonDocument doc = new MiltonDocument(host, xmldbUri, brokerPool); - doc.setConfiguration(webDavOptions); + doc.setSerializationConfiguration(webDavOptions); return doc; case COLLECTION: @@ -187,16 +166,16 @@ private ResourceType getResourceType(BrokerPool brokerPool, XmldbURI xmldbUri) { Collection collection = null; DocumentImpl document = null; ResourceType type = ResourceType.NOT_EXISTING; - + // MacOsX finder specific files String documentSeqment = xmldbUri.lastSegment().toString(); - if(documentSeqment.startsWith("._") || documentSeqment.equals(".DS_Store")){ + if (documentSeqment.startsWith("._") || documentSeqment.equals(".DS_Store")) { //LOG.debug(String.format("Ignoring MacOSX file '%s'", xmldbUri.lastSegment().toString())); //return ResourceType.IGNORABLE; } - - // Documents that start with a dot - if(documentSeqment.startsWith(".")){ + + // Documents that start with a dot + if (documentSeqment.startsWith(".")) { //LOG.debug(String.format("Ignoring '.' file '%s'", xmldbUri.lastSegment().toString())); //return ResourceType.IGNORABLE; } @@ -204,11 +183,11 @@ private ResourceType getResourceType(BrokerPool brokerPool, XmldbURI xmldbUri) { // Try to read as system user. Note that the actual user is not know // yet. In MiltonResource the actual authentication and authorization // is performed. - try(final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()))) { - if(LOG.isDebugEnabled()) { + try (final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()))) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Path: %s", xmldbUri.toString())); } - + // First check if resource is a collection collection = broker.openCollection(xmldbUri, LockMode.READ_LOCK); if (collection != null) { @@ -231,7 +210,7 @@ private ResourceType getResourceType(BrokerPool brokerPool, XmldbURI xmldbUri) { type = ResourceType.NOT_EXISTING; } } - + } catch (Exception ex) { LOG.error(String.format("Error determining nature of resource %s", xmldbUri.toString()), ex); @@ -250,11 +229,15 @@ private ResourceType getResourceType(BrokerPool brokerPool, XmldbURI xmldbUri) { } } - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Resource type=%s", type.toString())); } - + return type; } - + + private enum ResourceType { + DOCUMENT, COLLECTION, IGNORABLE, NOT_EXISTING + } + } diff --git a/extensions/webdav/src/org/exist/webdav/MiltonCollection.java b/extensions/webdav/src/org/exist/webdav/MiltonCollection.java index 182bf569ec3..b58fbe43cfd 100644 --- a/extensions/webdav/src/org/exist/webdav/MiltonCollection.java +++ b/extensions/webdav/src/org/exist/webdav/MiltonCollection.java @@ -21,42 +21,8 @@ */ package org.exist.webdav; -import com.bradmcevoy.http.Auth; -import com.bradmcevoy.http.CollectionResource; -import com.bradmcevoy.http.CopyableResource; -import com.bradmcevoy.http.DeletableResource; -import com.bradmcevoy.http.GetableResource; -import com.bradmcevoy.http.LockInfo; -import com.bradmcevoy.http.LockNullResource; -import com.bradmcevoy.http.LockResult; -import com.bradmcevoy.http.LockTimeout; -import com.bradmcevoy.http.LockToken; -import com.bradmcevoy.http.LockingCollectionResource; -import com.bradmcevoy.http.MakeCollectionableResource; -import com.bradmcevoy.http.MoveableResource; -import com.bradmcevoy.http.PropFindableResource; -import com.bradmcevoy.http.PutableResource; -import com.bradmcevoy.http.Range; -import com.bradmcevoy.http.Resource; -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.LockedException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.PreConditionFailedException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; - +import com.bradmcevoy.http.*; +import com.bradmcevoy.http.exceptions.*; import org.exist.EXistException; import org.exist.security.PermissionDeniedException; import org.exist.security.Subject; @@ -66,6 +32,14 @@ import org.exist.webdav.exceptions.CollectionExistsException; import org.exist.xmldb.XmldbURI; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.*; + /** * Class for representing an eXist-db collection as a Milton WebDAV collection. * See Milton. @@ -80,31 +54,31 @@ private ExistCollection existCollection; /** - * Constructor of representation of a Collection in the Milton framework, without subject information. + * Constructor of representation of a Collection in the Milton framework, without subject information. * To be called by the resource factory. * - * @param host FQ host name including port number. - * @param uri Path on server indicating path of resource - * @param pool Handle to Exist database. + * @param host FQ host name including port number. + * @param uri Path on server indicating path of resource + * @param pool Handle to Exist database. */ public MiltonCollection(String host, XmldbURI uri, BrokerPool pool) { this(host, uri, pool, null); } /** - * Constructor of representation of a Document in the Milton framework, with subject information. + * Constructor of representation of a Document in the Milton framework, with subject information. * To be called by the resource factory. * - * @param host FQ host name including port number. - * @param uri Path on server indicating path of resource. - * @param subject An Exist operation is performed with Subject. Can be NULL. - * @param pool Handle to Exist database. + * @param host FQ host name including port number. + * @param uri Path on server indicating path of resource. + * @param subject An Exist operation is performed with Subject. Can be NULL. + * @param pool Handle to Exist database. */ public MiltonCollection(String host, XmldbURI uri, BrokerPool pool, Subject subject) { super(); - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("COLLECTION=%s", uri.toString())); } @@ -130,7 +104,7 @@ public MiltonCollection(String host, XmldbURI uri, BrokerPool pool, Subject subj @Override public Resource child(String childName) { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("get child=%s", childName)); } @@ -177,7 +151,7 @@ public Resource child(String childName) { allResources.addAll(getCollectionResources()); allResources.addAll(getDocumentResources()); - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Nr of children=%s", allResources.size())); } @@ -198,7 +172,7 @@ public Date getCreateDate() { createDate = new Date(time); } - if(LOG.isTraceEnabled()) { + if (LOG.isTraceEnabled()) { LOG.trace(String.format("Create date=%s", createDate)); } @@ -210,8 +184,8 @@ public Date getCreateDate() { * ==================== */ @Override public void delete() throws NotAuthorizedException, ConflictException, BadRequestException { - - if(LOG.isDebugEnabled()) { + + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Delete collection '%s'.", resourceXmldbUri)); } @@ -279,8 +253,8 @@ public Resource createNew(String newName, InputStream is, Long length, String co * ========================= */ @Override public LockToken createAndLock(String name, LockTimeout timeout, LockInfo lockInfo) throws NotAuthorizedException { - - if(LOG.isDebugEnabled()) { + + if (LOG.isDebugEnabled()) { LOG.debug(String.format("'%s' name='%s'", resourceXmldbUri, name)); } @@ -307,7 +281,7 @@ public LockResult lock(LockTimeout timeout, LockInfo lockInfo) @Override public LockResult refreshLock(String token) throws NotAuthorizedException, PreConditionFailedException { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("'%s' token='%s'", resourceXmldbUri, token)); } @@ -322,14 +296,14 @@ public LockResult refreshLock(String token) throws NotAuthorizedException, PreCo @Override public void unlock(String tokenId) throws NotAuthorizedException, PreConditionFailedException { // Just do nothing - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("'%s' token='%s'", resourceXmldbUri, tokenId)); } } @Override public LockToken getCurrentLock() { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("'%s'", resourceXmldbUri)); } return null; // null is allowed @@ -342,7 +316,7 @@ public LockToken getCurrentLock() { @Override public void moveTo(CollectionResource rDest, String newName) throws ConflictException { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Move '%s' to '%s' in '%s'", resourceXmldbUri, newName, rDest.getName())); } @@ -362,10 +336,10 @@ public void moveTo(CollectionResource rDest, String newName) throws ConflictExce @Override public void copyTo(CollectionResource toCollection, String newName) { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Move '%s' to '%s' in '%s'", resourceXmldbUri, newName, toCollection.getName())); } - + XmldbURI destCollection = ((MiltonCollection) toCollection).getXmldbUri(); try { existCollection.resourceCopyMove(destCollection, newName, Mode.COPY); @@ -379,10 +353,10 @@ public void copyTo(CollectionResource toCollection, String newName) { /* ================ * GettableResource * ================ */ - + @Override public void sendContent(OutputStream out, Range range, Map params, - String contentType) throws IOException, NotAuthorizedException, BadRequestException { + String contentType) throws IOException, NotAuthorizedException, BadRequestException { try { XMLOutputFactory xf = XMLOutputFactory.newInstance(); @@ -394,6 +368,8 @@ public void sendContent(OutputStream out, Range range, Map param // Begin document writer.writeStartDocument(); + writer.writeComment("Warning: this XML format is *not* part of the WebDAV specification."); + // Root element writer.writeStartElement("exist", "result", "http://exist.sourceforge.net/NS/exist"); diff --git a/extensions/webdav/src/org/exist/webdav/MiltonDocument.java b/extensions/webdav/src/org/exist/webdav/MiltonDocument.java index 6ef1a2ba223..b615707de27 100644 --- a/extensions/webdav/src/org/exist/webdav/MiltonDocument.java +++ b/extensions/webdav/src/org/exist/webdav/MiltonDocument.java @@ -21,50 +21,30 @@ */ package org.exist.webdav; -import com.bradmcevoy.http.CollectionResource; -import com.bradmcevoy.http.Auth; -import com.bradmcevoy.http.CopyableResource; -import com.bradmcevoy.http.DeletableResource; -import com.bradmcevoy.http.GetableResource; -import com.bradmcevoy.http.HttpManager; -import com.bradmcevoy.http.LockInfo; -import com.bradmcevoy.http.LockResult; -import com.bradmcevoy.http.LockTimeout; -import com.bradmcevoy.http.LockToken; -import com.bradmcevoy.http.LockableResource; -import com.bradmcevoy.http.MoveableResource; -import com.bradmcevoy.http.PropFindableResource; -import com.bradmcevoy.http.Range; -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.LockedException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.PreConditionFailedException; +import com.bradmcevoy.http.*; +import com.bradmcevoy.http.exceptions.*; import com.bradmcevoy.http.webdav.DefaultUserAgentHelper; import com.bradmcevoy.http.webdav.UserAgentHelper; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Date; -import java.util.Map; -import java.util.Properties; - -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; - import org.apache.commons.io.IOUtils; - import org.exist.EXistException; -import org.exist.storage.BrokerPool; import org.exist.security.PermissionDeniedException; import org.exist.security.Subject; +import org.exist.storage.BrokerPool; import org.exist.util.VirtualTempFile; import org.exist.webdav.ExistResource.Mode; import org.exist.webdav.exceptions.DocumentAlreadyLockedException; import org.exist.webdav.exceptions.DocumentNotLockedException; import org.exist.xmldb.XmldbURI; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Date; +import java.util.Map; +import java.util.Properties; + /** * Class for representing an eXist-db document as a Milton WebDAV document. * See Milton. @@ -74,37 +54,26 @@ public class MiltonDocument extends MiltonResource implements GetableResource, PropFindableResource, DeletableResource, LockableResource, MoveableResource, CopyableResource { - + public static final String PROPFIND_METHOD_XML_SIZE = "org.exist.webdav.PROPFIND_METHOD_XML_SIZE"; public static final String GET_METHOD_XML_SIZE = "org.exist.webdav.GET_METHOD_XML_SIZE"; - + private static SIZE_METHOD propfindSizeMethod = null; + private static SIZE_METHOD getSizeMethod = null; + ; + private static UserAgentHelper userAgentHelper = null; private ExistDocument existDocument; - - private VirtualTempFile vtf = null;; + ; + private VirtualTempFile vtf = null; // Only for PROPFIND the estimate size for an XML document must be shown - private boolean isPropFind=false; - - private enum SIZE_METHOD { NULL, EXACT, APPROXIMATE }; - - private static SIZE_METHOD propfindSizeMethod=null; - private static SIZE_METHOD getSizeMethod=null; - - private static UserAgentHelper userAgentHelper = null; - - /** - * Set to TRUE if getContentLength is used for PROPFIND. - */ - public void setIsPropFind(boolean isPropFind) { - this.isPropFind = isPropFind; - } + private boolean isPropFind = false; /** - * Constructor of representation of a Document in the Milton framework, without subject information. + * Constructor of representation of a Document in the Milton framework, without subject information. * To be called by the resource factory. * - * @param host FQ host name including port number. - * @param uri Path on server indicating path of resource + * @param host FQ host name including port number. + * @param uri Path on server indicating path of resource * @param brokerPool Handle to Exist database. */ public MiltonDocument(String host, XmldbURI uri, BrokerPool brokerPool) { @@ -112,26 +81,26 @@ public MiltonDocument(String host, XmldbURI uri, BrokerPool brokerPool) { } /** - * Constructor of representation of a Document in the Milton framework, with subject information. + * Constructor of representation of a Document in the Milton framework, with subject information. * To be called by the resource factory. * - * @param host FQ host name including port number. - * @param uri Path on server indicating path of resource. - * @param subject An Exist operation is performed with User. Can be NULL. - * @param pool Handle to Exist database. + * @param host FQ host name including port number. + * @param uri Path on server indicating path of resource. + * @param subject An Exist operation is performed with User. Can be NULL. + * @param pool Handle to Exist database. */ public MiltonDocument(String host, XmldbURI uri, BrokerPool pool, Subject subject) { super(); - - if(userAgentHelper==null){ - userAgentHelper=new DefaultUserAgentHelper(); + + if (userAgentHelper == null) { + userAgentHelper = new DefaultUserAgentHelper(); } - if(LOG.isTraceEnabled()) { + if (LOG.isTraceEnabled()) { LOG.trace(String.format("DOCUMENT:%s", uri.toString())); } - + resourceXmldbUri = uri; brokerPool = pool; this.host = host; @@ -145,13 +114,13 @@ public MiltonDocument(String host, XmldbURI uri, BrokerPool pool, Subject subjec existDocument.setUser(subject); existDocument.initMetadata(); } - - - // PROPFIND method + + + // PROPFIND method if (propfindSizeMethod == null) { // get user supplied preferred size determination approach String systemProp = System.getProperty(PROPFIND_METHOD_XML_SIZE); - + if (systemProp == null) { // Default method is approximate propfindSizeMethod = SIZE_METHOD.APPROXIMATE; @@ -160,20 +129,20 @@ public MiltonDocument(String host, XmldbURI uri, BrokerPool pool, Subject subjec // Try to parse from environment property try { propfindSizeMethod = SIZE_METHOD.valueOf(systemProp.toUpperCase()); - + } catch (IllegalArgumentException ex) { LOG.debug(ex.getMessage()); // Set preffered default propfindSizeMethod = SIZE_METHOD.APPROXIMATE; } - } + } } - + // GET method if (getSizeMethod == null) { // get user supplied preferred size determination approach String systemProp = System.getProperty(GET_METHOD_XML_SIZE); - + if (systemProp == null) { // Default method is NULL getSizeMethod = SIZE_METHOD.NULL; @@ -182,52 +151,59 @@ public MiltonDocument(String host, XmldbURI uri, BrokerPool pool, Subject subjec // Try to parse from environment property try { getSizeMethod = SIZE_METHOD.valueOf(systemProp.toUpperCase()); - + } catch (IllegalArgumentException ex) { LOG.debug(ex.getMessage()); // Set preffered default getSizeMethod = SIZE_METHOD.APPROXIMATE; } - } + } } - + } - /* ================ - * GettableResource - * ================ */ + /** + * Set to TRUE if getContentLength is used for PROPFIND. + */ + public void setIsPropFind(boolean isPropFind) { + this.isPropFind = isPropFind; + } @Override public void sendContent(OutputStream out, Range range, Map params, String contentType) throws IOException, NotAuthorizedException, BadRequestException { try { - if(vtf==null){ + if (vtf == null) { LOG.debug("Serializing from database"); existDocument.stream(out); - + } else { // Experimental. Does not work right, the virtual file // Often does not contain the right amount of bytes. - + LOG.debug("Serializing from buffer"); InputStream is = vtf.getByteStream(); IOUtils.copy(is, out); out.flush(); IOUtils.closeQuietly(is); vtf.delete(); - vtf=null; + vtf = null; } - + } catch (PermissionDeniedException e) { LOG.debug(e.getMessage()); throw new NotAuthorizedException(this); - + } finally { IOUtils.closeQuietly(out); } } + /* ================ + * GettableResource + * ================ */ + @Override public Long getMaxAgeSeconds(Auth auth) { return null; @@ -240,8 +216,8 @@ public String getContentType(String accepts) { @Override public Long getContentLength() { - - + + // Note // Whilst for non-XML documents the exact size of the documents can // be determined by checking the administration, this is not possible @@ -260,35 +236,35 @@ public Long getContentLength() { // way the size is calculated. Supported values are // NULL, EXACT, APPROXIMATE // - // PROPFIND: Unfortunately both NULL and APPROXIMATE do not work for - // MacOsX Finder. The default behaviour for the Finder 'user-agent' is - // exact, for the others it is approximate. + // PROPFIND: Unfortunately both NULL and APPROXIMATE do not work for + // MacOsX Finder. The default behaviour for the Finder 'user-agent' is + // exact, for the others it is approximate. // This behaviour is swiched by the system properties. // // GET: the NULL value seems to be working well for macosx too. - - Long size=null; - + + Long size = null; + // MacOsX has a bad reputation - boolean isMacFinder = userAgentHelper.isMacFinder( HttpManager.request().getUserAgentHeader() ); - - if(existDocument.isXmlDocument()){ + boolean isMacFinder = userAgentHelper.isMacFinder(HttpManager.request().getUserAgentHeader()); + + if (existDocument.isXmlDocument()) { // XML document, exact size is not (directly) known) if (isPropFind) { - + // PROPFIND // In this scensario the XML document is not actually // downloaded, only the size needs to be known. // This is the most expensive scenario - - if(isMacFinder || SIZE_METHOD.EXACT==propfindSizeMethod) { - - // Returns the exact size, default behaviour for Finder, + + if (isMacFinder || SIZE_METHOD.EXACT == propfindSizeMethod) { + + // Returns the exact size, default behaviour for Finder, // or when set by a system property - - if(LOG.isDebugEnabled()){ - LOG.debug(String.format("Serializing XML to /dev/null to determine size (%s) MacFinder=%s", + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Serializing XML to /dev/null to determine size (%s) MacFinder=%s", resourceXmldbUri, isMacFinder)); } @@ -302,36 +278,36 @@ public Long getContentLength() { } size = counter.getByteCount(); - - - } else if (SIZE_METHOD.NULL==propfindSizeMethod) { - + + + } else if (SIZE_METHOD.NULL == propfindSizeMethod) { + // Returns size unknown. This is not supported // by MacOsX finder - + size = null; - - - } else { + + + } else { // Returns the estimated document size. This is the // default value, but not suitable for MacOsX Finder. size = existDocument.getContentLength(); } - - + + } else { - + // GET // In this scenario, the document will actually be downloaded // in the next step. - + if (SIZE_METHOD.EXACT == getSizeMethod) { // Return the exact size by pre-serializing the document // to a buffer first. isMacFinder is not needed try { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Serializing XML to virtual file (%s)", resourceXmldbUri)); } @@ -344,41 +320,37 @@ public Long getContentLength() { } size = vtf.length(); - - + + } else if (SIZE_METHOD.APPROXIMATE == getSizeMethod) { - + // Return approximate size, be warned to use this - + size = existDocument.getContentLength(); vtf = null; // force live serialization - + } else { - + // Return no size, the whole file will be downloaded // Works well for macosx finder - + size = null; vtf = null; // force live serialization } } - - + + } else { // Non XML document, actual size is known size = existDocument.getContentLength(); } - - if(LOG.isDebugEnabled()) { + + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Size=%s (%s)", size, resourceXmldbUri)); } return size; - - } - /* ==================== - * PropFindableResource - * ==================== */ + } @Override public Date getCreateDate() { @@ -392,19 +364,18 @@ public Date getCreateDate() { return createDate; } - /* ================= - * DeletableResource - * ================= */ + /* ==================== + * PropFindableResource + * ==================== */ @Override public void delete() throws NotAuthorizedException, ConflictException, BadRequestException { existDocument.delete(); } - - /* ================ - * LockableResource - * ================ */ + /* ================= + * DeletableResource + * ================= */ @Override public LockResult lock(LockTimeout timeout, LockInfo lockInfo) @@ -415,7 +386,7 @@ public LockResult lock(LockTimeout timeout, LockInfo lockInfo) if (LOG.isDebugEnabled()) { LOG.debug(String.format("Lock: %s", resourceXmldbUri)); } - + LockResult lr = null; try { org.exist.dom.persistent.LockToken existLT = existDocument.lock(inputToken); @@ -441,10 +412,15 @@ public LockResult lock(LockTimeout timeout, LockInfo lockInfo) return lr; } + + /* ================ + * LockableResource + * ================ */ + @Override public LockResult refreshLock(String token) throws NotAuthorizedException, PreConditionFailedException { - - if(LOG.isDebugEnabled()) { + + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Refresh: %s token=%s", resourceXmldbUri, token)); } @@ -476,10 +452,10 @@ public LockResult refreshLock(String token) throws NotAuthorizedException, PreCo @Override public void unlock(String tokenId) throws NotAuthorizedException, PreConditionFailedException { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("Unlock: %s", resourceXmldbUri)); } - + try { existDocument.unlock(); } catch (PermissionDeniedException ex) { @@ -496,10 +472,10 @@ public void unlock(String tokenId) throws NotAuthorizedException, PreConditionFa @Override public LockToken getCurrentLock() { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("getCurrentLock: %s", resourceXmldbUri)); } - + org.exist.dom.persistent.LockToken existLT = existDocument.getCurrentLock(); if (existLT == null) { @@ -514,15 +490,10 @@ public LockToken getCurrentLock() { return miltonLT; } - - /* ================ - * MoveableResource - * ================ */ - @Override public void moveTo(CollectionResource rDest, String newName) throws ConflictException { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("moveTo: %s newName=%s", resourceXmldbUri, newName)); } @@ -537,16 +508,16 @@ public void moveTo(CollectionResource rDest, String newName) throws ConflictExce /* ================ - * CopyableResource + * MoveableResource * ================ */ @Override public void copyTo(CollectionResource rDest, String newName) { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug(String.format("copyTo: %s newName=%s", resourceXmldbUri, newName)); } - + XmldbURI destCollection = ((MiltonCollection) rDest).getXmldbUri(); try { existDocument.resourceCopyMove(destCollection, newName, Mode.COPY); @@ -559,12 +530,12 @@ public void copyTo(CollectionResource rDest, String newName) { /* ================ - * StAX serializer + * CopyableResource * ================ */ - + /** - * Serialize document properties - * + * Serialize document properties + * * @param writer STAX writer * @throws XMLStreamException Thrown when writing data failed */ @@ -579,13 +550,20 @@ public void writeXML(XMLStreamWriter writer) throws XMLStreamException { writer.writeAttribute("size", "" + existDocument.getContentLength()); writer.writeEndElement(); } - + + + /* ================ + * StAX serializer + * ================ */ + /** * Set specific WebDAV serialization options - * + * * @param config XML serialization options */ - public void setConfiguration(Properties config){ - existDocument.setConfiguration(config); + public void setSerializationConfiguration(Properties config) { + existDocument.setSerializationConfiguration(config); } + + private enum SIZE_METHOD {NULL, EXACT, APPROXIMATE} } diff --git a/extensions/webdav/src/org/exist/webdav/MiltonResource.java b/extensions/webdav/src/org/exist/webdav/MiltonResource.java index 62921ad7fa4..125a6c8cdce 100644 --- a/extensions/webdav/src/org/exist/webdav/MiltonResource.java +++ b/extensions/webdav/src/org/exist/webdav/MiltonResource.java @@ -21,44 +21,35 @@ */ package org.exist.webdav; +import com.bradmcevoy.http.*; +import com.bradmcevoy.http.Request.Method; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.exist.security.Subject; +import org.exist.storage.BrokerPool; +import org.exist.xmldb.XmldbURI; -import com.bradmcevoy.http.Auth; -import com.bradmcevoy.http.LockInfo; -import com.bradmcevoy.http.LockTimeout; -import com.bradmcevoy.http.LockToken; -import com.bradmcevoy.http.Request; -import com.bradmcevoy.http.Request.Method; -import com.bradmcevoy.http.Resource; - +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; import java.net.URI; import java.net.URISyntaxException; - import java.util.Date; import java.util.GregorianCalendar; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.XMLGregorianCalendar; - -import org.exist.security.Subject; -import org.exist.storage.BrokerPool; -import org.exist.xmldb.XmldbURI; - /** * Generic class representing a Milton Resource. - * + * * @author Dannes Wessels */ public class MiltonResource implements Resource { protected final static Logger LOG = LogManager.getLogger(MiltonResource.class); + protected final static String AUTHENTICATED = "AUTHENTICATED"; protected XmldbURI resourceXmldbUri; protected BrokerPool brokerPool; protected String host; protected Subject subject; - protected final static String AUTHENTICATED = "AUTHENTICATED"; protected String REALM = "exist"; protected ExistResource existResource; @@ -66,7 +57,7 @@ private DatatypeFactory datatypeFactory; public MiltonResource() { - if(datatypeFactory==null){ + if (datatypeFactory == null) { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException ex) { @@ -90,13 +81,14 @@ private Subject getUserAsSubject() { /** * Convert date to dateTime XML format. * s + * * @param date Representation of data * @return ISO8601 like formatted representation of date.s */ - protected String getXmlDateTime(Long date){ + protected String getXmlDateTime(Long date) { // Convert to Calendar GregorianCalendar gc = new GregorianCalendar(); - gc.setTime( new Date(date) ); + gc.setTime(new Date(date)); // COnvert to XML dateTimes XMLGregorianCalendar xgc = datatypeFactory.newXMLGregorianCalendar(gc); @@ -104,7 +96,7 @@ protected String getXmlDateTime(Long date){ } /** - * Converts an org.exist.dom.persistent.LockToken into com.bradmcevoy.http.LockToken. + * Converts an org.exist.dom.persistent.LockToken into com.bradmcevoy.http.LockToken. * * @param existLT Exist-db representation of a webdav token. * @return Milton representation of a webdav token. @@ -166,12 +158,12 @@ protected LockToken convertToken(org.exist.dom.persistent.LockToken existLT) { Long timeout = existLT.getTimeOut(); // Special treatment when no LOCK was present - if(timeout == org.exist.dom.persistent.LockToken.NO_LOCK_TIMEOUT){ - timeout=null; + if (timeout == org.exist.dom.persistent.LockToken.NO_LOCK_TIMEOUT) { + timeout = null; - // Special treatment infinite lock - } else if(timeout == org.exist.dom.persistent.LockToken.LOCK_TIMEOUT_INFINITE){ - timeout=Long.MAX_VALUE; + // Special treatment infinite lock + } else if (timeout == org.exist.dom.persistent.LockToken.LOCK_TIMEOUT_INFINITE) { + timeout = Long.MAX_VALUE; } LockTimeout lt = new LockTimeout(timeout); @@ -185,7 +177,7 @@ protected LockToken convertToken(org.exist.dom.persistent.LockToken existLT) { } /** - * Converts an org.exist.dom.persistent.LockToken into com.bradmcevoy.http.LockToken. + * Converts an org.exist.dom.persistent.LockToken into com.bradmcevoy.http.LockToken. */ protected org.exist.dom.persistent.LockToken convertToken(LockTimeout timeout, LockInfo lockInfo) { @@ -230,38 +222,38 @@ protected LockToken convertToken(org.exist.dom.persistent.LockToken existLT) { if (timeout == null || timeout.getSeconds() == null) { existToken.setTimeOut(org.exist.dom.persistent.LockToken.NO_LOCK_TIMEOUT); - } else if (timeout.getSeconds() == Long.MAX_VALUE ) { + } else if (timeout.getSeconds() == Long.MAX_VALUE) { existToken.setTimeOut(org.exist.dom.persistent.LockToken.LOCK_TIMEOUT_INFINITE); - + } else { - Long futureDate = (new Date().getTime())/1000 + timeout.getSeconds(); - existToken.setTimeOut( futureDate ); + Long futureDate = (new Date().getTime()) / 1000 + timeout.getSeconds(); + existToken.setTimeOut(futureDate); } - + // Copy username if existent String user = lockInfo.lockedByUser; - if(user != null){ + if (user != null) { existToken.setOwner(user); } - + return existToken; } /** - * Convert % encoded string back to text + * Convert % encoded string back to text */ - protected XmldbURI decodePath(XmldbURI uri){ + protected XmldbURI decodePath(XmldbURI uri) { - XmldbURI retval =null; + XmldbURI retval = null; try { String path = new URI(uri.toString()).getPath(); - retval = XmldbURI.xmldbUriFor(""+path, false); - - } catch (URISyntaxException ex){ + retval = XmldbURI.xmldbUriFor("" + path, false); + + } catch (URISyntaxException ex) { // oops LOG.error(ex.getMessage()); @@ -270,11 +262,11 @@ protected XmldbURI decodePath(XmldbURI uri){ } /** - * Convert % encoded string back to text + * Convert % encoded string back to text */ - protected String decodePath(String uri){ + protected String decodePath(String uri) { - String path =null; + String path = null; try { path = new URI(uri).getPath(); @@ -289,7 +281,7 @@ protected String decodePath(String uri){ /* ======== * Resource * ======== */ - + @Override public String getUniqueId() { return null; // disables the ETag field @@ -297,13 +289,13 @@ public String getUniqueId() { @Override public String getName() { - return decodePath(""+resourceXmldbUri.lastSegment()); + return decodePath("" + resourceXmldbUri.lastSegment()); } @Override public Object authenticate(String username, String password) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("Authenticating user %s for %s", username, resourceXmldbUri)); // Check if username is provided. @@ -313,7 +305,7 @@ public Object authenticate(String username, String password) { // Check is subject was already authenticated. if (subject != null) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug("User was already authenticated."); return AUTHENTICATED; } @@ -323,7 +315,7 @@ public Object authenticate(String username, String password) { // Quick return if no subject object was returned if (subject == null) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug("User could not be authenticated."); return null; } @@ -340,7 +332,7 @@ public Object authenticate(String username, String password) { // Collect data for this resource existResource.initMetadata(); - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("User '%s' has been authenticated.", subject.getName())); return AUTHENTICATED; } @@ -354,7 +346,7 @@ public boolean authorise(Request request, Method method, Auth auth) { * First perform checks on Milton authentication */ if (auth == null) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug("User hasn't been authenticated."); return false; } @@ -370,7 +362,7 @@ public boolean authorise(Request request, Method method, Auth auth) { // If object does not exist, there was no successfull authentication if (tag == null) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("No tag, user %s not authenticated", userName)); return false; @@ -380,7 +372,7 @@ public boolean authorise(Request request, Method method, Auth auth) { // The correct TAG is returned! } else { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("Authentication tag contains wrong value, user %s is not authenticated", userName)); return false; } @@ -391,27 +383,27 @@ public boolean authorise(Request request, Method method, Auth auth) { */ if (method.isWrite) { if (!existResource.writeAllowed) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("User %s is NOT authorized to write resource, abort.", userName)); return false; } } else { if (!existResource.readAllowed) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("User %s is NOT authorized to read resource, abort.", userName)); return false; } } - if(auth.getUri()==null){ - if(LOG.isTraceEnabled()) + if (auth.getUri() == null) { + if (LOG.isTraceEnabled()) LOG.trace("URI is null"); // not sure why the null value can be there } String action = method.isWrite ? "write" : "read"; - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(String.format("User %s is authorized to %s resource %s", userName, action, resourceXmldbUri.toString())); return true; @@ -427,7 +419,7 @@ public Date getModifiedDate() { Date modifiedDate = null; - Long time = existResource.getLastModified(); + Long time = existResource.getLastModified(); if (time != null) { modifiedDate = new Date(time); } diff --git a/extensions/webdav/src/org/exist/webdav/MiltonWebDAVServlet.java b/extensions/webdav/src/org/exist/webdav/MiltonWebDAVServlet.java index 9a6af791e96..a21f263d362 100644 --- a/extensions/webdav/src/org/exist/webdav/MiltonWebDAVServlet.java +++ b/extensions/webdav/src/org/exist/webdav/MiltonWebDAVServlet.java @@ -1,4 +1,3 @@ - /* * eXist Open Source Native XML Database * Copyright (C) 2011 The eXist Project @@ -24,43 +23,41 @@ import com.bradmcevoy.http.MiltonServlet; import com.bradmcevoy.http.http11.DefaultHttp11ResponseHandler; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; import java.io.IOException; import java.io.InputStream; import java.util.Properties; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - /** - * Wrapper around the MiltonServlet for post-configuring the framework. - * + * Wrapper around the MiltonServlet for post-configuring the framework. + * * @author Dannes Wessels */ public class MiltonWebDAVServlet extends MiltonServlet { protected final static Logger LOG = LogManager.getLogger(MiltonWebDAVServlet.class); - - public static String POM_PROP="/META-INF/maven/com.ettrema/milton-api/pom.properties"; + + public static String POM_PROP = "/META-INF/maven/com.ettrema/milton-api/pom.properties"; @Override public void init(ServletConfig config) throws ServletException { - + LOG.info("Initializing webdav servlet"); - + // Show used version Properties props = new Properties(); try { - InputStream is = DefaultHttp11ResponseHandler.class.getResourceAsStream(POM_PROP); - if(is==null){ + InputStream is = DefaultHttp11ResponseHandler.class.getResourceAsStream(POM_PROP); + if (is == null) { LOG.error("Could not read the file milton.properties"); } else { props.load(is); } - + } catch (IOException ex) { LOG.warn("Failed to load milton properties file", ex); } @@ -71,22 +68,22 @@ public void init(ServletConfig config) throws ServletException { } else { LOG.info("Detected Milton WebDAV Server library version: " + miltonVersion); } - + // Initialize Milton super.init(config); // Retrieve parameters, set to FALSE if not existent - String enableInitParameter = config.getInitParameter("enable.expect.continue"); - if(enableInitParameter==null){ - enableInitParameter="FALSE"; + String enableInitParameter = config.getInitParameter("enable.expect.continue"); + if (enableInitParameter == null) { + enableInitParameter = "FALSE"; } - + // Calculate effective value boolean enableExpectContinue = "TRUE".equalsIgnoreCase(enableInitParameter); // Pass value to Milton httpManager.setEnableExpectContinue(enableExpectContinue); - + LOG.debug(String.format("Set 'Enable Expect Continue' to %s", enableExpectContinue)); } } diff --git a/extensions/webdav/src/org/exist/webdav/exceptions/CollectionDoesNotExistException.java b/extensions/webdav/src/org/exist/webdav/exceptions/CollectionDoesNotExistException.java index 0dda02b60d3..e26d3173bd4 100644 --- a/extensions/webdav/src/org/exist/webdav/exceptions/CollectionDoesNotExistException.java +++ b/extensions/webdav/src/org/exist/webdav/exceptions/CollectionDoesNotExistException.java @@ -24,22 +24,22 @@ /** * Class that represents a situation that a file cannot be created because the collection * does not exist. - * + * * @author wessels */ public class CollectionDoesNotExistException extends EXistWebdavException { - private static final long serialVersionUID = 5754679193191561751L; + private static final long serialVersionUID = 5754679193191561751L; - public CollectionDoesNotExistException() { + public CollectionDoesNotExistException() { super(); } - public CollectionDoesNotExistException( Throwable inner ) { + public CollectionDoesNotExistException(Throwable inner) { super(inner); } - public CollectionDoesNotExistException( String message ) { + public CollectionDoesNotExistException(String message) { super(message); } diff --git a/extensions/webdav/src/org/exist/webdav/exceptions/CollectionExistsException.java b/extensions/webdav/src/org/exist/webdav/exceptions/CollectionExistsException.java index 028c0b8130b..9445fbe9c10 100644 --- a/extensions/webdav/src/org/exist/webdav/exceptions/CollectionExistsException.java +++ b/extensions/webdav/src/org/exist/webdav/exceptions/CollectionExistsException.java @@ -29,17 +29,17 @@ */ public class CollectionExistsException extends EXistWebdavException { - private static final long serialVersionUID = 9147649778466124318L; + private static final long serialVersionUID = 9147649778466124318L; - public CollectionExistsException() { + public CollectionExistsException() { super(); } - public CollectionExistsException( Throwable inner ) { + public CollectionExistsException(Throwable inner) { super(inner); } - public CollectionExistsException( String message ) { + public CollectionExistsException(String message) { super(message); } diff --git a/extensions/webdav/src/org/exist/webdav/exceptions/DocumentAlreadyLockedException.java b/extensions/webdav/src/org/exist/webdav/exceptions/DocumentAlreadyLockedException.java index df0d81f9cd7..581ba5dcdae 100644 --- a/extensions/webdav/src/org/exist/webdav/exceptions/DocumentAlreadyLockedException.java +++ b/extensions/webdav/src/org/exist/webdav/exceptions/DocumentAlreadyLockedException.java @@ -24,22 +24,22 @@ /** * Class that represents a situation that a file cannot be created because the collection * does not exist. - * + * * @author wessels */ public class DocumentAlreadyLockedException extends Exception { - private static final long serialVersionUID = 7229034225491130620L; + private static final long serialVersionUID = 7229034225491130620L; - public DocumentAlreadyLockedException() { + public DocumentAlreadyLockedException() { super(); } - public DocumentAlreadyLockedException( Throwable inner ) { + public DocumentAlreadyLockedException(Throwable inner) { super(inner); } - public DocumentAlreadyLockedException( String message ) { + public DocumentAlreadyLockedException(String message) { super(message); } diff --git a/extensions/webdav/src/org/exist/webdav/exceptions/DocumentNotLockedException.java b/extensions/webdav/src/org/exist/webdav/exceptions/DocumentNotLockedException.java index 54ad8a37695..173d906ffdd 100644 --- a/extensions/webdav/src/org/exist/webdav/exceptions/DocumentNotLockedException.java +++ b/extensions/webdav/src/org/exist/webdav/exceptions/DocumentNotLockedException.java @@ -24,22 +24,22 @@ /** * Class that represents a situation that a file cannot be created because the collection * does not exist. - * + * * @author wessels */ public class DocumentNotLockedException extends Exception { - private static final long serialVersionUID = -4907184035845864493L; + private static final long serialVersionUID = -4907184035845864493L; - public DocumentNotLockedException() { + public DocumentNotLockedException() { super(); } - public DocumentNotLockedException( Throwable inner ) { + public DocumentNotLockedException(Throwable inner) { super(inner); } - public DocumentNotLockedException( String message ) { + public DocumentNotLockedException(String message) { super(message); } diff --git a/extensions/webdav/src/org/exist/webdav/exceptions/EXistWebdavException.java b/extensions/webdav/src/org/exist/webdav/exceptions/EXistWebdavException.java index 82df199a362..9d196cec09a 100644 --- a/extensions/webdav/src/org/exist/webdav/exceptions/EXistWebdavException.java +++ b/extensions/webdav/src/org/exist/webdav/exceptions/EXistWebdavException.java @@ -24,22 +24,22 @@ /** * Class that represents a situation that a file cannot be created because the collection * does not exist. - * + * * @author wessels */ public class EXistWebdavException extends Exception { - private static final long serialVersionUID = 6789177932722513095L; + private static final long serialVersionUID = 6789177932722513095L; - public EXistWebdavException() { + public EXistWebdavException() { super(); } - public EXistWebdavException( Throwable inner ) { + public EXistWebdavException(Throwable inner) { super(inner); } - public EXistWebdavException( String message ) { + public EXistWebdavException(String message) { super(message); }