com.bluexml.xforms.actions.AbstractAction.java Source code

Java tutorial

Introduction

Here is the source code for com.bluexml.xforms.actions.AbstractAction.java

Source

/*
Copyright (C) 2007-2011  BlueXML - www.bluexml.com
    
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 3 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, see <http://www.gnu.org/licenses/>.
    
*/

package com.bluexml.xforms.actions;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.chiba.xml.xforms.core.Submission;
import org.w3c.dom.Node;

import com.bluexml.xforms.controller.alfresco.AlfrescoController;
import com.bluexml.xforms.controller.alfresco.AlfrescoTransaction;
import com.bluexml.xforms.controller.navigation.NavigationPath;
import com.bluexml.xforms.controller.navigation.NavigationSessionListener;
import com.bluexml.xforms.messages.MsgId;

import edu.yale.its.tp.cas.client.CASReceipt;
import edu.yale.its.tp.cas.client.filter.CASFilter;

/**
 * The Class AbstractAction.<br>
 * Base class of all action handlers.
 */
public abstract class AbstractAction {

    /** The logger. */
    protected static Log logger = LogFactory.getLog(AbstractAction.class);

    /** The document transformer. */
    protected static Transformer documentTransformer;
    static {
        // initialize statically documentTransformer
        try {
            documentTransformer = TransformerFactory.newInstance().newTransformer();
            documentTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /** The request parameters. */
    protected Map<String, String> requestParameters;

    /** The session. */
    protected HttpSession session;

    /** The controller. */
    protected AlfrescoController controller;

    /** The uri. */
    protected String uri;

    /** The result. */
    protected Map<String, Object> result;

    /** The submission. */
    protected Submission submission;

    /** The node. */
    protected Node node;

    /** The servlet url. */
    protected String servletURL;

    /** The navigation path. */
    protected NavigationPath navigationPath;

    /** The transaction. */
    protected AlfrescoTransaction transaction;

    protected String transactionLogin = null;

    /** The session id. */
    protected String sessionId;

    /** The page id. */
    protected String pageId;

    /**
     * Adds a parameter to the map of parameters.
     * 
     * @param fragments
     *            the fragments
     * @param name
     *            the name
     * @param index
     *            the index
     */
    protected void registerParameter(String[] fragments, String name, int index) {
        if (fragments.length > index) {
            String fragment = fragments[index];
            requestParameters.put(name, fragment);
        }
    }

    /**
     * Execute resolve. Used for read operations.
     * 
     * @return the node
     * 
     * @throws Exception
     *             the exception
     */
    public abstract Node resolve() throws ServletException;

    /**
     * Execute submit. Used for write operations.
     * 
     * @throws Exception
     *             the exception
     */
    public abstract void submit() throws ServletException;

    /**
     * Checks if triggering this action causes all instances to be replaced.
     * 
     * @return true, if is replace all
     */
    public boolean isReplaceAll() {
        return true;
    }

    /**
     * Checks if this action requires the form to be validated first.
     * 
     * @return true, if the XForms engine should be checked that mandatory fields are filled
     */
    public boolean isValidateFirst() {
        return false;
    }

    /**
     * Gets the action name. This is the name by which an action handler declares the URLs it should
     * be mapped to. <br/>
     * e.g. the handler for "sidewriter://.../get" URLs should return "get".
     * 
     * @return the action name
     */
    public abstract String getActionName();

    /**
     * Gets the caption by which the action is labeled on a button.
     * 
     * @return the action caption
     */
    public String getActionCaption() {
        // by default, we consider the action is never used from a button
        return null;
    }

    /**
     * Gets the param names. The parameters expected by the action are listed in a specific order.
     * The URL that maps to the action must respect that order, with params separated using "/".<br/>
     * An action that requires a 'type' and 'parent' parameter would be
     * <tt>scheme://.../ACTION_NAME/TYPE/PARENT</tt> so the param names array would be
     * <tt>{"type", "parent"}</tt>.
     * 
     * @return the param names
     */
    protected String[] getParamNames() {
        // by default, we consider that the action is self-contained
        return new String[] {};
    }

    /**
     * Gets the request parameters. This function builds a map of parameters for the action.
     * Parameters are those declared in {@link #getParamNames()}.
     * <p/>
     * NOTE: <b>DO NOT</b> use transaction here. Otherwise, it would be null and cause an exception.
     * (Amenel)
     * 
     * @param fragments
     *            the fragments
     * @param realUri
     * 
     * @return the request parameters
     */
    private void getRequestParameters(String[] fragments, URI realUri) {
        requestParameters = new TreeMap<String, String>();

        String sessionIdPageId = fragments[2];
        String[] sessionFragments = sessionIdPageId.split(";");
        sessionId = sessionFragments[0];

        session = NavigationSessionListener.getSession(sessionId);
        if (session != null) {
            Object receiptAsObject = session.getAttribute(CASFilter.CAS_FILTER_RECEIPT);
            if (receiptAsObject != null) {
                CASReceipt receipt = (CASReceipt) receiptAsObject;
                transactionLogin = receipt.getUserName();
            }
        }
        pageId = sessionFragments[1];

        navigationPath = NavigationSessionListener.getNavigationPath(sessionId, pageId);

        String[] paramNames = getParamNames();

        String schemePart = realUri.getSchemeSpecificPart();
        for (String paramName : paramNames) {
            String paramValue = extractParamValue(paramName, schemePart);
            requestParameters.put(paramName, paramValue);
        }
    }

    private String extractParamValue(String paramName, String schemePart) {
        String paramLower = paramName.toLowerCase();
        String schemeLower = schemePart.toLowerCase();
        int pos = schemeLower.indexOf(paramLower);
        if (pos >= 0) {
            int posEq = schemeLower.indexOf("=", pos);
            int posEndVal = schemeLower.indexOf("&", pos);
            if (posEndVal == -1) {
                posEndVal = schemeLower.length();
            }

            // don't use the lower case scheme here.
            String value = schemePart.substring(posEq + 1, posEndVal);
            return value;
        }

        return null;
    }

    /**
     * Sets useful properties.
     * 
     * @param controller
     *            the controller
     * @param uri
     *            the uri
     */
    public void setProperties(AlfrescoController controller, String uri) {
        URI realUri;
        try {
            realUri = new URI(uri);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        String[] fragments = realUri.getSchemeSpecificPart().split("/");
        getRequestParameters(fragments, realUri);
        this.controller = controller;
        this.uri = uri;
        this.transaction = new AlfrescoTransaction(controller, transactionLogin);

        this.transaction.setPage(navigationPath.peekCurrentPage());
        if (StringUtils.trimToNull(transactionLogin) == null) { // no CAS receipt was available
            Map<String, String> initParams = transaction.getPage().getInitParams();
            transaction.setLogin(controller.getParamUserName(initParams));
        }
    }

    /**
     * Redirects the client to the given URL after a submission action.
     * 
     * @param nextPageURL
     */
    protected void redirectClient(String nextPageURL) {
        result.put("Location", nextPageURL);
    }

    /**
     * Sets the submission default location in case no forwarding mechanism is active: the web
     * client is redirected to the same page the action was called from. The form is simply
     * reloaded.
     * 
     * @param servletURL
     *            the servlet url
     * @param result
     *            the result
     */
    protected void setSubmissionDefaultLocation(String servletURL, Map<String, Object> result) {
        String location = servletURL + "?pageId=" + pageId + "&stackId=" + navigationPath.getSize();
        result.put("Location", location);
    }

    /**
     * Sets the submit properties.
     * 
     * @param result
     *            the result
     * @param submission
     *            the submission
     * @param node
     *            the node
     * @param servletURL
     *            the servlet url
     */
    public void setSubmitProperties(Map<String, Object> result, Submission submission, Node node,
            String servletURL) {
        this.result = result;
        this.submission = submission;
        this.node = node;
        this.servletURL = servletURL;
    }

    /**
     * Loads and executes a user class available in the class path. The class must implement and
     * expose a specific method.
     * 
     * @param className
     * @return the result of the call as defined by the contract method signature, or null if an
     *         exception occurs.
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws InstantiationException
     */
    protected String callExternalAction(String className) {
        try {
            String resultStr = "";
            Class<?> theClass = Class.forName(className);
            Method method = theClass.getMethod("run", new Class[] { // defined in #956
                    org.w3c.dom.Node.class, java.lang.String.class });
            String dataId = navigationPath.peekCurrentPage().getDataId();
            Object result = method.invoke(theClass.newInstance(), new Object[] { node, dataId });
            resultStr = (String) result;
            return resultStr;
        } catch (ClassCastException cce) {
            if (logger.isWarnEnabled()) {
                logger.warn("Returned result is not of type java.lang.String; will be ignored.", cce);
            }
            return null;
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
                logger.error("An error occurred when invoking class '" + className + "'", e);
            }
            return null;
        }
    }

    /**
     * Builds the URL for reaching the given workflow form using the servlet URL that triggered the
     * action.
     * 
     * @param formName
     * @return
     */
    protected String buildWorkflowFormURL(String formName) {
        return getServletURL() + "?" + MsgId.PARAM_DATA_TYPE + "=" + formName + "&" + MsgId.PARAM_FORM_TYPE + "="
                + MsgId.INT_FORMTYPE_WKFLW;
    }

    /**
     * @return the servletURL
     */
    public String getServletURL() {
        return servletURL;
    }

    /**
     * @return the sessionId
     */
    public String getSessionId() {
        return sessionId;
    }

}