diff --git a/source/java/org/alfresco/repo/webdav/AbstractMoveOrCopyMethod.java b/source/java/org/alfresco/repo/webdav/AbstractMoveOrCopyMethod.java index 18646c940f..a6f620c913 100644 --- a/source/java/org/alfresco/repo/webdav/AbstractMoveOrCopyMethod.java +++ b/source/java/org/alfresco/repo/webdav/AbstractMoveOrCopyMethod.java @@ -95,6 +95,10 @@ public abstract class AbstractMoveOrCopyMethod extends HierarchicalMethod FileInfo destParentInfo = null; try { + if (destPath.endsWith(WebDAVHelper.PathSeperator)) + { + destPath = destPath.substring(0, destPath.length() - 1); + } destParentInfo = getDAVHelper().getParentNodeForPath(rootNodeRef, destPath, servletPath); } catch (FileNotFoundException e) @@ -103,7 +107,7 @@ public abstract class AbstractMoveOrCopyMethod extends HierarchicalMethod { logger.debug("Destination parent folder doesn't exist: " + destPath); } - throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND); + throw new WebDAVServerException(HttpServletResponse.SC_CONFLICT); } // check for the existence of the destination node @@ -123,6 +127,8 @@ public abstract class AbstractMoveOrCopyMethod extends HierarchicalMethod // delete the destination node if it is not the same as the source node if (!destInfo.getNodeRef().equals(sourceInfo.getNodeRef())) { + checkNode(destInfo); + // attempting to move or copy onto another node fileFolderService.delete(destInfo.getNodeRef()); } @@ -138,7 +144,9 @@ public abstract class AbstractMoveOrCopyMethod extends HierarchicalMethod NodeRef sourceNodeRef = sourceInfo.getNodeRef(); NodeRef destParentNodeRef = destParentInfo.getNodeRef(); + String name = getDAVHelper().splitPath(destPath)[1]; + moveOrCopy(fileFolderService, sourceNodeRef, destParentNodeRef, name); // Set the response status diff --git a/source/java/org/alfresco/repo/webdav/DeleteMethod.java b/source/java/org/alfresco/repo/webdav/DeleteMethod.java index 6fa5f7d774..544cad0ed8 100644 --- a/source/java/org/alfresco/repo/webdav/DeleteMethod.java +++ b/source/java/org/alfresco/repo/webdav/DeleteMethod.java @@ -99,6 +99,9 @@ public class DeleteMethod extends WebDAVMethod } throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND); } + + checkNode(fileInfo); + // delete it fileFolderService.delete(fileInfo.getNodeRef()); } diff --git a/source/java/org/alfresco/repo/webdav/GetMethod.java b/source/java/org/alfresco/repo/webdav/GetMethod.java index f9ad8f6a18..4ab53d97d3 100644 --- a/source/java/org/alfresco/repo/webdav/GetMethod.java +++ b/source/java/org/alfresco/repo/webdav/GetMethod.java @@ -293,7 +293,7 @@ public class GetMethod extends WebDAVMethod * @param strETagHeader The header to parse * @return A list of ETags */ - private ArrayList parseETags(String strETagHeader) + private ArrayList parseETags(String strETagHeader) { ArrayList list = new ArrayList(); diff --git a/source/java/org/alfresco/repo/webdav/LockInfo.java b/source/java/org/alfresco/repo/webdav/LockInfo.java new file mode 100755 index 0000000000..b27c894c86 --- /dev/null +++ b/source/java/org/alfresco/repo/webdav/LockInfo.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webdav; + +import java.util.LinkedList; + +/** + * Class to represent a WebDAV lock info + * + * @author Ivan Rybnikov + * + */ +public class LockInfo +{ + // Exclusive lock token + private String token = null; + + // Lock scope + private String scope = null; + + // Lock depth + private String depth = null; + + // If lock is shared + private boolean shared = false; + + // Shared lock tokens + private LinkedList sharedLockTokens = null; + + // Shared lock token separator + private static final String SHARED_LOCK_TOKEN_SEPARATOR = ","; + + /** + * Default constructor + * + */ + public LockInfo() + { + } + + /** + * Constructor + * + * @param token Exclusive lock token + * @param scope Lock scope (shared/exclusive) + * @param depth Lock depth (0/infinity) + */ + public LockInfo(String token, String scope, String depth) + { + this.token = token; + this.scope = scope; + this.depth = depth; + } + + /** + * Returns true if node has shared or exclusive locks + * + * @return boolean + */ + public boolean isLocked() + { + if (token != null || (sharedLockTokens != null && !sharedLockTokens.isEmpty())) + { + return true; + } + return false; + } + + /** + * Setter for exclusive lock token + * + * @param token Lock token + */ + public void setToken(String token) + { + this.token = token; + } + + /** + * Getter for exclusive lock token + * @return + */ + public String getToken() + { + return token; + } + + /** + * Setter for lock scope. + * + * @param scope + */ + public void setScope(String scope) + { + this.scope = scope; + } + + /** + * Returns lock scope + * + * @return lock scope + */ + public String getScope() + { + return scope == null ? WebDAV.XML_EXCLUSIVE : scope; + } + + /** + * Setter for lock depth + * + * @param depth lock depth + */ + public void setDepth(String depth) + { + this.depth = depth; + } + + /** + * Returns lock depth + * + * @return lock depth + */ + public String getDepth() + { + return depth; + } + + /** + * Transforms shared lock tokens string to list. + * + * @param sharedLockTokens String contains all node's shared lock tokens + * divided with SHARED_LOCK_TOKEN_SEPARATOR value. + * @return List of shared lock tokens + */ + public static LinkedList parseSharedLockTokens(String sharedLockTokens) + { + if (sharedLockTokens == null) + { + return null; + } + + LinkedList result = new LinkedList(); + String[] sl = sharedLockTokens.split(SHARED_LOCK_TOKEN_SEPARATOR); + for (int i = 0; i < sl.length; i++) + { + result.add(sl[i]); + } + + return result; + } + + /** + * Getter for sharedLockTokens list + * + * @return LinkedList + */ + public LinkedList getSharedLockTokens() + { + return sharedLockTokens; + } + + /** + * Setter for sharedLockTokens list + * + * @param sharedLockTokens + */ + public void setSharedLockTokens(LinkedList sharedLockTokens) + { + this.sharedLockTokens = sharedLockTokens; + } + + /** + * Adds new shared lock token to sharedLockTokens list + * + * @param token new token + */ + public void addSharedLockToken(String token) + { + if (sharedLockTokens == null) + { + sharedLockTokens = new LinkedList(); + } + sharedLockTokens.add(token); + } + + /** + * Transforms list of shared locks to string. + * Lock tokens separated with SHARED_LOCK_TOKEN_SEPARATOR value. + * + * @param lockTokens list of shared locks + * @return String + */ + public static String makeSharedLockTokensString(LinkedList lockTokens) + { + StringBuilder str = new StringBuilder(); + + boolean first = true; + for (String token : lockTokens) + { + if (!first) + { + str.append(SHARED_LOCK_TOKEN_SEPARATOR); + } + else + { + first = false; + } + str.append(token); + } + return str.toString(); + } + + /** + * Setter for shared property + * + * @param shared + */ + public void setShared(boolean shared) + { + this.shared = shared; + } + + /** + * Returns true is lock is shared + * + * @return boolean + */ + public boolean isShared() + { + return shared; + } + + /** + * Return the lock info as a string + * + * @return String + */ + public String toString() + { + StringBuilder str = new StringBuilder(); + + str.append("["); + + str.append("token="); + str.append(getToken()); + str.append(",scope="); + str.append(getScope()); + str.append(",depth="); + str.append(getDepth()); + str.append(",shared locks="); + str.append(getSharedLockTokens()); + + str.append("]"); + + return str.toString(); + } + +} diff --git a/source/java/org/alfresco/repo/webdav/LockMethod.java b/source/java/org/alfresco/repo/webdav/LockMethod.java index 6e1df580a6..9ff2b448e2 100644 --- a/source/java/org/alfresco/repo/webdav/LockMethod.java +++ b/source/java/org/alfresco/repo/webdav/LockMethod.java @@ -1,437 +1,511 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.webdav; - -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.model.filefolder.FileFolderServiceImpl; -import org.alfresco.service.cmr.lock.LockService; -import org.alfresco.service.cmr.lock.LockStatus; -import org.alfresco.service.cmr.lock.LockType; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.model.FileInfo; -import org.alfresco.service.cmr.model.FileNotFoundException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.dom4j.DocumentHelper; -import org.dom4j.io.XMLWriter; -import org.xml.sax.Attributes; - -/** - * Implements the WebDAV LOCK method - * - * @author gavinc - */ -public class LockMethod extends WebDAVMethod -{ - public static final String EMPTY_NS = ""; - - private String m_strLockToken = null; - private int m_timeoutDuration = WebDAV.DEPTH_INFINITY; - - /** - * Default constructor - */ - public LockMethod() - { - } - - /** - * Check if the lock token is valid - * - * @return boolean - */ - protected final boolean hasLockToken() - { - return m_strLockToken != null ? true : false; - } - - /** - * Return the lock token of an existing lock - * - * @return String - */ - protected final String getLockToken() - { - return m_strLockToken; - } - - /** - * Return the lock timeout, in minutes - * - * @return int - */ - protected final int getLockTimeout() - { - return m_timeoutDuration; - } - - /** - * Parse the request headers - * - * @exception WebDAVServerException - */ - protected void parseRequestHeaders() throws WebDAVServerException - { - // Get the lock token, if any - - m_strLockToken = parseIfHeader(); - - // Get the lock timeout value - - String strTimeout = m_request.getHeader(WebDAV.HEADER_TIMEOUT); - - // If the timeout header starts with anything other than Second - // leave the timeout as the default - - if (strTimeout != null && strTimeout.startsWith(WebDAV.SECOND)) - { - try - { - // Some clients send header as Second-180 Seconds so we need to - // look for the space - - int idx = strTimeout.indexOf(" "); - - if (idx != -1) - { - // Get the bit after Second- and before the space - - strTimeout = strTimeout.substring(WebDAV.SECOND.length(), idx); - } - else - { - // The string must be in the correct format - - strTimeout = strTimeout.substring(WebDAV.SECOND.length()); - } - m_timeoutDuration = Integer.parseInt(strTimeout); - } - catch (Exception e) - { - // Warn about the parse failure and leave the timeout as the - // default - - logger.warn("Failed to parse Timeout header: " + strTimeout); - } - } - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("Lock lockToken=" + getLockToken() + ", timeout=" + getLockTimeout()); - } - - /** - * Parse the request body - * - * @exception WebDAVServerException - */ - protected void parseRequestBody() throws WebDAVServerException - { - // NOTE: There is a body for lock requests which contain the - // type of lock to apply and the lock owner but we will - // ignore these settings so don't bother reading the body - } - - /** - * Exceute the request - * - * @exception WebDAVServerException - */ - protected void executeImpl() throws WebDAVServerException, Exception - { - FileFolderService fileFolderService = getFileFolderService(); - String path = getPath(); - NodeRef rootNodeRef = getRootNodeRef(); - // Get the active user - String userName = getDAVHelper().getAuthenticationService().getCurrentUserName(); - - if (logger.isDebugEnabled()) - { - logger.debug("Locking node: \n" + - " user: " + userName + "\n" + - " path: " + path); - } - - FileInfo lockNodeInfo = null; - try - { - // Check if the path exists - lockNodeInfo = getDAVHelper().getNodeForPath(getRootNodeRef(), getPath(), m_request.getServletPath()); - } - catch (FileNotFoundException e) - { - // need to create it - String[] splitPath = getDAVHelper().splitPath(path); - // check - if (splitPath[1].length() == 0) - { - throw new WebDAVServerException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - - FileInfo dirInfo = null; - List dirPathElements = getDAVHelper().splitAllPaths(splitPath[0]); - if (dirPathElements.size() == 0) - { - // if there are no path elements we are at the root so get the root node - dirInfo = fileFolderService.getFileInfo(getRootNodeRef()); - } - else - { - // make sure folder structure is present - dirInfo = FileFolderServiceImpl.makeFolders(fileFolderService, rootNodeRef, dirPathElements, ContentModel.TYPE_FOLDER); - } - - if (dirInfo == null) - { - throw new WebDAVServerException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - - // create the file - lockNodeInfo = fileFolderService.create(dirInfo.getNodeRef(), splitPath[1], ContentModel.TYPE_CONTENT); - - if (logger.isDebugEnabled()) - { - logger.debug("Created new node for lock: \n" + - " path: " + path + "\n" + - " node: " + lockNodeInfo); - } - } - - - // Check if this is a new lock or a refresh - if (hasLockToken()) - { - // Refresh an existing lock - refreshLock(lockNodeInfo.getNodeRef(), userName); - } - else - { - // Create a new lock - createLock(lockNodeInfo.getNodeRef(), userName); - } - - m_response.setHeader(WebDAV.HEADER_LOCK_TOKEN, "<" + WebDAV.makeLockToken(lockNodeInfo.getNodeRef(), userName) + ">"); - m_response.setHeader(WebDAV.HEADER_CONTENT_TYPE, WebDAV.XML_CONTENT_TYPE); - - // We either created a new lock or refreshed an existing lock, send back the lock details - generateResponse(lockNodeInfo.getNodeRef(), userName); - } - - /** - * Create a new lock - * - * @param lockNode NodeRef - * @param userName String - * @exception WebDAVServerException - */ - private final void createLock(NodeRef lockNode, String userName) throws WebDAVServerException - { - LockService lockService = getLockService(); - - // Check the lock status of the node - LockStatus lockSts = lockService.getLockStatus(lockNode); - - // DEBUG - if (logger.isDebugEnabled()) - logger.debug("Create lock status=" + lockSts); - - if (lockSts == LockStatus.LOCKED || lockSts == LockStatus.LOCK_OWNER) - { - // Indicate that the resource is already locked - throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); - } - - // Lock the node - lockService.lock(lockNode, LockType.WRITE_LOCK, getLockTimeout()); - } - - /** - * Refresh an existing lock - * - * @param lockNode NodeRef - * @param userName String - * @exception WebDAVServerException - */ - private final void refreshLock(NodeRef lockNode, String userName) throws WebDAVServerException - { - LockService lockService = getLockService(); - - // Check the lock status of the node - LockStatus lockSts = lockService.getLockStatus(lockNode); - - // DEBUG - if (logger.isDebugEnabled()) - logger.debug("Refresh lock status=" + lockSts); - - if (lockSts != LockStatus.LOCK_OWNER) - { - // Indicate that the resource is already locked - throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); - } - - // Update the expiry for the lock - lockService.lock(lockNode, LockType.WRITE_LOCK, getLockTimeout()); - } - - /** - * Generates the XML lock discovery response body - */ - private void generateResponse(NodeRef lockNode, String userName) throws Exception - { - XMLWriter xml = createXMLWriter(); - - xml.startDocument(); - - String nsdec = generateNamespaceDeclarations(null); - xml.startElement(EMPTY_NS, WebDAV.XML_PROP + nsdec, WebDAV.XML_PROP + nsdec, - getDAVHelper().getNullAttributes()); - - // Output the lock details - generateLockDiscoveryXML(xml, lockNode); - - // Close off the XML - xml.endElement(EMPTY_NS, WebDAV.XML_PROP, WebDAV.XML_PROP); - - // Send the XML back to the client - xml.flush(); - } - - - /** - * Generates the lock discovery XML response - * - * @param xml XMLWriter - * @param lockNode NodeRef - */ - protected void generateLockDiscoveryXML(XMLWriter xml, NodeRef lockNode) throws Exception - { - Attributes nullAttr= getDAVHelper().getNullAttributes(); - - if (lockNode != null) - { - - // Get the lock details - - NodeService nodeService = getNodeService(); - - String owner = (String) nodeService.getProperty(lockNode, ContentModel.PROP_LOCK_OWNER); - Date expiryDate = (Date) nodeService.getProperty(lockNode, ContentModel.PROP_EXPIRY_DATE); - - // Output the XML response - - xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_DISCOVERY, WebDAV.XML_LOCK_DISCOVERY, nullAttr); - xml.startElement(EMPTY_NS, WebDAV.XML_ACTIVE_LOCK, WebDAV.XML_ACTIVE_LOCK, nullAttr); - - xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_TYPE, WebDAV.XML_LOCK_TYPE, nullAttr); - xml.write(DocumentHelper.createElement(WebDAV.XML_WRITE)); - xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_TYPE, WebDAV.XML_LOCK_TYPE); - - // NOTE: We only do exclusive lock tokens at the moment - - xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_LOCK_SCOPE, nullAttr); - xml.write(DocumentHelper.createElement(WebDAV.XML_EXCLUSIVE)); - xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_LOCK_SCOPE); - - // NOTE: We only support one level of lock at the moment - - xml.startElement(EMPTY_NS, WebDAV.XML_DEPTH, WebDAV.XML_DEPTH, nullAttr); - xml.write(WebDAV.ZERO); - xml.endElement(EMPTY_NS, WebDAV.XML_DEPTH, WebDAV.XML_DEPTH); - - xml.startElement(EMPTY_NS, WebDAV.XML_OWNER, WebDAV.XML_OWNER, nullAttr); - xml.write(owner); - xml.endElement(EMPTY_NS, WebDAV.XML_OWNER, WebDAV.XML_OWNER); - - xml.startElement(EMPTY_NS, WebDAV.XML_TIMEOUT, WebDAV.XML_TIMEOUT, nullAttr); - - // Output the expiry time - - String strTimeout = WebDAV.INFINITE; - if (expiryDate != null) - { - long timeoutRemaining = (expiryDate.getTime() - System.currentTimeMillis())/1000L; - - strTimeout = WebDAV.SECOND + timeoutRemaining; - } - xml.write(strTimeout); - - xml.endElement(EMPTY_NS, WebDAV.XML_TIMEOUT, WebDAV.XML_TIMEOUT); - - xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_TOKEN, WebDAV.XML_LOCK_TOKEN, nullAttr); - xml.startElement(EMPTY_NS, WebDAV.XML_HREF, WebDAV.XML_HREF, nullAttr); - - xml.write(WebDAV.makeLockToken(lockNode, owner)); - - xml.endElement(EMPTY_NS, WebDAV.XML_HREF, WebDAV.XML_HREF); - xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_TOKEN, WebDAV.XML_LOCK_TOKEN); - - xml.endElement(EMPTY_NS, WebDAV.XML_ACTIVE_LOCK, WebDAV.XML_ACTIVE_LOCK); - xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_DISCOVERY, WebDAV.XML_LOCK_DISCOVERY); - } - } - - /** - * Generates a list of namespace declarations for the response - */ - protected String generateNamespaceDeclarations(HashMap nameSpaces) - { - StringBuilder ns = new StringBuilder(); - - ns.append(" "); - ns.append(WebDAV.XML_NS); - ns.append("=\""); - ns.append(WebDAV.DEFAULT_NAMESPACE_URI); - ns.append("\""); - - // Add additional namespaces - - if ( nameSpaces != null) - { - Iterator namespaceList = nameSpaces.keySet().iterator(); - - while (namespaceList.hasNext()) - { - String strNamespaceUri = namespaceList.next(); - String strNamespaceName = nameSpaces.get(strNamespaceUri); - - ns.append(" ").append(WebDAV.XML_NS).append(":").append(strNamespaceName).append("=\""); - ns.append(strNamespaceUri).append("\" "); - } - } - - return ns.toString(); - } - - - -} +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webdav; + +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.model.ContentModel; +import org.alfresco.model.WebDAVModel; +import org.alfresco.repo.model.filefolder.FileFolderServiceImpl; +import org.alfresco.service.cmr.lock.LockService; +import org.alfresco.service.cmr.lock.LockType; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.dom4j.DocumentHelper; +import org.dom4j.io.XMLWriter; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.Attributes; + +/** + * Implements the WebDAV LOCK method + * + * @author gavinc + */ +public class LockMethod extends WebDAVMethod +{ + public static final String EMPTY_NS = ""; + + private int m_timeoutDuration = WebDAV.TIMEOUT_INFINITY; + + private LockInfo lockInfo = new LockInfo(); + + private String m_scope = null; + + private String lockToken= null; + + /** + * Default constructor + */ + public LockMethod() + { + } + + /** + * Returns true if request has lock token in the If header + * + * @return boolean + */ + protected final boolean hasLockToken() + { + if (m_conditions != null) + { + for (Condition condition : m_conditions) + { + if (!condition.getLockTokensMatch().isEmpty()) + { + return true; + } + } + } + return false; + } + + /** + * Return the lock timeout, in minutes + * + * @return int + */ + protected final int getLockTimeout() + { + return m_timeoutDuration; + } + + /** + * Parse the request headers + * + * @exception WebDAVServerException + */ + protected void parseRequestHeaders() throws WebDAVServerException + { + // Get the depth + + parseDepthHeader(); + + // According to the specification: "Values other than 0 or infinity MUST NOT be used with the Depth header on a LOCK method.". + // The specification does not specify the error code for this case - so we use HttpServletResponse.SC_INTERNAL_SERVER_ERROR. + if (m_depth != WebDAV.DEPTH_0 && m_depth != WebDAV.DEPTH_INFINITY) + { + throw new WebDAVServerException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + // Parse Lock tokens and ETags, if any + + parseIfHeader(); + + // Get the lock timeout value + + String strTimeout = m_request.getHeader(WebDAV.HEADER_TIMEOUT); + + // If the timeout header starts with anything other than Second + // leave the timeout as the default + + if (strTimeout != null && strTimeout.startsWith(WebDAV.SECOND)) + { + try + { + // Some clients send header as Second-180 Seconds so we need to + // look for the space + + int idx = strTimeout.indexOf(" "); + + if (idx != -1) + { + // Get the bit after Second- and before the space + + strTimeout = strTimeout.substring(WebDAV.SECOND.length(), idx); + } + else + { + // The string must be in the correct format + + strTimeout = strTimeout.substring(WebDAV.SECOND.length()); + } + m_timeoutDuration = Integer.parseInt(strTimeout); + } + catch (Exception e) + { + // Warn about the parse failure and leave the timeout as the + // default + + logger.warn("Failed to parse Timeout header: " + strTimeout); + } + } + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Timeout=" + getLockTimeout() + ", depth=" + getDepth()); + } + + /** + * Parse the request body + * + * @exception WebDAVServerException + */ + protected void parseRequestBody() throws WebDAVServerException + { + if (m_request.getContentLength() == -1) + { + return; + } + + Document body = getRequestBodyAsDocument(); + if (body != null) + { + Element rootElement = body.getDocumentElement(); + NodeList childList = rootElement.getChildNodes(); + + for (int i = 0; i < childList.getLength(); i++) + { + Node currentNode = childList.item(i); + switch (currentNode.getNodeType()) + { + case Node.TEXT_NODE: + break; + case Node.ELEMENT_NODE: + if (currentNode.getNodeName().endsWith(WebDAV.XML_LOCK_SCOPE)) + { + NodeList propertiesList = currentNode.getChildNodes(); + + for (int j = 0; j < propertiesList.getLength(); j++) + { + Node propertiesNode = propertiesList.item(j); + switch (propertiesNode.getNodeType()) + { + case Node.TEXT_NODE: + break; + case Node.ELEMENT_NODE: + m_scope = propertiesNode.getNodeName(); + break; + } + } + } + break; + } + } + } + } + + /** + * Execute the request + * + * @exception WebDAVServerException + */ + protected void executeImpl() throws WebDAVServerException, Exception + { + FileFolderService fileFolderService = getFileFolderService(); + String path = getPath(); + NodeRef rootNodeRef = getRootNodeRef(); + // Get the active user + String userName = getDAVHelper().getAuthenticationService().getCurrentUserName(); + + if (logger.isDebugEnabled()) + { + logger.debug("Locking node: \n" + + " user: " + userName + "\n" + + " path: " + path); + } + + FileInfo lockNodeInfo = null; + try + { + // Check if the path exists + lockNodeInfo = getDAVHelper().getNodeForPath(getRootNodeRef(), getPath(), m_request.getServletPath()); + } + catch (FileNotFoundException e) + { + // need to create it + String[] splitPath = getDAVHelper().splitPath(path); + // check + if (splitPath[1].length() == 0) + { + throw new WebDAVServerException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + FileInfo dirInfo = null; + List dirPathElements = getDAVHelper().splitAllPaths(splitPath[0]); + if (dirPathElements.size() == 0) + { + // if there are no path elements we are at the root so get the root node + dirInfo = fileFolderService.getFileInfo(getRootNodeRef()); + } + else + { + // make sure folder structure is present + dirInfo = FileFolderServiceImpl.makeFolders(fileFolderService, rootNodeRef, dirPathElements, ContentModel.TYPE_FOLDER); + } + + if (dirInfo == null) + { + throw new WebDAVServerException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + // create the file + lockNodeInfo = fileFolderService.create(dirInfo.getNodeRef(), splitPath[1], ContentModel.TYPE_CONTENT); + + if (logger.isDebugEnabled()) + { + logger.debug("Created new node for lock: \n" + + " path: " + path + "\n" + + " node: " + lockNodeInfo); + } + + m_response.setStatus(HttpServletResponse.SC_CREATED); + } + + + + // Check if this is a new lock or a lock refresh + if (hasLockToken()) + { + this.lockInfo = checkNode(lockNodeInfo); + // Refresh an existing lock + refreshLock(lockNodeInfo, userName); + } + else + { + this.lockInfo = checkNode(lockNodeInfo, true, WebDAV.XML_EXCLUSIVE.equals(m_scope)); + // Create a new lock + createLock(lockNodeInfo, userName); + } + + + m_response.setHeader(WebDAV.HEADER_LOCK_TOKEN, "<" + WebDAV.makeLockToken(lockNodeInfo.getNodeRef(), userName) + ">"); + m_response.setHeader(WebDAV.HEADER_CONTENT_TYPE, WebDAV.XML_CONTENT_TYPE); + + // We either created a new lock or refreshed an existing lock, send back the lock details + generateResponse(lockNodeInfo.getNodeRef(), userName); + } + + /** + * Create a new lock + * + * @param lockNode NodeRef + * @param userName String + * @exception WebDAVServerException + */ + private final void createLock(FileInfo lockNode, String userName) throws WebDAVServerException + { + LockService lockService = getLockService(); + + // Create Lock token + lockToken = WebDAV.makeLockToken(lockNode.getNodeRef(), userName); + + if (WebDAV.XML_EXCLUSIVE.equals(m_scope)) + { + // Lock the node + lockService.lock(lockNode.getNodeRef(), LockType.WRITE_LOCK, getLockTimeout()); + + //this.lockInfo.setToken(lockToken); + getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_OPAQUE_LOCK_TOKEN, lockToken); + } + else + { + this.lockInfo.addSharedLockToken(lockToken); + String sharedLockTokens = LockInfo.makeSharedLockTokensString(this.lockInfo.getSharedLockTokens()); + getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_SHARED_LOCK_TOKENS, sharedLockTokens); + + } + + // Store lock depth + getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_LOCK_DEPTH, WebDAV.getDepthName(m_depth)); + + // Store lock scope (shared/exclusive) + getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_LOCK_SCOPE, m_scope); + + } + + /** + * Refresh an existing lock + * + * @param lockNode NodeRef + * @param userName String + * @exception WebDAVServerException + */ + private final void refreshLock(FileInfo lockNode, String userName) throws WebDAVServerException + { + LockService lockService = getLockService(); + + if (WebDAV.XML_EXCLUSIVE.equals(m_scope)) + { + // Update the expiry for the lock + lockService.lock(lockNode.getNodeRef(), LockType.WRITE_LOCK, getLockTimeout()); + } + } + + /** + * Generates the XML lock discovery response body + */ + private void generateResponse(NodeRef lockNode, String userName) throws Exception + { + XMLWriter xml = createXMLWriter(); + + xml.startDocument(); + + String nsdec = generateNamespaceDeclarations(null); + xml.startElement(EMPTY_NS, WebDAV.XML_PROP + nsdec, WebDAV.XML_PROP + nsdec, + getDAVHelper().getNullAttributes()); + + // Output the lock details + generateLockDiscoveryXML(xml, lockNode); + + // Close off the XML + xml.endElement(EMPTY_NS, WebDAV.XML_PROP, WebDAV.XML_PROP); + + // Send the XML back to the client + xml.flush(); + } + + + /** + * Generates the lock discovery XML response + * + * @param xml XMLWriter + * @param lockNode NodeRef + */ + protected void generateLockDiscoveryXML(XMLWriter xml, NodeRef lockNode) throws Exception + { + Attributes nullAttr= getDAVHelper().getNullAttributes(); + + if (lockNode != null) + { + + // Get the lock details + + NodeService nodeService = getNodeService(); + + String owner = (String) nodeService.getProperty(lockNode, ContentModel.PROP_LOCK_OWNER); + Date expiryDate = (Date) nodeService.getProperty(lockNode, ContentModel.PROP_EXPIRY_DATE); + + // Output the XML response + + xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_DISCOVERY, WebDAV.XML_LOCK_DISCOVERY, nullAttr); + xml.startElement(EMPTY_NS, WebDAV.XML_ACTIVE_LOCK, WebDAV.XML_ACTIVE_LOCK, nullAttr); + + xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_TYPE, WebDAV.XML_LOCK_TYPE, nullAttr); + xml.write(DocumentHelper.createElement(WebDAV.XML_WRITE)); + xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_TYPE, WebDAV.XML_LOCK_TYPE); + + xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_LOCK_SCOPE, nullAttr); + if (lockToken != null) + { + // In case of lock creation take the scope from request header + xml.write(DocumentHelper.createElement(m_scope)); + } + else + { + // In case of lock refreshing take the scope from previously stored lock + xml.write(DocumentHelper.createElement(this.lockInfo.getScope())); + } + xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_LOCK_SCOPE); + + xml.startElement(EMPTY_NS, WebDAV.XML_DEPTH, WebDAV.XML_DEPTH, nullAttr); + xml.write(WebDAV.getDepthName(m_depth)); + xml.endElement(EMPTY_NS, WebDAV.XML_DEPTH, WebDAV.XML_DEPTH); + + xml.startElement(EMPTY_NS, WebDAV.XML_OWNER, WebDAV.XML_OWNER, nullAttr); + xml.write(owner); + xml.endElement(EMPTY_NS, WebDAV.XML_OWNER, WebDAV.XML_OWNER); + + xml.startElement(EMPTY_NS, WebDAV.XML_TIMEOUT, WebDAV.XML_TIMEOUT, nullAttr); + + // Output the expiry time + + String strTimeout = WebDAV.INFINITE; + if (expiryDate != null) + { + long timeoutRemaining = (expiryDate.getTime() - System.currentTimeMillis())/1000L; + + strTimeout = WebDAV.SECOND + timeoutRemaining; + } + xml.write(strTimeout); + + xml.endElement(EMPTY_NS, WebDAV.XML_TIMEOUT, WebDAV.XML_TIMEOUT); + + xml.startElement(EMPTY_NS, WebDAV.XML_LOCK_TOKEN, WebDAV.XML_LOCK_TOKEN, nullAttr); + xml.startElement(EMPTY_NS, WebDAV.XML_HREF, WebDAV.XML_HREF, nullAttr); + if (lockToken != null) + { + // Output created lock + xml.write(lockToken); + } + else + { + // Output refreshed lock + xml.write(this.lockInfo.getToken()); + } + xml.endElement(EMPTY_NS, WebDAV.XML_HREF, WebDAV.XML_HREF); + xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_TOKEN, WebDAV.XML_LOCK_TOKEN); + + xml.endElement(EMPTY_NS, WebDAV.XML_ACTIVE_LOCK, WebDAV.XML_ACTIVE_LOCK); + xml.endElement(EMPTY_NS, WebDAV.XML_LOCK_DISCOVERY, WebDAV.XML_LOCK_DISCOVERY); + } + } + + /** + * Generates a list of namespace declarations for the response + */ + protected String generateNamespaceDeclarations(HashMap nameSpaces) + { + StringBuilder ns = new StringBuilder(); + + ns.append(" "); + ns.append(WebDAV.XML_NS); + ns.append("=\""); + ns.append(WebDAV.DEFAULT_NAMESPACE_URI); + ns.append("\""); + + // Add additional namespaces + + if ( nameSpaces != null) + { + Iterator namespaceList = nameSpaces.keySet().iterator(); + + while (namespaceList.hasNext()) + { + String strNamespaceUri = namespaceList.next(); + String strNamespaceName = nameSpaces.get(strNamespaceUri); + + ns.append(" ").append(WebDAV.XML_NS).append(":").append(strNamespaceName).append("=\""); + ns.append(strNamespaceUri).append("\" "); + } + } + + return ns.toString(); + } + + +} diff --git a/source/java/org/alfresco/repo/webdav/MkcolMethod.java b/source/java/org/alfresco/repo/webdav/MkcolMethod.java index 3e447b4b3a..64199bd50f 100644 --- a/source/java/org/alfresco/repo/webdav/MkcolMethod.java +++ b/source/java/org/alfresco/repo/webdav/MkcolMethod.java @@ -31,7 +31,6 @@ import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.NodeRef; -import org.w3c.dom.Document; /** * Implements the WebDAV MKCOL method @@ -66,16 +65,14 @@ public class MkcolMethod extends WebDAVMethod { // There should not be a body with the MKCOL request - Document body = getRequestBodyAsDocument(); - - if (body != null) + if (m_request.getContentLength() > 0) { throw new WebDAVServerException(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); } } /** - * Exceute the request + * Execute the request * * @exception WebDAVServerException */ @@ -120,7 +117,7 @@ public class MkcolMethod extends WebDAVMethod catch (FileNotFoundException e) { // parent path is missing - throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND); + throw new WebDAVServerException(HttpServletResponse.SC_CONFLICT); } } else diff --git a/source/java/org/alfresco/repo/webdav/MoveMethod.java b/source/java/org/alfresco/repo/webdav/MoveMethod.java index 50b2236b04..3833859dd4 100644 --- a/source/java/org/alfresco/repo/webdav/MoveMethod.java +++ b/source/java/org/alfresco/repo/webdav/MoveMethod.java @@ -24,7 +24,13 @@ */ package org.alfresco.repo.webdav; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.NodeRef; /** @@ -47,6 +53,27 @@ public class MoveMethod extends AbstractMoveOrCopyMethod NodeRef destParentNodeRef, String name) throws Exception { + NodeRef rootNodeRef = getRootNodeRef(); + + String path = getPath(); + List pathElements = getDAVHelper().splitAllPaths(path); + FileInfo fileInfo = null; + try + { + // get the node to move + fileInfo = fileFolderService.resolveNamePath(rootNodeRef, pathElements); + } + catch (FileNotFoundException e) + { + if (logger.isDebugEnabled()) + { + logger.debug("Node not found: " + getPath()); + } + throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND); + } + + checkNode(fileInfo); + fileFolderService.move(sourceNodeRef, destParentNodeRef, name); } } diff --git a/source/java/org/alfresco/repo/webdav/PropFindMethod.java b/source/java/org/alfresco/repo/webdav/PropFindMethod.java index 76683a3093..af5f72851b 100644 --- a/source/java/org/alfresco/repo/webdav/PropFindMethod.java +++ b/source/java/org/alfresco/repo/webdav/PropFindMethod.java @@ -37,8 +37,6 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.SessionUser; import org.alfresco.repo.webdav.auth.AuthenticationFilter; -import org.alfresco.service.cmr.lock.LockService; -import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; @@ -68,8 +66,7 @@ public class PropFindMethod extends WebDAVMethod protected static final int GET_NAMED_PROPS = 1; protected static final int FIND_PROPS = 2; - // Find depth and request type - private int m_depth = WebDAV.DEPTH_INFINITY; + // Find request type protected int m_mode = GET_ALL_PROPS; // Requested properties @@ -86,16 +83,6 @@ public class PropFindMethod extends WebDAVMethod m_namespaces = new HashMap(); } - /** - * Return the property find depth - * - * @return int - */ - public final int getDepth() - { - return m_depth; - } - /** * Return the find mode * @@ -115,22 +102,8 @@ public class PropFindMethod extends WebDAVMethod { // Store the Depth header as this is used by several WebDAV methods - String strDepth = m_request.getHeader(WebDAV.HEADER_DEPTH); - if (strDepth != null && strDepth.length() > 0) - { - if (strDepth.equals(WebDAV.ZERO)) - { - m_depth = WebDAV.DEPTH_0; - } - else if (strDepth.equals(WebDAV.ONE)) - { - m_depth = WebDAV.DEPTH_1; - } - else - { - m_depth = WebDAV.DEPTH_INFINITY; - } - } + parseDepthHeader(); + } /** @@ -195,7 +168,7 @@ public class PropFindMethod extends WebDAVMethod } /** - * Exceute the main WebDAV request processing + * Execute the main WebDAV request processing * * @exception WebDAVServerException */ @@ -355,7 +328,7 @@ public class PropFindMethod extends WebDAVMethod String strName = node.getLocalName(); String strNamespaceUri = node.getNamespaceURI(); - if (strNamespaceUri.equals(WebDAV.DEFAULT_NAMESPACE_URI)) + if (WebDAV.DEFAULT_NAMESPACE_URI.equals(strNamespaceUri)) { property = new WebDAVProperty(strName); } @@ -373,6 +346,10 @@ public class PropFindMethod extends WebDAVMethod */ private String getNamespaceName(String strNamespaceUri) { + if (strNamespaceUri == null) + { + return null; + } String strNamespaceName = m_namespaces.get(strNamespaceUri); if (strNamespaceName == null) { @@ -465,7 +442,7 @@ public class PropFindMethod extends WebDAVMethod Object davValue = null; - if (propNamespaceUri.equals(WebDAV.DEFAULT_NAMESPACE_URI)) + if (WebDAV.DEFAULT_NAMESPACE_URI.equals(propNamespaceUri)) { // Check if the client is requesting lock information if (propName.equals(WebDAV.XML_LOCK_DISCOVERY)) // && metaData.isLocked()) @@ -624,7 +601,28 @@ public class PropFindMethod extends WebDAVMethod // TODO: Custom properties lookup // String qualifiedName = propNamespaceUri + WebDAV.NAMESPACE_SEPARATOR + propName; + + String value = (String) getNodeService().getProperty(nodeRef, property.createQName()); + if (value == null) + { propertiesNotFound.add(property); + } + else + { + if (property.hasNamespaceName()) + { + xml.startElement(property.getNamespaceName(), property.getName(), property.getNamespaceName() + WebDAV.NAMESPACE_SEPARATOR + property.getName(), nullAttr); + xml.write(value); + xml.endElement(property.getNamespaceName(), property.getName(), property.getNamespaceName() + WebDAV.NAMESPACE_SEPARATOR + property.getName()); + } + else + { + xml.startElement("", property.getName(), property.getName(), nullAttr); + xml.write(value); + xml.endElement("", property.getName(), property.getName()); + } + } + } } @@ -894,15 +892,13 @@ public class PropFindMethod extends WebDAVMethod */ protected void generateLockDiscoveryResponse(XMLWriter xml, NodeRef node, boolean isDir) throws Exception { - // Get the lock status for the node + // Output the lock status response - LockService lockService = getLockService(); - LockStatus lockSts = lockService.getLockStatus(node); - - // Output the lock status reponse - - if (lockSts != LockStatus.NO_LOCK) - generateLockDiscoveryXML(xml, node); + LockInfo lockInfo = getNodeLockInfo(node); + if (lockInfo.isLocked()) + { + generateLockDiscoveryXML(xml, node, lockInfo); + } } /** diff --git a/source/java/org/alfresco/repo/webdav/PropPatchMethod.java b/source/java/org/alfresco/repo/webdav/PropPatchMethod.java index 718b859fc0..ba03635ae1 100755 --- a/source/java/org/alfresco/repo/webdav/PropPatchMethod.java +++ b/source/java/org/alfresco/repo/webdav/PropPatchMethod.java @@ -31,7 +31,6 @@ import javax.servlet.http.HttpServletResponse; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; -import org.alfresco.service.cmr.repository.NodeRef; import org.dom4j.DocumentHelper; import org.dom4j.io.XMLWriter; import org.w3c.dom.Document; @@ -69,6 +68,8 @@ public class PropPatchMethod extends PropFindMethod throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND); } + checkNode(pathNodeInfo); + // Set the response content type m_response.setContentType(WebDAV.XML_CONTENT_TYPE); @@ -353,14 +354,29 @@ public class PropPatchMethod extends PropFindMethod } + /** + * Stores information about PROPPATCH action(set or remove) an according property. + * + * @author Ivan Rybnikov + */ private class PropertyAction { protected static final int SET = 0; protected static final int REMOVE = 1; + // Property on which action should be performed private WebDAVProperty property; + + // Action private int action; + + /** + * Constructor + * + * @param action + * @param property + */ public PropertyAction(int action, WebDAVProperty property) { this.action = action; diff --git a/source/java/org/alfresco/repo/webdav/PutMethod.java b/source/java/org/alfresco/repo/webdav/PutMethod.java index 21ab9914ca..7e13d03d6e 100644 --- a/source/java/org/alfresco/repo/webdav/PutMethod.java +++ b/source/java/org/alfresco/repo/webdav/PutMethod.java @@ -76,9 +76,9 @@ public class PutMethod extends WebDAVMethod m_expectHeaderPresent = true; } - // Get the lock token, if any + // Parse Lock tokens and ETags, if any - m_strLockToken = parseIfHeader(); + parseIfHeader(); } /** @@ -112,6 +112,9 @@ public class PutMethod extends WebDAVMethod { throw new WebDAVServerException(HttpServletResponse.SC_BAD_REQUEST); } + + checkNode(contentNodeInfo); + } catch (FileNotFoundException e) { diff --git a/source/java/org/alfresco/repo/webdav/UnlockMethod.java b/source/java/org/alfresco/repo/webdav/UnlockMethod.java index c101c95bc1..35f69d3023 100644 --- a/source/java/org/alfresco/repo/webdav/UnlockMethod.java +++ b/source/java/org/alfresco/repo/webdav/UnlockMethod.java @@ -24,12 +24,16 @@ */ package org.alfresco.repo.webdav; +import java.util.LinkedList; + import javax.servlet.http.HttpServletResponse; +import org.alfresco.model.WebDAVModel; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.NodeService; /** * Implements the WebDAV UNLOCK method @@ -104,7 +108,7 @@ public class UnlockMethod extends WebDAVMethod } /** - * Exceute the request + * Execute the request * * @exception WebDAVServerException */ @@ -135,6 +139,7 @@ public class UnlockMethod extends WebDAVMethod // Get the lock status for the node LockService lockService = getDAVHelper().getLockService(); + NodeService nodeService = getNodeService(); // String nodeId = lockInfo[0]; // String userName = lockInfo[1]; @@ -143,6 +148,9 @@ public class UnlockMethod extends WebDAVMethod { // Unlock the node lockService.unlock(lockNodeInfo.getNodeRef()); + nodeService.removeProperty(lockNodeInfo.getNodeRef(), WebDAVModel.PROP_OPAQUE_LOCK_TOKEN); + nodeService.removeProperty(lockNodeInfo.getNodeRef(), WebDAVModel.PROP_LOCK_DEPTH); + nodeService.removeProperty(lockNodeInfo.getNodeRef(), WebDAVModel.PROP_LOCK_SCOPE); // Indicate that the unlock was successful m_response.setStatus(HttpServletResponse.SC_NO_CONTENT); @@ -155,6 +163,28 @@ public class UnlockMethod extends WebDAVMethod } else if (lockSts == LockStatus.NO_LOCK) { + String sharedLocks = (String) nodeService.getProperty(lockNodeInfo.getNodeRef(), WebDAVModel.PROP_SHARED_LOCK_TOKENS); + if (sharedLocks != null) + { + LinkedList locks = LockInfo.parseSharedLockTokens(sharedLocks); + + if (locks != null && locks.contains(m_strLockToken)) + { + locks.remove(m_strLockToken); + nodeService.setProperty(lockNodeInfo.getNodeRef(), WebDAVModel.PROP_SHARED_LOCK_TOKENS, LockInfo.makeSharedLockTokensString(locks)); + + // Indicate that the unlock was successful + m_response.setStatus(HttpServletResponse.SC_NO_CONTENT); + + // DEBUG + if (logger.isDebugEnabled()) + { + logger.debug("Unlock token=" + getLockToken() + " Successful"); + } + } + } + else + { // DEBUG if (logger.isDebugEnabled()) logger.debug("Unlock token=" + getLockToken() + " Not locked"); @@ -162,6 +192,9 @@ public class UnlockMethod extends WebDAVMethod // Node is not locked throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); } + + + } else if (lockSts == LockStatus.LOCKED) { // DEBUG diff --git a/source/java/org/alfresco/repo/webdav/WebDAV.java b/source/java/org/alfresco/repo/webdav/WebDAV.java index 07a744f553..4f4d5e5f89 100644 --- a/source/java/org/alfresco/repo/webdav/WebDAV.java +++ b/source/java/org/alfresco/repo/webdav/WebDAV.java @@ -60,7 +60,7 @@ public class WebDAV public static final String DAV_NS = "D"; public static final String DAV_NS_PREFIX = DAV_NS + ":"; - // PROPFIND depth + // PROPFIND, LOCK depth public static final int DEPTH_0 = 0; public static final int DEPTH_1 = 1; @@ -83,6 +83,7 @@ public class WebDAV public static final String SC_NOT_FOUND_DESC = "Not Found"; public static final String SC_FORBIDDEN_DESC = "Forbidden"; + // HTTP methods public static final String METHOD_PUT = "PUT"; @@ -124,6 +125,10 @@ public class WebDAV public static final String HEADER_IF_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; + // If header keyword + + public static final String HEADER_KEY_NOT = "Not"; + // General string constants public static final String ASTERISK = "*"; @@ -214,6 +219,7 @@ public class WebDAV public static final String XML_NS_ERROR = DAV_NS_PREFIX + "error"; public static final String XML_NS_CANNOT_MODIFY_PROTECTED_PROPERTY = DAV_NS_PREFIX + "cannot-modify-protected-property"; + public static final String XML_CONTENT_TYPE = "text/xml; charset=UTF-8"; // Alfresco specific properties @@ -590,6 +596,30 @@ public class WebDAV return tokens; } + /** + * Returns string representation of the depth + * + * @param depth + * @return String + */ + public static final String getDepthName(int depth) + { + switch (depth) + { + case DEPTH_0: + return ZERO; + + case DEPTH_1: + return ONE; + + case DEPTH_INFINITY: + return INFINITY; + + default: + throw new IllegalArgumentException("Unknown depth:" + depth); + } + } + /** * Static initializer */ diff --git a/source/java/org/alfresco/repo/webdav/WebDAVMethod.java b/source/java/org/alfresco/repo/webdav/WebDAVMethod.java index c2da4257e8..1a89390244 100644 --- a/source/java/org/alfresco/repo/webdav/WebDAVMethod.java +++ b/source/java/org/alfresco/repo/webdav/WebDAVMethod.java @@ -28,6 +28,8 @@ import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -36,16 +38,23 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.alfresco.model.ContentModel; +import org.alfresco.model.WebDAVModel; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.lock.LockService; +import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -57,6 +66,7 @@ import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; + /** * Abstract base class for all the WebDAV method handling classes * @@ -89,6 +99,19 @@ public abstract class WebDAVMethod protected String m_strPath = null; + + // If header conditions + + protected LinkedList m_conditions = null; + + // If header resource-tag + + protected String m_resourceTag = null; + + // Depth header + + protected int m_depth = WebDAV.DEPTH_INFINITY; + /** * Default constructor */ @@ -125,6 +148,16 @@ public abstract class WebDAVMethod return false; } + /** + * Return the property find depth + * + * @return int + */ + public final int getDepth() + { + return m_depth; + } + /** * Executes the method, wrapping the call to {@link #executeImpl()} in an appropriate transaction * and handling the error conditions. @@ -233,13 +266,42 @@ public abstract class WebDAVMethod } /** - * Returns the lock token present in the If header + * Parses "Depth" request header * - * @return The lock token present in the If header + * @throws WebDAVServerException */ - protected String parseIfHeader() throws WebDAVServerException + protected void parseDepthHeader() throws WebDAVServerException { - String strLockToken = null; + // Store the Depth header as this is used by several WebDAV methods + + String strDepth = m_request.getHeader(WebDAV.HEADER_DEPTH); + if (strDepth != null && strDepth.length() > 0) + { + if (strDepth.equals(WebDAV.ZERO)) + { + m_depth = WebDAV.DEPTH_0; + } + else if (strDepth.equals(WebDAV.ONE)) + { + m_depth = WebDAV.DEPTH_1; + } + else + { + m_depth = WebDAV.DEPTH_INFINITY; + } + } + } + + /** + * Parses "If" header of the request. + * Stores conditions that should be checked. + * Parses both No-tag-list and Tagged-list formats + * See "10.4.2 Syntax" paragraph of the WebDAV specification for "If" header format. + * + */ + protected void parseIfHeader() throws WebDAVServerException + { + //String strLockToken = null; String strIf = m_request.getHeader(WebDAV.HEADER_IF); @@ -248,45 +310,78 @@ public abstract class WebDAVMethod if (strIf != null && strIf.length() > 0) { - if (strIf.startsWith("(<")) + if (strIf.startsWith("<")) { - // Parse the tokens (only get the first one though) + m_resourceTag = strIf.substring(1, strIf.indexOf(">")); + strIf = strIf.substring(m_resourceTag.length() + 3); + } + + m_conditions = new LinkedList(); + String[] parts = strIf.split("\\) \\("); + for (int i = 0; i < parts.length; i++) + { + + String partString = parts[i].replaceAll("\\(", "").replaceAll("\\)", ""); - int idx = strIf.indexOf(">"); - if (idx != -1) + Condition c = new Condition(); + String[] conditions = partString.split(" "); + + for (int j = 0; j < conditions.length; j++) + { + boolean fNot = false; + String eTag = null; + String lockToken = null; + + if (WebDAV.HEADER_KEY_NOT.equals(conditions[j])) + { + // Check if Not keyword followed by State-token or entity-tag + if (j == (conditions.length - 1)) + { + throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); + } + fNot = true; + j++; + } + + // read State-token + int index = conditions[j].indexOf('<'); + if (index != -1) { try { - strLockToken = strIf.substring(WebDAV.OPAQUE_LOCK_TOKEN.length() + 2, idx); - } - catch (IndexOutOfBoundsException e) + String s = conditions[j].substring(index + 1, conditions[j].indexOf(">")); + if (!s.startsWith(WebDAV.OPAQUE_LOCK_TOKEN)) + { + if(!fNot) { - logger.warn("Failed to parse If header: " + strIf); + throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); } } else { - throw new WebDAVServerException(HttpServletResponse.SC_BAD_REQUEST); + lockToken = s; + c.addLockTocken(lockToken, fNot); } - - // Print a warning if there are other tokens detected - - if (strIf.length() > idx + 2) + } + catch (IndexOutOfBoundsException e) { - logger.warn("The If header contained more than one lock token, only one is supported"); + throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); } } - else if (strIf.startsWith("<")) + + // read entity-tag + index = conditions[j].indexOf("[\""); + if (index != -1) { - logger.warn("Tagged lists in the If header are not supported"); + // TODO: implement parsing of weak ETags: W/"123..". + eTag = conditions[j].substring(index + 1, conditions[j].indexOf("]")); + c.addETag(eTag, fNot); } - else if (strIf.startsWith("([")) - { - logger.warn("ETags in the If header are not supported"); + + } + m_conditions.add(c); } } - - return strLockToken; } /** @@ -329,6 +424,26 @@ public abstract class WebDAVMethod return m_davHelper.getNodeService(); } + /** + * Convenience method to return the search service + * + * @return SearchService + */ + protected final SearchService getSearchService() + { + return m_davHelper.getSearchService(); + } + + /** + * Convenience method to return the namespace service + * + * @return NamespaceService + */ + protected final NamespaceService getNamespaceService() + { + return m_davHelper.getNamespaceService(); + } + /** * @return Returns the general file/folder manipulation service */ @@ -437,7 +552,7 @@ public abstract class WebDAVMethod * @param xml XMLWriter * @param lockNode NodeRef */ - protected void generateLockDiscoveryXML(XMLWriter xml, NodeRef lockNode) throws Exception + protected void generateLockDiscoveryXML(XMLWriter xml, NodeRef lockNode, LockInfo lockInfo) throws Exception { Attributes nullAttr= getDAVHelper().getNullAttributes(); @@ -463,13 +578,13 @@ public abstract class WebDAVMethod // NOTE: We only do exclusive lock tokens at the moment xml.startElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_NS_LOCK_SCOPE, nullAttr); - xml.write(DocumentHelper.createElement(WebDAV.XML_NS_EXCLUSIVE)); + xml.write(DocumentHelper.createElement(lockInfo.getScope())); xml.endElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_NS_LOCK_SCOPE); // NOTE: We only support one level of lock at the moment xml.startElement(WebDAV.DAV_NS, WebDAV.XML_DEPTH, WebDAV.XML_NS_DEPTH, nullAttr); - xml.write(WebDAV.ZERO); + xml.write(lockInfo.getDepth()); xml.endElement(WebDAV.DAV_NS, WebDAV.XML_DEPTH, WebDAV.XML_NS_DEPTH); xml.startElement(WebDAV.DAV_NS, WebDAV.XML_OWNER, WebDAV.XML_NS_OWNER, nullAttr); @@ -531,7 +646,7 @@ public abstract class WebDAVMethod String strNamespaceName = nameSpaces.get(strNamespaceUri); ns.append(" ").append(WebDAV.XML_NS).append(":").append(strNamespaceName).append("=\""); - ns.append(strNamespaceUri).append("\" "); + ns.append(strNamespaceUri == null ? "" : strNamespaceUri).append("\" "); } } @@ -539,4 +654,451 @@ public abstract class WebDAVMethod } + /** + * Checks if write operation can be performed on node. + * + * @param fileInfo - node's file info + * @param ignoreShared - if true ignores shared locks + * @param lockMethod - must be true if used from lock method + * @return node's lock info + * @throws WebDAVServerException if node has shared or exclusive lock + * or If header preconditions failed + */ + protected LockInfo checkNode(FileInfo fileInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException + { + LockInfo nodeLockInfo = getNodeLockInfo(fileInfo.getNodeRef()); + String nodeETag = getDAVHelper().makeQuotedETag(fileInfo.getNodeRef()); + + + if (m_conditions == null) + { + if (nodeLockInfo.getToken() == null) + { + if (nodeLockInfo.getSharedLockTokens() == null) + { + return nodeLockInfo; + } + if (!ignoreShared) + { + throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); + } + } + else + { + throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); + } + } + + // Checking of the If tag consists of two checks: + // 1. If the node is locked we need to check it's Lock token independently of conditions check result. + // For example "() (Not )" if always true, + // but request must fail with 423 Locked response because node is locked. + // 2. Check if ANY of the conditions in If header true. + checkLockToken(nodeLockInfo, ignoreShared, lockMethod); + checkConditions(nodeLockInfo.getToken(), nodeETag); + + return nodeLockInfo; + } + + /** + * Checks if write operation can be performed on node. + * + * @param fileInfo + * @return + * @throws WebDAVServerException if node has shared or exclusive lock + * or If header preconditions failed + */ + protected LockInfo checkNode(FileInfo fileInfo) throws WebDAVServerException + { + return checkNode(fileInfo, false, true); + } + + /** + * Checks if node can be accessed with WebDAV operation + * + * @param nodeLockToken - token to check + * @param lockInfo - node's lock info + * @param ignoreShared - if true - ignores shared lock tokens + * @param lockMethod - must be true if used from lock method + * @throws WebDAVServerException if node has no appropriate lock token + */ + private void checkLockToken(LockInfo lockInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException + { + String nodeLockToken = lockInfo.getToken(); + LinkedList sharedLockTokens = lockInfo.getSharedLockTokens(); + + if (m_conditions != null) + { + // Request has conditions to check + if (lockInfo.isShared()) + { + // Node has shared lock. Check if conditions contains lock token of the node. + // If not throw exception + if (sharedLockTokens != null) + { + if (!ignoreShared) + { + for (Condition condition : m_conditions) + { + for (String sharedLockToken : sharedLockTokens) + { + if (condition.getLockTokensMatch().contains(sharedLockToken)) + { + return; + } + } + } + throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); + } + return; + } + } + else + { + // Node has exclusive lock. Check if conditions contains lock token of the node + // If not throw exception + for (Condition condition : m_conditions) + { + if (nodeLockToken != null) + { + if (condition.getLockTokensMatch().contains(nodeLockToken)) + { + return; + } + } + } + throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); + } + } + else + { + // Request has no conditions + if (lockInfo.isShared()) + { + // If lock is shared and check was called not from LOCK method return + if (!lockMethod) + { + return; + } + // Throw exception - we can't set lock on node with shared lock + throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); + } + } + + throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); + } + + + /** + * Checks If header conditions. Throws WebDAVServerException with 412(Precondition failed) + * if none of the conditions success. + * + * @param nodeLockToken - node's lock token + * @param nodeETag - node's ETag + * @throws WebDAVServerException if conditions fail + */ + private void checkConditions(String nodeLockToken, String nodeETag) throws WebDAVServerException + { + // Checks If header conditions. + // Each condition can contain check of ETag and check of Lock token. + + if (m_conditions == null) + { + // No conditions were provided with "If" request header, so check successful + return; + } + + // Check the list of "If" header's conditions. + // If any condition conforms then check is successful + for (Condition condition : m_conditions) + { + // Flag for ETag conditions + boolean fMatchETag = true; + // Flag for Lock token conditions + boolean fMatchLockToken = true; + + // Check ETags that should match + if (condition.getETagsMatch() != null) + { + fMatchETag = condition.getETagsMatch().contains(nodeETag) ? true : false; + } + // Check ETags that shouldn't match + if (condition.getETagsNotMatch() != null) + { + fMatchETag = condition.getETagsNotMatch().contains(nodeETag) ? false : true; + } + // Check lock tokens that should match + if (condition.getLockTokensMatch() != null) + { + fMatchLockToken = condition.getLockTokensMatch().contains(nodeLockToken) ? true : false; + } + // Check lock tokens that shouldn't match + if (condition.getLockTokensNotMatch() != null) + { + fMatchLockToken = condition.getLockTokensNotMatch().contains(nodeLockToken) ? false : true; + } + + if (fMatchETag && fMatchLockToken) + { + // Condition conforms + return; + } + } + + // None of the conditions successful + throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); + } + + + /** + * Returns node Lock token in consideration of WebDav lock depth. + * + * @param fileInfo node + * @return String Lock token + */ + protected LockInfo getNodeLockInfo(NodeRef nodeRef) + { + LockInfo lockInfo = new LockInfo(); + NodeService nodeService = getNodeService(); + LockService lockService = getLockService(); + + // Check if node is locked directly. + LockStatus lockSts = lockService.getLockStatus(nodeRef); + if (lockSts == LockStatus.LOCKED || lockSts == LockStatus.LOCK_OWNER) + { + String propOpaqueLockToken = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_OPAQUE_LOCK_TOKEN); + if (propOpaqueLockToken != null) + { + // Get lock depth + String depth = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_LOCK_DEPTH); + //Get lock scope + String scope = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_LOCK_SCOPE); + // Get shared lock tokens + String sharedLocks = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_SHARED_LOCK_TOKENS); + + // Node has it's own Lock token. + // Store lock information to the lockInfo object + lockInfo.setToken(propOpaqueLockToken); + lockInfo.setDepth(depth); + lockInfo.setScope(scope); + lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks)); + + return lockInfo; + } + } + else + { + // No has no exclusive lock but can be locked with shared lock + String sharedLocks = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_SHARED_LOCK_TOKENS); + if (sharedLocks != null) + { + // Get lock depth + String depth = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_LOCK_DEPTH); + //Get lock scope + String scope = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_LOCK_SCOPE); + + // Node has it's own Lock token. + // Store lock information to the lockInfo object + lockInfo.setDepth(depth); + lockInfo.setScope(scope); + lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks)); + lockInfo.setShared(true); + + return lockInfo; + } + } + + + // Node isn't locked directly and has no it's own Lock token. + // Try to search indirect lock. + NodeRef node = nodeRef; + while (true) + { + List assocs = nodeService.getParentAssocs(node, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); + if (assocs.isEmpty()) + { + // Node has no lock and Lock token + return new LockInfo(); + } + NodeRef parent = assocs.get(0).getParentRef(); + + lockSts = lockService.getLockStatus(parent); + if (lockSts == LockStatus.LOCKED || lockSts == LockStatus.LOCK_OWNER) + { + // Check node lock depth. + // If depth is WebDAV.INFINITY then return this node's Lock token. + String depth = (String) nodeService.getProperty(parent, WebDAVModel.PROP_LOCK_DEPTH); + if (WebDAV.INFINITY.equals(depth)) + { + // In this case node is locked indirectly. + + //Get lock scope + String scope = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_LOCK_SCOPE); + // Get shared lock tokens + String sharedLocks = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_SHARED_LOCK_TOKENS); + + // Store lock information to the lockInfo object + + // Get lock token of the locked node - this is indirect lock token. + String propOpaqueLockToken = (String) nodeService.getProperty(parent, WebDAVModel.PROP_OPAQUE_LOCK_TOKEN); + lockInfo.setToken(propOpaqueLockToken); + lockInfo.setDepth(depth); + lockInfo.setScope(scope); + lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks)); + + return lockInfo; + } + } + else + { + // No has no exclusive lock but can be locked with shared lock + String sharedLocks = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_SHARED_LOCK_TOKENS); + if (sharedLocks != null) + { + // Check node lock depth. + // If depth is WebDAV.INFINITY then return this node's Lock token. + String depth = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_LOCK_DEPTH); + if (WebDAV.INFINITY.equals(depth)) + { + // In this case node is locked indirectly. + + //Get lock scope + String scope = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_LOCK_SCOPE); + + // Node has it's own Lock token. + lockInfo.setDepth(depth); + lockInfo.setScope(scope); + lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks)); + + lockInfo.setShared(true); + + return lockInfo; + } + } + } + + node = parent; + } + } + + /** + * Class used for storing conditions which comes with "If" header of the request + * + * @author ivanry + * + */ + protected class Condition + { + // These tokens will be checked on equivalence against node's lock token + private LinkedList lockTokensMatch = new LinkedList(); + + // These tokens will be checked on non-equivalence against node's lock token + private LinkedList lockTokensNotMatch = new LinkedList(); + + // These ETags will be checked on equivalence against node's ETags + private LinkedList eTagsMatch; + + // These ETags will be checked on non-equivalence against node's ETags + private LinkedList eTagsNotMatch; + + /** + * Default constructor + * + */ + public Condition() + { + } + + /** + * Returns the list of lock tokens that should be checked against node's lock token on equivalence. + * + * @return lock tokens + */ + public LinkedList getLockTokensMatch() + { + return this.lockTokensMatch; + } + + /** + * Returns the list of lock tokens that should be checked against node's lock token on non-equivalence. + * + * @return lock tokens + */ + public LinkedList getLockTokensNotMatch() + { + return this.lockTokensNotMatch; + } + + /** + * Returns the list of ETags that should be checked against node's ETag on equivalence. + * + * @return ETags list + */ + public LinkedList getETagsMatch() + { + return this.eTagsMatch; + } + + /** + * Returns the list of ETags that should be checked against node's ETag on non-equivalence. + * + * @return ETags list + */ + public LinkedList getETagsNotMatch() + { + return this.eTagsNotMatch; + } + + /** + * Adds lock token to check + * + * @param lockToken String + * @param notMatch true is lock token should be added to the list matched tokens. + * false if should be added to the list of non-matches. + */ + public void addLockTocken(String lockToken, boolean notMatch) + { + if (notMatch) + { + this.lockTokensNotMatch.add(lockToken); + } + else + { + this.lockTokensMatch.add(lockToken); + } + } + + /** + * Add ETag to check + * + * @param eTag String + * @param notMatch true is ETag should be added to the list matched ETags. + * false if should be added to the list of non-matches. + */ + public void addETag(String eTag, boolean notMatch) + { + if (notMatch) + { + if (eTagsNotMatch == null) + { + eTagsNotMatch = new LinkedList(); + } + this.eTagsNotMatch.add(eTag); + } + else + { + if (eTagsMatch == null) + { + eTagsMatch = new LinkedList(); + } + this.eTagsMatch.add(eTag); + } + } + } + + + + + + } diff --git a/source/java/org/alfresco/repo/webdav/WebDAVProperty.java b/source/java/org/alfresco/repo/webdav/WebDAVProperty.java index 9a934765bc..af0be0a163 100644 --- a/source/java/org/alfresco/repo/webdav/WebDAVProperty.java +++ b/source/java/org/alfresco/repo/webdav/WebDAVProperty.java @@ -1,191 +1,193 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.webdav; - -import org.alfresco.service.namespace.QName; - -/** - * Class to represent a WebDAV property - * - * @author gavinc - */ -public class WebDAVProperty -{ - private String m_strName = null; - private String m_strNamespaceUri = WebDAV.DEFAULT_NAMESPACE_URI; - private String m_strNamespaceName = null; - private String m_strValue = null; - - /** - * Constructs a WebDAVProperty - * - * @param strName - * @param strNamespaceUri - * @param strNamespaceName - * @param strValue - */ - public WebDAVProperty(String strName, String strNamespaceUri, String strNamespaceName, String strValue) - { - this(strName, strNamespaceUri, strNamespaceName); - m_strValue = strValue; - } - - /** - * Constructs a WebDAVProperty - * - * @param strName - * @param strNamespaceUri - * @param strNamespaceName - * @param strValue - */ - public WebDAVProperty(String strName, String strNamespaceUri, String strNamespaceName) - { - this(strName); - - m_strNamespaceUri = strNamespaceUri; - m_strNamespaceName = strNamespaceName; - } - - /** - * Constructs a WebDAVProperty with the default namespace details - * - * @param strName - */ - public WebDAVProperty(String strName) - { - m_strName = strName; - } - - /** - * Returns the name of the property - * - * @return The name of the property - */ - public String getName() - { - return m_strName; - } - - /** - * Returns the namespace URI for this property - * - * @return The namespace URI for this property - */ - public String getNamespaceUri() - { - return m_strNamespaceUri; - } - - /** - * Determine if the property has a namespace - * - * @return boolean - */ - public final boolean hasNamespaceName() - { - return m_strNamespaceName != null ? true : false; - } - - /** - * Returns the namespace name for this property - * - * @return The namespace name for this property - */ - public String getNamespaceName() - { - return m_strNamespaceName; - } - - /** - * Returns the value of this property - * - * @return The value of this property - */ - public String getValue() - { - return m_strValue; - } - - /** - * Sets the property's value - * - * @param strValue The new value - */ - public void setValue(String strValue) - { - m_strValue = strValue; - } - - /** - * Creates QName of the property - * - * @return QName - */ - public QName createQName() - { - return QName.createQName(m_strNamespaceUri, m_strName); - } - - /** - * Returns true if property is protected according to the WebDav specification - * - * @return boolean - */ - public boolean isProtected() - { - return WebDAV.XML_GET_CONTENT_LENGTH.equals(m_strName) || - WebDAV.XML_GET_ETAG.equals(m_strName) || - WebDAV.XML_GET_LAST_MODIFIED.equals(m_strName) || - WebDAV.XML_LOCK_DISCOVERY.equals(m_strName) || - WebDAV.XML_RESOURCE_TYPE.equals(m_strName) || - WebDAV.XML_SUPPORTED_LOCK.equals(m_strName); - } - - /** - * Return the property as a string - * - * @return String - */ - public String toString() - { - StringBuilder str = new StringBuilder(); - - str.append("["); - - str.append(getName()); - str.append("="); - str.append(getValue()); - str.append(",URI="); - str.append(getNamespaceUri()); - - if ( hasNamespaceName()) - { - str.append(","); - str.append(getNamespaceName()); - } - - return str.toString(); - } -} +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.webdav; + +import org.alfresco.service.namespace.QName; + +/** + * Class to represent a WebDAV property + * + * @author gavinc + */ +public class WebDAVProperty +{ + private String m_strName = null; + private String m_strNamespaceUri = WebDAV.DEFAULT_NAMESPACE_URI; + private String m_strNamespaceName = null; + private String m_strValue = null; + + /** + * Constructs a WebDAVProperty + * + * @param strName + * @param strNamespaceUri + * @param strNamespaceName + * @param strValue + */ + public WebDAVProperty(String strName, String strNamespaceUri, String strNamespaceName, String strValue) + { + this(strName, strNamespaceUri, strNamespaceName); + m_strValue = strValue; + } + + /** + * Constructs a WebDAVProperty + * + * @param strName + * @param strNamespaceUri + * @param strNamespaceName + * @param strValue + */ + public WebDAVProperty(String strName, String strNamespaceUri, String strNamespaceName) + { + this(strName); + + m_strNamespaceUri = strNamespaceUri; + m_strNamespaceName = strNamespaceName; + } + + /** + * Constructs a WebDAVProperty with the default namespace details + * + * @param strName + */ + public WebDAVProperty(String strName) + { + m_strName = strName; + } + + /** + * Returns the name of the property + * + * @return The name of the property + */ + public String getName() + { + return m_strName; + } + + /** + * Returns the namespace URI for this property + * + * @return The namespace URI for this property + */ + public String getNamespaceUri() + { + return m_strNamespaceUri; + } + + /** + * Determine if the property has a namespace + * + * @return boolean + */ + public final boolean hasNamespaceName() + { + return m_strNamespaceName != null ? true : false; + } + + /** + * Returns the namespace name for this property + * + * @return The namespace name for this property + */ + public String getNamespaceName() + { + return m_strNamespaceName; + } + + /** + * Returns the value of this property + * + * @return The value of this property + */ + public String getValue() + { + return m_strValue; + } + + /** + * Sets the property's value + * + * @param strValue The new value + */ + public void setValue(String strValue) + { + m_strValue = strValue; + } + + + /** + * Creates QName of the property + * + * @return QName + */ + public QName createQName() + { + return QName.createQName(m_strNamespaceUri, m_strName); + } + + /** + * Returns true if property is protected according to the WebDav specification + * + * @return boolean + */ + public boolean isProtected() + { + return WebDAV.XML_GET_CONTENT_LENGTH.equals(m_strName) || + WebDAV.XML_GET_ETAG.equals(m_strName) || + WebDAV.XML_GET_LAST_MODIFIED.equals(m_strName) || + WebDAV.XML_LOCK_DISCOVERY.equals(m_strName) || + WebDAV.XML_RESOURCE_TYPE.equals(m_strName) || + WebDAV.XML_SUPPORTED_LOCK.equals(m_strName); + } + + + /** + * Return the property as a string + * + * @return String + */ + public String toString() + { + StringBuilder str = new StringBuilder(); + + str.append("["); + + str.append(getName()); + str.append("="); + str.append(getValue()); + str.append(",URI="); + str.append(getNamespaceUri()); + + if ( hasNamespaceName()) + { + str.append(","); + str.append(getNamespaceName()); + } + + return str.toString(); + } +}