de.suse.swamp.modules.actions.WorkflowActions.java Source code

Java tutorial

Introduction

Here is the source code for de.suse.swamp.modules.actions.WorkflowActions.java

Source

/*
 * SWAMP Workflow Administration and Management Platform
 *
 * Copyright (c) 2004 Thomas Schmidt <tschmidt@suse.de>
 * Copyright (c) 2006 Novell Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * 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, write to the Free Software Foundation, Inc., 51 Franklin
 * St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * In addition, as a special exception, Novell Inc. gives permission to link the
 * code of this program with the following applications:
 *
 * - All applications of the Apache Software Foundation
 *
 * and distribute such linked combinations.
 */

package de.suse.swamp.modules.actions;

import java.io.*;
import java.util.*;

import org.apache.commons.collections.buffer.*;
import org.apache.commons.fileupload.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.*;
import org.apache.turbine.util.*;
import org.apache.velocity.context.*;

import de.suse.swamp.core.actions.*;
import de.suse.swamp.core.api.*;
import de.suse.swamp.core.container.*;
import de.suse.swamp.core.data.*;
import de.suse.swamp.core.security.*;
import de.suse.swamp.core.tasks.*;
import de.suse.swamp.core.util.*;
import de.suse.swamp.core.workflow.*;
import de.suse.swamp.modules.screens.*;
import de.suse.swamp.turbine.services.security.*;
import de.suse.swamp.util.*;

/**
 * Actions for workflow and template management
 *
 * @author <a href="mailto:dbaum@suse.de">Doris Baum</a>
 */
public class WorkflowActions extends SecureAction {

    /**
     *  IMPORTANT: doXxx methods may only have ONE upper case letter X
     *  after the do, anything else must be lower case.
     */

    /**
     * Empty standard-action
     */
    public void doPerform(RunData data, Context context) throws Exception {
        throw new Exception("Workflowactions called without explicit method.");
    }

    /**
     * Starts new workflow of a template
     */
    public void doStartnewworkflow(RunData data, Context context) throws Exception {

        String templateName = data.getParameters().get("templatename");
        String templateVersion = data.getParameters().get("templateversion");

        Logger.DEBUG("Trying to start new " + templateName + " workflow case.");
        String username = data.getUser().getName();
        WorkflowAPI wfapi = new WorkflowAPI();

        if (templateVersion == null || templateVersion.equals("")) {
            templateVersion = wfapi.getWorkflowTemplate(templateName, username).getVersion();
            Logger.DEBUG("No WfVersion specified to start, assuming latest, " + templateVersion);
        }

        ResultList history = new ResultList();
        Workflow wf = wfapi.createWorkflow(templateName, username, 0, null, templateVersion, true, history);

        context.put("statusmessage", "New workflow started with " + "SWAMPID: " + wf.getName());

        context.put("workflow", wf);
        context.put("workflowid", new Integer(wf.getId()));
        context.put("history", history);
        context.put("statusheader", "Success");
        context.put("statusclass", "success");
        context.put("icon", "ok");

        // check if we have one active usertask, and the user is an owner, then redirect to it:
        TaskAPI taskapi = new TaskAPI();
        List tasks = taskapi.getUserTasks(wf.getId(), true, username);
        if (tasks.size() == 1) {
            UserActionTemplate action = (UserActionTemplate) ((WorkflowTask) tasks.get(0)).getActionTemplate();
            if (!action.isRestricted() || wf.hasRole(username, action.getRoleName())) {
                data.getParameters().add("taskid", ((Task) tasks.get(0)).getId());
                setTemplate(data, "DisplayTask.vm");
            }
        }
    }

    /**
     * Is called when a task ok comes in.
     */
    public void doTaskok(RunData data, Context context) throws Exception {
        Logger.LOG("doTaskok() from webapp.");
        SWAMPUser user = ((SWAMPTurbineUser) data.getUser()).getSWAMPUser();
        WorkflowAPI wfapi = new WorkflowAPI();
        TaskAPI taskapi = new TaskAPI();
        ResultList history = new ResultList();

        if (data.getParameters().containsKey("taskid")) {
            // get the task we're working on
            int taskId = data.getParameters().getInt("taskid");
            WorkflowTask task = taskapi.doGetTask(taskId, user.getUserName());
            String taskType = null;
            ArrayList validationErrors = new ArrayList();

            // Check for availability of that Task:
            if (task != null && task.getState() == WorkflowTask.ACTIVE) {
                // get the action type of the task
                taskType = task.getActionType();

                // fill in the result for different
                if (taskType.equals("manualtask")) {
                    ManualtaskResult result = (ManualtaskResult) task.getResult();
                    result.setDone(true);

                } else if (taskType.equals("decision")) {
                    int answer = -1;
                    // get the answer given
                    if (data.getParameters().containsKey("answer")) {
                        answer = data.getParameters().getInt("answer");
                        Logger.DEBUG("Answer #" + answer);
                        // if no answer selected, log error
                    } else {
                        Logger.ERROR("in doTaskok: no answer on question given.");
                    }
                    // put selection into result
                    DecisionResult result = (DecisionResult) task.getResult();
                    result.setSelection(answer);
                } else if (taskType.equals("dataedit")) {
                    DataeditResult result = (DataeditResult) task.getResult();
                    context.put("result", result);

                    DataeditActionTemplate action = (DataeditActionTemplate) task.getActionTemplate();
                    HashMap actionFields = action.getAllFields(task.getWorkflowId());
                    Workflow wf = wfapi.getWorkflow(task.getWorkflowId(), user.getUserName());

                    // put all values in the result object
                    for (Iterator iter = actionFields.keySet().iterator(); iter.hasNext();) {
                        ArrayList setField = (ArrayList) actionFields.get(iter.next());
                        for (Iterator it = setField.iterator(); it.hasNext();) {
                            Field f = (Field) it.next();
                            String fieldpath = f.getPath();
                            String field = "field_" + fieldpath;
                            if (data.getParameters().containsKey(field)) {
                                // binary data need extra storage
                                if (f.getDatatype().equals("fileref")) {
                                    FileItem value = data.getParameters().getFileItem(field);
                                    Logger.DEBUG("Value for key (file)" + field + ": " + value);
                                    // need to store the file now
                                    Databit dbit = wf.getDatabit(fieldpath);
                                    if (DatapackActions.storeFile(dbit, true, value, user.getUserName())) {
                                        String fileName = value.getName();
                                        // fix for browsers setting complete path as name: 
                                        if (fileName.indexOf("\\") >= 0)
                                            fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
                                        if (fileName.indexOf("/") >= 0)
                                            fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
                                        result.setValue(fieldpath, fileName);
                                    }
                                } else if (f.getDatatype().equalsIgnoreCase("multienum")) {
                                    SWAMPHashSet values = new SWAMPHashSet(data.getParameters().getStrings(field));
                                    result.setValue(fieldpath, values.toString(", "));
                                } else if (f.getDatatype().equalsIgnoreCase("patchdocumd")) {
                                    String value = data.getParameters().get(field);
                                    Logger.DEBUG("Value for key " + field + ": " + value);
                                    result.setValue(fieldpath, value);
                                } else {
                                    String value = StringEscapeUtils.unescapeHtml(data.getParameters().get(field));
                                    Logger.DEBUG("Value for key " + field + ": " + value);
                                    result.setValue(fieldpath, value);
                                }
                            } else if (data.getParameters().containsKey("boolean_" + fieldpath)) {
                                result.setValue(fieldpath, "false");
                            } else if (!f.isMandatory()) {
                                // don't complain about missing, non-mandatory fields
                            } else {
                                Logger.ERROR("Mandatory field " + fieldpath + " not set.");
                            }
                        }
                    }
                }
                // validate task result
                validationErrors = task.validate();

                // if everything is ok, try to finish the task
                if (validationErrors.size() == 0) {
                    try {
                        taskapi.finishTask(task, user.getUserName(), history);
                    } catch (Exception e) {
                        e.printStackTrace();
                        validationErrors.add(e.getMessage());
                    }
                }

                if (validationErrors.size() == 0) {
                    Logger.LOG("Webapp: Done with working on task with id " + task.getId());

                    WorkflowTask wftask = task;
                    Workflow wf = wfapi.getWorkflow(wftask.getWorkflowId(), user.getUserName());

                    context.put("statusheader", "Success");
                    context.put("statusmessage", "Task \"" + task.getReplacedDescription() + "\" done in workflow "
                            + wf.getName() + ".");

                    context.put("statusclass", "success");
                    context.put("icon", "ok");
                    context.put("history", history);
                    context.put("workflow", wf);

                    // add general Workflow Help
                    SWAMPScreen.addHelplink(wf.getTemplate(), context, user.getUserName());
                    ArrayList helps = new ArrayList();
                    if (context.get("helps") != null) {
                        helps = (ArrayList) context.get("helps");
                    }

                    // add helplinks if there are new Tasks:
                    if (wf.getActiveTasks().size() > 0) {
                        List activeTasks = wf.getActiveTasks();
                        for (Iterator it = activeTasks.iterator(); it.hasNext();) {
                            WorkflowTask helptask = (WorkflowTask) it.next();
                            String helpConext = helptask.getActionTemplate().getHelpContext();
                            if (helpConext != null && !helpConext.equals("")) {
                                ContextHelp help = new DocumentationAPI().getContextHelp(helpConext,
                                        user.getUserName());
                                if (help != null && !helps.contains(help)) {
                                    helps.add(help);
                                }
                            }
                        }
                        context.put("helps", helps);
                    }

                    if (user.getPerm("taskpage", "results").equals("workflow")) {
                        Logger.DEBUG("Doing redirect to workflow page after task for " + user.getUserName());
                        setTemplate(data, "DisplayWorkflow.vm");
                    } else if (user.getPerm("taskpage", "results").equals("previous")) {
                        CircularFifoBuffer pageBuffer = (CircularFifoBuffer) data.getUser().getTemp("pageBuffer",
                                new CircularFifoBuffer(2));
                        SWAMPHashMap params = (SWAMPHashMap) pageBuffer.get();
                        if (params != null && params.containsKey("template")) {
                            Logger.DEBUG("Redirect to previous page (" + params.get("template") + ") for "
                                    + user.getUserName());
                            data.getParameters().clear();
                            for (Iterator it = params.keySet().iterator(); it.hasNext();) {
                                String key = (String) it.next();
                                data.getParameters().add(key, (String) params.get(key));
                            }
                            setTemplate(data, (String) params.get("template"));
                        } else {
                            Logger.WARN("Desired redirect not possible, no pageBuffer");
                        }
                    }

                    // if there were errors during validation, log the error
                } else {
                    // go back to the Task-Page
                    context.put("taskerror", "true");
                    setTemplate(data, "DisplayTask.vm");

                    Iterator errIter = validationErrors.iterator();
                    String message = "", error;
                    while (errIter.hasNext()) {
                        error = (String) errIter.next();
                        message = message + "<br />" + error;
                        Logger.ERROR(error);
                    }
                    message = message + "<p />Please correct the above mistake!";
                    context.put("statusclass", "error");
                    context.put("statusheader", "Error validating task");
                    context.put("statusmessage", message);
                    context.put("icon", "error");

                    // fix page buffer
                    CircularFifoBuffer pageBuffer = (CircularFifoBuffer) data.getUser().getTemp("pageBuffer",
                            new CircularFifoBuffer(2));
                    pageBuffer.add(pageBuffer.get());
                } // end validation

            } else {
                // illegal task requested, redirect
                setTemplate(data, "DisplayTask.vm");
            }

        } else {
            Logger.ERROR("in doTaskok: no task id.");
        } //end taskid
    } //end dotaskok

    /**
     * Gets Workflow.toString() from the given workflowid
     * @param data
     * @param context
     * @throws Exception when toString() couldn't be generated from the Workflow
     */
    public void doGetwftext(RunData data, Context context) throws Exception {
        if (data.getParameters().containsKey("workflowid")) {
            int wfId = data.getParameters().getInt("workflowid");
            WorkflowAPI wfapi = new WorkflowAPI();
            Workflow wf = wfapi.getWorkflow(wfId, data.getUser().getName());
            context.put("wftxt", wf.toString());
        } else {
            context.put("statusmessage", "No WorkflowId set!.");
            context.put("statusclass", "error");
            context.put("statusheader", "");
            context.put("icon", "error");
            Logger.ERROR("No WorkflowID set for getting toString().");
        }
    }

    /**
     * Gets Workflow.toXML() from the given workflowid
     * @param data
     * @param context
     * @throws Exception when XML couldn't be generated from the Workflow
     */
    public void doGetwfxml(RunData data, Context context) throws Exception {
        if (data.getParameters().containsKey("workflowid")) {
            int wfId = data.getParameters().getInt("workflowid");
            WorkflowAPI wfapi = new WorkflowAPI();
            Workflow wf = wfapi.getWorkflow(wfId, data.getUser().getName());
            context.put("wfxml", wf.toXML());
        } else {
            context.put("statusmessage", "No WorkflowId set!.");
            context.put("statusclass", "error");
            context.put("statusheader", "");
            context.put("icon", "error");
            Logger.ERROR("No WorkflowID set for getting toString().");
        }
    }

    public void doChangenodesactivity(RunData data, Context context) throws Exception {
        int wfid = data.getParameters().getInt("workflowid");
        WorkflowAPI wfapi = new WorkflowAPI();
        Workflow wf = wfapi.getWorkflowForWriting(wfid, data.getUser().getName());
        if (wf != null) {
            ResultList results = new ResultList();
            for (Iterator it = wf.getAllNodes().iterator(); it.hasNext();) {
                Node node = (Node) it.next();
                if (data.getParameters().containsKey(node.getName())) {
                    boolean newState = data.getParameters().getBoolean(node.getName());
                    if (node.isActive() != newState) {
                        Logger.DEBUG("Adminaction: changing " + node.getName() + " state from " + node.isActive()
                                + " to " + newState);
                        if (newState) {
                            node.activate(data.getUser().getName(), results);
                        } else {
                            node.deactivate();
                        }
                    }
                    MileStone mileStone = node.getMileStone();
                    if (mileStone != null && data.getParameters().containsKey(mileStone.getName())) {
                        newState = data.getParameters().getBoolean(mileStone.getName());
                        if (mileStone.isDisplayed() != newState) {
                            Logger.DEBUG("Adminaction: changing milestone display " + mileStone.getName()
                                    + " state from " + mileStone.isDisplayed() + " to " + newState);
                            mileStone.setDisplayed(newState);
                        }
                    }
                }
            }
            wfapi.storeWorkflow(wf, data.getUser().getName());
            context.put("history", results);
        } else {
            Logger.ERROR("Illegal Wf-ID: " + wfid + " in doChangenodesactivity");
        }
    }

    public void doRestartworkflow(RunData data, Context context) throws Exception {
        int wfid = data.getParameters().getInt("workflowid");
        WorkflowAPI wfapi = new WorkflowAPI();
        TaskAPI taskapi = new TaskAPI();
        Workflow wf = wfapi.getWorkflowForWriting(wfid, data.getUser().getName());
        taskapi.cancelAllTasks(wfid, data.getUser().getName());
        wf.deactivateAllNodes();
        wf.start(data.getUser().getName(), new ResultList());
    }

    /**
     * Store the uploaded workflow to a temp. directory and verify it
     */
    public void doUploadworkflow(RunData data, Context context) throws Exception {

        org.apache.turbine.util.parser.ParameterParser pp = data.getParameters();
        String separator = System.getProperty("file.separator");
        String tmpdir = System.getProperty("java.io.tmpdir");
        ArrayList results = new ArrayList();
        // storing file
        FileItem fi = pp.getFileItem("filename");
        if (fi == null || fi.getName() == null || fi.getSize() == 0) {
            throw new Exception("Empty file uploaded.");
        }

        if (fi.getName().endsWith(".xml") || fi.getName().endsWith(".zip")) {
            String uniqueid = String.valueOf(new Date().getTime());
            String basePath = tmpdir + separator + uniqueid;
            FileUtils.forceMkdir(new File(basePath));
            WorkflowReadResult result = null;

            if (fi.getName().endsWith("xml")) {
                File wfTmpFile = new File(basePath + separator + "workflow.xml");
                if (wfTmpFile.exists()) {
                    wfTmpFile.delete();
                }
                fi.write(wfTmpFile);
                if (!wfTmpFile.exists()) {
                    throw new Exception("Storing of file: " + fi.getName() + " failed.");
                }
            } else {
                // unpack uploaded workflow resource bundle
                de.suse.swamp.util.FileUtils.uncompress(fi.getInputStream(), basePath);
            }
            // read + verify the workflow:
            WorkflowReader reader = new WorkflowReader(new File(basePath));
            result = reader.readWorkflow(basePath);
            results.add(result);
            context.put("uniqueid", uniqueid);
            // clean uploaded stuff on errors
            if (result.hasErrors()) {
                FileUtils.deleteDirectory(new File(basePath));
            }
        } else {
            throw new Exception(
                    "Only upload of single \"workflow.xml\" and \".zip\" packed workflow bundles is supported.");
        }
        context.put("workflowreadresults", results);
    }

    /**
     * Install an uploaded workflow
     */
    public void doInstallworkflow(RunData data, Context context) throws Exception {
        String separator = System.getProperty("file.separator");
        String tmpdir = System.getProperty("java.io.tmpdir");
        String uniqueid = data.getParameters().get("uniqueid");
        String basePath = tmpdir + separator + uniqueid;

        WorkflowReader reader = new WorkflowReader(new File(tmpdir + separator + uniqueid));
        WorkflowReadResult result = reader.readWorkflow(basePath);

        if (result.hasErrors()) {
            throw new Exception("Uploaded template contains errors.");
        } else {
            Logger.DEBUG("No Errors detected, installing new workflow");
            String name = result.getTemplate().getName();
            data.getParameters().add("templatename", name);
            String version = result.getTemplate().getVersion();
            String wfPath = SWAMP.getInstance().getWorkflowLocation() + separator + name + separator + version;
            FileUtils.forceMkdir(new File(wfPath));
            FileUtils.copyDirectory(new File(basePath), new File(wfPath));
            WorkflowManager.getInstance().reloadWorkflowDefinition(name, version);
            context.put("statusmessage",
                    "New workflow: " + name + " with version: " + version + " successfully installed.");
            context.put("statusclass", "success");
            context.put("statusheader", "Workflow installed");
            context.put("icon", "ok");
            // clean uploaded stuff
            FileUtils.deleteDirectory(new File(basePath));
        }
    }

    public void doRemoveworkflow(RunData data, Context context) throws Exception {
        WorkflowAPI wfapi = new WorkflowAPI();
        String uname = data.getUser().getName();
        int wfId = data.getParameters().getInt("wfid", 0);
        wfapi.removeWorkflow(uname, wfId);
        context.put("statusmessage", "Workflow #" + wfId + " successfully removed.");
        context.put("statusclass", "success");
        context.put("statusheader", "Workflow removed");
        context.put("icon", "ok");
    }

    public void doChangeparentid(RunData data, Context context) throws Exception {
        WorkflowAPI wfapi = new WorkflowAPI();
        String uname = data.getUser().getName();
        int wfId = data.getParameters().getInt("wfid", 0);
        int parentId = data.getParameters().getInt("parentid", 0);
        if (wfapi.changeParentId(wfId, parentId, uname)) {
            context.put("statusmessage", "Parent ID successfully changed to: " + parentId);
            context.put("statusclass", "success");
            context.put("statusheader", "Workflow parent changed");
            context.put("icon", "ok");
        }
    }

}