com.silverpeas.workflowdesigner.control.WorkflowDesignerSessionController.java Source code

Java tutorial

Introduction

Here is the source code for com.silverpeas.workflowdesigner.control.WorkflowDesignerSessionController.java

Source

/**
* Copyright (C) 2000 - 2013 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.silverpeas.workflowdesigner.control;

import com.silverpeas.admin.components.ComponentsInstanciatorIntf;
import com.silverpeas.admin.components.Instanciateur;
import com.silverpeas.admin.components.InstanciationException;
import com.silverpeas.admin.components.Profile;
import com.silverpeas.admin.components.WAComponent;
import com.silverpeas.util.FileUtil;
import com.silverpeas.util.i18n.I18NHelper;
import com.silverpeas.workflow.api.ProcessModelManager;
import com.silverpeas.workflow.api.Workflow;
import com.silverpeas.workflow.api.WorkflowException;
import com.silverpeas.workflow.api.model.Action;
import com.silverpeas.workflow.api.model.Actions;
import com.silverpeas.workflow.api.model.AllowedActions;
import com.silverpeas.workflow.api.model.Columns;
import com.silverpeas.workflow.api.model.Consequence;
import com.silverpeas.workflow.api.model.Consequences;
import com.silverpeas.workflow.api.model.ContextualDesignation;
import com.silverpeas.workflow.api.model.ContextualDesignations;
import com.silverpeas.workflow.api.model.DataFolder;
import com.silverpeas.workflow.api.model.Form;
import com.silverpeas.workflow.api.model.Forms;
import com.silverpeas.workflow.api.model.Input;
import com.silverpeas.workflow.api.model.Item;
import com.silverpeas.workflow.api.model.Parameter;
import com.silverpeas.workflow.api.model.Participant;
import com.silverpeas.workflow.api.model.Participants;
import com.silverpeas.workflow.api.model.ProcessModel;
import com.silverpeas.workflow.api.model.QualifiedUsers;
import com.silverpeas.workflow.api.model.RelatedUser;
import com.silverpeas.workflow.api.model.Role;
import com.silverpeas.workflow.api.model.Roles;
import com.silverpeas.workflow.api.model.State;
import com.silverpeas.workflow.api.model.States;
import com.silverpeas.workflow.api.model.UserInRole;
import com.silverpeas.workflow.engine.WorkflowHub;
import com.silverpeas.workflow.engine.model.ProcessModelManagerImpl;
import com.silverpeas.workflowdesigner.model.WorkflowDesignerException;
import com.stratelia.silverpeas.peasCore.AbstractComponentSessionController;
import com.stratelia.silverpeas.peasCore.ComponentContext;
import com.stratelia.silverpeas.peasCore.MainSessionController;
import com.stratelia.webactiv.util.FileServerUtils;
import com.stratelia.webactiv.util.exception.SilverpeasException;
import org.apache.commons.fileupload.FileItem;

import javax.xml.bind.JAXBException;
import java.io.File;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.StringTokenizer;

public class WorkflowDesignerSessionController extends AbstractComponentSessionController {

    public static final String TYPE_USER = "user";
    public static final String FORMS = "forms";
    public static final String DATA_FOLDER = "dataFolder";
    public static final String USER_INFOS = "userInfos";
    public static final String ACTIONS = "actions";
    public static final String INPUTS = "inputs";
    public static final String STATES = "states";
    public static final String PARAMETERS = "parameters";
    public static final String PARTICIPANTS = "participants";
    public static final String PRESENTATION = "presentation";
    public static final String ROLES = "roles";
    public static final String RELATED_USER = "relatedUser";
    public static final String WORKING_USERS = "workingUsers";
    public static final String INTERESTED_USERS = "interestedUsers";
    public static final String NOTIFIED_USERS = "notifiedUsers";
    public static final String ALLOWED_USERS = "allowedUsers";
    public static final String CONSEQUENCES = "consequences";
    public static final String FORM_TYPE_PRESENTATION = "presentationForm";
    public static final String FORM_TYPE_PRINT = "printForm";
    public static final String FORM_TYPE_ACTION = "action";
    public static final String NEW_ELEMENT_NAME = "New"; // an initial name for new model elements
    public static final String TITLES = "titles";
    public static final String ACTIVITIES = "activities";
    public static final String DESCRIPTIONS = "descriptions";
    public static final String LABELS = "labels";
    private static final String CONTEXT_DELIMS = "/[]";
    private ProcessModel processModel; // The process model being edited.
    private String processModelFileName; // we have to store the file path as
    // well, since it is not included in
    // the ProcessModel object...
    private String referencedInComponent; // the name of a Component

    // Descriptor where the current
    // process model is referenced

    /**
    * Standard Session Controller Constructeur
    *
    * @param mainSessionCtrl The user's profile
    * @param componentContext The component's profile
    * @see
    */
    public WorkflowDesignerSessionController(MainSessionController mainSessionCtrl,
            ComponentContext componentContext) {
        super(mainSessionCtrl, componentContext, "com.silverpeas.workflowdesigner.multilang.workflowDesignerBundle",
                "com.silverpeas.workflowdesigner.settings.workflowDesignerIcons",
                "com.silverpeas.workflowdesigner.settings.workflowDesigner");
    }

    /**
    * Get the list of all process models available for edition
    *
    * @return A list of Strings containing relative paths to process model file names.
    * @throws WorkflowDesignerException
    */
    public List<String> listProcessModels() throws WorkflowDesignerException {
        try {
            return Workflow.getProcessModelManager().listProcessModels();
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.getPorcesModels",
                    SilverpeasException.ERROR, "workflowDesigner.EX_GETTING_RPOCES_MODELS_FAILED", e);
        }
    }

    /**
    * Create a new ProcessModel descriptor that is not yet saved in a XML file.
    *
    * @return ProcessModel object
    */
    public ProcessModel createProcessModel() throws WorkflowDesignerException {
        try {
            processModel = Workflow.getProcessModelManager().createProcessModelDescriptor();
            processModelFileName = NEW_ELEMENT_NAME;
            referencedInComponent = null;
            return processModel;
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.createPorcesModel",
                    SilverpeasException.ERROR, "workflowDesigner.EX_CREATING_PROCESS_DESCRIPTIOR_FAILED", e);
        }
    }

    /**
    * Load the process model from the specified file, cache it before returning.
    *
    * @param strProcessFileName relative path and the file name
    * @return An object implementing the ProcessModel interface
    * @throws WorkflowDesignerException
    */
    public ProcessModel loadProcessModel(String strProcessFileName) throws WorkflowDesignerException {
        try {
            // Load the process model from the XML file
            //
            processModel = Workflow.getProcessModelManager().loadProcessModel(strProcessFileName, false);
            processModelFileName = strProcessFileName;

            // check if a component descriptor exists for this process model
            // store this info in an attribute
            //
            referencedInComponent = findComponentDescriptor(processModelFileName);

            return processModel;
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.loadProcesModel",
                    SilverpeasException.ERROR, "workflowDesigner.EX_LOADING_PROCES_MODEL_FAILED", e);
        }
    }

    /**
    * Save the currently cached process model in a XML file
    *
    * @param strProcessModelFileName the relative path and the name of the file
    * @throws WorkflowDesignerException when the saving goes wrong...
    */
    public void saveProcessModel(String strProcessModelFileName) throws WorkflowDesignerException {
        try {
            // Is this the first save of a process model?
            //
            if (strProcessModelFileName != null && NEW_ELEMENT_NAME.equals(processModelFileName)) {
                // Make sure that you are not overwriting sth.
                //
                List<String> processList = Workflow.getProcessModelManager().listProcessModels();
                strProcessModelFileName = FileUtil.convertPathToServerOS(strProcessModelFileName);

                if (processList.contains(strProcessModelFileName)) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.saveProcesModel",
                            SilverpeasException.ERROR, "workflowDesigner.EX_PROCESS_MODEL_EXISTS");
                }
                // Cache the file name if it is the first save
                processModelFileName = strProcessModelFileName;
            }
            Workflow.getProcessModelManager().saveProcessModel(processModel, processModelFileName);
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.saveProcesModel",
                    SilverpeasException.ERROR, "workflowDesigner.EX_SAVING_PROCESS_MODEL_FAILED", e);
        }
    }

    /**
    * Removes the process model descriptor file from the filesystem
    *
    * @param strProcessModelFileName the relative path to the process file name
    * @throws WorkflowDesignerException when something goes wrong
    */
    public void removeProcessModel(String strProcessModelFileName) throws WorkflowDesignerException {
        try {
            Workflow.getProcessModelManager().deleteProcessModelDescriptor(strProcessModelFileName);
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeProcesModel",
                    SilverpeasException.ERROR, "workflowDesigner.EX_REMOVING_PROCESS_DESCRIPTIOR_FAILED", e);
        }
    }

    /**
    * An object implementing the ProcessModel interface containing the currently loaded model or null
    * if none.
    */
    public ProcessModel getProcessModel() {
        return processModel;
    }

    /**
    * Is it a new Process Model that has not yet been saved to a file?
    */
    public Boolean isNewProcessModel() {
        return NEW_ELEMENT_NAME.equals(processModelFileName);
    }

    /**
    * The relative path and file name of the currently loaded model or null if none.
    */
    public String getProcessFileName() {
        return processModelFileName;
    }

    /**
    * The name of the component descriptor that references this process model definition
    *
    * @return the component descriptor file name (without .xml) or <code>null</code> if no components
    * reference this process model.
    */
    public String getComponentDescriptorName() {
        return referencedInComponent;
    }

    /**
    * Update the header of the cached process model
    *
    * @param processModel the reference object
    */
    public void updateProcessModelHeader(ProcessModel processModel) {
        // Update the current process Model
        this.processModel.setName(processModel.getName());
    }

    /**
    * Create a new columns object to be added to the model
    *
    * @return an object implementing Columns
    */
    public Columns addColumns() {
        Columns columns = processModel.getPresentation().createColumns();

        columns.setRoleName(NEW_ELEMENT_NAME);
        return columns;
    }

    /**
    * Update or insert a new columns section of the presentation element of the cached process model
    *
    * @param source the reference object
    * @throws WorkflowDesignerException
    */
    public void updateColumns(Columns source, String strRoleOriginal) throws WorkflowDesignerException {
        Columns check = processModel.getPresentation().getColumnsByRole(source.getRoleName());

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strRoleOriginal)) {
            // If a 'columns' element with the same name as the new element
            // already exists we have a problem...
            //
            if (check != null) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateColumns",
                        SilverpeasException.ERROR, "workflowDesigner.EX_COLUMNS_ALREADY_EXISTS");
            }
        } else // Existing object
        {
            // If a 'columns' element with the same name as the element's new name
            // already exists we have a problem...
            //
            if (check != null && !strRoleOriginal.equals(source.getRoleName())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateColumns",
                        SilverpeasException.ERROR, "workflowDesigner.EX_COLUMNS_ALREADY_EXISTS");
            }

            try {
                processModel.getPresentation().deleteColumns(strRoleOriginal);
            } catch (WorkflowException e) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateColumns",
                        SilverpeasException.ERROR, "workflowDesigner.EX_UPDATING_COLUMNS_FAILED", e);
            }
        }

        processModel.getPresentation().addColumns(source);
    }

    /**
    * Removes the 'columns' object specified by the role name
    *
    * @param strRoleName the value of the role attribute
    * @throws WorkflowDesignerException when something goes wrong
    */
    public void deleteColumns(String strRoleName) throws WorkflowDesignerException {
        try {
            processModel.getPresentation().deleteColumns(strRoleName);
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.deleteColumns",
                    SilverpeasException.ERROR, "workflowDesigner.EX_DELETING_COLUMNS_FAILED", e);
        }
    }

    /**
    * Create a new role object to be added to the model
    *
    * @return an object implementing Role
    */
    public Role createRole() {
        Roles roles = processModel.getRolesEx();
        if (roles == null) {
            roles = processModel.createRoles();
            processModel.setRoles(roles);
        }

        Role role = roles.createRole();
        role.setName(NEW_ELEMENT_NAME);
        return role;
    }

    /**
    * Update or insert a new role element of the cached process model
    *
    * @param source the data carrier object
    * @param strNameOriginal the original name of the object
    * @throws WorkflowDesignerException if another object with the same name already exists
    */
    public void updateRole(Role source, String strNameOriginal) throws WorkflowDesignerException {
        Role check = processModel.getRolesEx().getRole(source.getName());

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strNameOriginal)) {
            // If the new 'role' element's name does not clash with other elements
            // add it to the collection
            //
            if (check == null) {
                processModel.getRolesEx().addRole(source);
            } else {
                // If a 'role' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateRole",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ROLE_EXISTS");
            }
        } else // Existing object
        {
            // If a 'role' element with the same name as the element's new name
            // already exists we have a problem...
            //
            if (check != null && !strNameOriginal.equals(source.getName())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateRole",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ROLE_EXISTS");
            }

            // Update the name
            //
            processModel.getRolesEx().getRole(strNameOriginal).setName(source.getName());
        }
    }

    /**
    * Remove the role specified
    *
    * @param strRoleName the name of the role
    * @throws WorkflowDesignerException if the role cannot be found or is referenced elsewhere.
    */
    public void removeRole(String strRoleName) throws WorkflowDesignerException {
        Map<ContextualDesignations, String> mapDesignations = collectContextualDesignations();
        Iterator<ContextualDesignations> iterKeys = mapDesignations.keySet().iterator();
        Iterator<ContextualDesignation> iterDesignation;
        Iterator<RelatedUser> iterRelatedUser;
        ContextualDesignations designations;
        ContextualDesignation designation;
        QualifiedUsers qualifiedUsers;
        RelatedUser relatedUser;

        if (strRoleName == null) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                    SilverpeasException.ERROR, "workflowDesigner.EX_ROLE_NOT_FOUND");
        }
        // Check if this role is referenced elsewhere ...
        //
        // ... in Contextual Designation ( labels, descriptions, titles, activities)
        //
        while (iterKeys.hasNext()) {
            designations = iterKeys.next();
            iterDesignation = designations.iterateContextualDesignation();

            while (iterDesignation.hasNext()) {
                designation = iterDesignation.next();

                if (strRoleName.equals(designation.getRole())) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                            SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                            mapDesignations.get(designations) + " ( role: '" + strRoleName + "'"
                                    + (designation.getLanguage() == null ? ""
                                            : (", lang: '" + designation.getLanguage() + "'"))
                                    + " )");
                }
            }
        }

        // ... in Columns
        //
        if (processModel.getPresentation() != null
                && processModel.getPresentation().getColumnsByRole(strRoleName) != null) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                    SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                    "presentation, (columns: '" + strRoleName + "')");
        }

        // ... in Forms
        //
        if (processModel.getForms() != null) {
            Iterator<Form> iterForm = processModel.getForms().iterateForm();
            while (iterForm.hasNext()) {
                Form form = iterForm.next();
                if (strRoleName.equals(form.getRole())) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                            SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                            "form: '" + form.getName() + "', (role: '" + strRoleName + "')");
                }
            }
        }

        // ... in Qualified users ( role, userInRole, relatedUsers )
        //
        Map<QualifiedUsers, String> mapQualifiedUsers = collectQualifiedUsers();

        for (QualifiedUsers qualifiedUsers1 : mapQualifiedUsers.keySet()) {
            qualifiedUsers = qualifiedUsers1;

            if (strRoleName.equals(qualifiedUsers.getRole())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                        mapQualifiedUsers.get(qualifiedUsers) + " (role: '" + strRoleName + "')");
            }

            if (qualifiedUsers.getUserInRole(strRoleName) != null) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                        mapQualifiedUsers.get(qualifiedUsers) + " (userInRole: '" + strRoleName + "')");
            }

            // in Related Users
            //
            iterRelatedUser = qualifiedUsers.iterateRelatedUser();

            while (iterRelatedUser.hasNext()) {
                relatedUser = iterRelatedUser.next();

                if (strRoleName.equals(relatedUser.getRole())) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                            SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                            mapQualifiedUsers.get(qualifiedUsers) + " (relatedUser: ["
                                    + (relatedUser.getParticipant() == null ? ""
                                            : (" participant: '" + relatedUser.getParticipant().getName() + "'"))
                                    + (relatedUser.getFolderItem() == null ? ""
                                            : (" folderItem: '" + relatedUser.getFolderItem().getName() + "'"))
                                    + (relatedUser.getRelation() == null ? ""
                                            : (" relation: '" + relatedUser.getRelation() + "'"))
                                    + " role: '" + strRoleName + "'" + " ])");
                }
            }
        }

        try {
            processModel.getRolesEx().removeRole(strRoleName);
            processModel.setRoles(null);
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeRole",
                    SilverpeasException.ERROR, "workflowDesigner.EX_ROLE_NOT_FOUND");
        }
    }

    /**
    * Create a new participant object to be added to the model
    *
    * @return an object implementing Participant
    */
    public Participant createParticipant() {
        Participants participants = processModel.getParticipantsEx();
        Participant participant;

        if (participants == null) {
            participants = processModel.createParticipants();
            processModel.setParticipants(participants);
        }

        participant = participants.createParticipant();
        participant.setName(NEW_ELEMENT_NAME);
        return participant;
    }

    /**
    * Update or insert a new participant element of the cached process model
    *
    * @param source the reference object
    * @throws WorkflowDesignerException
    */
    public void updateParticipant(Participant source, String strNameOriginal) throws WorkflowDesignerException {
        Participant check = processModel.getParticipantsEx().getParticipant(source.getName()), participant;

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strNameOriginal)) {
            // If the new 'participant' element's name does not clash with other
            // elements
            // add it to the collection
            //
            if (check == null) {
                processModel.getParticipantsEx().addParticipant(source);
            } else {
                // If a 'participant' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateParticipant",
                        SilverpeasException.ERROR, "workflowDesigner.EX_PARTICIPANT_EXISTS");
            }
        } else // Existing object
        {
            // If a 'particiapnt' element with the same name as the element's new name
            // already exists we have a problem...
            //
            if (check != null && !strNameOriginal.equals(source.getName())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateParticipant",
                        SilverpeasException.ERROR, "workflowDesigner.EX_PARTICIPANT_EXISTS");
            }

            // Update the name and resolved state
            //
            participant = processModel.getParticipantsEx().getParticipant(strNameOriginal);
            participant.setName(source.getName());
            participant.setResolvedState(source.getResolvedState());
        }
    }

    /**
    * Remove the participant specified
    *
    * @param strParticipantName the name of the participant
    * @throws WorkflowDesignerException if the participant cannot be found or is referenced
    * elsewhere.
    */
    public void removeParticipant(String strParticipantName) throws WorkflowDesignerException {
        Participant reference = processModel.getParticipantsEx().getParticipant(strParticipantName);

        if (reference == null) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeParticipant",
                    SilverpeasException.ERROR, "workflowDesigner.EX_PARTICIPANT_NOT_FOUND");
        }
        // Check if this participant is referenced elsewhere ...
        //
        // ... in Qualified users ( relatedUsers )
        //
        Map<QualifiedUsers, String> mapQualifiedUsers = collectQualifiedUsers();

        for (QualifiedUsers qualifiedUsers : mapQualifiedUsers.keySet()) {
            // in Related Users
            Iterator<RelatedUser> iterRelatedUser = qualifiedUsers.iterateRelatedUser();

            while (iterRelatedUser.hasNext()) {
                RelatedUser relatedUser = iterRelatedUser.next();

                if (reference == relatedUser.getParticipant()) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeParticipant",
                            SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                            mapQualifiedUsers.get(qualifiedUsers) + " (relatedUser: ["
                                    + (relatedUser.getParticipant() == null ? ""
                                            : (" participant: '" + relatedUser.getParticipant().getName() + "'"))
                                    + (relatedUser.getFolderItem() == null ? ""
                                            : (" folderItem: '" + relatedUser.getFolderItem().getName() + "'"))
                                    + (relatedUser.getRelation() == null ? ""
                                            : (" relation: '" + relatedUser.getRelation() + "'"))
                                    + (relatedUser.getRole() == null ? ""
                                            : (" role: '" + relatedUser.getRole() + "'"))
                                    + " ])");
                }
            }
        }

        try {
            processModel.getParticipantsEx().removeParticipant(strParticipantName);
            processModel.setParticipants(null);
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeParticipant",
                    SilverpeasException.ERROR, "workflowDesigner.EX_PARTICIPANT_NOT_FOUND");
        }
    }

    /**
    * Create a new state object to be added to the model
    *
    * @return an object implementing State
    */
    public State createState() {
        States states = processModel.getStatesEx();
        State state;

        if (states == null) {
            states = processModel.createStates();
            processModel.setStates(states);
        }

        state = states.createState();
        state.setName(NEW_ELEMENT_NAME);
        return state;
    }

    /**
    * Update or insert a new state element of the cached process model
    *
    * @param source the reference object
    * @throws WorkflowDesignerException
    */
    public void updateState(State source, String strNameOriginal) throws WorkflowDesignerException {
        State check = processModel.getStatesEx().getState(source.getName()), state;

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strNameOriginal)) {
            // If the new 'state' element's name does not clash with other elements
            // add it to the collection
            //
            if (check == null) {
                processModel.getStatesEx().addState(source);
            } else {
                // If a 'state' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateState",
                        SilverpeasException.ERROR, "workflowDesigner.EX_STATE_EXISTS");
            }
        } else // Existing object
        {
            // If a 'state' element with the same name as the element's new name
            // already exists we have a problem...
            //
            if (check != null && !strNameOriginal.equals(source.getName())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateState",
                        SilverpeasException.ERROR, "workflowDesigner.EX_STATE_EXISTS");
            }

            // Update the state attributes
            //
            state = processModel.getStatesEx().getState(strNameOriginal);
            state.setName(source.getName());
            state.setTimeoutAction(source.getTimeoutAction());
            state.setTimeoutInterval(source.getTimeoutInterval());
            state.setTimeoutNotifyAdmin(source.getTimeoutNotifyAdmin());
            state.setAllowedActions(source.getAllowedActionsEx());
        }
    }

    /**
    * Remove the state specified
    *
    * @param strStateName the name of the state
    * @throws WorkflowDesignerException if the state cannot be found or is referenced elsewhere.
    */
    public void removeState(String strStateName) throws WorkflowDesignerException {
        Actions actions = processModel.getActionsEx();
        Participants participants = processModel.getParticipantsEx();

        // Check if this state is not referenced in Actions' consequences
        if (actions != null) {
            Iterator<Action> iterAction = actions.iterateAction();

            while (iterAction.hasNext()) {
                Action action = iterAction.next();

                Consequences consequences = action.getConsequences();

                if (consequences != null) {
                    Iterator<Consequence> iterConsequence = consequences.iterateConsequence();

                    while (iterConsequence.hasNext()) {
                        Consequence consequence = iterConsequence.next();
                        if (consequence.getTargetState(strStateName) != null
                                || consequence.getUnsetState(strStateName) != null) {
                            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeState",
                                    SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                                    "action : '" + action.getName() + "' (set/unset state : '" + strStateName
                                            + "')");
                        }
                    }
                }
            }
        }

        // Check if this state is not referenced in Participants
        //
        if (participants != null) {
            Iterator<Participant> iterParticipant = participants.iterateParticipant();

            while (iterParticipant.hasNext()) {
                Participant participant = iterParticipant.next();

                if (participant.getResolvedState().equals(strStateName)) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeState",
                            SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED", "participant : '"
                                    + participant.getName() + "' (resolved state : '" + strStateName + "')");
                }
            }
        }

        try {
            processModel.getStatesEx().removeState(strStateName);
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeState",
                    SilverpeasException.ERROR, "workflowDesigner.EX_STATE_NOT_FOUND");
        }
    }

    /**
    * Update Qualified Users referenced by the context, create the object if it was <code>null</code>
    * before.
    *
    * @param source the new Qualified Users
    * @param strContext the context of the QualifiedUsers being updated
    * @throws WorkflowException when the update goes wrong
    * @throws WorkflowDesignerException when the update goes wrong
    */
    public void updateQualifiedUsers(QualifiedUsers source, String strContext)
            throws WorkflowException, WorkflowDesignerException {
        QualifiedUsers qualifiedUsers = findQualifiedUsers(strContext);
        if (qualifiedUsers == null) {
            setQualifiedUsers(source, strContext);
        } else {
            // Update the qualified users.
            qualifiedUsers.setRole(source.getRole());
            qualifiedUsers.setMessage(source.getMessage());
            qualifiedUsers.removeUserInRoles();
            Iterator<UserInRole> iter = source.iterateUserInRole();

            while (iter.hasNext()) {
                qualifiedUsers.addUserInRole(iter.next());
            }
        }
    }

    /**
    * Find a related user corresponding to the criteria given
    *
    * @param strContext the context
    * @param strParticipant the name of the participant, may be <code>null</code>
    * @param strFolderItem the name of the data folder item, may be <code>null</code>
    * @param strRelation the relation, may be <code>null</code>
    * @param strRole the name of the role, may be <code>null</code>
    * @return an object implementing RelatedUser
    * @throws WorkflowException when something goes wrong
    */
    public RelatedUser findRelatedUser(String strContext, String strParticipant, String strFolderItem,
            String strRelation, String strRole) throws WorkflowException {
        RelatedUser reference = processModel.createRelatedUser();

        if (strContext == null) {
            return null;
        }
        // Initialise the reference object
        if (strParticipant == null) {
            reference.setParticipant(null);
        } else {
            reference.setParticipant(processModel.getParticipantsEx().getParticipant(strParticipant));
        }

        if (strFolderItem == null) {
            reference.setFolderItem(null);
        } else {
            reference.setFolderItem(processModel.getDataFolder().getItem(strFolderItem));
        }

        reference.setRelation(strRelation);
        reference.setRole(strRole);

        // Check the context
        QualifiedUsers qualifiedUsers = findQualifiedUsers(strContext);
        if (qualifiedUsers != null) {
            return qualifiedUsers.getRelatedUser(reference);
        }

        return null;
    }

    /**
    * Update a related user corresponding to the criteria given
    *
    * @param strContext the context
    * @param strParticipantOriginal the original name of the participant, may be <code>null</code>
    * @param strFolderItemOriginal the original name of the data folder item, may be
    * <code>null</code>
    * @param strRelationOriginal the original relation, may be <code>null</code>
    * @param strRoleOriginal the original name of the role, may be <code>null</code>
    * @return an object implementing RelatedUser
    * @throws WorkflowDesignerException when something goes wrong
    * @throws WorkflowException when something goes wrong
    */
    public void updateRelatedUser(RelatedUser source, String strContext, String strParticipantOriginal,
            String strFolderItemOriginal, String strRelationOriginal, String strRoleOriginal)
            throws WorkflowDesignerException, WorkflowException {
        String strParticipant = source.getParticipant() == null ? null : source.getParticipant().getName(),
                strFolderItem = source.getFolderItem() == null ? null : source.getFolderItem().getName();
        RelatedUser check = findRelatedUser(strContext, strParticipant, strFolderItem, source.getRelation(),
                source.getRole()), relatedUser, reference;
        QualifiedUsers qualifiedUsers = findQualifiedUsers(strContext);

        // Is it a new object or an existing one?
        if (NEW_ELEMENT_NAME.equals(strRoleOriginal)) {
            // If the new 'relatedUser' element's name does not clash with other
            // elements add it to the collection
            if (check == null) {
                qualifiedUsers.addRelatedUser(source);
            } else {
                // If a 'state' element with the same attributes as the new element
                // already exists we have a problem...
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateRelatedUser",
                        SilverpeasException.ERROR, "workflowDesigner.EX_RELATED_USER_EXISTS");
            }
        } else // Existing object
        {
            // If a different 'relatedUser' element with the same attributes as the
            // new element
            // already exists we have a problem...
            // So if an object with the same attributes has been found ('check')
            // it should be the object that is being modified, just that the attribute
            // values did not change.
            // Therefore we compare all the attributes with their initial values.
            //
            if (check != null && !((strParticipantOriginal == null && strParticipant == null
                    || strParticipantOriginal != null && strParticipantOriginal.equals(strParticipant))
                    && (strFolderItemOriginal == null && strFolderItem == null
                            || strFolderItemOriginal != null && strFolderItemOriginal.equals(strFolderItem))
                    && (strRelationOriginal == null && source.getRelation() == null
                            || strRelationOriginal != null && strRelationOriginal.equals(source.getRelation()))
                    && (strRoleOriginal == null && source.getRole() == null
                            || strRoleOriginal != null && strRoleOriginal.equals(source.getRole())))) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateRelatedUser",
                        SilverpeasException.ERROR, "workflowDesigner.EX_RELATED_USER_EXISTS");
            }

            // Update the relatedUser
            //
            reference = processModel.createRelatedUser();

            if (strParticipantOriginal != null) {
                reference.setParticipant(processModel.getParticipantsEx().getParticipant(strParticipantOriginal));
            } else {
                reference.setParticipant(null);
            }

            if (strFolderItemOriginal != null) {
                reference.setFolderItem(processModel.getDataFolder().getItem(strFolderItemOriginal));
            } else {
                reference.setFolderItem(null);
            }

            reference.setRelation(strRelationOriginal);
            reference.setRole(strRoleOriginal);

            relatedUser = qualifiedUsers.getRelatedUser(reference);
            relatedUser.setParticipant(source.getParticipant());
            relatedUser.setFolderItem(source.getFolderItem());
            relatedUser.setRelation(source.getRelation());
            relatedUser.setRole(source.getRole());
        }
    }

    /**
    * Remove the related user specified
    *
    * @param reference the reference for the related user to remove
    * @param strContext the context
    * @throws WorkflowException if the related user cannot be found or when something goes
    * wrong
    */
    public void removeRelatedUser(RelatedUser reference, String strContext) throws WorkflowException {
        QualifiedUsers qualifiedUsers = findQualifiedUsers(strContext);
        qualifiedUsers.removeRelatedUser(reference);
    }

    /**
    * Create a new action object to be added to the model
    *
    * @return an object implementing Action
    */
    public Action createAction() {
        Actions actions = processModel.getActionsEx();
        Action action;

        if (actions == null) {
            actions = processModel.createActions();
            processModel.setActions(actions);
        }

        action = actions.createAction();
        action.setName(NEW_ELEMENT_NAME);
        return action;
    }

    /**
    * Update or insert a new action element of the cached process model
    *
    * @param source the reference object
    * @param strNameOriginal
    * @throws WorkflowDesignerException when something goes wrong
    * @throws WorkflowException when something goes wrong
    */
    public void updateAction(Action source, String strNameOriginal)
            throws WorkflowDesignerException, WorkflowException {
        Action check = null, action;

        try {
            check = processModel.getActionsEx().getAction(source.getName());
        } catch (WorkflowException e) {
            // We expect an exception when the action has not been found
            //
            if (!"WorkflowEngine.EX_ERR_ACTION_NOT_FOUND_IN_MODEL".equals(e.getMessage())) {
                throw e;
            }
        }

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strNameOriginal)) {
            // If the new 'action' element's name does not clash with other elements
            // add it to the collection
            //
            if (check == null) {
                processModel.getActionsEx().addAction(source);
            } else {
                // If a 'action' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateAction",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ACTION_EXISTS");
            }
        } else // Existing object
        {
            // If a 'action' element with the same name as the element's new name
            // already exists we have a problem...
            //
            if (check != null && !strNameOriginal.equals(source.getName())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateAction",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ACTION_EXISTS");
            }

            // Update the action attributes
            //
            action = processModel.getActionsEx().getAction(strNameOriginal);
            action.setName(source.getName());
            action.setForm(source.getForm());
            action.setKind(source.getKind());
        }
    }

    /**
    * Remove the action specified
    *
    * @param strActionName the name of the action
    * @throws WorkflowException if the action cannot be found
    * @throws WorkflowDesignerException if the action is referenced elsewhere
    */
    public void removeAction(String strActionName) throws WorkflowException, WorkflowDesignerException {
        States states = processModel.getStatesEx();

        // check if this action is referenced in states
        //
        if (states != null) {
            Iterator<State> iterState = states.iterateState();
            while (iterState.hasNext()) {
                State state = iterState.next();

                // Might be a timeout action
                //
                if (state.getTimeoutAction() != null && state.getTimeoutAction().getName().equals(strActionName)) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeAction",
                            SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                            "state : '" + state.getName() + "' (timeoutAction : '" + strActionName + "')");
                }
                AllowedActions allowedActions = state.getAllowedActionsEx();

                // or it might be an allowed action
                //
                if (allowedActions != null) {
                    if (allowedActions.getAllowedAction(strActionName) != null) {
                        throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeAction",
                                SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                                "state : '" + state.getName() + "' (allowedAction : '" + strActionName + "')");
                    }
                }
            }
        }

        processModel.getActionsEx().removeAction(strActionName);

        // Was this the last action defined?
        //
        if (!processModel.getActionsEx().iterateAction().hasNext()) {
            processModel.setActions(null);
        }
    }

    /**
    * Update or insert a new consequence element of the cached process model
    *
    * @param source the reference object
    * @param strContext the context of Consequence
    * @throws WorkflowDesignerException when something goes wrong
    * @throws WorkflowException when something goes wrong
    */
    public void updateConsequence(Consequence source, String strContext)
            throws WorkflowDesignerException, WorkflowException {
        Action action = findAction(strContext);
        Consequences consequences = action.getConsequences();
        int idxCheck = -1, idxConsequence = Integer.parseInt(strContext.substring(strContext.lastIndexOf('/') + 1));

        // If it's a new object the 'Consequences' may not yet exits
        //
        if (consequences == null) {
            consequences = action.createConsequences();
            action.setConsequences(consequences);
        } else {
            // Check if identical consequence exists
            idxCheck = consequences.getConsequenceList().indexOf(source);
        }

        // Is it a new object or an existing one?
        //
        if (consequences.getConsequenceList().size() == idxConsequence) {
            // If the new 'consequence' element's condition does not clash with other
            // elements
            // add it to the collection
            //
            if (idxCheck < 0) {
                consequences.addConsequence(source);
            } else {
                // If a 'consequence' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateConsequence",
                        SilverpeasException.ERROR, "workflowDesigner.EX_CONSEQUENCE_EXISTS");
            }
        } else // Existing object
        {
            Consequence consequence; // the consequence being updated

            // If a different 'consequence' element with the same attributes
            // already exists we have a problem...
            //
            if (idxCheck >= 0 && idxCheck != idxConsequence) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateConsequence",
                        SilverpeasException.ERROR, "workflowDesigner.EX_CONSEQUENCE_EXISTS");
            }

            // Update the consequence attributes
            // get the consequence by number, replace it with the source one, updating
            // the source...
            //
            consequence = consequences.getConsequenceList().set(idxConsequence, source);
            source.setNotifiedUsers(consequence.getNotifiedUsers());
        }
    }

    /**
    * Move the consequence specified by the context inside the collection
    *
    * @param strContext the context of the consequence
    * @param iConsequence the current index of the consequence in the collection
    * @param nDirection the offset and the direction to move by
    * @throws WorkflowDesignerException if the consequence cannot be found.
    */
    public void moveConsequence(String strContext, int iConsequence, int nDirection)
            throws WorkflowDesignerException {
        try {
            Action action = findAction(strContext);
            Consequences consequences = action.getConsequences();

            // Move the consequence within the consequences collection
            //
            if (consequences != null) {
                Consequence consequence = consequences.getConsequenceList().remove(iConsequence);
                consequences.getConsequenceList().add(iConsequence + nDirection, consequence);
            }
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.moveConsequence",
                    SilverpeasException.ERROR, "workflowDesigner.EX_CONSEQUENCE_NOT_FOUND");
        }
    }

    /**
    * Remove the consequence specified by the context
    *
    * @param strContext the context of the consequence
    * @throws WorkflowDesignerException if the consequence cannot be found.
    */
    public void removeConsequence(String strContext) throws WorkflowDesignerException {
        try {
            Action action = findAction(strContext);
            Consequences consequences = action.getConsequences();
            int idxConsequence = Integer.parseInt(strContext.substring(strContext.lastIndexOf('/') + 1));
            // If it is the last consequence to be removed, remove the consequences
            // object as well...
            if (consequences.getConsequenceList().size() == 1) {
                action.setConsequences(null);
            } else {
                consequences.getConsequenceList().remove(idxConsequence);
            }
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeConsequence",
                    SilverpeasException.ERROR, "workflowDesigner.EX_CONSEQUENCE_NOT_FOUND");
        }
    }

    /**
    * Create a new form object to be added to the model
    *
    * @return an object implementing Form
    */
    public Form createForm() {
        Forms forms = processModel.getForms();
        Form form;

        if (forms == null) {
            forms = processModel.createForms();
            processModel.setForms(forms);
        }

        form = forms.createForm();
        form.setName(NEW_ELEMENT_NAME);
        return form;
    }

    /**
    * Find the form by context
    *
    * @param strContext the context
    * @return a Form object
    */
    public Form findForm(String strContext) {
        String[] astrElements;
        String strRoleName;
        Form form = null;

        if (strContext != null) {
            astrElements = strContext.split("[,/\\[\\]]", -2);

            try {
                if (FORMS.equals(astrElements[0])) {
                    if ("".equals(astrElements[2])) {
                        strRoleName = null;
                    } else {
                        strRoleName = astrElements[2];
                    }

                    form = processModel.getForms().getForm(astrElements[1], strRoleName);
                }
            } catch (RuntimeException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            }
        }
        return form;
    }

    /**
    * Update Form referenced by the context.
    *
    * @param source the object carrying the new values
    * @param strContext the context of the form being updated
    * @param strNameOriginal the original name of the form
    * @throws WorkflowDesignerException when the update goes wrong
    */
    public void updateForm(Form source, String strContext, String strNameOriginal, String strRoleOriginal)
            throws WorkflowDesignerException {
        Form form = null;

        Form check = processModel.getForms().getForm(source.getName(), source.getRole());

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strNameOriginal)) {
            // If the new 'Form' element does not clash with other elements
            // with the same name add it to the collection
            //
            if (check == null // or CHECK not really identical to source
                    || (source.getRole() != null && !source.getRole().equals(check.getRole()))) {
                // add the object to the collection;
                //
                processModel.getForms().addForm(source);
            } else {
                // If an 'Form' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateForm",
                        SilverpeasException.ERROR, "workflowDesigner.EX_FORM_EXISTS");
            }
        } else // Existing object
        {
            // If a different 'Form' element with the same name and role as the
            // element's new name
            // already exists we have a problem...
            // So if an object with the same attributes has been found ('check')
            // it should be the object that is being modified, just that the attribute
            // values did not change.
            // Therefore we compare all the attributes with their initial values.
            //
            if (check != null && (check.getRole() == null && source.getRole() == null // the
                    // "check's"
                    // name
                    // role
                    // &
                    // role
                    // are
                    // really
                    // ...
                    || source.getRole() != null && source.getRole().equals(check.getRole())) // ...
            // the
            // same
            // as
            // "source's";
                    && !(strNameOriginal.equals(source.getName()) // name & role didn't
                            // change
                            && (strRoleOriginal == null && source.getRole() == null
                                    || strRoleOriginal != null && strRoleOriginal.equals(source.getRole())))) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateForm",
                        SilverpeasException.ERROR, "workflowDesigner.EX_FORM_EXISTS");
            }

            // Update the form.
            //
            form = findForm(strContext);
            form.setName(source.getName());
            form.setRole(source.getRole());
            form.setHTMLFileName(source.getHTMLFileName());
        }
    }

    /**
    * Remove the form described by the context
    *
    * @param strContext the context
    * @throws WorkflowException if the form cannot be found
    * @throws WorkflowDesignerException if the form is referenced elsewhere
    */
    public void removeForm(String strContext) throws WorkflowException, WorkflowDesignerException {
        String[] astrElements;
        String strRoleName;

        if (strContext != null) {
            astrElements = strContext.split("[,/\\[\\]]", -2);

            try {
                if (FORMS.equals(astrElements[0])) {
                    if ("".equals(astrElements[2])) {
                        strRoleName = null;
                    } else {
                        strRoleName = astrElements[2];
                    }

                    // Check if the form is no referenced in actions
                    //
                    if (processModel.getActionsEx() != null) {
                        Iterator<Action> iterAction = processModel.getActionsEx().iterateAction();

                        while (iterAction.hasNext()) {
                            Action action = iterAction.next();

                            if (action.getForm() != null && astrElements[1].equals(action.getForm().getName())) {
                                throw new WorkflowDesignerException(
                                        "WorkflowDesignerSessionController.removeForm()", SilverpeasException.ERROR,
                                        "workflowDesigner.EX_ELEMENT_REFERENCED",
                                        "action: '" + action.getName() + "' : form");
                            }
                        }
                    }

                    processModel.getForms().removeForm(astrElements[1], strRoleName);

                    // Was this the last form?
                    //
                    if (!processModel.getForms().iterateForm().hasNext()) {
                        processModel.setForms(null);
                    }
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                // Thrown when no token was found where expected
                // re-throw an exception
                //
                throw new WorkflowException("WorkflowDesignerSessionController.removeForm",
                        SilverpeasException.ERROR, "workflowEngine.EX_FORM_NOT_FOUND", e);
            }
        }
    }

    /**
    * Find the input by context
    *
    * @param strContext the context
    * @return a Input object
    */
    public Input findInput(String strContext) {
        String[] astrElements;
        Input input = null;
        Form form = findForm(strContext);

        if (form != null) {
            astrElements = strContext.split("[,/\\[\\]]", -2);

            try {
                if (astrElements[5].length() > 0) {
                    input = form.getInput(Integer.parseInt(astrElements[5]));
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            } catch (NumberFormatException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            }
        }
        return input;
    }

    /**
    * Update or insert a new input element of the cached process model
    *
    * @param source the reference object
    * @param strContext the context of Input
    * @throws WorkflowDesignerException when something goes wrong
    */
    public void updateInput(Input source, String strContext) throws WorkflowDesignerException {
        Form form = findForm(strContext);
        Input check;
        Input input = findInput(strContext); // the input being updated

        // Check if identical input exists
        //
        check = form.getInput(source);

        // Is it a new object or an existing one?
        //
        if (input == null) {
            // If the new 'input' element's is not identical with other element
            // add it to the collection
            //
            if (check == null) {
                form.addInput(source);
            } else {
                // If a 'input' element with the same item/value as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateInput",
                        SilverpeasException.ERROR, "workflowDesigner.EX_INPUT_EXISTS");
            }
        } else // Existing object
        {
            // If a different 'input' element with the same attributes
            // already exists we have a problem...
            //
            if (check != null && check != input) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateInput",
                        SilverpeasException.ERROR, "workflowDesigner.EX_INPUT_EXISTS");
            }

            // Update the input attributes
            //
            input.setDisplayerName(source.getDisplayerName());
            input.setItem(source.getItem());
            input.setMandatory(source.isMandatory());
            input.setReadonly(source.isReadonly());
            input.setValue(source.getValue());
        }
    }

    /**
    * Remove the input specified by the context
    *
    * @param strContext the context of the input
    * @throws WorkflowDesignerException if the input cannot be found.
    * @throws WorkflowException if the input cannot be found
    */
    public void removeInput(String strContext) throws WorkflowDesignerException, WorkflowException {
        Form form = findForm(strContext);
        String[] astrElements;

        if (form != null) {
            astrElements = strContext.split("[,/\\[\\]]", -2);

            try {
                if (astrElements[5].length() > 0) {
                    form.removeInput(Integer.parseInt(astrElements[5]));
                    return;
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                // Thrown when no token was found where expected
                //
            } catch (NumberFormatException e) {
                // Thrown when the token could not have been interpreted
                //
            }
        }

        throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeInput",
                SilverpeasException.ERROR, "workflowDesigner.EX_INPUT_NOT_FOUND");
    }

    /**
    * Create a new ContextualDesignation object to be added to the model
    *
    * @return an object implementing ContextualDesignation
    */
    public ContextualDesignation createDesignation() {
        ContextualDesignation designation = processModel.createDesignation();

        designation.setLanguage(NEW_ELEMENT_NAME);
        return designation;
    }

    /**
    * Update or insert a new ContextualDesignation element of the cached process model
    *
    * @param strContext
    * @param source the reference object
    * @param strLangOriginal
    * @param strRoleOriginal
    * @throws WorkflowDesignerException
    */
    public void updateContextualDesignations(String strContext, ContextualDesignation source,
            String strLangOriginal, String strRoleOriginal) throws WorkflowDesignerException {
        ContextualDesignations designations = findContextualDesignations(strContext);
        ContextualDesignation check = designations.getSpecificLabel(source.getRole(), source.getLanguage());

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strLangOriginal)) {
            // If the new 'ContextualDesignation' element does not clash with other
            // elements
            // with the same role & language add it to the collection
            //
            if (check == null) {
                designations.addContextualDesignation(source);
            } else {
                // If a 'ContextualDesignation' element with the same role & language as
                // the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException(
                        "WorkflowDesignerSessionController.updateContextualDesignations", SilverpeasException.ERROR,
                        "workflowDesigner.EX_CONTEXTUAL_DESIGNATION_EXISTS");
            }
        } else // Existing object
        {
            // If a different 'ContextualDesignation' element with the same role &
            // language as the element's new name
            // already exists we have a problem...
            //
            if (check != null && !(strLangOriginal.equals(source.getLanguage())
                    && strRoleOriginal.equals(source.getRole()))) {
                throw new WorkflowDesignerException(
                        "WorkflowDesignerSessionController.updateContextualDesignations", SilverpeasException.ERROR,
                        "workflowDesigner.EX_CONTEXTUAL_DESIGNATION_EXISTS");
            }

            // Update the contextual designation
            //
            check = designations.getSpecificLabel(strRoleOriginal, strLangOriginal);
            check.setRole(source.getRole());
            check.setLanguage(source.getLanguage());
            check.setContent(source.getContent());
        }
    }

    /**
    * Finds the contextual designation with the given attributes in the specified context
    *
    * @param strContext the context of the designation
    * @param strLanguage the language
    * @param strRole the role name
    * @return contextual designation of the given role & name or <code>null</code>
    * @throws WorkflowDesignerException if something goes wrong
    */
    public ContextualDesignation findContextualDesignation(String strContext, String strRole, String strLanguage)
            throws WorkflowDesignerException {
        return findContextualDesignations(strContext).getSpecificLabel(strRole, strLanguage);
    }

    /**
    * Removes the contextual designation with the attributes as the reference object in the specified
    * context
    *
    * @param strContext the context of the designation
    * @param contextualDesignation the reference object
    * @throws WorkflowDesignerException when something goes wrong e.g. designation not found
    */
    public void removeContextualDesignation(String strContext, ContextualDesignation contextualDesignation)
            throws WorkflowDesignerException {
        try {
            findContextualDesignations(strContext).removeContextualDesignation(contextualDesignation);
        } catch (WorkflowException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeContextualDesignation",
                    SilverpeasException.ERROR, "workflowDesigner.EX_CONTEXTUAL_DESIGNATION_NOT_FOUND");
        }
    }

    /**
    * Finds the contextual designations object in the specified context
    *
    * @param strContext the context of the designations
    * @return ContextualDesignations collection or <code>null</code> if nothing found
    * @throws WorkflowDesignerException when something goes wrong
    */
    private ContextualDesignations findContextualDesignations(String strContext) throws WorkflowDesignerException {
        StringTokenizer strtok;
        String strElement;
        ContextualDesignations designations = null;

        if (strContext != null) {
            try {
                strtok = new StringTokenizer(strContext, "/[]@'=,");

                if (strtok.hasMoreTokens()) {
                    strElement = strtok.nextToken();

                    if (LABELS.equals(strElement)) {
                        designations = processModel.getLabels();
                    } else if (DESCRIPTIONS.equals(strElement)) {
                        designations = processModel.getDescriptions();
                    } else if (ROLES.equals(strElement)) {
                        Role role;
                        strElement = strtok.nextToken();
                        role = processModel.getRolesEx().getRole(strElement);
                        strElement = strtok.nextToken();

                        if (LABELS.equals(strElement)) {
                            designations = role.getLabels();
                        } else if (DESCRIPTIONS.equals(strElement)) {
                            designations = role.getDescriptions();
                        }
                    } else if (PRESENTATION.equals(strElement)) {
                        strElement = strtok.nextToken();

                        if (TITLES.equals(strElement)) {
                            designations = processModel.getPresentation().getTitles();
                        }
                    } else if (PARTICIPANTS.equals(strElement)) {
                        Participant participant;
                        strElement = strtok.nextToken();
                        participant = processModel.getParticipantsEx().getParticipant(strElement);
                        strElement = strtok.nextToken();

                        if (LABELS.equals(strElement)) {
                            designations = participant.getLabels();
                        } else if (DESCRIPTIONS.equals(strElement)) {
                            designations = participant.getDescriptions();
                        }
                    } else if (STATES.equals(strElement)) {
                        State state;
                        strElement = strtok.nextToken();
                        state = processModel.getStatesEx().getState(strElement);
                        strElement = strtok.nextToken();

                        if (LABELS.equals(strElement)) {
                            designations = state.getLabels();
                        } else if (DESCRIPTIONS.equals(strElement)) {
                            designations = state.getDescriptions();
                        } else if (ACTIVITIES.equals(strElement)) {
                            designations = state.getActivities();
                        }
                    } else if (ACTIONS.equals(strElement)) {
                        Action action;
                        strElement = strtok.nextToken();
                        action = processModel.getActionsEx().getAction(strElement);
                        strElement = strtok.nextToken();

                        if (LABELS.equals(strElement)) {
                            designations = action.getLabels();
                        } else if (DESCRIPTIONS.equals(strElement)) {
                            designations = action.getDescriptions();
                        }
                    } else if (USER_INFOS.equals(strElement)) {
                        Item item;
                        strElement = strtok.nextToken();
                        item = processModel.getUserInfos().getItem(strElement);
                        strElement = strtok.nextToken();

                        if (LABELS.equals(strElement)) {
                            designations = item.getLabels();
                        } else if (DESCRIPTIONS.equals(strElement)) {
                            designations = item.getDescriptions();
                        }
                    } else if (DATA_FOLDER.equals(strElement)) {
                        Item item;
                        strElement = strtok.nextToken();
                        item = processModel.getDataFolder().getItem(strElement);
                        strElement = strtok.nextToken();

                        if (LABELS.equals(strElement)) {
                            designations = item.getLabels();
                        } else if (DESCRIPTIONS.equals(strElement)) {
                            designations = item.getDescriptions();
                        }
                    } else if (FORMS.equals(strElement)) {
                        Form form;
                        String strFormName;

                        strFormName = strtok.nextToken();
                        strElement = strtok.nextToken();

                        // If the next token is not a keyword, must be the optional role
                        // name
                        // eg. forms[form-name,role-name]/titles
                        //
                        if (!TITLES.equals(strElement) && !INPUTS.equals(strElement)) {
                            form = processModel.getForms().getForm(strFormName, strElement);
                        } else {
                            form = processModel.getForms().getForm(strFormName);
                        }

                        if (TITLES.equals(strElement)) {
                            designations = form.getTitles();
                        } else if (INPUTS.equals(strElement)) {
                            Input input;
                            strElement = strtok.nextToken();
                            input = form.getInputs()[Integer.parseInt(strElement)];

                            if (LABELS.equals(strElement)) {
                                designations = input.getLabels();
                            }
                        }

                    }
                }
            } catch (RuntimeException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            } catch (WorkflowException e) {
                // Throw when no action has been found,
                // do nothing, just return null...
            }
        }

        if (designations == null) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.getContextualDesignations",
                    SilverpeasException.ERROR, "workflowDesigner.EX_CONTEXTUAL_DESIGNATIONS_NOT_FOUND");
        }
        return designations;
    }

    /**
    * Collect all the object of the type ContextualDesignations instantiated in the Process Model
    *
    * @return a map, where the key is the reference to the object and the value is a textual
    * description of the object location
    */
    private Map<ContextualDesignations, String> collectContextualDesignations() {
        Map<ContextualDesignations, String> map = new IdentityHashMap<ContextualDesignations, String>();
        Roles roles = processModel.getRolesEx();

        // Process Model Labels & Descriptions
        //
        map.put(processModel.getDescriptions(), "processModel: " + DESCRIPTIONS);
        map.put(processModel.getLabels(), "processModel: " + LABELS);

        // Role Labels & Descriptions
        //
        if (roles != null) {
            Iterator<Role> iterRole = roles.iterateRole();
            while (iterRole.hasNext()) {
                Role role = iterRole.next();
                map.put(role.getDescriptions(), "role: '" + role.getName() + "' : description");
                map.put(role.getLabels(), "role: '" + role.getName() + "' : label");
            }
        }

        // Presentation - titles
        //
        if (processModel.getPresentation() != null) {
            map.put(processModel.getPresentation().getTitles(),
                    WorkflowDesignerSessionController.PRESENTATION + ": title");
        }

        // Participants
        //
        if (processModel.getParticipantsEx() != null) {
            Iterator<Participant> iterParticipant = processModel.getParticipantsEx().iterateParticipant();

            while (iterParticipant.hasNext()) {
                Participant participant = iterParticipant.next();
                map.put(participant.getDescriptions(),
                        "participant: '" + participant.getName() + "' : description");
                map.put(participant.getLabels(), "participant: '" + participant.getName() + "' : label");
            }
        }

        // States
        //
        if (processModel.getStatesEx() != null) {
            Iterator<State> iterState = processModel.getStatesEx().iterateState();
            while (iterState.hasNext()) {
                State state = iterState.next();
                map.put(state.getDescriptions(), "state: '" + state.getName() + "' : description");
                map.put(state.getLabels(), "state: '" + state.getName() + "' : label");
                map.put(state.getActivities(), "state: '" + state.getName() + "' : activity");
            }
        }

        // Actions
        //
        if (processModel.getActionsEx() != null) {
            Iterator<Action> iterAction = processModel.getActionsEx().iterateAction();
            while (iterAction.hasNext()) {
                Action action = iterAction.next();
                map.put(action.getDescriptions(), "action: '" + action.getName() + "' : description");
                map.put(action.getLabels(), "action: '" + action.getName() + "' : label");
            }
        }

        // UserInfos
        //
        if (processModel.getUserInfos() != null) {
            Iterator<Item> iterItem = processModel.getUserInfos().iterateItem();
            while (iterItem.hasNext()) {
                Item item = iterItem.next();
                map.put(item.getDescriptions(), "userInfos item: '" + item.getName() + "' : description");
                map.put(item.getLabels(), "userInfos item: '" + item.getName() + "' : label");
            }
        }

        // DataFolder
        //
        if (processModel.getDataFolder() != null) {
            Iterator<Item> iterItem = processModel.getDataFolder().iterateItem();
            while (iterItem.hasNext()) {
                Item item = iterItem.next();
                map.put(item.getDescriptions(), "dataFolder item: '" + item.getName() + "' : description");
                map.put(item.getLabels(), "dataFolder item: '" + item.getName() + "' : label");
            }
        }

        // Forms
        //
        if (processModel.getForms() != null) {
            Iterator<Form> iterForm = processModel.getForms().iterateForm();

            while (iterForm.hasNext()) {
                Form form = iterForm.next();
                String strFormId;
                if (form.getRole() == null) {
                    strFormId = "form: '" + form.getName() + "'";
                } else {
                    strFormId = "form [ name: '" + form.getName() + "', role: '" + form.getRole() + "' ]";
                }
                map.put(form.getTitles(), strFormId + " : title");
                Iterator<Input> iterInput = form.iterateInput();
                while (iterInput.hasNext()) {
                    Input input = iterInput.next();
                    map.put(input.getLabels(), strFormId + " : input"
                            + (input.getItem() == null ? ""
                                    : (" " + "[ item: '" + input.getItem().getName() + "' ] : label"))
                            + (input.getValue() == null ? "" : (" [ value: '" + input.getValue() + "' ] : label")));
                }
            }
        }

        return map;
    }

    /**
    * Create a new item object to be added to the model
    *
    * @return an object implementing Item
    */
    public Item createItem(String strContext) {
        Item item = null;
        if (strContext != null) {
            String[] astrElements = strContext.split("[,/\\[\\]]");
            if (USER_INFOS.equals(astrElements[0])) {
                DataFolder items = processModel.getUserInfos();

                if (items == null) {
                    items = processModel.createDataFolder();
                    processModel.setUserInfos(items);
                }
                item = items.createItem();
                item.setName(NEW_ELEMENT_NAME);
            } else if (DATA_FOLDER.equals(astrElements[0])) {
                DataFolder items = processModel.getDataFolder();

                if (items == null) {
                    items = processModel.createDataFolder();
                    processModel.setDataFolder(items);
                }
                item = items.createItem();
                item.setName(NEW_ELEMENT_NAME);
            }
        }
        return item;
    }

    /**
    * Find the Item specified by the context
    *
    * @param strContext the context
    * @return an Item object or <code>null</code>
    */
    public Item findItem(String strContext) {
        Item item = null;
        if (strContext != null) {
            StringTokenizer strtok = new StringTokenizer(strContext, CONTEXT_DELIMS);
            try {
                String strElement = strtok.nextToken();
                if (DATA_FOLDER.equals(strElement)) {
                    strElement = strtok.nextToken();
                    item = processModel.getDataFolder().getItem(strElement);
                } else if (USER_INFOS.equals(strElement)) {
                    strElement = strtok.nextToken();
                    item = processModel.getUserInfos().getItem(strElement);
                }
            } catch (NoSuchElementException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            }
        }
        return item;
    }

    /**
    * Update Item referenced by the context.
    *
    * @param source the object carrying the new values
    * @param strContext the context of the item being updated
    * @param strNameOriginal the original name of the item
    * @throws WorkflowDesignerException when the update goes wrong
    */
    public void updateItem(Item source, String strContext, String strNameOriginal)
            throws WorkflowDesignerException {
        Item item, check = null;
        String strCollection = "";
        int idx = strContext.indexOf("/");

        if (idx > 0) {
            strCollection = strContext.substring(0, idx);
        }

        // Look for an object with the same name...
        if (DATA_FOLDER.equals(strCollection)) {
            check = processModel.getDataFolder().getItem(source.getName());
        } else if (USER_INFOS.equals(strCollection)) {
            check = processModel.getUserInfos().getItem(source.getName());
        }

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strNameOriginal)) {
            // If the new 'Item' element does not clash with other elements
            // with the same name add it to the collection
            //
            if (check == null) {
                // add the object to the appropriate collection;
                //
                if (DATA_FOLDER.equals(strCollection)) {
                    processModel.getDataFolder().addItem(source);
                } else if (USER_INFOS.equals(strCollection)) {
                    processModel.getUserInfos().addItem(source);
                }
            } else {
                // If an 'Item' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateItem",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ITEM_EXISTS");
            }
        } else // Existing object
        {
            // If a different 'Item' element with the same name as the element's new
            // name
            // already exists we have a problem...
            //
            if (check != null && !strNameOriginal.equals(source.getName())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateItem",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ITEM_EXISTS");
            }

            // Update the item.
            //
            item = findItem(strContext);
            item.setName(source.getName());
            item.setComputed(source.isComputed());
            item.setFormula(source.getFormula());
            item.setMapTo(source.getMapTo());
            item.setReadonly(source.isReadonly());
            item.setType(source.getType());
        }
    }

    /**
    * Remove the item described by the context
    *
    * @param strContext the context
    * @throws WorkflowException when the item cannot be found
    * @throws WorkflowDesignerException when the item is referenced elsewhere
    */
    public void removeItem(String strContext) throws WorkflowException, WorkflowDesignerException {
        String strItemName = null;
        DataFolder items;

        if (strContext == null) {
            throw new WorkflowException("WorkflowDesignerSessionController.removeItem()",
                    "workflowEngine.EX_ITEM_NOT_FOUND"); // $NON-NLS-1$
        }
        StringTokenizer strtok = new StringTokenizer(strContext, CONTEXT_DELIMS);

        // Determine the item name and the collection to remove from
        //
        try {
            String strElement = strtok.nextToken();

            if (DATA_FOLDER.equals(strElement)) {
                strItemName = strtok.nextToken();
                items = processModel.getDataFolder();
            } else if (USER_INFOS.equals(strElement)) {
                strItemName = strtok.nextToken();
                items = processModel.getUserInfos();
            } else {
                throw new WorkflowException("WorkflowDesignerSessionController.removeItem()",
                        "workflowEngine.EX_ITEM_NOT_FOUND", // $NON-NLS-1$
                        strItemName == null ? "<null>" : strItemName);
            }
        } catch (NoSuchElementException e) {
            throw new WorkflowException("WorkflowDesignerSessionController.removeItem()",
                    "workflowEngine.EX_ITEM_NOT_FOUND", e); // $NON-NLS-1$
        }

        // check if the item is not referenced elsewhere...
        //
        // ... if it is a UserInfos item...
        //
        if (items == processModel.getUserInfos()) {
            // ... in UserInfos
            //
            if (processModel.getUserInfos() != null) {
                Iterator<Item> iterItem = processModel.getUserInfos().iterateItem();

                while (iterItem.hasNext()) {
                    Item item = iterItem.next();

                    if (strItemName.equals(item.getMapTo()) && !strItemName.equals(item.getName())) {
                        throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeItem()",
                                SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                                "userInfos item: '" + item.getName() + "' : mapTo");
                    }
                }
            }

            // ... in DataFolder
            //
            if (processModel.getDataFolder() != null) {
                Iterator<Item> iterItem = processModel.getDataFolder().iterateItem();

                while (iterItem.hasNext()) {
                    Item item = iterItem.next();

                    if (strItemName.equals(item.getMapTo())) {
                        throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeItem()",
                                SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                                "dataFolder item: '" + item.getName() + "' : mapTo");
                    }
                }
            }
        } else if (items == processModel.getDataFolder()) {
            // ... if it is a dataFolder item ...
            //
            // ... in Columns
            //
            if (processModel.getPresentation() != null) {
                Iterator<Columns> iterColumns = processModel.getPresentation().iterateColumns();

                while (iterColumns.hasNext()) {
                    Columns columns = iterColumns.next();

                    if (columns.getColumn(strItemName) != null) {
                        throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeItem()",
                                SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                                "presentation, (columns: '" + columns.getRoleName() + "')");
                    }
                }
            }

            // ... in Consequence
            //
            // Check if this state is not referenced in Actions' consequences
            //
            if (processModel.getActionsEx() != null) {
                Consequences consequences;
                Iterator<Action> iterAction = processModel.getActionsEx().iterateAction();

                while (iterAction.hasNext()) {
                    Action action = iterAction.next();

                    consequences = action.getConsequences();

                    if (consequences != null) {
                        Iterator<Consequence> iterConsequence = consequences.iterateConsequence();

                        while (iterConsequence.hasNext()) {
                            Consequence consequence = iterConsequence.next();

                            if (strItemName.equals(consequence.getItem())) {
                                throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeItem",
                                        SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                                        "action : '" + action.getName() + "' (item : '" + strItemName + "')");
                            }
                        }
                    }
                }
            }

            // ... in Input (in Forms)
            //
            if (processModel.getForms() != null) {
                Iterator<Form> iterForm = processModel.getForms().iterateForm();
                String strFormId;

                while (iterForm.hasNext()) {
                    Form form = iterForm.next();
                    if (form.getRole() == null) {
                        strFormId = "form: '" + form.getName() + "'";
                    } else {
                        strFormId = "form [ name: '" + form.getName() + "', role: '" + form.getRole() + "' ]";
                    }

                    // Inputs
                    //
                    Iterator<Input> iterInput = form.iterateInput();

                    while (iterInput.hasNext()) {
                        Input input = iterInput.next();

                        if (input.getItem() != null && strItemName.equals(input.getItem().getName())) {
                            throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeItem",
                                    SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                                    strFormId + " : input" + " [ item: '" + strItemName + "' ]");
                        }
                    }
                }
            }
        }

        // ... and in both cases in relatedUsers ( in Qualified users )
        //
        Map<QualifiedUsers, String> mapQualifiedUsers = collectQualifiedUsers();

        for (QualifiedUsers qualifiedUsers : mapQualifiedUsers.keySet()) {
            // in Related Users
            Iterator<RelatedUser> iterRelatedUser = qualifiedUsers.iterateRelatedUser();

            while (iterRelatedUser.hasNext()) {
                RelatedUser relatedUser = iterRelatedUser.next();

                // if it is a dataFolder item check relatedUsers' folder Item
                // If it is a userInfos item check relatedUsers' relation
                //
                if ((items == processModel.getDataFolder() && relatedUser.getFolderItem() != null
                        && strItemName.equals(relatedUser.getFolderItem().getName()))
                        || (items == processModel.getUserInfos()
                                && strItemName.equals(relatedUser.getRelation()))) {
                    throw new WorkflowDesignerException("WorkflowDesignerSessionController.removeItem()",
                            SilverpeasException.ERROR, "workflowDesigner.EX_ELEMENT_REFERENCED",
                            mapQualifiedUsers.get(qualifiedUsers) + " (relatedUser: ["
                                    + (relatedUser.getParticipant() == null ? ""
                                            : (" participant: '" + relatedUser.getParticipant().getName() + "'"))
                                    + (relatedUser.getFolderItem() == null ? ""
                                            : (" folderItem: '" + relatedUser.getFolderItem().getName() + "'"))
                                    + (relatedUser.getRelation() == null ? ""
                                            : (" relation: '" + relatedUser.getRelation() + "'"))
                                    + (relatedUser.getRole() == null ? ""
                                            : (" role: '" + relatedUser.getRole() + "'"))
                                    + " ])");
                }
            }
        }

        items.removeItem(strItemName);

        // Was this the last item?
        //
        if (!items.iterateItem().hasNext()) {
            processModel.setUserInfos(null);
        }
    }

    /**
    * Update Parameter referenced by the context and parameter name.
    *
    * @param source the object carrying the new values
    * @param strContext the context of the item being updated
    * @param strNameOriginal the original name of the parameter
    * @throws WorkflowDesignerException when the update goes wrong
    */
    public void updateParameter(Parameter source, String strContext, String strNameOriginal)
            throws WorkflowDesignerException {
        Item item = findItem(strContext);
        // Look for an object with the same name...
        Parameter check = item.getParameter(source.getName());

        // Is it a new object or an existing one?
        //
        if (NEW_ELEMENT_NAME.equals(strNameOriginal)) {
            // If the new 'Parameter' element does not clash with other elements
            // with the same name add it to the collection
            //
            if (check == null) {
                item.addParameter(source);
            } else {
                // If a 'Parameter' element with the same name as the new element
                // already exists we have a problem...
                //
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateParameter",
                        SilverpeasException.ERROR, "workflowDesigner.EX_PARAMETER_EXISTS");
            }
        } else {// Existing object
            // If a different 'Parameter' element with the same name as the element's
            // new name already exists we have a problem...
            if (check != null && !strNameOriginal.equals(source.getName())) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.updateParameter",
                        SilverpeasException.ERROR, "workflowDesigner.EX_PARAMETER_EXISTS");
            }
            // Update the parameter.
            Parameter parameter = item.getParameter(strNameOriginal);
            parameter.setName(source.getName());
            parameter.setValue(source.getValue());
        }
    }

    /**
    * Remove the parameter described by the context and name
    *
    * @param strContext the context
    * @param strName the name of the parameter
    * @throws WorkflowException
    */
    public void removeParameter(String strContext, String strName) throws WorkflowException {
        Item item = findItem(strContext);
        item.removeParameter(strName);
    }

    /**
    * Find the QualifiedUsers specified by the context
    *
    * @param strContext the context
    * @return a QualifiedUsers object or <code>null</code>
    */
    public QualifiedUsers findQualifiedUsers(String strContext) throws WorkflowException {
        StringTokenizer strtok;
        String strElement;
        QualifiedUsers qualifiedUsers = null;

        if (strContext != null) {
            strtok = new StringTokenizer(strContext, "/");

            try {
                if (strtok.hasMoreTokens()) {
                    strElement = strtok.nextToken();

                    if (STATES.equals(strElement)) {
                        State state;

                        strElement = strtok.nextToken();
                        state = processModel.getStatesEx().getState(strElement);
                        strElement = strtok.nextToken();

                        if (WORKING_USERS.equals(strElement)) {
                            qualifiedUsers = state.getWorkingUsersEx();
                        } else if (INTERESTED_USERS.equals(strElement)) {
                            qualifiedUsers = state.getInterestedUsersEx();
                        }
                    } else if (ACTIONS.equals(strElement)) {
                        Action action;

                        strElement = strtok.nextToken();
                        action = processModel.getActionsEx().getAction(strElement);
                        strElement = strtok.nextToken();

                        if (ALLOWED_USERS.equals(strElement)) {
                            qualifiedUsers = action.getAllowedUsers();
                        } else if (CONSEQUENCES.equals(strElement)) {
                            // notifiedUsers
                            strElement = strtok.nextToken(); // consequence no.
                            Consequence consequence = action.getConsequences().getConsequenceList()
                                    .get(Integer.parseInt(strElement));
                            strElement = strtok.nextToken(); // notified users

                            if (NOTIFIED_USERS.equals(strElement)) {
                                int i = -1;
                                try {
                                    strElement = strtok.nextToken(); // id of notified users
                                    i = Integer.parseInt(strElement);
                                } catch (NoSuchElementException e) {
                                    //no id defined, it's a creation
                                }

                                List<QualifiedUsers> qualifiedUsersList = consequence.getNotifiedUsers();
                                if (i != -1 && qualifiedUsersList != null && !qualifiedUsersList.isEmpty()) {
                                    qualifiedUsers = qualifiedUsersList.get(i);
                                } else {
                                    qualifiedUsers = null;
                                }
                            }
                        }
                    }
                }
            } catch (NoSuchElementException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            } catch (ArrayIndexOutOfBoundsException e) {
                // Thrown when no consequence was found at the specified index
                // do nothing, just return null...
            } catch (NumberFormatException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            }
        }
        return qualifiedUsers;
    }

    /**
    * Set the QualifiedUsers specified by the context to the given value
    *
    * @param qualifiedUsers the new value of qualified users
    * @param strContext the context
    * @throws WorkflowDesignerException When the qualified users' parent could not be found
    */
    public void setQualifiedUsers(QualifiedUsers qualifiedUsers, String strContext)
            throws WorkflowException, WorkflowDesignerException {
        if (strContext != null) {
            StringTokenizer strtok = new StringTokenizer(strContext, "/");

            try {
                if (strtok.hasMoreTokens()) {
                    String strElement = strtok.nextToken();

                    if (STATES.equals(strElement)) {
                        strElement = strtok.nextToken();
                        State state = processModel.getStatesEx().getState(strElement);
                        strElement = strtok.nextToken();

                        if (WORKING_USERS.equals(strElement)) {
                            state.setWorkingUsers(qualifiedUsers);
                        } else if (INTERESTED_USERS.equals(strElement)) {
                            state.setInterestedUsers(qualifiedUsers);
                        }
                    } else if (ACTIONS.equals(strElement)) {
                        strElement = strtok.nextToken();
                        Action action = processModel.getActionsEx().getAction(strElement);
                        strElement = strtok.nextToken();

                        if (ALLOWED_USERS.equals(strElement)) {
                            action.setAllowedUsers(qualifiedUsers);
                        } else if (CONSEQUENCES.equals(strElement)) {
                            // notifiedUsers
                            //
                            strElement = strtok.nextToken(); // consequence no.
                            Consequence consequence = action.getConsequences().getConsequenceList()
                                    .get(Integer.parseInt(strElement));
                            strElement = strtok.nextToken(); // notifiedUsers

                            if (NOTIFIED_USERS.equals(strElement)) {
                                if (qualifiedUsers == null) {
                                    try {
                                        strElement = strtok.nextToken(); // id of notified users
                                        int i = Integer.parseInt(strElement);
                                        consequence.getNotifiedUsers().remove(i);
                                    } catch (NoSuchElementException e) {
                                        //no id defined, it's a creation
                                    }
                                } else {
                                    consequence.addNotifiedUsers(qualifiedUsers);
                                }
                            }
                        }
                    }
                }
            } catch (RuntimeException e) {
                // Thrown when no token was found where expected
                // or the number coludn't to be interpreted,
                // or the index is out of bounds
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.setQualifiedUsers",
                        SilverpeasException.ERROR, "workflowDesigner.EX_QUALIFIED_USERS_NOT_FOUND");
            }
        }
    }

    /**
    * Collect all the objects of the type QalifiedUsers instantiated in the Process Model
    *
    * @return a map, where the key is the reference to the object and the value is a textual
    * description of the object location
    */
    private Map<QualifiedUsers, String> collectQualifiedUsers() {
        Map<QualifiedUsers, String> map = new IdentityHashMap<QualifiedUsers, String>();

        // States
        //
        if (processModel.getStatesEx() != null) {
            for (State state : processModel.getStatesEx().getStates()) {

                if (state.getWorkingUsersEx() != null) {
                    map.put(state.getWorkingUsersEx(), "state: '" + state.getName() + "' : workingUsers");
                }

                if (state.getInterestedUsersEx() != null) {
                    map.put(state.getInterestedUsersEx(), "state: '" + state.getName() + "' : interestedUsers");
                }
            }
        }

        // Actions
        //
        if (processModel.getActionsEx() != null) {
            Action action;
            Iterator<Action> iterAction = processModel.getActionsEx().iterateAction();

            while (iterAction.hasNext()) {
                action = iterAction.next();

                if (action.getAllowedUsers() != null) {
                    map.put(action.getAllowedUsers(), "action: '" + action.getName() + "' : allowedUsers");
                }

                if (action.getConsequences() != null) {
                    Iterator<Consequence> iterConsequence = action.getConsequences().iterateConsequence();

                    while (iterConsequence.hasNext()) {
                        Consequence consequence = iterConsequence.next();

                        List<QualifiedUsers> qualifiedUsersList = consequence.getNotifiedUsers();
                        if (qualifiedUsersList != null && !qualifiedUsersList.isEmpty()) {
                            map.put(qualifiedUsersList.get(0),
                                    "action: '" + action.getName() + "' : consequence: ["
                                            + (consequence.getItem() == null ? "Default"
                                                    : (" item: '" + consequence.getItem() + "', operator: '"
                                                            + consequence.getOperator() + "', value: '"
                                                            + consequence.getValue() + "'"))
                                            + " ]");
                        }
                    }
                }
            }
        }

        return map;
    }

    /**
    * Get the Action specified by the context
    *
    * @param strContext the context
    * @return an Action object or <code>null</code>
    */
    public Action findAction(String strContext) throws WorkflowException {
        StringTokenizer strtok;
        String strElement;
        Action action = null;

        if (strContext != null) {
            strtok = new StringTokenizer(strContext, "/");

            try {
                strElement = strtok.nextToken();

                if (ACTIONS.equals(strElement)) {
                    strElement = strtok.nextToken();
                    action = processModel.getActionsEx().getAction(strElement);
                }
            } catch (NoSuchElementException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            }
        }
        return action;
    }

    /**
    * Find the Consequence specified by the context
    *
    * @param strContext the context
    * @return an Consequence object or <code>null</code>
    */
    public Consequence findConsequence(String strContext) throws WorkflowException {
        StringTokenizer strtok;
        String strElement;
        Action action = findAction(strContext);
        Consequence consequence = null;

        if (strContext != null) {
            strtok = new StringTokenizer(strContext, "/");

            try {
                if (action != null) {
                    strElement = strtok.nextToken(); // actions/
                    strElement = strtok.nextToken(); // <name>
                    strElement = strtok.nextToken(); // consequences/
                    strElement = strtok.nextToken(); // <consequence-no>

                    consequence = action.getConsequences().getConsequenceList().get(Integer.parseInt(strElement));
                }
            } catch (NoSuchElementException e) {
                // Thrown when no token was found where expected
                // do nothing, just return null...
            } catch (NumberFormatException e) {
                // Thrown when token could not be interpreted
                // do nothing, just return null...
            } catch (ArrayIndexOutOfBoundsException e) {
                // Thrown when no consequence was found at the specified index
                // do nothing, just return null...
            }
        }
        return consequence;
    }

    /**
    * Returns the language codes as configured in the properties
    *
    * @param fDefault if <code>true</code> the 'default' option shall be included
    * @return an array of language codes
    */
    public String[] retrieveLanguageCodes(boolean fDefault) {
        StringTokenizer strtok = new StringTokenizer(getSettings().getString("languages"), ",");
        List<String> list = new ArrayList<String>(strtok.countTokens() + 1);
        if (fDefault) {
            list.add("default");
        }
        while (strtok.hasMoreTokens()) {
            list.add(strtok.nextToken());
        }

        return list.toArray(new String[list.size()]);
    }

    /**
    * Returns names of available languages as configured in the properties, localised for the current
    * user
    *
    * @param fDefault if <code>true</code> the 'default' option shall be included
    * @return an array of language names
    */
    public String[] retrieveLanguageNames(boolean fDefault) {
        StringTokenizer strtok = new StringTokenizer(getSettings().getString("languages"), ",");
        Locale locale = new Locale(getLanguage());
        List<String> list = new ArrayList<String>(strtok.countTokens() + 1);
        if (fDefault) {
            list.add(getString("workflowDesigner.default"));
        }
        while (strtok.hasMoreTokens()) {
            Locale inLocale = new Locale(strtok.nextToken());

            list.add(inLocale.getDisplayLanguage(locale));
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Returns the item type codes as configured in the properties
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @return an array of codes
    */
    public String[] retrieveItemTypeCodes(boolean fNone) {
        StringTokenizer strtok = new StringTokenizer(getSettings().getString("itemTypes"), ",");
        List<String> list = new ArrayList<String>(strtok.countTokens() + 1);
        if (fNone) {
            list.add("");
        }
        while (strtok.hasMoreTokens()) {
            list.add(strtok.nextToken());
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Returns a list of comparison operators as configured in the properties,
    *
    * @param fNone if <code>true</code> the 'none' option shall be included
    * @return an array of operators
    */
    public String[] retrieveOperators(boolean fNone) {
        StringTokenizer strtok = new StringTokenizer(getSettings().getString("operators"), ",");
        List<String> list = new ArrayList<String>(strtok.countTokens() + 1);

        if (fNone) {
            list.add("");
        }

        while (strtok.hasMoreTokens()) {
            list.add(strtok.nextToken());
        }

        return list.toArray(new String[list.size()]);
    }

    /**
    * Returns the action kind codes as configured in the properties retrieve
    *
    * @return an array of codes
    */
    public String[] retrieveActionKindCodes() {
        StringTokenizer strtok = new StringTokenizer(getSettings().getString("actionKinds"), ",");
        List<String> list = new ArrayList<String>(strtok.countTokens());
        while (strtok.hasMoreTokens()) {
            list.add(strtok.nextToken());
        }

        return list.toArray(new String[list.size()]);
    }

    /**
    * Returns the input displayer type codes as configured in the properties
    *
    * @return an array of codes
    */
    public String[] retrieveDisplayerNames() {
        StringTokenizer strtok = new StringTokenizer(getSettings().getString("displayerNames"), ",");
        List<String> list = new ArrayList<String>(strtok.countTokens() + 1);
        list.add("");
        while (strtok.hasMoreTokens()) {
            list.add(strtok.nextToken());
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Produce a list of action names
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @return an array of Strings or an empty array.
    */
    public String[] retrieveActionNames(boolean fNone) {
        List<String> list = new ArrayList<String>();
        Actions actions = getProcessModel().getActionsEx();
        if (fNone) {
            list.add("");
        }
        if (actions != null) {
            Iterator<Action> iterAction = actions.iterateAction();
            while (iterAction.hasNext()) {
                list.add(iterAction.next().getName());
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Produce a list of role names
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @param fDefault if <code>true</code> the 'default' option shall be included
    * @return an array of Strings or an empty array.
    */
    public String[] retrieveRoleNames(boolean fNone, boolean fDefault) {
        List<String> list = new ArrayList<String>();
        Roles roles = getProcessModel().getRolesEx();
        if (fNone) {
            list.add("");
        }
        if (fDefault) {
            list.add("default");
        }
        if (roles != null) {
            Iterator<Role> iterRole = roles.iterateRole();
            while (iterRole.hasNext()) {
                list.add(iterRole.next().getName());
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Produce a list of state names
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @return an array of Strings or an empty array.
    */
    public String[] retrieveStateNames(boolean fNone) {
        List<String> list = new ArrayList<String>();
        States states = getProcessModel().getStatesEx();
        if (fNone) {
            list.add("");
        }
        if (states != null) {
            Iterator<State> iterState = states.iterateState();
            while (iterState.hasNext()) {
                list.add(iterState.next().getName());
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Produce a list of participant names
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @return an array of Strings or an empty array.
    */
    public String[] retrieveParticipantNames(boolean fNone) {
        List<String> list = new ArrayList<String>();
        Participants participants = getProcessModel().getParticipantsEx();
        if (fNone) {
            list.add("");
        }
        if (participants != null) {
            Iterator<Participant> iterParticipant = participants.iterateParticipant();

            while (iterParticipant.hasNext()) {
                list.add(iterParticipant.next().getName());
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Produce a list of user info item names, optionally those where the type = 'user'
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @param fUsersOnly if <code>true</code> only the items of type 'user' shall be included
    * @return an array of Strings or an empty array.
    */
    public String[] retrieveUserInfoItemNames(boolean fNone, boolean fUsersOnly) {
        List<String> list = new ArrayList<String>();
        DataFolder userInfos = getProcessModel().getUserInfos();
        if (fNone) {
            list.add("");
        }
        if (userInfos != null) {
            Iterator<Item> iterInfosItem = userInfos.iterateItem();
            Item item;

            while (iterInfosItem.hasNext()) {
                item = iterInfosItem.next();
                if (!fUsersOnly || TYPE_USER.equals(item.getType())) {
                    list.add(item.getName());
                }
            }
        }

        return list.toArray(new String[list.size()]);
    }

    /**
    * Produce a list of data folder item names, optionally those where the type = 'user'
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @param fUsersOnly if <code>true</code> only the items of type 'user' shall be included
    * @return an array of Strings or an empty array.
    */
    public String[] retrieveFolderItemNames(boolean fNone, boolean fUsersOnly) {
        List<String> list = new ArrayList<String>();
        DataFolder dataFolder = getProcessModel().getDataFolder();

        if (fNone) {
            list.add("");
        }

        if (dataFolder != null) {
            Iterator<Item> iterFolderItem = dataFolder.iterateItem();
            Item item;

            while (iterFolderItem.hasNext()) {
                item = iterFolderItem.next();
                if (!fUsersOnly || TYPE_USER.equals(item.getType())) {
                    list.add(item.getName());
                }
            }
        }

        return list.toArray(new String[list.size()]);
    }

    /**
    * Produce a list of form names, only forms other than 'presentationForm' and 'printForm'
    *
    * @param fNone if <code>true</code> the 'None' option shall be included
    * @return an array of Strings or an empty array.
    */
    public String[] retrieveFormNames(boolean fNone) {
        Forms forms = getProcessModel().getForms();
        List<String> list = new ArrayList<String>();
        if (fNone) {
            list.add("");
        }

        if (forms != null) {
            Iterator<Form> iterForm = forms.iterateForm();

            while (iterForm.hasNext()) {
                String strName = iterForm.next().getName();

                if (!(FORM_TYPE_PRINT.equals(strName) || FORM_TYPE_PRESENTATION.equals(strName))) {
                    list.add(strName);
                }
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
    * Generates component descriptor file in the appropriate directory, reloads the cache to take the
    * new file into account, stores the new descriptor's name to be able to access it later
    *
    * @throws WorkflowDesignerException when something goes wrong
    */
    public void generateComponentDescriptor() throws WorkflowDesignerException {
        List<Profile> listSPProfile = new ArrayList<Profile>();
        List<com.silverpeas.admin.components.Parameter> spParameters = new ArrayList<com.silverpeas.admin.components.Parameter>();
        com.silverpeas.admin.components.Parameter spParameter = new com.silverpeas.admin.components.Parameter();
        spParameter.setName(ComponentsInstanciatorIntf.PROCESS_XML_FILE_NAME);
        spParameter.getLabel().put(I18NHelper.defaultLanguage,
                getSettings().getString("componentDescriptor.parameterLabel"));
        spParameter.getHelp().put(I18NHelper.defaultLanguage, "");
        spParameter.getWarning().put(I18NHelper.defaultLanguage, "");
        spParameter.setValue(processModelFileName.replaceAll("\\\\", "/"));
        spParameter.setMandatory(true);
        spParameter.setUpdatable("always");
        spParameter.setType("text");
        // Create the list of roles, to be placed as profiles in the component descriptor
        if (processModel.getRolesEx() != null) {
            // 'supervisor' must be present in the list
            if (processModel.getRolesEx().getRole("supervisor") == null) {
                listSPProfile.add(getSupervisorProfile());
            }

            for (Role role : processModel.getRolesEx().getRoles()) {
                Profile profile = new Profile();
                profile.setName(role.getName());
                Iterator<ContextualDesignation> labels = role.getLabels().iterateContextualDesignation();
                while (labels.hasNext()) {
                    ContextualDesignation label = labels.next();
                    profile.getLabel().put(getSureLanguage(label.getLanguage()), label.getContent());
                    profile.getHelp().put(getSureLanguage(label.getLanguage()), label.getContent());
                }
                listSPProfile.add(profile);
            }
        } else {
            listSPProfile.add(getSupervisorProfile());
        }

        WAComponent waComponent = new WAComponent();
        waComponent.setName(processModel.getName());
        Iterator<ContextualDesignation> labels = processModel.getLabels().iterateContextualDesignation();
        while (labels.hasNext()) {
            ContextualDesignation label = labels.next();
            waComponent.getLabel().put(getSureLanguage(label.getLanguage()), label.getContent());
        }
        if (waComponent.getLabel().isEmpty()) {
            // no explicit labels, use name of process
            waComponent.getLabel().put(I18NHelper.defaultLanguage, processModel.getName());
        }
        Iterator<ContextualDesignation> descriptions = processModel.getDescriptions()
                .iterateContextualDesignation();
        while (descriptions.hasNext()) {
            ContextualDesignation description = descriptions.next();
            waComponent.getDescription().put(getSureLanguage(description.getLanguage()), description.getContent());
        }
        if (waComponent.getDescription().isEmpty()) {
            // no explicit description, use name of process
            waComponent.getDescription().put(I18NHelper.defaultLanguage, processModel.getName());
        }
        waComponent.setVisible(true);
        waComponent.setPortlet(false);
        waComponent.setInstanceClassName(getSettings().getString("componentDescriptor.managerInstanciator"));
        waComponent.getSuite().put(I18NHelper.defaultLanguage,
                getSettings().getString("componentDescriptor.suite"));
        waComponent.setProfiles(listSPProfile);
        waComponent.setRouter(getSettings().getString("componentDescriptor.managerRequestRouter"));
        spParameters.add(spParameter);
        waComponent.setParameters(spParameters);

        try {
            Instanciateur.saveComponent(waComponent, waComponent.getName() + ".xml", true);
            referencedInComponent = processModel.getName();
        } catch (JAXBException e) {
            throw new WorkflowDesignerException("WorkflowDesignerSessionController.generateComponentDescriptor()",
                    SilverpeasException.FATAL, "workflowDesigner.EX_ERR_WRITE_WA_COMPONENTS", e);
        }

        // Clear the descriptor cache and load it again
        rebuildComponentDescriptorCache();
    }

    private String getSureLanguage(String language) {
        if (language.equalsIgnoreCase("default")) {
            return I18NHelper.defaultLanguage;
        }
        return language;
    }

    private Profile getSupervisorProfile() {
        Profile profile = new Profile();
        profile.setName("supervisor");
        profile.getLabel().put(I18NHelper.defaultLanguage,
                getSettings().getString("componentDescriptor.supervisor"));
        profile.getHelp().put(I18NHelper.defaultLanguage,
                getSettings().getString("componentDescriptor.supervisor"));
        return profile;
    }

    /**
    * Finds the component that references the given process model
    *
    * @param strProcessModelFileName the relative path to the file containing the process model
    * description
    * @return the name of the component descriptor file name (without .XML ) or <code>null</code> if
    * no components reference the given model.
    */
    private String findComponentDescriptor(String strProcessModelFileName) {
        Map<String, WAComponent> waComponents = Instanciateur.getWAComponents();
        Set<Map.Entry<String, WAComponent>> enumWAComponent = waComponents.entrySet();
        if (strProcessModelFileName != null) {
            strProcessModelFileName = strProcessModelFileName.replaceAll("\\\\", "/");
            // Look for the descriptor in the cache, return the key if found.
            for (Map.Entry<String, WAComponent> componentEntry : enumWAComponent) {
                String strComponentName = componentEntry.getKey();
                WAComponent waComponent = componentEntry.getValue();
                if (waComponent.getParameters() != null) {
                    for (com.silverpeas.admin.components.Parameter spParameter : waComponent.getParameters()) {
                        if (ComponentsInstanciatorIntf.PROCESS_XML_FILE_NAME.equals(spParameter.getName())
                                && strProcessModelFileName.equals(spParameter.getValue())) {
                            return strComponentName;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
    * Clear the Component Descriptor cache and load it again
    *
    * @throws WorkflowDesignerException when something goes wrong
    */
    private void rebuildComponentDescriptorCache() throws WorkflowDesignerException {
        try {
            Instanciateur.rebuildWAComponentCache();
        } catch (InstanciationException e) {
            throw new WorkflowDesignerException(
                    "WorkflowDesignerSessionController.rebuildComponentDescriptorCache()",
                    SilverpeasException.FATAL, "workflowDesigner.EX_ERR_READ_WA_COMPONENTS", e);
        }
    }

    /**
    * Upload given process model in workflow repository.
    *
    * @param model process model file
    * @throws WorkflowDesignerException , WorkflowException
    */
    public void uploadProcessModel(FileItem model) throws WorkflowDesignerException, WorkflowException {
        String name = model.getName();
        if (name != null) {
            name = name.substring(name.lastIndexOf(File.separator) + 1, name.length());
            name = replaceSpecialChars(name);

            ProcessModelManager manager = WorkflowHub.getProcessModelManager();
            String workflowRepositoryDir = manager.getProcessModelDir();

            // on vrifie qu'un modle portant ce nom n'exista pas dj
            File modelFile = new File(workflowRepositoryDir + name);
            if (modelFile.exists()) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.uploadProcessModel()",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ERR_MODEL_ALREADY_EXISTS");
            }

            // upload du fichier
            try {
                model.write(modelFile);
            } catch (Exception e) {
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.uploadProcessModel()",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ERR_IMPORT_MODEL_FAILED", e);
            }

            // on charge le modele pour vrifier qu'il est valide
            try {
                manager.loadProcessModel(name, false);
            } catch (Exception e) {
                // le modle est invalide, on le supprime
                modelFile.delete();
                throw new WorkflowDesignerException("WorkflowDesignerSessionController.uploadProcessModel()",
                        SilverpeasException.ERROR, "workflowDesigner.EX_ERR_TRY_TO_IMPORT_INVALID_MODEL", e);
            }

        }
    }

    public synchronized void clearCache() {
        ProcessModelManagerImpl pmmi = new ProcessModelManagerImpl();
        pmmi.clearProcessModelCache();
    }

    public static String replaceSpecialChars(String toParse) {
        return FileServerUtils.replaceInvalidPathChars(toParse);
    }
}