jp.aegif.alfresco.online_webdav.PropPatchMethod.java Source code

Java tutorial

Introduction

Here is the source code for jp.aegif.alfresco.online_webdav.PropPatchMethod.java

Source

/*
 * Copyright (C) 2005-2013 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 jp.aegif.alfresco.online_webdav;

import java.util.ArrayList;

import javax.servlet.http.HttpServletResponse;

import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.webdav.WebDAV;
import org.alfresco.repo.webdav.WebDAVProperty;
import org.alfresco.repo.webdav.WebDAVServerException;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
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 PROPPATCH method
 * 
 * @author Ivan Rybnikov
 */
public class PropPatchMethod extends PropFindMethod {

    // Properties to patch
    protected ArrayList<PropertyAction> m_propertyActions = null;

    /**
     * @return          Returns <tt>false</tt> always
     */
    @Override
    protected boolean isReadOnly() {
        return false;
    }

    @Override
    protected void executeImpl() throws WebDAVServerException, Exception {

        m_response.setStatus(WebDAV.WEBDAV_SC_MULTI_STATUS);

        FileInfo pathNodeInfo = null;
        try {
            pathNodeInfo = this.getDAVHelper().getFileInfoFromRequestPath(m_request);
        } catch (FileNotFoundException e) {
            // The path is not valid - send a 404 error back to the client
            throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND);
        }

        checkNode(pathNodeInfo);

        // 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
        generateResponse(xml, pathNodeInfo, basePath);

        // Close the outer XML element
        xml.endElement(WebDAV.DAV_NS, WebDAV.XML_MULTI_STATUS, WebDAV.XML_NS_MULTI_STATUS);

        // Send remaining data
        flushXML(xml);
    }

    /**
     * Parse the request body
     * 
     * @exception WebDAVServerException
     */
    @Override
    protected void parseRequestBody() throws WebDAVServerException {
        Document body = getRequestBodyAsDocument();
        if (body != null) {
            Element rootElement = body.getDocumentElement();
            NodeList childList = rootElement.getChildNodes();

            m_propertyActions = new ArrayList<PropertyAction>();

            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_SET)
                            || currentNode.getNodeName().endsWith(WebDAV.XML_REMOVE)) {
                        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:
                                if (propertiesNode.getNodeName().endsWith(WebDAV.XML_PROP)) {
                                    NodeList propList = propertiesNode.getChildNodes();

                                    for (int k = 0; k < propList.getLength(); k++) {
                                        Node propNode = propList.item(k);
                                        switch (propNode.getNodeType()) {
                                        case Node.TEXT_NODE:
                                            break;
                                        case Node.ELEMENT_NODE:
                                            int action = currentNode.getNodeName().endsWith(WebDAV.XML_SET)
                                                    ? PropertyAction.SET
                                                    : PropertyAction.REMOVE;
                                            WebDAVProperty prop = createProperty(propNode);
                                            if (prop != null) {
                                                m_propertyActions.add(new PropertyAction(action, prop));
                                            }
                                            break;
                                        }
                                    }
                                }
                                break;
                            }
                        }
                    }
                    break;
                }
            }

        }

    }

    /**
     * Parse the request headers
     * 
     * @exception WebDAVServerException
     */
    @Override
    protected void parseRequestHeaders() throws WebDAVServerException {
        // Parse Lock tokens and ETags, if any
        parseIfHeader();
    }

    /**
     * Creates a WebDAVProperty from the given XML node
     */
    protected WebDAVProperty createProperty(Node node) {
        WebDAVProperty property = super.createProperty(node);

        String strValue = null;
        Node value = node.getFirstChild();
        if (value != null) {
            strValue = value.getNodeValue();
        }
        property.setValue(strValue);

        return property;
    }

    /**
     * Generates the required response XML
     * 
     * @param xml XMLWriter
     * @param node NodeRef
     * @param path String
     */
    protected void generateResponse(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);

        boolean failed = false;
        WebDAVProperty failedProperty = null;
        for (PropertyAction action : m_propertyActions) {
            if (action.getProperty().isProtected()) {
                generateError(xml);
                failed = true;
                failedProperty = action.getProperty();
                break;
            }
        }

        for (PropertyAction propertyAction : m_propertyActions) {
            int statusCode;
            String statusCodeDescription;
            WebDAVProperty property = propertyAction.getProperty();

            if (!failed) {
                if (PropertyAction.SET == propertyAction.getAction()) {
                    getNodeService().setProperty(nodeInfo.getNodeRef(), property.createQName(),
                            property.getValue());
                } else if (PropertyAction.REMOVE == propertyAction.getAction()) {
                    getNodeService().removeProperty(nodeInfo.getNodeRef(), property.createQName());
                } else {
                    throw new WebDAVServerException(HttpServletResponse.SC_BAD_REQUEST);
                }
                statusCode = HttpServletResponse.SC_OK;
                statusCodeDescription = WebDAV.SC_OK_DESC;
            } else if (failedProperty == property) {
                statusCode = HttpServletResponse.SC_FORBIDDEN;
                statusCodeDescription = WebDAV.SC_FORBIDDEN_DESC;
            } else {
                statusCode = WebDAV.WEBDAV_SC_FAILED_DEPENDENCY;
                statusCodeDescription = WebDAV.WEBDAV_SC_FAILED_DEPENDENCY_DESC;
            }

            generatePropertyResponse(xml, property, statusCode, statusCodeDescription);
        }

        // 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 list of
     * all known properties
     * 
     * @param xml XMLWriter
     * @param node NodeRef
     * @param isDir boolean
     */
    protected void generatePropertyResponse(XMLWriter xml, WebDAVProperty property, int status,
            String description) {
        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);

            // Output property name
            xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP, nullAttr);
            if (property.hasNamespaceName()) {
                xml.write(DocumentHelper.createElement(
                        property.getNamespaceName() + WebDAV.NAMESPACE_SEPARATOR + property.getName()));
            } else {
                xml.write(DocumentHelper.createElement(property.getName()));
            }
            xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP);

            // Output action result status
            xml.startElement(WebDAV.DAV_NS, WebDAV.XML_STATUS, WebDAV.XML_NS_STATUS, nullAttr);
            xml.write(WebDAV.HTTP1_1 + " " + status + " " + description);
            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 error tag
     * 
     * @param xml XMLWriter
     */
    protected void generateError(XMLWriter xml) {
        try {
            // Output the start of the error element
            Attributes nullAttr = getDAVHelper().getNullAttributes();

            xml.startElement(WebDAV.DAV_NS, WebDAV.XML_ERROR, WebDAV.XML_NS_ERROR, nullAttr);
            // Output error
            xml.write(DocumentHelper.createElement(WebDAV.XML_NS_CANNOT_MODIFY_PROTECTED_PROPERTY));

            xml.endElement(WebDAV.DAV_NS, WebDAV.XML_ERROR, WebDAV.XML_NS_ERROR);
        } catch (Exception ex) {
            // Convert to a runtime exception
            throw new AlfrescoRuntimeException("XML processing error", ex);
        }
    }

    /**
     * Stores information about PROPPATCH action(set or remove) an according property.
     * 
     * @author Ivan Rybnikov
     */
    protected class PropertyAction {
        public static final int SET = 0;
        public 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;
            this.property = property;
        }

        public int getAction() {
            return action;
        }

        public WebDAVProperty getProperty() {
            return property;
        }

        public String toString() {
            StringBuilder str = new StringBuilder();

            str.append("[");
            str.append("action=");
            str.append(getAction() == 0 ? "SET" : "REMOVE");
            str.append(",property=");
            str.append(getProperty());
            str.append("]");

            return str.toString();
        }
    }

}