org.toobsframework.pres.doit.DoItRunner.java Source code

Java tutorial

Introduction

Here is the source code for org.toobsframework.pres.doit.DoItRunner.java

Source

/*
 * This file is licensed to the Toobs Framework Group under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The Toobs Framework Group licenses this file to You under the Apache 
 * License, Version 2.0 (the "License"); you may not use this file 
 * except in compliance with the License.  You may obtain a copy of the 
 * License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.toobsframework.pres.doit;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;

import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.validation.Errors;
import org.toobsframework.pres.component.config.Parameter;
import org.toobsframework.pres.doit.config.Action;
import org.toobsframework.pres.doit.config.Actions;
import org.toobsframework.pres.doit.config.DoIt;
import org.toobsframework.pres.doit.controller.strategy.ForwardStrategy;
import org.toobsframework.biz.validation.IValidator;
import org.toobsframework.data.IObjectLoader;
import org.toobsframework.data.beanutil.BeanMonkey;
import org.toobsframework.exception.ValidationException;
import org.toobsframework.pres.component.dataprovider.api.IDataProvider;
import org.toobsframework.pres.util.ComponentRequestManager;
import org.toobsframework.pres.util.ParameterUtil;
import org.toobsframework.search.index.ISingleIndexBuilder;
import org.toobsframework.util.IRequest;
import org.toobsframework.util.constants.PlatformConstants;

public class DoItRunner implements IDoItRunner {

    private static Log log = LogFactory.getLog(DoItRunner.class);

    private ComponentRequestManager componentRequestManager;
    private ISingleIndexBuilder indexBuilder;

    private IDataProvider dataProvider;

    public void runDoIt(IRequest request, DoIt doIt) throws Exception {
        // Run Actions
        Action thisAction = null;
        if (doIt.getActions() != null) {
            Actions actionsObj = doIt.getActions();

            String multipleActionsKey = "defaultAction";
            String[] multipleActionsAry = new String[] { "" };
            Map<String, Object> paramMap = request.getParams();
            Map<String, Object> responseMap = request.getResponseParams();
            try {
                if (actionsObj.getMultipleActionsKey() != null && !actionsObj.getMultipleActionsKey().equals("")) {
                    multipleActionsKey = actionsObj.getMultipleActionsKey();
                    Object multActObj = paramMap.get(actionsObj.getMultipleActionsKey());
                    if (multActObj != null && multActObj.getClass().isArray()) {
                        multipleActionsAry = (String[]) multActObj;
                    } else if (multActObj != null) {
                        multipleActionsAry = new String[] { (String) multActObj };
                    } else {
                        multipleActionsAry = new String[] { "" };
                    }
                }

                for (int i = 0; i < multipleActionsAry.length; i++) {
                    Map<String, Object> actionParams = new HashMap<String, Object>(paramMap);
                    responseMap.clear();
                    actionParams.put(multipleActionsKey, multipleActionsAry[i]);
                    actionParams.put(PlatformConstants.MULTI_ACTION_INSTANCE, new Integer(i));
                    Enumeration<Action> actions = doIt.getActions().enumerateAction();
                    while (actions.hasMoreElements()) {
                        thisAction = actions.nextElement();
                        runAction(request, doIt.getName(), thisAction, actionParams, responseMap,
                                (i == (multipleActionsAry.length - 1)));
                    }
                }
                Iterator<String> iter = responseMap.keySet().iterator();
                while (iter.hasNext()) {
                    String key = iter.next();
                    paramMap.put(key, responseMap.get(key));
                    /*
                    if (componentRequestManager.get().getHttpRequest() != null) {
                      componentRequestManager.get().getHttpRequest().setAttribute((String)key, responseMap.get(key));
                    }
                    */
                }
            }

            // if validation errors are thrown, make sure to correctly pull
            // error objects..
            catch (Exception e) {
                if (e.getCause() instanceof ValidationException) {
                    log.warn("Caught validation exception.");
                    this.pullErrorObjectsIntoRequest(request, doIt, paramMap, responseMap, multipleActionsKey,
                            multipleActionsAry, (ValidationException) e.getCause());
                }
                throw e;
            }
        }
    }

    private void runAction(IRequest request, String doItName, Action thisAction, Map<String, Object> params,
            Map<String, Object> responseParams, boolean lastAction) throws Exception {

        String actionType = thisAction.getActionType();
        Object retObj = null;
        if (actionType.equalsIgnoreCase("objectAction")) {
            //Fix the input params using the param mapping for 
            //this configuration.
            if (thisAction.getParameters() != null) {
                // Cant do this for now cause of the array problem
                //ParameterUtil.mapParameters(thisAction.getParameters().getParameter(), params, params, doItName);
                ParameterUtil.mapDoItParameters(request, thisAction.getParameters().getParameter(), params, params,
                        true);
            }
            try {
                if (thisAction.isExtended()) {
                    retObj = this.getDataProvider().dispatchActionEx(request, thisAction.getAction(),
                            ((String[]) ParameterUtil.resolveParam(request, thisAction.getServiceProvider(),
                                    params))[0],
                            ((String[]) ParameterUtil.resolveParam(request, thisAction.getInputObjectType(),
                                    params))[0],
                            thisAction.getReturnObjectType(),
                            ((String[]) ParameterUtil.resolveParam(request, thisAction.getGuidParam(), params))[0],
                            thisAction.getPermissionContext(), thisAction.getIndexParam(),
                            thisAction.getNamespace(), params, responseParams);
                } else {
                    retObj = this.getDataProvider().dispatchAction(thisAction.getAction(),
                            ((String[]) ParameterUtil.resolveParam(request, thisAction.getServiceProvider(),
                                    params))[0],
                            ((String[]) ParameterUtil.resolveParam(request, thisAction.getInputObjectType(),
                                    params))[0],
                            thisAction.getReturnObjectType(),
                            ((String[]) ParameterUtil.resolveParam(request, thisAction.getGuidParam(), params))[0],
                            thisAction.getPermissionContext(), thisAction.getIndexParam(),
                            thisAction.getNamespace(), params, responseParams);
                }
                /* TODO: Remove this later 
                Iterator iter = responseParams.keySet().iterator();
                while (iter.hasNext()) {
                  Object key = iter.next();
                  params.put((String)key, responseParams.get(key));
                }
                */
            } catch (Exception e) {
                /* TODO Check to see if making responseParams work as error forward params
                 * cause this sucks balls
                if (e.getCause() instanceof ValidationException) {
                  responseParams.put("ErrorForwardParams", params.get("ErrorForwardParams"));
                }
                */
                throw e;
            }
        } else if (actionType.equalsIgnoreCase("cookieAction")) {
            String cookieName = ((String[]) ParameterUtil.resolveParam(request, params.get("cookieName"),
                    params))[0];
            String cookieValue = ((String[]) ParameterUtil.resolveParam(request, params.get("cookieValue"),
                    params))[0];
            int maxAge = -1;
            try {
                maxAge = Integer.parseInt(
                        ((String[]) ParameterUtil.resolveParam(request, params.get("maxAge"), params))[0]);
            } catch (Exception e) {
            }

            Cookie doitCookie = new Cookie(cookieName, cookieValue);
            doitCookie.setMaxAge(maxAge);
            componentRequestManager.get().getHttpResponse().addCookie(doitCookie);
        } else if (actionType.equalsIgnoreCase("sessionAction")) {
            Map<String, Object> sessionMap = new HashMap<String, Object>();

            if (thisAction.getParameters() != null) {
                ParameterUtil.mapDoItParameters(request, thisAction.getParameters().getParameter(), params,
                        sessionMap, true);
            }
            HttpSession session = componentRequestManager.get().getHttpRequest().getSession();
            Iterator<Map.Entry<String, Object>> iter = sessionMap.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, Object> entry = iter.next();
                session.setAttribute(entry.getKey(), entry.getValue());
            }
        } else if (actionType.equalsIgnoreCase("indexAction") && lastAction) {
            if (this.getIndexBuilder() != null) {
                indexBuilder.buildIndexes(thisAction.getServiceProvider());
            }
        } else {
            //TODO -- Add the ability to run scripts defined in config here.
        }

        //HashMap responseParams = new HashMap();
        //Add the output params into the request for 
        //this configuration.
        if (thisAction.getOutputParameters() != null && retObj != null) {
            JXPathContext context = null;
            if ("delete".equalsIgnoreCase(thisAction.getAction())) {
                context = JXPathContext.newContext(responseParams);
                responseParams.put("deleted", String.valueOf(((Boolean) retObj).booleanValue()));
            } else {
                context = JXPathContext.newContext(retObj);
            }
            Parameter[] paramMap = thisAction.getOutputParameters().getParameter();
            for (int j = 0; j < paramMap.length; j++) {
                Parameter thisParam = paramMap[j];
                String[] paramPath = ParameterUtil.resolveParam(request, thisParam.getPath(), params);
                String[] paramName = ParameterUtil.resolveParam(request, thisParam.getName(), params);
                Object value = null;
                for (int i = 0; i < paramName.length; i++) {
                    if (thisParam.getIsStatic()) {
                        value = thisParam.getPath();
                    } else {
                        try {
                            value = context.getValue(paramPath[i]);
                        } catch (org.apache.commons.jxpath.JXPathException e) {
                            if (!thisParam.getIgnoreNull()) {
                                log.warn("Problem evaluating jxpath: " + paramName[i] + " value: " + paramPath[i]
                                        + " action: " + thisAction.getServiceProvider(), e);
                            }
                            continue;
                        }
                        if (value != null && value.getClass().isArray()) {
                            value = ((String[]) value)[0];
                        }
                    }
                    responseParams.put(paramName[i], value);
                }
            }
        }

        //Add 
        if (thisAction.getReturnAttributeName() != null && retObj != null) {
            JXPathContext context = JXPathContext.newContext(retObj);
            responseParams.put(thisAction.getReturnAttributeName(), context.getValue("./valueObject/guid"));
        }

        Iterator<String> iter = responseParams.keySet().iterator();
        while (iter.hasNext()) {
            String key = iter.next();
            params.put(key, responseParams.get(key));
        }

    }

    /**
     *  Called upon receipt of a validation error.  Iterates over all the
     *  actions for this DoIt, retrieving an object of appropriate type out
     *  of the posted request.  All such objects are put in the response parameter
     *  mapping under the "ValidationErrorObjects" key.
     */
    @SuppressWarnings("unchecked")
    private void pullErrorObjectsIntoRequest(IRequest request, DoIt doIt, Map<String, Object> paramMap,
            Map<String, Object> responseMap, String multipleActionsKey, String[] multipleActionsAry,
            ValidationException ve) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("ENTER pullErrorObjectsIntoRequest");
        }
        Action thisAction = null;
        Collection globalErrorObjects = new ArrayList();
        Collection<String> globalErrorMessages = new ArrayList<String>();
        BeanFactory beanFactory = BeanMonkey.getBeanFactoryInstance();

        if (doIt.getActions() != null) {
            paramMap.remove("guid");
            //Actions actionsObj = doIt.getActions();

            for (int i = 0; i < multipleActionsAry.length; i++) {
                HashMap actionParams = new HashMap(paramMap);
                responseMap.clear();
                actionParams.put(multipleActionsKey, multipleActionsAry[i]);
                actionParams.put(PlatformConstants.MULTI_ACTION_INSTANCE, new Integer(i));
                Collection instanceErrorObjects = new ArrayList();
                Collection instanceErrorMessages = new ArrayList();

                if (ve != null) {
                    Iterator errIter = ve.getErrors().iterator();
                    while (errIter.hasNext()) {
                        Errors err = (Errors) errIter.next();
                        instanceErrorMessages.addAll(err.getAllErrors());
                    }
                }
                // iterate over the create and update actions
                Enumeration actions = doIt.getActions().enumerateAction();
                while (actions.hasMoreElements()) {
                    // for each, retrieve the object of appropriate type
                    thisAction = (Action) actions.nextElement();

                    // get parameters from action object
                    String actionStr = thisAction.getAction();
                    // for now, only do error object handling for creates and updates..
                    if (!actionStr.startsWith("create") && !actionStr.startsWith("update")) {
                        continue;
                    }

                    //retrieve the input object for this action
                    Object inputObject = constructInputObjectFromAction(request, thisAction, actionParams);

                    //if there's an input object 
                    if (inputObject != null || actionStr.endsWith("Collection")) {
                        if (thisAction.getNamespace() != null && !"".equals(thisAction.getNamespace())) {
                            actionParams.put("namespace", thisAction.getNamespace());
                        }
                        // before calling the getSafeBean method, have to 
                        // stick this action's returnObjectType in the paramMap
                        String objectReturnType = ((String[]) ParameterUtil.resolveParam(request,
                                thisAction.getReturnObjectType(), actionParams))[0];
                        actionParams.put("returnObjectType", objectReturnType);

                        // use the bean monkey to populate that object
                        // (pass false in as last arg to block validation)
                        boolean collection = false;
                        String className = null;
                        if (actionStr.endsWith("Collection")) {
                            String beanClazz = ((String[]) ParameterUtil.resolveParam(request,
                                    thisAction.getInputObjectType(), actionParams))[0];
                            inputObject = BeanMonkey.populateCollection(beanClazz, thisAction.getIndexParam(),
                                    actionParams, false, thisAction.getValidationErrorMode(),
                                    instanceErrorMessages);
                            collection = true;
                            className = beanClazz.substring(beanClazz.lastIndexOf(".") + 1);
                        } else {
                            try {
                                BeanMonkey.populate(inputObject, actionParams, instanceErrorMessages);
                            } catch (ValidationException e) {
                                Iterator errIter = e.getErrors().iterator();
                                while (errIter.hasNext()) {
                                    Errors err = (Errors) errIter.next();
                                    instanceErrorMessages.addAll(err.getAllErrors());
                                }
                            }
                            className = inputObject.getClass().getName();
                        }
                        // If there are no error messages for the object don't produce an error object
                        //if (instanceErrorMessages.size() == 0) continue;

                        // and get the validator for the input object
                        IValidator v = null;
                        className = className.substring(className.lastIndexOf(".") + 1);
                        String validatorName = className + "Validator";
                        if (beanFactory.containsBean(validatorName)) {
                            v = (IValidator) beanFactory.getBean(validatorName);
                        } else {
                            log.warn("No validator " + validatorName + " for " + className);
                        }

                        // if there's no validator, then just continue...
                        if (v == null)
                            continue;

                        // call the validator's prepare method,
                        // pipe the populated bean through the validator's getSafeBean method
                        // and, finally dump the populated object into the error objects map
                        actionParams.put("doit.validation.error.mode", new Boolean(true));
                        v.prepare(inputObject, actionParams);
                        if (collection && inputObject != null && inputObject instanceof Collection) {
                            Iterator iter = ((Collection) inputObject).iterator();
                            while (iter.hasNext()) {
                                instanceErrorObjects.add(v.getSafeBean(iter.next(), actionParams));
                            }
                        } else {
                            instanceErrorObjects.add(v.getSafeBean(inputObject, actionParams));
                        }
                    }

                    continue;
                }
                globalErrorMessages.addAll(instanceErrorMessages);
                globalErrorObjects.addAll(instanceErrorObjects);
            }
            // put the populated error objs in the request scope.
            responseMap.put(ForwardStrategy.VALIDATION_ERROR_OBJECTS, globalErrorObjects);
            responseMap.put(ForwardStrategy.VALIDATION_ERROR_MESSAGES, globalErrorMessages);

        }

        if (log.isDebugEnabled()) {
            log.debug("EXIT pullErrorObjectsIntoRequest");
        }
    }

    /**
     *   Given an action, looks at parameters w.in that action to either 
     *   load an object of appropriate type using a dao, or just construct
     *   an empty object of appropriate type.
     */
    @SuppressWarnings("unchecked")
    private Object constructInputObjectFromAction(IRequest request, Action action, Map paramMap) throws Exception {
        String objectDao = ((String[]) ParameterUtil.resolveParam(request, action.getServiceProvider(),
                paramMap))[0];
        String objectInputType = ((String[]) ParameterUtil.resolveParam(request, action.getInputObjectType(),
                paramMap))[0];

        // Fix the input params using the param mapping for 
        // this configuration.
        if (action.getParameters() != null) {
            ParameterUtil.mapDoItParameters(request, action.getParameters().getParameter(), paramMap, paramMap,
                    true);
        }

        Object inputObject = null;

        // if the object input type was specified, construct an empty object 
        if (objectInputType != null && !"".equals(objectInputType)) {
            // otherwise just instantiate a new object of the appropriate type
            try {
                Class clazz = Class.forName(objectInputType);
                if (clazz != null)
                    inputObject = clazz.getConstructor().newInstance();
            } catch (ClassNotFoundException cnfe) {
                // if class isn't found here... don't do shit..
                // method will return null, and this action will be skipped in the
                // populated list of error objects
            } catch (InstantiationException ie) {
                // Abstract too
            }
        }

        //NOTE: passing leading '$' forces a lookup in the parameter map
        String[] objectGuidArray = ((String[]) ParameterUtil.resolveParam(request, "$" + action.getGuidParam(),
                paramMap));
        String objectGuid = objectGuidArray == null ? null : objectGuidArray[0];

        // but if guid is present, replace the empty object with db load
        if (objectGuid != null && !"".equals(objectGuid)) {
            // then use the dao to load the object from the db
            Object daoBean = null;
            //if a dao bean is specified ... load it up
            if (objectDao != null && !"".equals(objectDao)) {
                // fetch the object using a dao bean..
                try {
                    daoBean = BeanMonkey.getBeanFactoryInstance().getBean(objectDao);
                } catch (org.springframework.beans.factory.NoSuchBeanDefinitionException nsbde) {
                    //if there isn't a daoBean matching that specified in the DOIT, this is so
                    //because there is most likely a custom js script underlying the definition
                    //so, bypass this exception by just returning null here.
                    log.warn("No bean named " + objectDao + " is defined.  Returning null.");
                    return null;
                }

                // get the personId parameter
                //String personGuid = (String) paramMap.get("personId");

                try {
                    inputObject = ((IObjectLoader) daoBean).load(objectGuid);
                } catch (ClassCastException cce) {
                    // if dao is not of type IBaseObjectDao, then just return null
                    return null;
                }
            }
        }

        return inputObject;
    }

    public void setDataProvider(IDataProvider dataProvider) {
        this.dataProvider = dataProvider;
    }

    public IDataProvider getDataProvider() {
        return dataProvider;
    }

    public ComponentRequestManager getComponentRequestManager() {
        return componentRequestManager;
    }

    public void setComponentRequestManager(ComponentRequestManager componentRequestManager) {
        this.componentRequestManager = componentRequestManager;
    }

    public ISingleIndexBuilder getIndexBuilder() {
        return indexBuilder;
    }

    public void setIndexBuilder(ISingleIndexBuilder indexBuilder) {
        this.indexBuilder = indexBuilder;
    }

}