org.alfresco.module.vti.web.actions.VtiSoapAction.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.module.vti.web.actions.VtiSoapAction.java

Source

/*
 * #%L
 * Alfresco Sharepoint Protocol
 * %%
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 * %%
 * This file is part of the Alfresco software. 
 * If the software was purchased under a paid Alfresco license, the terms of 
 * the paid license agreement will prevail.  Otherwise, the software is 
 * provided under the following open source license terms:
 * 
 * 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/>.
 * #L%
 */
package org.alfresco.module.vti.web.actions;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.alfresco.module.vti.handler.DwsException;
import org.alfresco.module.vti.handler.VtiHandlerException;
import org.alfresco.module.vti.metadata.dic.DwsError;
import org.alfresco.module.vti.web.VtiAction;
import org.alfresco.module.vti.web.VtiFilter;
import org.alfresco.module.vti.web.VtiUtilBase;
import org.alfresco.module.vti.web.ws.VtiEndpoint;
import org.alfresco.module.vti.web.ws.VtiSoapException;
import org.alfresco.module.vti.web.ws.VtiSoapRequest;
import org.alfresco.module.vti.web.ws.VtiSoapResponse;
import org.alfresco.repo.webdav.WebDAVLockService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
import org.dom4j.QName;

/**
* <p>VtiSoapAction is processor of Web service requests. It provides 
* the back-end controller for dispatching among set of VtiEndpoints. 
* It selects and invokes a realization of {@link VtiEndpoint} to perform 
* the requested Web service method. In addition it is an adapter for
* wrapping HttpServletRequest and HttpServletResponse in {@link VtiSoapRequest}
* and {@link VtiSoapResponse}.</p>
*
* @author Stas Sokolovsky
*
*/
public class VtiSoapAction extends VtiUtilBase implements VtiAction {
    private WebDAVLockService lockService;
    private Map<String, VtiEndpoint> endpointsMapping;

    private final static Log logger = LogFactory.getLog(VtiSoapAction.class);

    /**
     * <p>Process Web service request, dispatch among set of VtiEndpoints. 
     * Select and invoke a realization of {@link VtiEndpoint} to perform the
     * requested Web service method</p> 
     *
     * @param httpServletRequest HTTP request
     * @param httpServletResponse HTTP response
     */
    public void execute(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        VtiSoapRequest soapRequest = new VtiSoapRequest(httpServletRequest);
        VtiSoapResponse soapResponse = new VtiSoapResponse(httpServletResponse);
        VtiEndpoint endpoint = dispatchRequest(soapRequest);
        if (endpoint != null) {
            try {
                getLockService().setCurrentSession(soapRequest.getSession());
                soapResponse.setContentType(VtiFilter.CONTENT_TYPE_XML);

                endpoint.execute(soapRequest, soapResponse);
            } catch (Exception e) {
                logger.debug(e.getMessage(), e);
                soapResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                createFaultSOAPResponse(soapRequest, soapResponse.getDocument(), e, endpoint);
                logger.warn("Failure executing Vti request", e);
            }
            try {
                soapResponse.flushBuffer();
            } catch (IOException e) {
                // doesn't matter
            }
        } else {
            if (logger.isDebugEnabled()) {
                String action = getSOAPAction(httpServletRequest);
                logger.debug("Target endpoint wasn't found for SOAP Action '" + action + "'");
            }
        }

    }

    /**
     * <p>Endpoints mapping setter.</p>
     *
     * @param endpointsMapping describe mapping from name of Web service method to
     * its realization.    
     */
    public void setEndpointsMapping(Map<String, VtiEndpoint> endpointsMapping) {
        this.endpointsMapping = endpointsMapping;
    }

    /**
     * Returns the SOAP Action that was requested, or NULL if the request isn't a SOAP action.
     * This method handles any de-quoting that is required.
     */
    public static String getSOAPAction(HttpServletRequest request) {
        // Fetch, and de-quote if needed the action
        String soapAction = request.getHeader("SOAPAction");
        if (soapAction != null) {
            // SOAP 1.1, de-quote
            if (soapAction.startsWith("\"") && soapAction.endsWith("\"")) {
                soapAction = soapAction.substring(1, soapAction.length() - 1);
            }
        } else {
            // SOAP 1.2
            if (request.getContentType() != null) {
                Pattern p = Pattern.compile("action=\"(.*?)\"");
                Matcher m = p.matcher(request.getContentType());
                if (m.find()) {
                    soapAction = m.group(1);
                }
            }
        }

        return soapAction;
    }

    /**
     * <p>
     * Dispatch among set of VtiEndpoints.
     * 
     * @param request {@link VtiSoapRequest}
     */
    protected VtiEndpoint dispatchRequest(VtiSoapRequest request) {
        String soapAction = getSOAPAction(request);
        VtiEndpoint result = endpointsMapping.get(soapAction);
        return result;
    }

    /**
     * Creates an appropriate SOAP Fault Response, in the appropriate
     *  of the two different formats
     */
    private void createFaultSOAPResponse(VtiSoapRequest request, Element responseElement, Exception e,
            VtiEndpoint vtiEndpoint) {
        // Is it something like
        //  <FooResponse><FooResult><Error ID="123"/></FooResult></FooResponse> ?
        if (e instanceof VtiHandlerException) {
            VtiHandlerException handlerException = (VtiHandlerException) e;
            Element endpointResponseE = responseElement.addElement(vtiEndpoint.getName() + "Response",
                    vtiEndpoint.getNamespace());
            Element endpointResultE = endpointResponseE.addElement(vtiEndpoint.getName() + "Result");

            //String errorMessage = handlerException.getMessage();
            String errorCode;
            if (handlerException.getErrorCode() > -1) {
                errorCode = Long.toString(handlerException.getErrorCode());
            } else {
                errorCode = "13";
            }

            // Return it as an ID based error, without the message
            endpointResultE.addElement("Error").addAttribute("ID", errorCode);
        } else if (e instanceof DwsException) {
            // <FooResponse><FooResult><Error>[ID]</Error></FooResult></FooResponse>
            DwsException handlerException = (DwsException) e;
            Element endpointResponseE = responseElement.addElement(vtiEndpoint.getResponseTagName(),
                    vtiEndpoint.getNamespace());
            Element endpointResultE = endpointResponseE.addElement(vtiEndpoint.getResultTagName());

            DwsError error = handlerException.getError();
            // Error value, numeric ID
            int errorId = error.toInt();
            // Error code, e.g. "ServerFailure"
            String errorCode = error.toCode();

            // Return it as an Coded ID based error, without the message
            Map<String, Object> errorAttrs = new HashMap<String, Object>(1);
            errorAttrs.put("ID", errorId);
            StringBuilder sb = startTag("Error", errorAttrs);
            sb.append(errorCode);
            sb.append(endTag("Error"));
            String elText = sb.toString();
            endpointResultE.setText(elText);
        } else {
            // We need to return a regular SOAP Fault
            String errorMessage = e.getMessage();
            if (errorMessage == null) {
                errorMessage = "Unknown error";
            }

            // Manually generate the Soap error response
            Element fault = responseElement.addElement(QName.get("Fault", "s", VtiSoapResponse.NAMESPACE));

            if ("1.2".equals(request.getVersion())) {
                // SOAP 1.2 is Code + Reason
                Element faultCode = fault.addElement(QName.get("Code", "s", VtiSoapResponse.NAMESPACE));
                Element faultCodeText = faultCode.addElement(QName.get("Value", "s", VtiSoapResponse.NAMESPACE));
                faultCodeText.addText("s:Server");

                Element faultReason = fault.addElement(QName.get("Reason", "s", VtiSoapResponse.NAMESPACE));
                Element faultReasonText = faultReason.addElement(QName.get("Text", "s", VtiSoapResponse.NAMESPACE));
                faultReasonText.addText("Exception of type '" + e.getClass().getName() + "' was thrown.");
            } else {
                // SOAP 1.1 is Code + String
                Element faultCode = fault.addElement("faultcode");
                faultCode.addText("s:Server");
                Element faultString = fault.addElement("faultstring");
                faultString.addText(e.getClass().getName());
            }

            // Both versions get the detail
            Element detail = fault.addElement("detail");
            Element errorstring = detail
                    .addElement(QName.get("errorstring", "", "http://schemas.microsoft.com/sharepoint/soap/"));
            errorstring.addText(errorMessage);

            // Include the code if known
            if (e instanceof VtiSoapException) {
                VtiSoapException soapException = (VtiSoapException) e;
                if (soapException.getErrorCode() > 0) {
                    Element errorcode = detail.addElement(
                            QName.get("errorcode", "", "http://schemas.microsoft.com/sharepoint/soap/"));

                    // Codes need to be zero padded to 8 characters, eg 0x12345678
                    String codeHex = Long.toHexString(soapException.getErrorCode());
                    while (codeHex.length() < 8) {
                        codeHex = "0" + codeHex;
                    }
                    errorcode.addText("0x" + codeHex);
                }
            }
        }
    }

    /**
     * Access the WebDAVLockService.
     * 
     * @return the lockService
     */
    protected WebDAVLockService getLockService() {
        return this.lockService;
    }

    /**
     * Provide the WebDAVLockService.
     * 
     * @param lockService the lockService to set
     */
    public void setLockService(WebDAVLockService lockService) {
        this.lockService = lockService;
    }
}