Files
alfresco-community-repo/source/java/org/alfresco/repo/webdav/PropFindMethod.java
Dave Ward 43bed77f05 Merged V4.1-BUG-FIX to HEAD
40605: ALF-15273: Merged PATCHES/V4.0.1 to V4.1-BUG-FIX
      40132: ALF-15376:  Activiti schema updates fail when hibernate.default_schema is set with ORA-00942. 
         - Corrected schema case to uppercase when database is Oracle.
      40235: ALF-15367: Reverse merged the following revisions because the fix is deemed not robust enough.
         40132: ALF-15376:  Activiti schema updates fail when hibernate.default_schema is set with ORA-00942. 
            - Corrected schema case to uppercase when database is Oracle.
         40041: ALF-15376: Merged V4.1-BUG-FIX to PATCHES/V4.0.1
            39969: Merged DEV/BELARUS-V4.1-BUG-FIX-2012_07_09 to V4.1-BUG-FIX:
               ALF-15273 : Activiti schema updates fail when hibernate.default_schema is set with ORA-00942. The Activiti database is now correctly initialized with the correct "hibernate.default_schema"
      40470: ALF-15376: how to debug the creation of Activiti tables (ACT_) when upgrading to 4.X
         - added more logging to Activiti schema creation
      40471: ALF-15376: Activiti schema updates fail when hibernate.default_schema is set with ORA-00942
         - Ignore hibernate.default_schema and determine default schema from the Connection DatabaseMetaData
         - Provided the Activiti schema initializer with the default schema information
         - Provided countAppliedPatches() with default schema information
      40501: ALF-15376: Improved webapp logging.properties to use a console handler so that it doesn't suppress absolutely everything and we can selectively turn on logging!
   40608: Fix for ALF-4274 - JSF - Paste action does not work when browse.jsp is overrided
   40611: GERMAN: Translation updates based on EN r40604
   40612: SPANISH: Translation updates based on EN r40604
   40613: FRENCH: Translation updates based on EN r40604
   40614: ITALIAN: Translation updates based on EN r40604
   40615: JAPANESE: Translation updates based on EN r40604
   40616: DUTCH: Translation updates based on EN r40604
   40617: CHINESE: Translation updates based on EN r40604
   40629: ALF-15321: upgrade Activiti to fix logging
   40632: Fix for ALF-15487 Search not working for queries containing 3-digit versions
   Fix for ALF-15356 SOLR doesn't support searching by cm:name of file with underscore and dots
   40655: Fix for ALF-14752 - Collapse Links part at the WCM details page lead to error.
   40662: Eclipse classpath fixes
   40663: Merged DEV to V4.1-BUG-FIX
      40661: ALF-15318 (part 2): It's possible to log in by disabled user (NTLM with SSO in a clustered env)
         The onValidateFailed() methods were moved to BaseSSOAuthenticationFilter to response with a 401 for a disabled user.
   40665: ALF-15448: Merged V3.4-BUG-FIX (3.4.11) to V4.1-BUG-FIX (4.1.1)
      40664: ALF-15578 CLONE 3.4.11: LibreOffice 3.6 startup on Mac fails 
   40685: Merged PATCHES/V4.0.2 to V4.1-BUG-FIX
      39274: Merged DEV to V4.0.2 (4.0.2.4)
         << Unable to merge code as supplied as it introduced a change to a public API, which would break alfresco.log
            if the RM AMP was installed See RM-452 >>
         39166: ALF-15583 / ALF-14584: autoVersionOnUpdateProps=true does not increment the version label after checkout/checkin
            'VersionableAspectTest' has been modified in accordance with concept: several modifications of node in
      	  a single transaction are interpreted as a single version. Each operation in the test which should provide
      	  a new version have been made atomic
         39089: ALF-15583 / ALF-14584: autoVersionOnUpdateProps=true does not increment the version label after checkout/checkin
            Check of lock has been corrected since 'cm:lockable' aspect doesn't indicate lock state:
            - 'LockService' service has been extended with 'isLocked(NodRef)' method which returns 'true' if document
              is locked and current user is not an owner of the lock;
            - new 'VersionableAspectTest' has been added to test the use-case described in the issue and to test
              whether 'VersionableAspect' changes version label of a locked document
      39369: ALF-15583 / ALF-14584 autoVersionOnUpdateProps=true does not increment the version label after checkout/checkin
         - Test failures: A READ_ONLY lock was being set because we are adding a versionable aspect. This resulted in an
           Exception when attempting to update the version. Change made to the isLocked method (now called isLockedOrReadOnly)
           to reflect that a node is locked even for the owner and the lock type is not a WRITE lock.
      39939: ALF-15584 / ALF-15001: Gracefully handle stale NodeRefs in query results in DMDiscoveryServicePort
      - SOLR makes this more likely to occur
      40455: ALF-15585 / ALF-15383: Long-running Feed Cleaner
       - Part 1: Limit problems caused by missing indexes
         - Remove all count calls
         - Remove logic requiring calls to SiteService to list all sites
         - Added in an ID range limit to act as a hard-stop to entry growth (set to 1M)
       - TODO: use JobLockService
      40461: ALF-15585 / ALF-15383: Long running Feed Cleaner 
       - Part 2: Added JobLockService usage to ensure only one instance runs at a time
      40463: ALF-15585 / ALF-15383: Long running Feed Cleaner
       - A bit more trace and debug
      40526: ALF-15586: Fixed ALF-15540: CMIS: Synchronized block in service interceptor
      40574: ALF-15585 / ALF-15383: Long running Feed Cleaner
      - Fix MySQL variant of activities-common-SqlMap
      40579: ALF-15585: Fix fallout from rev 40455: ALF-15383: Long-running Feed Cleaner
       - MySQL dialect was duplicating ALL SQL statements
       - Split 'large' SQL selects into activities-select-SqlMap.xml containing 7 statements that are all overridden for MySQL
       - Fixed split in common file between different types of statements
      40588: ALF-15587 / ALF-15385: Merged V3.4-BUG-FIX to PATCHES/V4.0.2 (Lost revision)
         28830: ALF-7622 Refactored JScriptWorkflowTask. Now when setProperties() is called it properly updates the WorkflowTask properties via the WorflowService.updateTask() method.
   40687: Merged V3.4-BUG-FIX to V4.1-BUG-FIX
      40599: ALF-15567: Merged PATCHES/V3.4.10 to V3.4-BUG-FIX
         40511: ALF-12008: Merged DEV to PATCHES/V3.4.10
            Due to Windows Explorer's URL concatenation behaviour, we must present links as shortcuts to the real URL, rather than direct hrefs.
            This is at least consistent with the way the CIFS server handles links. See org.alfresco.filesys.repo.ContentDiskDriver.openFile().
         40518: ALF-12008: Fixed compilation error


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@40691 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2012-08-21 16:31:48 +00:00

965 lines
37 KiB
Java

/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.webdav;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
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.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.TypeConverter;
import org.alfresco.service.namespace.QName;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
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;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* Implements the WebDAV PROPFIND method
*
* @author Gavin Cornwell
*/
public class PropFindMethod extends WebDAVMethod
{
// Request types
protected static final int GET_ALL_PROPS = 0;
protected static final int GET_NAMED_PROPS = 1;
protected static final int FIND_PROPS = 2;
// Find request type
protected int m_mode = GET_ALL_PROPS;
// Requested properties
protected ArrayList<WebDAVProperty> m_properties = null;
// Available namespaces list
protected HashMap<String, String> m_namespaces = null;
/**
* Default constructor
*/
public PropFindMethod()
{
m_namespaces = new HashMap<String, String>();
}
/**
* Return the find mode
*
* @return int
*/
public final int getMode()
{
return m_mode;
}
/**
* Parse the request headers
*
* @exception WebDAVServerException
*/
protected void parseRequestHeaders() throws WebDAVServerException
{
// Store the Depth header as this is used by several WebDAV methods
parseDepthHeader();
}
/**
* Parse the request body
*
* @exception WebDAVServerException
*/
protected void parseRequestBody() throws WebDAVServerException
{
Document body = getRequestBodyAsDocument();
if (body != null)
{
Element rootElement = body.getDocumentElement();
NodeList childList = rootElement.getChildNodes();
Node node = null;
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_ALLPROP))
{
m_mode = GET_ALL_PROPS;
}
else if (currentNode.getNodeName().endsWith(WebDAV.XML_PROP))
{
m_mode = GET_NAMED_PROPS;
node = currentNode;
}
else if (currentNode.getNodeName().endsWith(WebDAV.XML_PROPNAME))
{
m_mode = FIND_PROPS;
}
break;
}
}
if (m_mode == GET_NAMED_PROPS)
{
m_properties = new ArrayList<WebDAVProperty>();
childList = node.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:
m_properties.add(createProperty(currentNode));
break;
}
}
}
}
}
/**
* @return Returns <tt>true</tt> always
*/
@Override
protected boolean isReadOnly()
{
return true;
}
/**
* Execute the main WebDAV request processing
*
* @exception WebDAVServerException
*/
protected void executeImpl() throws WebDAVServerException, Exception
{
m_response.setStatus(WebDAV.WEBDAV_SC_MULTI_STATUS);
FileFolderService fileFolderService = getFileFolderService();
FileInfo pathNodeInfo = null;
try
{
// Check that the path exists
pathNodeInfo = getDAVHelper().getNodeForPath(getRootNodeRef(), m_strPath, m_request.getServletPath());
}
catch (FileNotFoundException e)
{
// The path is not valid - send a 404 error back to the client
throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND);
}
// Set the response content type
m_response.setContentType(WebDAV.XML_CONTENT_TYPE);
// Create multistatus response
XMLWriter xml = createXMLWriter();
xml.startDocument();
String nsdec = generateNamespaceDeclarations(m_namespaces);
xml.startElement(
WebDAV.DAV_NS,
WebDAV.XML_MULTI_STATUS + nsdec,
WebDAV.XML_NS_MULTI_STATUS + nsdec,
getDAVHelper().getNullAttributes());
// Create the path for the current location in the tree
StringBuilder baseBuild = new StringBuilder(256);
baseBuild.append(getPath());
if (baseBuild.length() == 0 || baseBuild.charAt(baseBuild.length() - 1) != WebDAVHelper.PathSeperatorChar)
{
baseBuild.append(WebDAVHelper.PathSeperatorChar);
}
String basePath = baseBuild.toString();
// Output the response for the root node, depth zero
generateResponseForNode(xml, pathNodeInfo, basePath);
// If additional levels are required and the root node is a folder then recurse to the required
// level and output node details a level at a time
if (getDepth() != WebDAV.DEPTH_0 && pathNodeInfo.isFolder())
{
// Create the initial list of nodes to report
List<FileInfo> nodeInfos = new ArrayList<FileInfo>(10);
nodeInfos.add(pathNodeInfo);
int curDepth = WebDAV.DEPTH_1;
// Save the base path length
int baseLen = baseBuild.length();
// List of next level of nodes to report
List<FileInfo> nextNodeInfos = null;
if (getDepth() > WebDAV.DEPTH_1)
{
nextNodeInfos = new ArrayList<FileInfo>(10);
}
// Loop reporting each level of nodes to the requested depth
while (curDepth <= getDepth() && nodeInfos != null)
{
// Clear out the next level of nodes, if required
if (nextNodeInfos != null)
{
nextNodeInfos.clear();
}
// Output the current level of node(s), the node list should
// only contain folder nodes
for (FileInfo curNodeInfo : nodeInfos)
{
// Get the list of child nodes for the current node
List<FileInfo> childNodeInfos = fileFolderService.list(curNodeInfo.getNodeRef());
// can skip the current node if it doesn't have children
if (childNodeInfos.size() == 0)
{
continue;
}
// Output the child node details
// Generate the base path for the current parent node
baseBuild.setLength(baseLen);
try
{
String pathSnippet = getDAVHelper().getPathFromNode(pathNodeInfo.getNodeRef(), curNodeInfo.getNodeRef());
baseBuild.append(pathSnippet);
}
catch (FileNotFoundException e)
{
// move to the next node
continue;
}
int curBaseLen = baseBuild.length();
// Output the child node details
for (FileInfo curChildInfo : childNodeInfos)
{
// Build the path for the current child node
baseBuild.setLength(curBaseLen);
baseBuild.append(curChildInfo.getName());
// Output the current child node details
generateResponseForNode(xml, curChildInfo, baseBuild.toString());
// If the child is a folder add it to the list of next level nodes
if (nextNodeInfos != null && curChildInfo.isFolder())
{
nextNodeInfos.add(curChildInfo);
}
}
}
// Update the current tree depth
curDepth++;
// Move the next level of nodes to the current node list
nodeInfos = nextNodeInfos;
}
}
// Close the outer XML element
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_MULTI_STATUS, WebDAV.XML_NS_MULTI_STATUS);
// Send remaining data
flushXML(xml);
}
@Override
protected OutputFormat getXMLOutputFormat()
{
String userAgent = m_request.getHeader("User-Agent");
return ((null != userAgent) && userAgent.toLowerCase().startsWith("microsoft-webdav-miniredir/5.1.")) ? OutputFormat.createCompactFormat() : super.getXMLOutputFormat();
}
/**
* Creates a WebDAVProperty from the given XML node
*/
protected WebDAVProperty createProperty(Node node)
{
WebDAVProperty property = null;
String strName = node.getLocalName();
String strNamespaceUri = node.getNamespaceURI();
if (WebDAV.DEFAULT_NAMESPACE_URI.equals(strNamespaceUri))
{
property = new WebDAVProperty(strName);
}
else
{
property = new WebDAVProperty(strName, strNamespaceUri, getNamespaceName(strNamespaceUri));
}
return property;
}
/**
* Retrieves the namespace name for the given namespace URI, one is
* generated if it doesn't exist
*/
private String getNamespaceName(String strNamespaceUri)
{
if (strNamespaceUri == null)
{
return null;
}
String strNamespaceName = m_namespaces.get(strNamespaceUri);
if (strNamespaceName == null)
{
strNamespaceName = "ns" + m_namespaces.size();
m_namespaces.put(strNamespaceUri, strNamespaceName);
}
return strNamespaceName;
}
/**
* Generates the required response XML for the current node
*
* @param xml XMLWriter
* @param node NodeRef
* @param path String
*/
protected void generateResponseForNode(XMLWriter xml, FileInfo nodeInfo, String path) throws Exception
{
boolean isFolder = nodeInfo.isFolder();
// Output the response block for the current node
xml.startElement(
WebDAV.DAV_NS,
WebDAV.XML_RESPONSE,
WebDAV.XML_NS_RESPONSE,
getDAVHelper().getNullAttributes());
// Build the href string for the current node
String strHRef = getURLForPath(m_request, path, isFolder);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_HREF, WebDAV.XML_NS_HREF, getDAVHelper().getNullAttributes());
xml.write(strHRef);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_HREF, WebDAV.XML_NS_HREF);
switch (m_mode)
{
case GET_NAMED_PROPS:
generateNamedPropertiesResponse(xml, nodeInfo, isFolder);
break;
case GET_ALL_PROPS:
generateAllPropertiesResponse(xml, nodeInfo, isFolder);
break;
case FIND_PROPS:
generateFindPropertiesResponse(xml, nodeInfo, isFolder);
break;
}
// Close off the response element
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_RESPONSE, WebDAV.XML_NS_RESPONSE);
}
/**
* Generates the XML response for a PROPFIND request that asks for a
* specific set of properties
*
* @param xml XMLWriter
* @param node NodeRef
* @param isDir boolean
*/
private void generateNamedPropertiesResponse(XMLWriter xml, FileInfo nodeInfo, boolean isDir) throws Exception
{
// Get the properties for the node
Map<QName, Serializable> props = nodeInfo.getProperties();
// Output the start of the properties element
Attributes nullAttr = getDAVHelper().getNullAttributes();
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT, nullAttr);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP, nullAttr);
ArrayList<WebDAVProperty> propertiesNotFound = new ArrayList<WebDAVProperty>();
TypeConverter typeConv = DefaultTypeConverter.INSTANCE;
// Loop through the requested property list
for (WebDAVProperty property : m_properties)
{
// Get the requested property details
String propName = property.getName();
String propNamespaceUri = property.getNamespaceUri();
// Check if the property is a standard WebDAV property
Object davValue = null;
if (WebDAV.DEFAULT_NAMESPACE_URI.equals(propNamespaceUri))
{
// Check if the client is requesting lock information
if (propName.equals(WebDAV.XML_LOCK_DISCOVERY)) // && metaData.isLocked())
{
generateLockDiscoveryResponse(xml, nodeInfo, isDir);
}
else if (propName.equals(WebDAV.XML_SUPPORTED_LOCK))
{
// Output the supported lock types
writeLockTypes(xml);
}
// Check if the client is requesting the resource type
else if (propName.equals(WebDAV.XML_RESOURCE_TYPE))
{
// If the node is a folder then return as a collection type
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_RESOURCE_TYPE, WebDAV.XML_NS_RESOURCE_TYPE, nullAttr);
if (isDir)
{
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_COLLECTION));
}
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_RESOURCE_TYPE, WebDAV.XML_NS_RESOURCE_TYPE);
}
else if (propName.equals(WebDAV.XML_DISPLAYNAME))
{
// Get the node name
if (getRootNodeRef().equals(nodeInfo.getNodeRef()))
{
// Output an empty name for the root node
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_SOURCE));
}
else
{
// Get the node name
davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_DISPLAYNAME);
// Output the node name
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_DISPLAYNAME, WebDAV.XML_NS_DISPLAYNAME, nullAttr);
if (davValue != null)
{
String name = typeConv.convert(String.class, davValue);
if (name == null || name.length() == 0)
{
logger.error("WebDAV name is null, value=" + davValue.getClass().getName() + ", node=" + nodeInfo.getNodeRef());
}
xml.write(name);
}
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_DISPLAYNAME, WebDAV.XML_NS_DISPLAYNAME);
}
}
else if (propName.equals(WebDAV.XML_SOURCE))
{
// NOTE: source is always a no content element in our
// implementation
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_SOURCE));
}
else if (propName.equals(WebDAV.XML_GET_LAST_MODIFIED))
{
// Get the modifed date/time
davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_GET_LAST_MODIFIED);
// Output the last modified date of the node
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_LAST_MODIFIED, WebDAV.XML_NS_GET_LAST_MODIFIED,
nullAttr);
if (davValue != null)
xml.write(WebDAV.formatModifiedDate(typeConv.convert(Date.class, davValue)));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_LAST_MODIFIED, WebDAV.XML_NS_GET_LAST_MODIFIED);
}
else if (propName.equals(WebDAV.XML_GET_CONTENT_LANGUAGE) && !isDir)
{
// Get the content language
// TODO:
// Output the content language
xml.startElement(
WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LANGUAGE,
WebDAV.XML_NS_GET_CONTENT_LANGUAGE, nullAttr);
// TODO:
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LANGUAGE, WebDAV.XML_NS_GET_CONTENT_LANGUAGE);
}
else if (propName.equals(WebDAV.XML_GET_CONTENT_TYPE) && !isDir)
{
// Get the content type
davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_GET_CONTENT_TYPE);
// Output the content type
xml.startElement(
WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_TYPE,
WebDAV.XML_NS_GET_CONTENT_TYPE, nullAttr);
if (davValue != null)
xml.write(typeConv.convert(String.class, davValue));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_TYPE, WebDAV.XML_NS_GET_CONTENT_TYPE);
}
else if (propName.equals(WebDAV.XML_GET_ETAG) && !isDir)
{
// Output the etag
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_ETAG, WebDAV.XML_NS_GET_ETAG, nullAttr);
xml.write(getDAVHelper().makeETag(nodeInfo));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_ETAG, WebDAV.XML_NS_GET_ETAG);
}
else if (propName.equals(WebDAV.XML_GET_CONTENT_LENGTH))
{
// Get the content length, if it's not a folder
long len = 0;
if (!isDir)
{
ContentData contentData = (ContentData) props.get(ContentModel.PROP_CONTENT);
if (contentData != null)
len = contentData.getSize();
}
// Output the content length
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LENGTH, WebDAV.XML_NS_GET_CONTENT_LENGTH,
nullAttr);
xml.write("" + len);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LENGTH, WebDAV.XML_NS_GET_CONTENT_LENGTH);
}
else if (propName.equals(WebDAV.XML_CREATION_DATE))
{
// Get the creation date
davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_CREATION_DATE);
// Output the creation date
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_CREATION_DATE, WebDAV.XML_NS_CREATION_DATE, nullAttr);
if (davValue != null)
xml.write(WebDAV.formatCreationDate(typeConv.convert(Date.class, davValue)));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_CREATION_DATE, WebDAV.XML_NS_CREATION_DATE);
}
else if ( propName.equals( WebDAV.XML_ALF_AUTHTICKET))
{
// Get the users authentication ticket
SessionUser davUser = (SessionUser) m_request.getSession().getAttribute( AuthenticationFilter.AUTHENTICATION_USER);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET, nullAttr);
if ( davUser != null)
xml.write( davUser.getTicket());
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET);
}
else
{
// Could not map the requested property to an Alfresco property
if (property.getName().equals(WebDAV.XML_HREF) == false)
propertiesNotFound.add(property);
}
}
else
{
// Look in the custom properties
// TODO: Custom properties lookup
// String qualifiedName = propNamespaceUri + WebDAV.NAMESPACE_SEPARATOR + propName;
String value = (String) nodeInfo.getProperties().get(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());
}
}
}
}
// Close off the successful part of the response
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS, nullAttr);
xml.write(WebDAV.HTTP1_1 + " " + HttpServletResponse.SC_OK + " " + WebDAV.SC_OK_DESC);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT);
// If some of the requested properties were not found return another
// status section
if (propertiesNotFound.size() > 0)
{
// Start the second status section
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT, nullAttr);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP, nullAttr);
// Loop through the list of properties that were not found
for (WebDAVProperty property : propertiesNotFound)
{
// Output the property not found status block
String propName = property.getName();
String propNamespaceName = property.getNamespaceName();
String propQName = propName;
if (propNamespaceName != null && propNamespaceName.length() > 0)
propQName = propNamespaceName + ":" + propName;
xml.write(DocumentHelper.createElement(propQName));
}
// Close the unsuccessful part of the response
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS, nullAttr);
xml.write(WebDAV.HTTP1_1 + " " + HttpServletResponse.SC_NOT_FOUND + " " + WebDAV.SC_NOT_FOUND_DESC);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT);
}
}
/**
* Generates the XML response for a PROPFIND request that asks for all known
* properties
*
* @param xml XMLWriter
* @param node NodeRef
* @param isDir boolean
*/
protected void generateAllPropertiesResponse(XMLWriter xml, FileInfo nodeInfo, boolean isDir) throws Exception
{
// Get the properties for the node
Map<QName, Serializable> props = nodeInfo.getProperties();
// Output the start of the properties element
Attributes nullAttr = getDAVHelper().getNullAttributes();
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT, nullAttr);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP, nullAttr);
// Generate a lock status report, if locked
generateLockDiscoveryResponse(xml, nodeInfo, isDir);
// Output the supported lock types
writeLockTypes(xml);
// If the node is a folder then return as a collection type
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_RESOURCE_TYPE, WebDAV.XML_NS_RESOURCE_TYPE, nullAttr);
if (isDir)
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_COLLECTION));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_RESOURCE_TYPE, WebDAV.XML_NS_RESOURCE_TYPE);
// Get the node name
Object davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_DISPLAYNAME);
TypeConverter typeConv = DefaultTypeConverter.INSTANCE;
// Output the node name
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_DISPLAYNAME, WebDAV.XML_NS_DISPLAYNAME, nullAttr);
if (davValue != null)
{
String name = typeConv.convert(String.class, davValue);
if (name == null || name.length() == 0)
{
logger.error("WebDAV name is null, value=" + davValue.getClass().getName() + ", node=" + nodeInfo.getNodeRef());
}
xml.write(name);
}
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_DISPLAYNAME, WebDAV.XML_NS_DISPLAYNAME);
// Output the source
//
// NOTE: source is always a no content element in our implementation
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_SOURCE));
// Get the creation date
davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_CREATION_DATE);
// Output the creation date
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_CREATION_DATE, WebDAV.XML_NS_CREATION_DATE, nullAttr);
if (davValue != null)
xml.write(WebDAV.formatCreationDate(typeConv.convert(Date.class, davValue)));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_CREATION_DATE, WebDAV.XML_NS_CREATION_DATE);
// Get the modifed date/time
davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_GET_LAST_MODIFIED);
// Output the last modified date of the node
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_LAST_MODIFIED, WebDAV.XML_NS_GET_LAST_MODIFIED, nullAttr);
if (davValue != null)
xml.write(WebDAV.formatModifiedDate(typeConv.convert(Date.class, davValue)));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_LAST_MODIFIED, WebDAV.XML_NS_GET_LAST_MODIFIED);
// For a file node output the content language and content type
if (isDir == false)
{
// Get the content language
// TODO:
// Output the content language
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LANGUAGE, WebDAV.XML_NS_GET_CONTENT_LANGUAGE,
nullAttr);
// TODO:
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LANGUAGE, WebDAV.XML_NS_GET_CONTENT_LANGUAGE);
// Get the content type
davValue = WebDAV.getDAVPropertyValue(props, WebDAV.XML_GET_CONTENT_TYPE);
// Output the content type
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_TYPE, WebDAV.XML_NS_GET_CONTENT_TYPE, nullAttr);
if (davValue != null)
xml.write(typeConv.convert(String.class, davValue));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_TYPE, WebDAV.XML_NS_GET_CONTENT_TYPE);
// Output the etag
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_ETAG, WebDAV.XML_NS_GET_ETAG, nullAttr);
xml.write(getDAVHelper().makeETag(nodeInfo));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_ETAG, WebDAV.XML_NS_GET_ETAG);
}
// Get the content length, if it's not a folder
long len = 0;
if (isDir == false)
{
ContentData contentData = (ContentData) props.get(ContentModel.PROP_CONTENT);
if (contentData != null)
len = contentData.getSize();
}
// Output the content length
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LENGTH, WebDAV.XML_NS_GET_CONTENT_LENGTH, nullAttr);
xml.write("" + len);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_GET_CONTENT_LENGTH, WebDAV.XML_NS_GET_CONTENT_LENGTH);
// Print out all the custom properties
SessionUser davUser = (SessionUser) m_request.getSession().getAttribute( AuthenticationFilter.AUTHENTICATION_USER);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET, nullAttr);
if ( davUser != null)
xml.write( davUser.getTicket());
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_ALF_AUTHTICKET, WebDAV.XML_NS_ALF_AUTHTICKET);
// Close off the response
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS, nullAttr);
xml.write(WebDAV.HTTP1_1 + " " + HttpServletResponse.SC_OK + " " + WebDAV.SC_OK_DESC);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT);
}
/**
* Generates the XML response for a PROPFIND request that asks for a list of
* all known properties
*
* @param xml XMLWriter
* @param node NodeRef
* @param isDir boolean
*/
protected void generateFindPropertiesResponse(XMLWriter xml, FileInfo nodeInfo, boolean isDir)
{
try
{
// Output the start of the properties element
Attributes nullAttr = getDAVHelper().getNullAttributes();
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT, nullAttr);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP, nullAttr);
// Output the well-known properties
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_LOCK_DISCOVERY));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_SUPPORTED_LOCK));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_RESOURCE_TYPE));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_DISPLAYNAME));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_GET_LAST_MODIFIED));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_GET_CONTENT_LENGTH));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_CREATION_DATE));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_GET_ETAG));
if (isDir)
{
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_GET_CONTENT_LANGUAGE));
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_GET_CONTENT_TYPE));
}
// Output the custom properties
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_ALF_AUTHTICKET));
// Close off the response
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS, nullAttr);
xml.write(WebDAV.HTTP1_1 + " " + HttpServletResponse.SC_OK + " " + WebDAV.SC_OK_DESC);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROPSTAT, WebDAV.XML_NS_PROPSTAT);
}
catch (Exception ex)
{
// Convert to a runtime exception
throw new AlfrescoRuntimeException("XML processing error", ex);
}
}
/**
* Generates the XML response snippet showing the lock information for the
* given path
*
* @param xml XMLWriter
* @param node NodeRef
* @param isDir boolean
*/
protected void generateLockDiscoveryResponse(XMLWriter xml, FileInfo nodeInfo, boolean isDir) throws Exception
{
// Output the lock status response
LockInfo lockInfo = getNodeLockInfo(nodeInfo);
lockInfo.getRWLock().readLock().lock();
try
{
if (lockInfo.isLocked())
{
generateLockDiscoveryXML(xml, nodeInfo, lockInfo);
}
}
finally
{
lockInfo.getRWLock().readLock().unlock();
}
}
/**
* Output the supported lock types XML element
*
* @param xml XMLWriter
*/
protected void writeLockTypes(XMLWriter xml)
{
try
{
AttributesImpl nullAttr = getDAVHelper().getNullAttributes();
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_SUPPORTED_LOCK, WebDAV.XML_NS_SUPPORTED_LOCK, nullAttr);
// Output exclusive lock
writeLock(xml, WebDAV.XML_NS_EXCLUSIVE);
// Output shared lock
writeLock(xml, WebDAV.XML_NS_SHARED);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_SUPPORTED_LOCK, WebDAV.XML_NS_SUPPORTED_LOCK);
}
catch (Exception ex)
{
throw new AlfrescoRuntimeException("XML write error", ex);
}
}
/**
* Output the lockentry element of the specified type
* @param xml XMLWriter
* @param lockType lock type. Can be WebDAV.XML_NS_EXCLUSIVE or WebDAV.XML_NS_SHARED
* @param lockType lock type containing namespace
* @throws SAXException
* @throws IOException
*/
private void writeLock(XMLWriter xml, String lockType) throws SAXException, IOException
{
AttributesImpl nullAttr = getDAVHelper().getNullAttributes();
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_ENTRY, WebDAV.XML_NS_LOCK_ENTRY, nullAttr);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_NS_LOCK_SCOPE, nullAttr);
xml.write(DocumentHelper.createElement(lockType));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_SCOPE, WebDAV.XML_NS_LOCK_SCOPE);
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_TYPE, WebDAV.XML_NS_LOCK_TYPE, nullAttr);
xml.write(DocumentHelper.createElement(WebDAV.XML_NS_WRITE));
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_TYPE, WebDAV.XML_NS_LOCK_TYPE);
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_LOCK_ENTRY, WebDAV.XML_NS_LOCK_ENTRY);
}
}