org.openflexo.foundation.wkf.FlexoProcess.java Source code

Java tutorial

Introduction

Here is the source code for org.openflexo.foundation.wkf.FlexoProcess.java

Source

/*
 * (c) Copyright 2010-2011 AgileBirds
 *
 * This file is part of OpenFlexo.
 *
 * OpenFlexo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * OpenFlexo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package org.openflexo.foundation.wkf;

/*
 * FlexoProcess.java
 * Project WorkflowEditor
 *
 * Created by benoit on Mar 3, 2004
 */

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;

import javax.naming.InvalidNameException;

import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.DualHashBidiMap;
import org.openflexo.foundation.AttributeDataModification;
import org.openflexo.foundation.CodeType;
import org.openflexo.foundation.FlexoException;
import org.openflexo.foundation.FlexoImportableObject;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.Inspectors;
import org.openflexo.foundation.NameChanged;
import org.openflexo.foundation.TargetType;
import org.openflexo.foundation.action.FlexoActionType;
import org.openflexo.foundation.action.FlexoActionizer;
import org.openflexo.foundation.bindings.Bindable;
import org.openflexo.foundation.bindings.BindingModel;
import org.openflexo.foundation.bindings.BindingVariable;
import org.openflexo.foundation.dm.AutoGeneratedProcessBusinessDataDMEntity;
import org.openflexo.foundation.dm.DMEntity;
import org.openflexo.foundation.dm.DMModel;
import org.openflexo.foundation.dm.DMObject;
import org.openflexo.foundation.dm.DMProperty;
import org.openflexo.foundation.dm.DMPropertyImplementationType;
import org.openflexo.foundation.dm.DMType;
import org.openflexo.foundation.dm.DuplicatePropertyNameException;
import org.openflexo.foundation.dm.ProcessDMEntity;
import org.openflexo.foundation.dm.ProcessInstanceRepository;
import org.openflexo.foundation.dm.eo.DMEOAttribute;
import org.openflexo.foundation.dm.eo.DMEOEntity;
import org.openflexo.foundation.dm.eo.EOAccessException;
import org.openflexo.foundation.gen.FlexoProcessImageBuilder;
import org.openflexo.foundation.help.ApplicationHelpEntryPoint;
import org.openflexo.foundation.ie.ComponentInstance;
import org.openflexo.foundation.ie.IEWOComponent;
import org.openflexo.foundation.ie.OperationComponentInstance;
import org.openflexo.foundation.ie.TabComponentInstance;
import org.openflexo.foundation.ie.cl.TabComponentDefinition;
import org.openflexo.foundation.ie.dm.ComponentDeleteRequest;
import org.openflexo.foundation.ie.dm.ComponentDeleted;
import org.openflexo.foundation.ie.dm.ComponentNameChanged;
import org.openflexo.foundation.ie.util.TextFieldType;
import org.openflexo.foundation.ie.widget.IECheckBoxWidget;
import org.openflexo.foundation.ie.widget.IEDropDownWidget;
import org.openflexo.foundation.ie.widget.IEHyperlinkWidget;
import org.openflexo.foundation.ie.widget.IERadioButtonWidget;
import org.openflexo.foundation.ie.widget.IEStringWidget;
import org.openflexo.foundation.ie.widget.IETabWidget;
import org.openflexo.foundation.ie.widget.IETextAreaWidget;
import org.openflexo.foundation.ie.widget.IETextFieldWidget;
import org.openflexo.foundation.ie.widget.IEWidget;
import org.openflexo.foundation.ie.widget.IEWidgetWithValueList;
import org.openflexo.foundation.ie.widget.IEWysiwygWidget;
import org.openflexo.foundation.param.DMEntityParameter;
import org.openflexo.foundation.param.ParameterDefinition;
import org.openflexo.foundation.param.TextFieldParameter;
import org.openflexo.foundation.rm.DuplicateResourceException;
import org.openflexo.foundation.rm.FlexoProcessResource;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.foundation.rm.FlexoResource;
import org.openflexo.foundation.rm.FlexoWorkflowResource;
import org.openflexo.foundation.rm.FlexoXMLStorageResource;
import org.openflexo.foundation.rm.InvalidFileNameException;
import org.openflexo.foundation.rm.ProjectRestructuration;
import org.openflexo.foundation.rm.RMNotification;
import org.openflexo.foundation.rm.SaveResourceException;
import org.openflexo.foundation.rm.XMLStorageResourceData;
import org.openflexo.foundation.stats.ProcessStatistics;
import org.openflexo.foundation.utils.FlexoCSS;
import org.openflexo.foundation.utils.FlexoIndexManager;
import org.openflexo.foundation.utils.FlexoProjectFile;
import org.openflexo.foundation.validation.FixProposal;
import org.openflexo.foundation.validation.ParameteredFixProposal;
import org.openflexo.foundation.validation.Validable;
import org.openflexo.foundation.validation.ValidationError;
import org.openflexo.foundation.validation.ValidationIssue;
import org.openflexo.foundation.validation.ValidationModel;
import org.openflexo.foundation.validation.ValidationReport;
import org.openflexo.foundation.validation.ValidationRule;
import org.openflexo.foundation.validation.ValidationWarning;
import org.openflexo.foundation.wkf.MetricsValue.MetricsValueOwner;
import org.openflexo.foundation.wkf.action.AddProcessMetricsValue;
import org.openflexo.foundation.wkf.action.AddRole;
import org.openflexo.foundation.wkf.action.AddServiceInterface;
import org.openflexo.foundation.wkf.action.AddStatus;
import org.openflexo.foundation.wkf.action.AddSubProcess;
import org.openflexo.foundation.wkf.action.DeleteMetricsValue;
import org.openflexo.foundation.wkf.action.GenerateProcessScreenshot;
import org.openflexo.foundation.wkf.action.OpenPortRegistery;
import org.openflexo.foundation.wkf.action.WKFDelete;
import org.openflexo.foundation.wkf.dm.AssociationInserted;
import org.openflexo.foundation.wkf.dm.PostInserted;
import org.openflexo.foundation.wkf.dm.ProcessInserted;
import org.openflexo.foundation.wkf.dm.ProcessRemoved;
import org.openflexo.foundation.wkf.dm.ServiceInterfaceInserted;
import org.openflexo.foundation.wkf.dm.ServiceInterfaceRemoved;
import org.openflexo.foundation.wkf.dm.WKFAttributeDataModification;
import org.openflexo.foundation.wkf.edge.FlexoPostCondition;
import org.openflexo.foundation.wkf.edge.InternalMessageInEdge;
import org.openflexo.foundation.wkf.edge.InternalMessageOutEdge;
import org.openflexo.foundation.wkf.edge.InvalidEdgeException;
import org.openflexo.foundation.wkf.edge.MessageEdge;
import org.openflexo.foundation.wkf.edge.WKFAssociation;
import org.openflexo.foundation.wkf.node.AbstractActivityNode;
import org.openflexo.foundation.wkf.node.AbstractNode;
import org.openflexo.foundation.wkf.node.ActionNode;
import org.openflexo.foundation.wkf.node.ActivityNode;
import org.openflexo.foundation.wkf.node.EventNode;
import org.openflexo.foundation.wkf.node.FlexoNode;
import org.openflexo.foundation.wkf.node.LOOPOperator;
import org.openflexo.foundation.wkf.node.OperationNode;
import org.openflexo.foundation.wkf.node.OperatorNode;
import org.openflexo.foundation.wkf.node.PetriGraphNode;
import org.openflexo.foundation.wkf.node.SelfExecutableNode;
import org.openflexo.foundation.wkf.node.SubProcessNode;
import org.openflexo.foundation.wkf.node.WKFNode;
import org.openflexo.foundation.wkf.ws.DefaultServiceInterface;
import org.openflexo.foundation.wkf.ws.DeletePort;
import org.openflexo.foundation.wkf.ws.FlexoPort;
import org.openflexo.foundation.wkf.ws.FlexoPortMap;
import org.openflexo.foundation.wkf.ws.NewPort;
import org.openflexo.foundation.wkf.ws.OutPort;
import org.openflexo.foundation.wkf.ws.PortRegistery;
import org.openflexo.foundation.wkf.ws.ServiceInterface;
import org.openflexo.foundation.ws.DuplicateWSObjectException;
import org.openflexo.foundation.xml.FlexoProcessBuilder;
import org.openflexo.inspector.InspectableObject;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.toolbox.EmptyVector;
import org.openflexo.toolbox.FileUtils;
import org.openflexo.toolbox.JavaUtils;
import org.openflexo.toolbox.ProgrammingLanguage;
import org.openflexo.toolbox.ReservedKeyword;
import org.openflexo.toolbox.ToolBox;
import org.openflexo.ws.client.PPMWebService.PPMObject;
import org.openflexo.ws.client.PPMWebService.PPMProcess;
import org.openflexo.xmlcode.XMLMapping;

/**
 * TODO: rewrite this, since it's no more up-to-date ! A FlexoProcess contains all the data needed by the <I>workflow processor</I> to
 * execute an instance of a process. In other words, a FlexoProcess contains all the information about the structure of a single workflow.<BR>
 * <B>Note : </B> The <I>process instance</I> is a running instance of a FlexoProcess. The <I>workflow processor</I> is a processor that can
 * run a <I>process instance</I>, so one of the most important capabilities of a <I>workflow processor</I> is the interpretation of a
 * FlexoProcess.<BR>
 * A FlexoProcess can be part of a FlexoWorkflow. In this case, there will be some links between the different flexo process inside the same
 * workflow. For instance, a particular node of this process can be able to start one or more process instance of another process of the
 * same workflow. The dual case is that the end of one or more process instances of another process can have an effect on this process.
 * 
 * @author benoit, sylvain
 */
public final class FlexoProcess extends WKFObject
        implements FlexoImportableObject, ApplicationHelpEntryPoint, XMLStorageResourceData, InspectableObject,
        Bindable, ExecutableWorkflowElement, MetricsValueOwner, LevelledObject {

    static final Logger logger = Logger.getLogger(FlexoProcess.class.getPackage().getName());

    public static final String ACTIVITY_CONTEXT = "ACTIVITY";
    public static final String OPERATION_CONTEXT = "OPERATION";
    public static final String ACTION_CONTEXT = "ACTION";
    public static final String EXECUTION_CONTEXT = "EXECUTION";

    // ==========================================================================
    // ============================= Instance variables
    // =========================
    // ==========================================================================

    private transient FlexoProject _project;

    private FlexoProcessResource _resource;

    private String _name;

    // Now stored at workflow level
    // private RoleList _roleList;

    // deprecated
    // private DeadLineList _deadLineList;

    private StatusList _statusList;

    private Vector<FlexoProcess> _subProcesses;

    private FlexoCSS cssSheet;

    private transient FlexoProcessNode _processNode;

    private ActivityPetriGraph _petriGraph;

    private boolean _isWebService;

    private PortRegistery _registery;

    private Vector<ServiceInterface> _serviceInterfaces;

    private ProcessBindingModel _bindingModel;

    private String acronym;

    private Vector<SubProcessNode> _subProcessNodes;

    private Vector<AbstractNode> allAbstractNodes = null;
    private Vector<WKFNode> allNodes = null;

    private Date lastUpdate;

    /* Key: String, Value: FlexoModelObject */
    private BidiMap nameForNodeMap = new DualHashBidiMap();

    // Not Serialized
    private DefaultServiceInterface _portRegistryInterface;

    private transient ProcessStatistics statistics;

    public static FlexoActionizer<AddStatus, WKFObject, WKFObject> addStatusActionizer;
    public static FlexoActionizer<WKFDelete, WKFObject, WKFObject> deleteActionizer;

    private Vector<MetricsValue> metricsValues;

    public static FlexoActionizer<AddProcessMetricsValue, FlexoProcess, WKFObject> addMetricsActionizer;
    public static FlexoActionizer<DeleteMetricsValue, MetricsValue, MetricsValue> deleteMetricsActionizer;

    // ==========================================================================
    // ============================= Constructor
    // ================================
    // ==========================================================================

    public FlexoProcess(FlexoProcessBuilder builder) {
        this(builder.getProject());
        builder.process = this;
        _resource = builder.resource;
        setProject(builder.getProject());
        _name = new String(builder.defaultProcessName);
        initializeDeserialization(builder);
    }

    private FlexoProcess(FlexoProject project) {
        super(project);
        setProject(project);
        setProcess(this);
        _subProcessNodes = new Vector<SubProcessNode>();
        _serviceInterfaces = new Vector<ServiceInterface>();
        metricsValues = new Vector<MetricsValue>();
    }

    /**
     * Creates a new FlexoProcess with default values (public API outside XML serialization)
     * 
     * @param workflow
     * @throws DuplicateResourceException
     */
    public FlexoProcess(String processName, FlexoWorkflow workflow) throws DuplicateResourceException {
        this(workflow.getProject());
        _name = processName;
    }

    /**
     * Creates and returns a newly created root process
     * 
     * @return a newly created workflow
     * @throws InvalidFileNameException
     */
    public static FlexoProcess createNewRootProcess(FlexoWorkflow workflow) {
        if (workflow.getRootProcess() == null) {
            try {
                FlexoProcess returned = createNewProcess(workflow, null, workflow.getWorkflowName(), true);
                workflow.setRootProcess(returned);
                return returned;
            } catch (DuplicateResourceException e) {
                // Warns about the exception
                if (logger.isLoggable(Level.WARNING)) {
                    logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
                }
                e.printStackTrace();
                if (logger.isLoggable(Level.WARNING)) {
                    logger.warning("Cannot create root process !");
                }
                return null;
            } catch (InvalidFileNameException e) {
                e.printStackTrace();
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.severe("Cannot create root process because " + workflow.getWorkflowName()
                            + " is not a valid file name");
                }
                return null;
            }
        } else {
            if (logger.isLoggable(Level.WARNING)) {
                logger.warning("Cannot create root process: a root process is already declared");
            }
            return null;
        }
    }

    /**
     * Creates and returns a newly created process
     * 
     * @param isRoot
     *            TODO
     * 
     * @return a newly created workflow
     * @throws DuplicateResourceException
     * @throws InvalidFileNameException
     */
    // TODO: Move that in a FlexoAction !!!!
    public static FlexoProcess createNewProcess(FlexoWorkflow workflow, FlexoProcess parentProcess,
            String processName, boolean isRoot) throws DuplicateResourceException, InvalidFileNameException {
        if (processWithSimilarNameExists(workflow, null, ToolBox.getJavaName(processName))) {
            throw new InvalidFileNameException("A process with similar name exists");
        }
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("BEGIN createNewProcess()");
        }
        FlexoProject project = workflow.getProject();

        if (workflow.getLocalFlexoProcessWithName(processName) != null) {
            throw new DuplicateResourceException("PROCESS." + processName);
        }
        FlexoProcess newProcess = new FlexoProcess(processName, workflow);
        newProcess.setProject(project);
        ProcessDMEntity e = project.getDataModel().getProcessInstanceRepository().getProcessDMEntity(newProcess);
        if (e != null && logger.isLoggable(Level.SEVERE)) {
            logger.severe("Dm entity for process " + processName + "already exists.");
        }
        FlexoProcessResource processRes = createProcessResource(parentProcess, processName, project, newProcess,
                false);

        initProcessObjects(newProcess);
        project.registerResource(processRes);
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("END createNewProcess()");
        }
        return newProcess;
    }

    /**
     * @param process
     */
    public static void initProcessObjects(FlexoProcess process) {
        // TODO: Use FlexoActions !!!
        process.isImported = false;
        process.createsProcessDMEntityIfRequired();
        process.createsAutoGeneratedProcessBusinessDataDMEntityIfRequired();
        process.updateMetricsValues();
        process.setStatusList(new StatusList(process, true));
        ActivityPetriGraph.createNewActivityPetriGraph(process);
        NewPort _newPort = new NewPort(process,
                process.findNextInitialName("NEW_PORT", NewPort.getDefaultInitialName()));
        _newPort.setIndexValue(0);
        process.getPortRegistery().addToNewPorts(_newPort);
        DeletePort _deletePort = new DeletePort(process,
                process.findNextInitialName("DELETE_PORT", DeletePort.getDefaultInitialName()));
        _deletePort.setIndexValue(1);
        process.getPortRegistery().addToDeletePorts(_deletePort);
        OutPort _processTerminated = new OutPort(process,
                process.findNextInitialName("PROCESS_TERMINATED", OutPort.getDefaultInitialName()));
        _processTerminated.setIndexValue(2);
        process.getPortRegistery().addToOutPorts(_processTerminated);

        // ActivityNode begin = (ActivityNode) process.getActivityPetriGraph()
        // .getAllBeginNodes().firstElement();
        // ActivityNode end = (ActivityNode) process.getActivityPetriGraph()
        // .getAllEndNodes().firstElement();
        // new OperationPetriGraph(begin);
        // new OperationPetriGraph(end);

        EventNode begin = process.getActivityPetriGraph().getAllEventNodes().firstElement();
        EventNode end = process.getActivityPetriGraph().getAllEventNodes().lastElement();

        // FlexoPreCondition beginCondition = new FlexoPreCondition(begin, begin
        // .getOperationPetriGraph().getAllBeginNodes().firstElement());
        // FlexoPreCondition endCondition = new FlexoPreCondition(end, end
        // .getOperationPetriGraph().getAllBeginNodes().firstElement());
        try {
            FlexoPostCondition newBeginPostCondition = new InternalMessageInEdge(_newPort, begin, process);
            newBeginPostCondition.updateMetricsValues();
            _newPort.addToOutgoingPostConditions(newBeginPostCondition);
        } catch (InvalidEdgeException e1) {
            e1.printStackTrace();
        }
        try {
            FlexoPostCondition deleteEndPostCondition = new InternalMessageInEdge(_deletePort, end, process);
            deleteEndPostCondition.updateMetricsValues();
            _deletePort.addToOutgoingPostConditions(deleteEndPostCondition);
        } catch (InvalidEdgeException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            FlexoPostCondition processTerminatedPostCondition = new InternalMessageOutEdge(end, _processTerminated);
            processTerminatedPostCondition.updateMetricsValues();
            processTerminatedPostCondition.setName(FlexoLocalization.localizedForKey("process_terminated"));
            end.addToOutgoingPostConditions(processTerminatedPostCondition);
        } catch (InvalidEdgeException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        process.getPortRegistery().setIsVisible(false);
    }

    /**
     * @param workflow
     * @param parentProcess
     * @param processName
     * @param project
     * @param processResFile
     * @param newProcess
     * @return
     * @throws InvalidFileNameException
     */
    private static FlexoProcessResource createProcessResource(FlexoProcess parentProcess, String processName,
            FlexoProject project, FlexoProcess newProcess, boolean isImported) throws InvalidFileNameException {
        FlexoWorkflow workflow = project.getWorkflow();
        FlexoWorkflowResource workflowRes = workflow.getFlexoResource();
        File processFile = ProjectRestructuration.getExpectedProcessFile(project, processName);
        FlexoProjectFile processResFile = new FlexoProjectFile(processFile, project);
        if (!processResFile.nameIsValid()) {
            processResFile.fixName();
        }

        FlexoProcessNode newProcessNode = new FlexoProcessNode(processName, processResFile.getRelativePath(),
                newProcess, project);
        if (parentProcess == null) {
            if (isImported) {
                workflow.addToImportedRootNodeProcesses(newProcessNode);
            } else {
                workflow.addToTopLevelNodeProcesses(newProcessNode);
            }
        } else {
            if (isImported && !parentProcess.isImported()) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.severe("Trying to add an imported process to an non-imported process!");
                }
            } else if (!isImported && parentProcess.isImported()) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.severe("Trying to add an non-imported process to an imported process!");
                }
            }
            parentProcess.addToSubProcesses(newProcess);
            // parentProcess.getProcessNode().addToSubProcesses(newProcessNode);
        }

        FlexoProcessResource processRes = null;
        try {
            processRes = new FlexoProcessResource(project, newProcess, workflowRes, processResFile);
        } catch (InvalidFileNameException e1) {
            boolean ok = false;
            for (int i = 0; i < 10000 && !ok; i++) {
                try {
                    processFile = ProjectRestructuration.getExpectedProcessFile(project,
                            FileUtils.getValidFileName(processName) + i);
                    processResFile = new FlexoProjectFile(processFile, project);
                    processRes = new FlexoProcessResource(project, newProcess, workflowRes, processResFile);
                    ok = true;
                } catch (InvalidFileNameException e2) {

                }
            }
            if (!ok) {
                processFile = ProjectRestructuration.getExpectedProcessFile(project,
                        FileUtils.getValidFileName(processName) + newProcess.getFlexoID());
                processResFile = new FlexoProjectFile(processFile, project);
                processResFile.setProject(project);
                processRes = new FlexoProcessResource(project, newProcess, workflowRes, processResFile);
            }
        }
        if (processRes == null) {
            throw new InvalidFileNameException(processResFile.getRelativePath());
        }
        return processRes;
    }

    public static FlexoProcess createImportedProcessFromProcess(FlexoWorkflow workflow, PPMProcess process)
            throws InvalidFileNameException, DuplicateResourceException {
        FlexoProject project = workflow.getProject();
        FlexoProcess newFIP = workflow.getRecursivelyImportedProcessWithURI(process.getUri());
        FlexoProcess parentProcess = null;
        if (process.getParentProcess() != null) {
            parentProcess = workflow.getRecursivelyImportedProcessWithURI(process.getParentProcess().getUri());
            if (parentProcess == null) {
                if (logger.isLoggable(Level.WARNING)) {
                    logger.warning("Could not find parent process: " + process.getParentProcess().getName());
                }
            }
        }
        if (newFIP != null) {
            if (parentProcess != null) {
                parentProcess.getProcessNode().addToSubProcesses(newFIP.getProcessNode());
            }
            try {
                newFIP.updateFromObject(process);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return newFIP;
        }

        FlexoProcess fip = new FlexoProcess(workflow.getProject());
        fip.isImported = true;
        try {
            fip.updateFromObject(process);
        } catch (Exception e) {
            // Should not happen for imported processes
            if (logger.isLoggable(Level.SEVERE)) {
                logger.severe("setName threw an exception for imported FlexoProcess!!!");
            }
            e.printStackTrace();
        }
        FlexoProcessResource resource = createProcessResource(parentProcess, process.getName(), project, fip, true);
        String name = resource.getName();
        if (project.resourceForKey(resource.getResourceType(), name) != null) {
            name = name + "FromServer";
        }
        int attempt = 1;
        String base = name;
        while (project.resourceForKey(resource.getResourceType(), name) != null) {
            name = base + "_" + String.valueOf(attempt);
            attempt++;
        }
        if (!resource.getName().equals(name)) {
            resource.setName(name);
        }
        project.registerResource(resource);
        fip.setFlexoResource(resource);
        if (process.getSubProcesses() != null) {
            for (int i = 0; i < process.getSubProcesses().length; i++) {
                PPMProcess sub = process.getSubProcesses()[i];
                createImportedProcessFromProcess(workflow, sub);
            }
        }
        return fip;
    }

    // Temporary flag to prevent unuseful code from being executed.
    private boolean isImported = false;

    @Override
    public boolean isImported() {
        if (getProcessNode() != null) {
            return getProcessNode().isImported();
        }
        return isImported;
    }

    @Override
    public Class<? extends PPMObject> getEquivalentPPMClass() {
        return PPMProcess.class;
    }

    public void updateFromObject(PPMProcess process) throws Exception {
        super.updateFromObject(process);
    }

    public PPMProcess getEquivalentPPMProcess() {
        return getEquivalentPPMProcess(true);
    }

    public PPMProcess getEquivalentPPMProcess(boolean includeChildren) {
        PPMProcess process = new PPMProcess();
        copyObjectAttributesInto(process);
        if (includeChildren) {
            int i = 0;
            PPMProcess[] subs = new PPMProcess[getSubProcesses().size()];
            for (FlexoProcess sub : getSubProcesses()) {
                subs[i] = sub.getEquivalentPPMProcess(includeChildren);
                i++;
            }
            process.setSubProcesses(subs);
        }
        return process;
    }

    public boolean isEquivalentTo(PPMProcess p) {
        return isEquivalentTo(p, true);
    }

    public boolean isEquivalentTo(PPMProcess p, boolean compareChildren) {
        if (!super.isEquivalentTo(p)) {
            return false;
        }
        /*
         * if (getParentProcess()==null && p.getParentProcess()!=null) return
         * false; else if(getParentProcess()!=null &&
         * p.getParentProcess()==null) return false; else if
         * (getParentProcess()!=null && p.getParentProcess()!=null &&
         * !(getParentProcess().getURI().equals(p.getParentProcess().getUri())))
         * { return false; }
         */
        if (compareChildren) {
            boolean ok = getSubProcesses().size() != 0 && p.getSubProcesses() != null
                    && p.getSubProcesses().length == getSubProcesses().size()
                    || getSubProcesses().size() == 0
                            && (p.getSubProcesses() == null || p.getSubProcesses().length == 0);
            for (int i = 0; ok && i < getSubProcesses().size(); i++) {
                FlexoProcess fip = getSubProcesses().get(i);
                if (p.getSubProcesses() == null || p.getSubProcesses().length <= i) {
                    ok = false;
                } else {
                    ok &= fip.isEquivalentTo(p.getSubProcesses()[i], compareChildren);
                }
                ok &= fip.getParentProcess() == this;
            }
            if (!ok) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void setIsDeletedOnServer(boolean isDeletedOnServer) {
        super.setIsDeletedOnServer(isDeletedOnServer);
        for (FlexoProcess sub : getSubProcesses()) {
            sub.setIsDeletedOnServer(isDeletedOnServer);
        }
    }

    // ==========================================================================
    // ===================== Resource managing
    // ==================================
    // ==========================================================================

    @Override
    public FlexoProcessResource getFlexoResource() {
        return _resource;
    }

    /**
     * Overrides getXMLMapping
     * 
     * @see org.openflexo.foundation.wkf.WKFObject#getXMLMapping()
     */
    @Override
    public XMLMapping getXMLMapping() {
        // if you change this line, change it also in WKFObject (same method)
        return getProject().getXmlMappings().getWKFMapping();
    }

    @Override
    public FlexoXMLStorageResource getFlexoXMLFileResource() {
        return _resource;
    }

    @Override
    public void setFlexoResource(FlexoResource resource) {
        _resource = (FlexoProcessResource) resource;
    }

    @Override
    public FlexoProject getProject() {
        return _project;
    }

    @Override
    public void setProject(FlexoProject aProject) {
        _project = aProject;
    }

    /**
     * Save this object using ResourceManager scheme
     * 
     * Overrides
     * 
     * @see org.openflexo.foundation.rm.FlexoResourceData#save()
     * @see org.openflexo.foundation.rm.FlexoResourceData#save()
     */
    @Override
    public void save() throws SaveResourceException {
        _resource.saveResourceData();
    }

    public void clearCachedObjects() {
        allAbstractNodes = null;
        allNodes = null;
    }

    /**
     * Implements
     * 
     * @see org.openflexo.foundation.rm.FlexoResourceData#receiveRMNotification(org.openflexo.foundation.rm.RMNotification) Receive a
     *      notification that has been propagated by the ResourceManager scheme and coming from a modification on an other resource
     * 
     *      Handles ComponentNameChanged notifications
     * 
     * @see org.openflexo.foundation.rm.FlexoResourceData#receiveRMNotification(org.openflexo.foundation.rm.RMNotification)
     */
    @Override
    public void receiveRMNotification(RMNotification aNotification) {
        if (aNotification instanceof ComponentNameChanged) {
            ComponentNameChanged notification = (ComponentNameChanged) aNotification;
            for (Enumeration en = getAllEmbeddedOperationNodes().elements(); en.hasMoreElements();) {
                OperationNode node = (OperationNode) en.nextElement();
                if (node.getComponentInstance() != null) {
                    OperationComponentInstance ci = node.getComponentInstance();
                    if (ci.getComponentName().equals(notification.oldValue())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info("Process " + getName() + " Updating component instance "
                                    + notification.component.getName() + " for " + node.getName());
                        }
                        ci.notifyComponentNameChanged(notification.component);
                    }
                }
                if (node.getTabOperationComponentInstance() != null) {
                    TabComponentInstance ci = node.getTabOperationComponentInstance();
                    if (ci.getComponentName().equals(notification.oldValue())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info("Process " + getName() + " Updating tab component instance "
                                    + notification.component.getName() + " for " + node.getName());
                        }
                        ci.notifyComponentNameChanged(notification.component);
                    }
                }
            }
            for (ActionNode action : getAllEmbeddedActionNodes()) {
                if (action.getTabActionComponentInstance() != null) {
                    TabComponentInstance ci = action.getTabActionComponentInstance();
                    if (ci.getComponentName().equals(notification.oldValue())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info("Process " + getName() + " Updating component instance "
                                    + notification.component.getName() + " for " + action.getName());
                        }
                        ci.notifyComponentNameChanged(notification.component);
                    }
                }
            }
        }
        if (aNotification instanceof ComponentDeleteRequest) {
            ComponentDeleteRequest notification = (ComponentDeleteRequest) aNotification;
            for (Enumeration en = getAllEmbeddedOperationNodes().elements(); en.hasMoreElements();) {
                OperationNode node = (OperationNode) en.nextElement();
                if (node.getComponentInstance() != null) {
                    OperationComponentInstance ci = node.getComponentInstance();
                    if (ci.getComponentName().equals(notification.component.getComponentName())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info("Receive a deletion request for "
                                    + notification.component.getComponentName() + " in " + getName());
                        }
                        notification.addToWarnings(notification.component.getComponentName()
                                + " is used by operation : " + node.getName());
                    }
                }
                if (node.getTabOperationComponentInstance() != null) {
                    TabComponentInstance ci = node.getTabOperationComponentInstance();
                    if (ci.getComponentName().equals(notification.component.getComponentName())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info("Receive a deletion request for "
                                    + notification.component.getComponentName() + " in " + getName());
                        }
                        notification.addToWarnings(notification.component.getComponentName()
                                + " is used by operation : " + node.getName());
                    }
                }
            }
            // We don't check action nodes
        }
        if (aNotification instanceof ComponentDeleted) {
            ComponentDeleted notification = (ComponentDeleted) aNotification;
            for (Enumeration en = getAllEmbeddedOperationNodes().elements(); en.hasMoreElements();) {
                OperationNode node = (OperationNode) en.nextElement();
                if (node.getTabOperationComponentInstance() != null) {
                    TabComponentInstance ci = node.getTabOperationComponentInstance();
                    if (ci.getComponentName().equals(notification.component.getComponentName())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info(
                                    "Operation named " + node.getName() + " has received a deletion request for "
                                            + notification.component.getComponentName() + " in " + getName());
                        }
                        node.removeTabComponentInstance();
                    }
                }
                if (node.getComponentInstance() != null) {
                    OperationComponentInstance ci = node.getComponentInstance();
                    if (ci.getComponentName().equals(notification.component.getComponentName())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info(
                                    "Operation named " + node.getName() + " has received a deletion request for "
                                            + notification.component.getComponentName() + " in " + getName());
                        }
                        node.removeComponentInstance();
                    }
                }
            }
            for (ActionNode action : getAllEmbeddedActionNodes()) {
                if (action.getTabActionComponentInstance() != null) {
                    TabComponentInstance ci = action.getTabActionComponentInstance();
                    if (ci.getComponentName().equals(notification.oldValue())) {
                        if (logger.isLoggable(Level.INFO)) {
                            logger.info("Process " + getName() + " Updating component instance "
                                    + notification.component.getName() + " for " + action.getName());
                        }
                        action.removeTabComponentInstance();
                    }
                }
            }

        }
    }

    // ==========================================================================
    // ============================= Accessors
    // ==================================
    // ==========================================================================

    @Override
    public String getFullyQualifiedName() {
        FlexoProcess current = this;
        String returned = "" + getName();
        while (current.getParentProcess() != null) {
            returned = current.getParentProcess().getName() + "." + returned;
            current = current.getParentProcess();
        }
        return returned;
    }

    /*
     * public FlexoPetriGraph getPetriGraph(String context) { return
     * getActivityPetriGraph(); }
     *
     * public void setPetriGraph(FlexoPetriGraph aPetriGraph, String context) {
     * setActivityPetriGraph((ActivityPetriGraph) aPetriGraph); }
     */

    public ActivityPetriGraph getActivityPetriGraph() {
        return _petriGraph;
    }

    public void setActivityPetriGraph(ActivityPetriGraph aPetriGraph) {
        _petriGraph = aPetriGraph;
        if (_petriGraph != null) {
            _petriGraph.setContainer(this, ACTIVITY_CONTEXT);
        }
    }

    /**
     * 
     * @return
     * @deprecated
     */
    @Deprecated
    public DeadLineList getDeadLineList() {
        /*
         * if (_deadLineList == null) { _deadLineList = new DeadLineList(this);
         * } return _deadLineList;
         */
        return null;
    }

    /**
     * @param lineList
     * @deprecated
     */
    @Deprecated
    public void setDeadLineList(DeadLineList lineList) {
        // _deadLineList = lineList;
    }

    /**
     * @return
     * @deprecated use getWorkflow().getRoleList()
     */
    @Deprecated
    public RoleList getRoleList() {
        return getWorkflow().getRoleList();
    }

    /**
     * DEPRECATED: we will use this to add all roles defined in supplied role list to workflow role list
     * 
     * @param list
     * @deprecated
     */
    @Deprecated
    public void setRoleList(RoleList list) {
        for (Role role : list.getRoles()) {
            try {
                getRoleList().addToRoles(role, true);
            } catch (DuplicateRoleException e) {
                logger.warning("DuplicateRoleException: " + e);
                if (logger.isLoggable(Level.FINE)) {
                    logger.log(Level.FINE, "Duplicate role: " + role.getName(), e);
                }
            }
        }
    }

    public StatusList getStatusList() {
        return getStatusList(!isImported());
    }

    protected StatusList getStatusList(boolean createIfMissing) {
        if (_statusList == null && createIfMissing) {
            if (!isDeserializing()) {
                _statusList = new StatusList(this, true);
            } else {
                _statusList = new StatusList(this, false);
            }
        }
        return _statusList;
    }

    public void setStatusList(StatusList list) {
        _statusList = list;
    }

    protected void notifyStatusListUpdated() {
        setChanged();
        notifyObservers(new WKFAttributeDataModification("statusList.defaultStatus", null, null));
    }

    /**
     * @return
     * @deprecated
     */
    @Deprecated
    public FlexoCSS getCalculatedCssSheet() {
        if (cssSheet == null) {
            if (isTopLevelProcess()) {
                return getProject().getCssSheet();
            } else {
                return getParentProcess().getCalculatedCssSheet();
            }
        } else {
            return cssSheet;
        }
    }

    /**
     * @return
     * @deprecated
     */
    @Deprecated
    public FlexoCSS getCssSheet() {
        return cssSheet;
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void setCssSheet(FlexoCSS cssSheet) {
        FlexoCSS old = this.cssSheet;
        this.cssSheet = cssSheet;
        setChanged();
        notifyAttributeModification("cssSheet", old, cssSheet);
    }

    /*
     * public String getComponentPrefix() { return componentPrefix; }
     *
     *
     * public void setComponentPrefix(String componentPrefix) {
     * this.componentPrefix = componentPrefix; }
     */

    @Override
    public void updateMetricsValues() {
        getWorkflow().updateMetricsForProcess(this);
    }

    @Override
    public Vector<MetricsValue> getMetricsValues() {
        return metricsValues;
    }

    public void setMetricsValues(Vector<MetricsValue> metricsValues) {
        this.metricsValues = metricsValues;
        setChanged();
    }

    @Override
    public void addToMetricsValues(MetricsValue value) {
        if (value.getMetricsDefinition() != null) {
            metricsValues.add(value);
            value.setOwner(this);
            setChanged();
            notifyObservers(new MetricsValueAdded(value, "metricsValues"));
        }
    }

    @Override
    public void removeFromMetricsValues(MetricsValue value) {
        metricsValues.remove(value);
        value.setOwner(null);
        setChanged();
        notifyObservers(new MetricsValueRemoved(value, "metricsValues"));
    }

    public void addMetrics() {
        if (addMetricsActionizer != null) {
            addMetricsActionizer.run(this, null);
        }
    }

    public void deleteMetrics(MetricsValue value) {
        if (deleteMetricsActionizer != null) {
            deleteMetricsActionizer.run(value, null);
        }
    }

    @Override
    protected Vector<FlexoActionType> getSpecificActionListForThatClass() {
        Vector<FlexoActionType> returned = super.getSpecificActionListForThatClass();
        returned.add(AddSubProcess.actionType);
        returned.add(AddRole.actionType);
        returned.add(AddStatus.actionType);
        returned.add(AddServiceInterface.actionType);
        returned.add(GenerateProcessScreenshot.actionType);
        returned.add(OpenPortRegistery.actionType);
        return returned;
    }

    // ==========================================================================
    // ============================= InspectableObject
    // ==========================
    // ==========================================================================

    @Override
    public String getInspectorName() {
        if (isImported()) {
            return Inspectors.WKF.IMPORTED_PROCESS;
        }
        return Inspectors.WKF.FLEXO_PROCESS_INSPECTOR;
    }

    // ==========================================================================
    // ============================= Instance Methods
    // ===========================
    // ==========================================================================

    /**
     * Same as getParentProcess(), but used in an interactive context (inspector)
     */
    /*
     * public FlexoProcess getInteractiveParentProcess() { return
     * getParentProcess(); }
     */

    /**
     * Same as setParentProcess(), but used in an interactive context (inspector) In this case, just throw an ProcessMovingConfirmation that
     * will be caught by a controller which has the responsability to continue process if confirmation was given.
     */
    /*
     * public void setInteractiveParentProcess(FlexoProcess aNewParentProcess) {
     * if (aNewParentProcess != getInteractiveParentProcess()) { throw new
     * ProcessMovingConfirmation(this, aNewParentProcess); } }
     */

    /**
     * Return the parent process of this process
     * 
     * @return FlexoProcess
     */
    public FlexoProcess getParentProcess() {
        if (_processNode != null) {
            if (_processNode.getFatherProcessNode() != null) {
                return _processNode.getFatherProcessNode().getProcess();
            } else {
                // This is a top-level process
                return null;
            }
        }
        return null;
    }

    /**
     * Sets the parent process of this process (move)
     * 
     */
    public void setParentProcess(FlexoProcess aNewParentProcess)
            throws InvalidParentProcessException, InvalidProcessReferencesException {
        if (getParentProcess() != aNewParentProcess) {
            if (aNewParentProcess != null && this.getIsWebService()) {
                throw new InvalidParentProcessException(this, aNewParentProcess);
            }
            boolean isImported = isImported();
            if (!isImported && !isAcceptableAsParentProcess(aNewParentProcess)) {
                throw new InvalidParentProcessException(this, aNewParentProcess);
            }
            if (aNewParentProcess == null) {
                if (logger.isLoggable(Level.INFO)) {
                    logger.info("Making process " + this + " context free");
                }
            } else {
                if (logger.isLoggable(Level.INFO)) {
                    logger.info("Moving process " + this + " under process " + aNewParentProcess);
                }
            }
            FlexoProcessNode newParentProcessNode = aNewParentProcess != null ? aNewParentProcess.getProcessNode()
                    : null;
            if (newParentProcessNode != null) {
                newParentProcessNode.addToSubProcesses(getProcessNode());
            } else {
                if (isImported) {
                    getWorkflow().addToImportedRootNodeProcesses(getProcessNode());
                } else {
                    getWorkflow().addToTopLevelNodeProcesses(getProcessNode());
                }
            }

            if (getProcessDMEntity() != null) {
                getProcessDMEntity().updateParentProcessPropertyIfRequired();
            }
            if (!isImported()) {
                validateAfterMoving();
            }
        }
    }

    public boolean isAcceptableAsParentProcess(FlexoProcess aProcess) {
        return isProcessHierarchyValidForNewParentProcess(aProcess);
    }

    private boolean isProcessHierarchyValidForNewParentProcess(FlexoProcess aNewParentProcess) {
        return !isImported() && !isAncestorOf(aNewParentProcess)
                && (aNewParentProcess == null || !aNewParentProcess.isImported());
    }

    private void validateAfterMoving() throws InvalidProcessReferencesException {
        ValidationReport report = getWorkflow().validate(getProcessMovingValidationModel());
        if (report.getErrorNb() > 0) {
            throw new InvalidProcessReferencesException(this, report);
        }
    }

    private ProcessMovingValidationModel processMovingValidationModel;

    public ProcessMovingValidationModel getProcessMovingValidationModel() {
        if (processMovingValidationModel == null && getProject() != null) {
            processMovingValidationModel = new ProcessMovingValidationModel(getProject());
        }
        return processMovingValidationModel;
    }

    private static class ProcessMovingValidationModel extends ValidationModel {

        public ProcessMovingValidationModel(FlexoProject project) {
            super(project, project.getTargetType());

            registerRule(new FlexoProcess.ProcessHierarchyIsConsistent());
            registerRule(new SubProcessNode.SubProcessReferenceMustBeValid());
            registerRule(new ComponentInstance.DefinedBindingsMustBeValid());

            // Notify that the validation model is complete and that inheritance
            // computation could be performed
            update();
        }

        /**
         * Return a boolean indicating if validation of supplied object must be notified
         * 
         * @param next
         * @return a boolean
         */
        @Override
        protected boolean shouldNotifyValidation(Validable next) {
            return next instanceof FlexoWorkflow || next instanceof FlexoProcess;
        }

        /**
         * Overrides fixAutomaticallyIfOneFixProposal
         * 
         * @see org.openflexo.foundation.validation.ValidationModel#fixAutomaticallyIfOneFixProposal()
         */
        @Override
        public boolean fixAutomaticallyIfOneFixProposal() {
            return false;
        }

    }

    public boolean isTopLevelProcess() {
        return getParentProcess() == null;
    }

    public boolean isRootProcess() {
        return isTopLevelProcess() && getWorkflow().getRootProcess() == this;
    }

    public boolean isAncestorOf(FlexoProcess anOtherProcess) {
        FlexoProcess current = anOtherProcess;
        while (current != null) {
            if (current == this) {
                return true;
            }
            current = current.getParentProcess();
        }
        return false;
    }

    /**
     * Return all sub-processes of this process, as a Vector of FlexoProcess
     * 
     * @return a Vector of FlexoProcess
     */
    public Vector<FlexoProcess> getSubProcesses() {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("getSubProcesses() for " + getName());
        }
        _subProcesses = rebuildSubProcesses();
        return _subProcesses;
    }

    public boolean isSingleSubProcess() {
        boolean hasAtLeastOne = false;
        for (SubProcessNode subProcessNode : getSubProcessNodes()) {
            if (!subProcessNode.isSingle()) {
                return false;
            }
            hasAtLeastOne = true;
        }

        return hasAtLeastOne;
    }

    public Vector<FlexoProcess> getSortedSubProcesses() {
        Vector<FlexoProcess> reply = new Vector<FlexoProcess>();
        Enumeration<FlexoProcessNode> en = getProcessNode().getSortedSubprocesses();
        while (en.hasMoreElements()) {
            reply.add(en.nextElement().getProcess());
        }
        return reply;
    }

    public void addToSubProcesses(FlexoProcess aProcess) {
        if (logger.isLoggable(Level.INFO)) {
            logger.info("Adding process " + aProcess.getName() + " as subprocess of " + getName());
        }
        getProcessNode().addToSubProcesses(aProcess.getProcessNode());
        rebuildSubProcesses();
        if (aProcess.getProcessDMEntity() != null) {
            aProcess.getProcessDMEntity().createParentProcessPropertyIfRequired();
        }
        setChanged();
        notifyObservers(new ProcessInserted(aProcess, this));
        if (logger.isLoggable(Level.INFO)) {
            logger.info("DONE. Adding process " + aProcess.getName() + " as subprocess of " + getName());
        }
    }

    public void removeFromSubProcesses(FlexoProcess aProcess) {
        getProcessNode().removeFromSubProcesses(aProcess.getProcessNode());
        rebuildSubProcesses();
        setChanged();
        notifyObservers(new ProcessRemoved(this, getParentProcess()));
    }

    /**
     * Return all sub-processes of this process, as a Vector of FlexoProcess
     * 
     * @return a Vector of FlexoProcess
     */
    protected Vector<FlexoProcess> rebuildSubProcesses() {
        if (_subProcesses != null) {
            _subProcesses.clear();
        }
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("rebuildSubProcesses() for " + getName());
        }
        if (getProcessNode() == null || getProcessNode().getSubProcesses() == null) {
            return new Vector<FlexoProcess>();
        }
        _subProcesses = new Vector<FlexoProcess>();
        Enumeration en = getProcessNode().getSubProcesses().elements();
        while (en.hasMoreElements()) {
            FlexoProcess subProcess = ((FlexoProcessNode) en.nextElement()).getProcess();
            if (subProcess != null) {
                _subProcesses.add(subProcess);
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine("Sub-process: " + subProcess.getName());
                }
            }
        }
        return _subProcesses;
    }

    @Override
    public double getWidth(String context) {
        return getWidth(context, 1000.0);
    }

    @Override
    public double getHeight(String context) {
        return getHeight(context, 1000.0);
    }

    public double getScale(String context, double defaultValue) {
        return _doubleGraphicalPropertyForKey("scale_" + context, defaultValue);
    }

    public void setScale(String context, double value) {
        boolean wasNull = !hasGraphicalPropertyForKey("scale_" + context);
        double oldValue = getScale(context, value);
        logger.info("setScale from " + oldValue + " to " + value + " wasNull=" + wasNull);
        if (wasNull || value != oldValue) {
            _setGraphicalPropertyForKey(value, "scale_" + context);
            setChanged();

        }
    }

    /**
     * Return all OperationNode contained in this process
     * 
     * @return a Vector of OperationNode
     */
    public Vector<OperationNode> getAllEmbeddedOperationNodes() {
        Vector<OperationNode> v = new Vector<OperationNode>();
        if (isImported()) {
            return v;
        }
        if (_petriGraph != null) {
            for (AbstractActivityNode activity : _petriGraph.getAllEmbeddedAbstractActivityNodes()) {
                v.addAll(activity.getAllEmbeddedOperationNodes());
            }
            return v;
        }
        if (logger.isLoggable(Level.WARNING)) {
            logger.warning("_petriGraph is null for process:" + getName());
        }
        return v;
    }

    /**
     * Return all OperationNode contained in this process that are associated with a WOComponent
     * 
     * @return a Vector of OperationNode
     */
    public Vector<OperationNode> getAllOperationNodesWithComponent() {
        Vector<OperationNode> retval = new Vector<OperationNode>();
        Vector<OperationNode> v = getAllEmbeddedOperationNodes();
        Enumeration<OperationNode> en = v.elements();
        while (en.hasMoreElements()) {
            OperationNode node = en.nextElement();
            if (node.hasWOComponent()) {
                retval.add(node);
            }
        }
        return retval;
    }

    public OperationNode getOperationNodeWithFlexoID(long flexoID) {
        for (Enumeration e = getAllEmbeddedOperationNodes().elements(); e.hasMoreElements();) {
            OperationNode operation = (OperationNode) e.nextElement();
            if (operation != null) {
                if (operation.getFlexoID() == flexoID) {
                    return operation;
                }
            }
        }
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Could not find operation with flexoID " + flexoID);
        }
        return null;
    }

    /**
     * Return all OperationNode contained in this process
     * 
     * @return a Vector of OperationNode
     */
    public Vector<WKFArtefact> getAllEmbeddedArtefacts() {
        return _petriGraph.getAllEmbeddedArtefacts();
    }

    /**
     * Return all WOComponents contained in this process
     * 
     * @return a Vector of ComponentDefinition
     */
    /*
     * public Vector<ComponentDefinition> getAllComponents() {
     * Vector<ComponentDefinition> answer = new Vector<ComponentDefinition>();
     * answer.addAll(getAllOperationComponents());
     * answer.addAll(getAllThumnailComponents()); return answer; }
     */
    public Vector<OperationComponentInstance> getAllComponentInstances() {
        Vector<OperationComponentInstance> answer = new Vector<OperationComponentInstance>();
        Enumeration en = getAllEmbeddedOperationNodes().elements();
        OperationNode cur = null;
        while (en.hasMoreElements()) {
            cur = (OperationNode) en.nextElement();
            if (cur.getComponentInstance() != null && cur.getComponentInstance().getComponentDefinition() != null) {
                answer.add(cur.getComponentInstance());
            }
        }
        return answer;
    }

    /**
     * Return all thumnail components contained in this process
     * 
     * @return a Vector of ThumbnailComponentDefinition
     */
    public Vector<TabComponentDefinition> getAllThumnailComponents() {
        /*
         * Vector answer = new Vector(); Enumeration en =
         * getAllOperationNodes().elements(); OperationNode cur = null;
         * while(en.hasMoreElements()){ cur = (OperationNode)en.nextElement();
         * if(cur.getComponentDefinition()!=null){
         * answer.addAll(cur.getComponentDefinition
         * ().getThumbnailsComponentList()); } }
         */
        return getProject().getFlexoComponentLibrary().getTabComponentList();
    }

    /**
     * Return all ActionNode contained in this process
     * 
     * @return a Vector of ActionNode
     */
    public Vector<ActionNode> getAllEmbeddedActionNodes() {
        if (_petriGraph != null) {
            Vector<ActionNode> v = new Vector<ActionNode>();
            for (AbstractActivityNode a : _petriGraph.getAllEmbeddedAbstractActivityNodes()) {
                for (OperationNode o : a.getAllEmbeddedOperationNodes()) {
                    v.addAll(o.getAllEmbeddedActionNodes());
                }
            }
            return v;
        } else {
            return new Vector<ActionNode>();
        }
    }

    @Override
    public String toString() {
        return getName();
    }

    @Override
    public String getName() {
        return _name;
    }

    public String getProcessInstanceEntityName() {
        return getProcessInstanceEntityName(_name);
    }

    public String getProcessInstanceEntityName(String aProcessName) {
        return beautifyName(aProcessName) + "ProcessInstance";
    }

    public static String beautifyName(String name) {
        if (name == null) {
            return null;
        }
        if (name.matches(JavaUtils.JAVA_CLASS_NAME_REGEXP)) {
            return name;
        }
        Matcher m = JavaUtils.JAVA_VARIABLE_ACCEPTABLE_PATTERN.matcher(name);
        StringBuffer sb = new StringBuffer();
        int i = 0;
        while (m.find()) {
            int n = m.start() - i;
            for (int j = 0; j < n; j++) {
                sb.append('_');
            }
            sb.append(ToolBox.capitalize(m.group(), true));
            i = m.start() + m.end();
        }
        if (sb.length() == 0 || sb.charAt(0) >= '0' && sb.charAt(0) <= '9') {
            sb.insert(0, '_');
        }
        return sb.toString();
    }

    private static boolean processWithSimilarNameExists(FlexoWorkflow workflow, FlexoProcess thisProcess,
            String nameCandidate) {
        String javaNameCandidate = ToolBox.getJavaName(nameCandidate);
        for (FlexoProcess p : workflow.getAllFlexoProcesses()) {
            if (p != thisProcess) {
                String processJavaName = ToolBox.getJavaName(p.getName());
                if (processJavaName.equals(javaNameCandidate)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void setName(String newName) throws DuplicateResourceException, InvalidNameException {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("FlexoProcess.setName() with " + newName + " was: " + _name);
        }
        if (!newName.equals(_name) || _name == null) {
            if (processWithSimilarNameExists(getWorkflow(), this, ToolBox.getJavaName(newName))) {
                throw new InvalidNameException("A process with similar name exists");
            }
            if (getProject() != null && getFlexoResource() != null && !isDeserializing()) {
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine("renameResource() with " + newName);
                }
                try {
                    getProject().renameResource(getFlexoResource(), newName);
                } catch (DuplicateResourceException e) {
                    if (!isImported()) {
                        setChanged(false);
                        notifyObserversAsReentrantModification(new NameChanged(_name, _name));
                        throw e;
                    } else if (logger.isLoggable(Level.WARNING)) {
                        logger.warning("Duplicate resource thrown on imported process: " + newName);
                    }
                }
                if (getProcessNode() != null) {
                    getProcessNode().setChanged();// Workflow needs to be saved
                    // again
                }
            }
            if (!isDeserializing() && getProcessDMEntity() != null) {
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine("rename process entity with " + getProcessInstanceEntityName(newName));
                }
                getProcessDMEntity().setName(getProcessInstanceEntityName(newName));
            }
            String oldName = _name;
            _name = newName;
            /*
             * if (getProcessNode() != null) { if
             * (logger.isLoggable(Level.FINE))
             * logger.fine("rename process node with " + newName);
             * getProcessNode().setName(newName); }
             */
            setChanged();
            notifyObservers(new NameChanged(oldName, newName));
        } else {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("setName() ignored");
            }
        }
    }

    public void createsAutoGeneratedProcessBusinessDataDMEntityIfRequired() {
        if (!isImported() && getBusinessDataType() == null) {
            getProject().getDataModel().getProcessBusinessDataRepository()
                    .getAutoGeneratedProcessBusinessDataDMEntity(this);
        }
    }

    public ProcessDMEntity createsProcessDMEntityIfRequired() {
        if (!isImported()) {
            return getProcessDMEntity();
        }
        return null;
    }

    private ProcessDMEntity _processDMEntity = null;

    public ProcessDMEntity getProcessDMEntity() {
        if (_processDMEntity == null && !isImported()) {
            if (getProject() != null) {
                DMModel dmModel = getProject().getDataModel();
                ProcessInstanceRepository processInstanceRepository = dmModel.getProcessInstanceRepository();
                _processDMEntity = processInstanceRepository.getProcessDMEntity(this);
                // logger.info("************ getProcessNode()="+getProcessNode());
                if (_processDMEntity == null) {
                    if (logger.isLoggable(Level.INFO)) {
                        logger.info("Creates entry for process " + getName() + " in ProcessInstanceRepository");
                    }
                    _processDMEntity = new ProcessDMEntity(getProject().getDataModel(), this);
                    getProject().getDataModel().getProcessInstanceRepository().registerEntity(_processDMEntity);
                }
                _processDMEntity.setProcess(this);
            }
        }
        return _processDMEntity;
    }

    /*
     * public BindingVariable getBusinessData() { if (_businessData == null) {
     * _businessData = new BindingVariable(this,getProject().getDataModel()); }
     * return _businessData; }
     *
     * public void setBusinessData(BindingVariable businessData) { _businessData
     * = businessData; }
     */

    public DMProperty getBusinessDataProperty() {
        ProcessDMEntity processDMEntity = getProcessDMEntity();
        if (processDMEntity != null) {
            return processDMEntity.getBusinessDataProperty();
        }
        return null;
    }

    public String getBusinessDataVariableName() {
        if (getBusinessDataProperty() != null) {
            return getBusinessDataProperty().getName();
        }
        return null;
    }

    public void setBusinessDataVariableName(String aName)
            throws InvalidNameException, DuplicatePropertyNameException {
        if (aName == null) {
            return;
        }
        if (ReservedKeyword.contains(aName)) {
            throw new InvalidNameException();
        }
        if (getBusinessDataProperty() != null) {
            getBusinessDataProperty().setName(aName);
        } else if (getProcessDMEntity() != null) {
            if (!aName.trim().equals("")) {
                getProcessDMEntity().createBusinessDataProperty(aName);
            }
        }
    }

    public DMEntity getBusinessDataType() {
        if (getBusinessDataProperty() != null) {
            return getBusinessDataProperty().getType().getBaseEntity();
        }
        return null;
    }

    public void setBusinessDataType(DMEntity aType) {
        if (getBusinessDataProperty() != null) {
            getBusinessDataProperty().setType(DMType.makeResolvedDMType(aType));
        } else if (getProcessDMEntity() != null) {
            getProcessDMEntity().createBusinessDataProperty(aType);
            setChanged();
            notifyAttributeModification("businessDataVariableName", null, getBusinessDataProperty());
        }
        setChanged();
        notifyAttributeModification("businessDataType", null, aType);
    }

    @Override
    public BindingModel getBindingModel() {
        if (_bindingModel == null) {
            _bindingModel = new ProcessBindingModel();
        }
        return _bindingModel;
    }

    public class ProcessBindingModel extends BindingModel {
        private ProcessBindingVariable _processInstance;

        ProcessBindingModel() {
            super();
            _processInstance = new ProcessBindingVariable();
        }

        @Override
        public int getBindingVariablesCount() {
            return 1;
        }

        @Override
        public BindingVariable getBindingVariableAt(int index) {
            return getProcessInstanceBindingVariable();
        }

        public BindingVariable getProcessInstanceBindingVariable() {
            return _processInstance;
        }

        @Override
        public boolean allowsNewBindingVariableCreation() {
            return false;
        }

        public class ProcessBindingVariable extends BindingVariable {
            private DMType _processBindingVariableType = null;

            ProcessBindingVariable() {
                super(FlexoProcess.this, FlexoProcess.this.getProject().getDataModel(),
                        FlexoLocalization.localizedForKey("access_to_the_current_process_instance"));
                setVariableName("processInstance");
            }

            @Override
            public DMType getType() {
                if (_processBindingVariableType == null
                        || _processBindingVariableType.getKindOfType() != DMType.KindOfType.RESOLVED
                        || _processBindingVariableType.getBaseEntity() != getProcessDMEntity()) {
                    _processBindingVariableType = DMType.makeResolvedDMType(getProcessDMEntity());
                }
                return _processBindingVariableType;
            }

        }
    }

    public FlexoProcessNode getProcessNode() {
        return _processNode;
    }

    public void setProcessNode(FlexoProcessNode processNode) {
        _processNode = processNode;
        rebuildSubProcesses();
    }

    /**
     * Return all abstract node at all levels for this process
     * 
     * @return a Vector of AbstractNode
     */
    public Vector<AbstractNode> getAllAbstractNodes() {
        if (allAbstractNodes == null) {
            allAbstractNodes = new Vector<AbstractNode>();
            if (getPortRegistery() != null) {
                allAbstractNodes.addAll(getPortRegistery().getAllPorts());
            }
            appendAllAbstractNodesOfPetriGraph(getActivityPetriGraph(), allAbstractNodes);
            /*
             * allAbstractNodes.addAll(getAllActivities()); if
             * (getPortRegistery() != null) {
             * allAbstractNodes.addAll(getPortRegistery().getAllPorts()); } for
             * (Enumeration e = getAllSubProcessNodes().elements();
             * e.hasMoreElements();) { SubProcessNode node = (SubProcessNode)
             * e.nextElement(); if (node.getPortMapRegistery() != null) {
             * allAbstractNodes
             * .addAll(node.getPortMapRegistery().getPortMaps()); } }
             *
             * // Don't do this, this will be done while adding
             * getAllDeepOperatorNodes() // All activity-level operator nodes
             * were recorded twice !!!!!!
             *
             * // allAbstractNodes.addAll(getAllOperatorNodes());
             *
             * if (_petriGraph != null) {
             * allAbstractNodes.addAll(_petriGraph.getAllOperationNodes());
             * allAbstractNodes.addAll(_petriGraph.getAllActionNodes());
             * allAbstractNodes.addAll(_petriGraph.getAllDeepOperatorNodes()); }
             */
        }
        return allAbstractNodes;
    }

    private void appendAllAbstractNodesOfPetriGraph(FlexoPetriGraph pg, Vector<AbstractNode> returned) {
        for (AbstractNode n : pg.getNodes()) {
            appendAllAbstractNodes(n, returned);
        }
    }

    private void appendAllAbstractNodes(AbstractNode node, Vector<AbstractNode> returned) {
        returned.add(node);
        if (node instanceof FlexoNode) {
            returned.addAll(((FlexoNode) node).getPreConditions());
        }
        if (node instanceof SubProcessNode) {
            if (((SubProcessNode) node).getPortMapRegistery() != null) {
                returned.addAll(((SubProcessNode) node).getPortMapRegistery().getPortMaps());
            }
        }
        if (node instanceof AbstractActivityNode && ((AbstractActivityNode) node).hasContainedPetriGraph()) {
            appendAllAbstractNodesOfPetriGraph(((AbstractActivityNode) node).getContainedPetriGraph(), returned);
        }
        if (node instanceof OperationNode && ((OperationNode) node).hasContainedPetriGraph()) {
            appendAllAbstractNodesOfPetriGraph(((OperationNode) node).getContainedPetriGraph(), returned);
        }
        if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).hasExecutionPetriGraph()) {
            appendAllAbstractNodesOfPetriGraph(((SelfExecutableNode) node).getExecutionPetriGraph(), returned);
        }
        if (node instanceof LOOPOperator && ((LOOPOperator) node).hasExecutionPetriGraph()) {
            appendAllAbstractNodesOfPetriGraph(((LOOPOperator) node).getExecutionPetriGraph(), returned);
        }
    }

    /**
     * Return all abstract node at all levels for this process
     * 
     * @return a Vector of AbstractNode
     */
    public Vector<WKFNode> getAllNodes() {
        if (allNodes == null) {
            allNodes = new Vector<WKFNode>();
            if (getPortRegistery() != null) {
                allNodes.addAll(getPortRegistery().getAllPorts());
            }
            appendAllNodesOfPetriGraph(getActivityPetriGraph(), allNodes);
            /*
             * allAbstractNodes.addAll(getAllActivities()); if
             * (getPortRegistery() != null) {
             * allAbstractNodes.addAll(getPortRegistery().getAllPorts()); } for
             * (Enumeration e = getAllSubProcessNodes().elements();
             * e.hasMoreElements();) { SubProcessNode node = (SubProcessNode)
             * e.nextElement(); if (node.getPortMapRegistery() != null) {
             * allAbstractNodes
             * .addAll(node.getPortMapRegistery().getPortMaps()); } }
             *
             * // Don't do this, this will be done while adding
             * getAllDeepOperatorNodes() // All activity-level operator nodes
             * were recorded twice !!!!!!
             *
             * // allAbstractNodes.addAll(getAllOperatorNodes());
             *
             * if (_petriGraph != null) {
             * allAbstractNodes.addAll(_petriGraph.getAllOperationNodes());
             * allAbstractNodes.addAll(_petriGraph.getAllActionNodes());
             * allAbstractNodes.addAll(_petriGraph.getAllDeepOperatorNodes()); }
             */
        }
        return allNodes;
    }

    private void appendAllNodesOfPetriGraph(FlexoPetriGraph pg, Vector<WKFNode> returned) {
        for (AbstractNode n : pg.getNodes()) {
            appendAllNodes(n, returned);
        }
        returned.addAll(pg.getArtefacts());
    }

    private void appendAllNodes(WKFNode node, Vector<WKFNode> returned) {
        returned.add(node);
        if (node instanceof FlexoNode) {
            returned.addAll(((FlexoNode) node).getPreConditions());
        }
        if (node instanceof SubProcessNode) {
            if (((SubProcessNode) node).getPortMapRegistery() != null) {
                returned.addAll(((SubProcessNode) node).getPortMapRegistery().getPortMaps());
            }
        }
        if (node instanceof AbstractActivityNode && ((AbstractActivityNode) node).hasContainedPetriGraph()) {
            appendAllNodesOfPetriGraph(((AbstractActivityNode) node).getContainedPetriGraph(), returned);
        }
        if (node instanceof OperationNode && ((OperationNode) node).hasContainedPetriGraph()) {
            appendAllNodesOfPetriGraph(((OperationNode) node).getContainedPetriGraph(), returned);
        }
        if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).hasExecutionPetriGraph()) {
            appendAllNodesOfPetriGraph(((SelfExecutableNode) node).getExecutionPetriGraph(), returned);
        }
        if (node instanceof LOOPOperator && ((LOOPOperator) node).hasExecutionPetriGraph()) {
            appendAllNodesOfPetriGraph(((LOOPOperator) node).getExecutionPetriGraph(), returned);
        }
    }

    /**
     * Return all activities for this process
     * 
     * @return a Vector of AbstractActivityNode
     */
    public Vector<AbstractActivityNode> getAllAbstractActivityNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllAbstractActivityNodes();
        } else {
            return new Vector<AbstractActivityNode>();
        }
    }

    public Vector<AbstractActivityNode> getAllMeaningFullActivityNodes() {
        Vector<AbstractActivityNode> all = getAllAbstractActivityNodes();
        Vector<AbstractActivityNode> reply = new Vector<AbstractActivityNode>();
        for (AbstractActivityNode node : all) {
            if (!node.isBeginOrEndNode() && node.getName().trim().length() > 0) {
                if (!node.getDontGenerate()) {
                    reply.add(node);
                }
            }
        }
        return reply;
    }

    public Vector<SubProcessNode> getAllMeaningSubProcessNodes() {
        Vector<AbstractActivityNode> all = getAllAbstractActivityNodes();
        Vector<SubProcessNode> reply = new Vector<SubProcessNode>();
        for (AbstractActivityNode node : all) {
            if (!node.isBeginOrEndNode() && node.getName().trim().length() > 0) {
                if (node instanceof SubProcessNode) {
                    reply.add((SubProcessNode) node);
                }
            }
        }
        return reply;
    }

    public Vector<AbstractActivityNode> getAllEmbeddedAbstractActivityNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllEmbeddedAbstractActivityNodes();
        } else {
            return new Vector<AbstractActivityNode>();
        }
    }

    public Vector<PetriGraphNode> getAllAbstractActivityNodesAndActivityOperators() {
        if (_petriGraph != null) {
            Vector<PetriGraphNode> v = new Vector<PetriGraphNode>();
            v.addAll(_petriGraph.getAllEmbeddedAbstractActivityNodes());
            v.addAll(_petriGraph.getAllEmbeddedOperatorsOfSameLevel());
            return v;
        } else {
            return new Vector<PetriGraphNode>();
        }
    }

    public Vector<PetriGraphNode> getAllAbstractActivityNodesAndActivityOperatorsWithEvents() {
        if (_petriGraph != null) {
            Vector<PetriGraphNode> v = new Vector<PetriGraphNode>();
            v.addAll(_petriGraph.getAllEmbeddedNodesOfClass(AbstractActivityNode.class));
            v.addAll(_petriGraph.getAllEmbeddedNodesOfClassOfSameLevel(OperatorNode.class));
            v.addAll(_petriGraph.getAllEmbeddedNodesOfClassOfSameLevel(EventNode.class));
            return v;
        } else {
            return new Vector<PetriGraphNode>();
        }
    }

    /**
     * Return all activities of the underlying petri graph.
     * 
     * @return a Vector of ActivityNode
     */
    public Vector<ActivityNode> getAllActivityNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllActivityNodes();
        } else {
            return new Vector<ActivityNode>();
        }
    }

    public AbstractActivityNode getAbstractActivityNodeNamed(String name) {
        Enumeration<AbstractActivityNode> en = getAllEmbeddedAbstractActivityNodes().elements();
        while (en.hasMoreElements()) {
            AbstractActivityNode node = en.nextElement();
            if (node.getName().equals(name)) {
                return node;
            }
        }
        if (logger.isLoggable(Level.WARNING)) {
            logger.warning(
                    "AbstractActivity named " + name + " could not be found in process " + getProcess().getName());
        }
        return null;
    }

    public EventNode getEventNodeNamed(String name) {
        Enumeration<EventNode> en = getAllEventNodes().elements();
        while (en.hasMoreElements()) {
            EventNode node = en.nextElement();
            if (node.getName().equals(name)) {
                return node;
            }
        }
        if (logger.isLoggable(Level.WARNING)) {
            logger.warning(
                    "AbstractActivity named " + name + " could not be found in process " + getProcess().getName());
        }
        return null;
    }

    /**
     * Return all sub-processes for this process
     * 
     * @return a Vector of SubProcessNode
     */
    public Vector<SubProcessNode> getAllSubProcessNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllSubProcessNodes();
        } else {
            return new Vector<SubProcessNode>();
        }
    }

    public Vector<SubProcessNode> getAllProcessInstances() {
        return getWorkflow().getAllSubProcessNodeUsingProcess(this);
    }

    /**
     * Return a vector of all BEGIN_NODE of the underlying Petri Graph
     * 
     * @return Vector of Begin nodes
     */
    public Vector<FlexoNode> getAllBeginNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllBeginNodes();
        } else {
            return new Vector<FlexoNode>();
        }
    }

    /**
     * Return a vector of all END_NODE of the underlying Petri Graph
     * 
     * @return Vector of end nodes
     */
    public Vector<FlexoNode> getAllEndNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllEndNodes();
        } else {
            return new Vector<FlexoNode>();
        }
    }

    /**
     * Return a vector of all OPERATOR of the underlying Petri Graph
     * 
     * @return Vector of ActivityNode
     */
    public Vector<OperatorNode> getAllOperatorNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllOperatorNodes();
        } else {
            return new Vector<OperatorNode>();
        }
    }

    public Vector<OperatorNode> getAllEmbeddedOperatorNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllEmbeddedOperators();
        } else {
            return new Vector<OperatorNode>();
        }
    }

    /**
     * Return a vector of all Event nodes of the underlying Petri Graph
     * 
     * @return Vector of EventNode
     */
    public Vector<EventNode> getAllEventNodes() {
        // TODO: optimize me later !!!
        if (_petriGraph != null) {
            return _petriGraph.getAllEventNodes();
        } else {
            return new Vector<EventNode>();
        }
    }

    public Vector<FlexoPostCondition<?, ?>> getAllPostConditions() {
        Vector<FlexoPostCondition<?, ?>> returned = new Vector<FlexoPostCondition<?, ?>>() {
            @Override
            public synchronized boolean addAll(Collection<? extends FlexoPostCondition<?, ?>> c) {
                for (FlexoPostCondition<?, ?> edge : c) {
                    if (!contains(edge)) {
                        add(edge);
                    }
                }
                return true;
            }
        };
        for (AbstractNode n : getAllAbstractNodes()) {
            returned.addAll(n.getOutgoingPostConditions());
            returned.addAll(n.getIncomingPostConditions());
        }
        return returned;
    }

    public Vector<WKFAssociation> getAllAssociations() {
        Vector<WKFAssociation> returned = new Vector<WKFAssociation>() {
            @Override
            public synchronized boolean addAll(Collection<? extends WKFAssociation> c) {
                for (WKFAssociation edge : c) {
                    if (!contains(edge)) {
                        add(edge);
                    }
                }
                return true;
            }
        };
        for (WKFNode n : getAllNodes()) {
            returned.addAll(n.getOutgoingAssociations());
            returned.addAll(n.getIncomingAssociations());
        }
        return returned;
    }

    public Vector<MessageEdge<?, ?>> getAllMessageEdges() {
        // logger.info("getAllMessageEdges for process "+getName());
        Vector<MessageEdge<?, ?>> returned = new Vector<MessageEdge<?, ?>>();
        for (FlexoPostCondition<?, ?> e : getAllPostConditions()) {
            if (e instanceof MessageEdge) {
                returned.add((MessageEdge<?, ?>) e);
                // logger.info("Found "+e.getDerivedNameFromStartingObject()+" to "+e.getDerivedNameFromEndingObject());
            }
        }
        return returned;
    }

    /**
     * Returns the level of a FlexoProcess (which is {@link FlexoLevel.PROCESS} ).
     * 
     * @see org.openflexo.foundation.wkf.LevelledObject#getLevel()
     */
    @Override
    public FlexoLevel getLevel() {
        return FlexoLevel.PROCESS;
    }

    // ==========================================================================
    // ================================= Delete ===============================
    // ==========================================================================

    @Override
    public final void delete() {
        if (isImported()) {
            isImported = true;// This is important, because it allows to do some
        }
        // tests on this deleted object
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("delete: FlexoProcess " + getName());
        }
        for (FlexoProcess p : new Vector<FlexoProcess>(getSubProcesses())) {
            p.delete();
        }
        Vector<SubProcessNode> allBoundSubProcessNodes = new Vector<SubProcessNode>(getSubProcessNodes());
        for (Enumeration<SubProcessNode> e = allBoundSubProcessNodes.elements(); e.hasMoreElements();) {
            SubProcessNode subProcessNode = e.nextElement();
            subProcessNode.setSubProcess(null);
            if (logger.isLoggable(Level.INFO)) {
                logger.info("Set subprocess to null for " + subProcessNode.getName());
            }
        }
        /*
         * FlexoProcessNode processNode = getProcessNode(); if (processNode !=
         * null) { processNode.delete(); processNode = null; }
         */
        if (_petriGraph != null) {
            _petriGraph.delete();
        }
        FlexoProcess parentProcess = getParentProcess();
        if (getFlexoResource() != null) {
            getFlexoResource().delete();
        }
        if (getProcessDMEntity() != null) {
            getProcessDMEntity().delete();
        }
        if (getProcessNode() != null) {
            getProcessNode().delete();
        } else {
            if (logger.isLoggable(Level.WARNING)) {
                logger.warning("Process " + getName() + " has no process node associated!");
            }
        }
        FlexoProcessImageBuilder.deleteSnapshot(this);
        super.delete();
        if (nameForNodeMap != null) {
            nameForNodeMap.clear();
        }
        nameForNodeMap = null;
        setChanged();
        notifyObservers(new ProcessRemoved(this, parentProcess));
        deleteObservers();
    }

    /**
     * Build and return a vector of all the objects that will be deleted during process deletion
     * 
     * @param aVector
     *            of DeletableObject
     */
    @Override
    public Vector<WKFObject> getAllEmbeddedDeleted() {
        return getAllEmbeddedWKFObjects();
    }

    /**
     * Return a Vector of all embedded WKFObjects
     * 
     * @return a Vector of WKFObject instances
     */
    @Override
    public Vector<WKFObject> getAllEmbeddedWKFObjects() {
        Vector<WKFObject> returned = new Vector<WKFObject>();
        returned.add(this);
        if (_petriGraph != null) {
            returned.addAll(_petriGraph.getAllEmbeddedWKFObjects());
        }
        if (getPortRegistery() != null) {
            returned.addAll(getPortRegistery().getAllEmbeddedWKFObjects());
        }

        if (getServiceInterfaces() != null) {
            Enumeration en = getServiceInterfaces().elements();
            while (en.hasMoreElements()) {
                ServiceInterface service = (ServiceInterface) en.nextElement();
                returned.addAll(service.getAllEmbeddedWKFObjects());
            }
        }
        if (getStatusList() != null) {
            returned.addAll(getStatusList().getAllEmbeddedWKFObjects());
        }
        returned.addAll(getMetricsValues());

        return returned;
    }

    /**
     * Return a vector of all embedded objects on which the validation will be performed
     * 
     * @return a Vector of Validable objects
     */
    @Override
    public Vector<Validable> getAllEmbeddedValidableObjects() {
        Vector<Validable> returned = new Vector<Validable>();
        returned.addAll(getAllEmbeddedWKFObjects());
        for (Enumeration en = getAllEmbeddedOperationNodes().elements(); en.hasMoreElements();) {
            OperationNode next = (OperationNode) en.nextElement();
            if (next.getComponentInstance() != null) {
                returned.add(next.getComponentInstance());
            }
        }
        return returned;
    }

    /**
     * @param baseName
     * @param node
     * @return
     */
    public String findNextInitialName(String baseName) {
        return nextInitialName(baseName, getFullyQualifiedName() + "." + baseName);
    }

    /**
     * @param baseName
     * @param node
     * @return
     */
    public String findNextInitialName(String prefix, String baseName) {
        return nextInitialName(baseName, getFullyQualifiedName() + "." + prefix + "." + baseName);
    }

    /**
     * @param baseName
     * @param node
     * @return
     */
    public String findNextNonAmbigousNameForNode(String baseName, AbstractNode aNode) {
        if (aNode instanceof PetriGraphNode) {
            if (aNode instanceof AbstractActivityNode) {
                return findNextInitialName(baseName);
            }
            if (aNode instanceof OperationNode) {
                return findNextInitialName(baseName, ((OperationNode) aNode).getAbstractActivityNode());
            }
            if (aNode instanceof ActionNode) {
                return findNextInitialName(baseName, ((ActionNode) aNode).getOperationNode());
            }
        } else if (aNode instanceof OperatorNode) {
            if (aNode.getLevel() == FlexoLevel.ACTIVITY) {
                return findNextInitialName(baseName);
            }
            if (aNode.getLevel() == FlexoLevel.OPERATION) {
                return findNextInitialName(baseName, ((OperatorNode) aNode).getAbstractActivityNode());
            }
            if (aNode.getLevel() == FlexoLevel.ACTION) {
                return findNextInitialName(baseName, ((OperatorNode) aNode).getOperationNode());
            }
        } else if (aNode instanceof FlexoPort) {
            return findNextInitialName(baseName);
        } else if (aNode instanceof FlexoPortMap) {
            return findNextInitialName(baseName, ((FlexoPortMap) aNode).getSubProcessNode());
        }
        if (logger.isLoggable(Level.WARNING)) {
            logger.warning("Unexpected type " + aNode.getClass().getName());
        }
        return null;
    }

    /**
     * @param baseName
     * @param node
     * @return
     */
    public String findNextInitialName(String baseName, WKFObject node) {
        if (node instanceof AbstractNode) {
            return findNextNonAmbigousNameForNode(baseName, (AbstractNode) node);
        }
        return baseName;
    }

    /**
     * @param baseName
     * @param node
     * @return
     */
    public String findNextInitialName(String baseName, AbstractActivityNode activityNode) {
        if (activityNode == null) {
            return baseName;
        }
        return nextInitialName(baseName, getFullyQualifiedName() + "." + activityNode.getName() + "." + baseName);
    }

    /**
     * @param baseName
     * @param node
     * @return
     */
    public String findNextInitialName(String baseName, OperationNode operationNode) {
        if (operationNode == null) {
            return baseName;
        }
        return nextInitialName(baseName,
                getFullyQualifiedName() + "." + operationNode.getAbstractActivityNode().getName() + "."
                        + operationNode.getName() + "." + baseName);
    }

    /**
     * @param fullQualifiedBaseName
     * @param node
     * @return
     */
    private String nextInitialName(String baseName, String fullQualifiedBaseName) {
        // Scrum 1.3.2: request to remove disambiguation of node names
        /*
         * Vector allNodes = getAllAbstractNodes();
         *
         * boolean found = false; int i = 0; String tryWith =
         * fullQualifiedBaseName; String returnedName = baseName;
         *
         * if (logger.isLoggable(Level.FINE))
         * logger.fine("findNextInitialName() for " + fullQualifiedBaseName);
         *
         * while (!found) { boolean alreadyExists = false; if
         * (logger.isLoggable(Level.FINE)) logger.fine("look " + tryWith); for
         * (Enumeration e = allNodes.elements(); (e.hasMoreElements() &&
         * !(alreadyExists));) { String next = ((AbstractNode)
         * e.nextElement()).getFullyQualifiedName(); if
         * (logger.isLoggable(Level.FINE)) logger.fine("  > already " + next);
         * if (next.equalsIgnoreCase(tryWith)) { alreadyExists = true; } }
         * alreadyExists |= getName().equalsIgnoreCase(returnedName); if
         * (alreadyExists) { i++; tryWith = fullQualifiedBaseName + "-" + i;
         * returnedName = baseName + "-" + i; } else { found = true; } } if
         * (logger.isLoggable(Level.FINE))
         * logger.fine("findNextInitialName() return " + tryWith); return
         * returnedName;
         */
        return baseName;
    }

    public PortRegistery getPortRegistery() {
        if (_registery == null && !isImported()) {
            _registery = new PortRegistery(this);
            // TODO: following must be put in some finalizer
            /*
             * _registery.setX(250,WKFRepresentableObject.BASIC_PROCESS_EDITOR);
             * _registery.setY(60,WKFRepresentableObject.BASIC_PROCESS_EDITOR);
             * _registery
             * .setWidth(80,WKFRepresentableObject.BASIC_PROCESS_EDITOR);
             * _registery
             * .setHeight(20,WKFRepresentableObject.BASIC_PROCESS_EDITOR);
             * _registery.setX(250,WKFRepresentableObject.SWIMMING_LANE_EDITOR);
             * _registery.setY(60,WKFRepresentableObject.SWIMMING_LANE_EDITOR);
             * _registery
             * .setWidth(80,WKFRepresentableObject.SWIMMING_LANE_EDITOR);
             * _registery
             * .setHeight(20,WKFRepresentableObject.SWIMMING_LANE_EDITOR);
             */
        }
        return _registery;
    }

    public void setPortRegistery(PortRegistery registery) {
        _registery = registery;
        if (registery.getProcess() != this) {
            if (logger.isLoggable(Level.WARNING)) {
                logger.warning("there is a problem!");
            }
        }
        _registery.setProcess(this);
    }

    public DefaultServiceInterface getPortRegisteryInterface() {
        if (getPortRegistery() != null && _portRegistryInterface == null) {
            try {
                _portRegistryInterface = new DefaultServiceInterface(this);
                _portRegistryInterface.updateFromPortRegistery();
            } catch (FlexoException f) {
                if (logger.isLoggable(Level.WARNING)) {
                    logger.warning("Exception should not arise");
                }
                f.printStackTrace();
            }
        }
        return _portRegistryInterface;
    }

    public Vector<ServiceInterface> getServiceInterfaces() {
        return _serviceInterfaces;
    }

    public void setServiceInterfaces(Vector<ServiceInterface> vector) {
        _serviceInterfaces = vector;
    }

    public ServiceInterface addServiceInterface(String name)
            throws DuplicateWKFObjectException, DuplicateWSObjectException {
        // will throw an exception
        ServiceInterface newInterface;
        try {
            ServiceInterface.checkInterfaceName(this, name, null);
            newInterface = new ServiceInterface(this, name);
        } catch (DuplicateWKFObjectException e) {
            if (logger.isLoggable(Level.WARNING)) {
                logger.warning("An interface with the same name (" + name + ") already exist");
            }
            throw e;
        } catch (DuplicateWSObjectException e) {
            throw e;
        }

        addToServiceInterfaces(newInterface);
        return newInterface;
    }

    public void addToServiceInterfaces(ServiceInterface anInterface) {
        if (!_serviceInterfaces.contains(anInterface)) {
            _serviceInterfaces.add(anInterface);
            anInterface.setProcess(this);
            setChanged();
            notifyObservers(new ServiceInterfaceInserted(anInterface));
        }
    }

    public void removeFromServiceInterfaces(ServiceInterface anInterface) {
        if (_serviceInterfaces.contains(anInterface)) {
            _serviceInterfaces.remove(anInterface);
            setChanged();
            notifyObservers(new ServiceInterfaceRemoved(anInterface));
            anInterface.setProcess(null);
        }
    }

    public ServiceInterface getServiceInterfaceNamed(String interfaceName) {
        Enumeration<ServiceInterface> en = _serviceInterfaces.elements();
        while (en.hasMoreElements()) {
            ServiceInterface intf = en.nextElement();
            if (intf.getName().equals(interfaceName)) {
                return intf;
            }
        }
        return null;
    }

    @Deprecated
    public boolean getIsWebService() {
        return _isWebService;
    }

    @Deprecated
    public void setIsWebService(boolean isWebService) {
        boolean oldValue = _isWebService;
        _isWebService = isWebService;
        if (isWebService != oldValue) {
            notifyAttributeModification("isWebService", new Boolean(oldValue), new Boolean(isWebService));
        }
    }

    public Vector<SubProcessNode> getSubProcessNodes() {
        return _subProcessNodes;
    }

    public void addToSubProcessNodes(SubProcessNode node) {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine(getName() + ": addToSubProcessNodes() " + node.getName());
        }
        if (!node.getXMLResourceData().getFlexoXMLFileResource().isConverting()
                && !_subProcessNodes.contains(node)) {
            _subProcessNodes.add(node);
            addObserver(node);
        }
    }

    public void removeFromSubProcessNodes(SubProcessNode node) {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine(getName() + ": removeFromSubProcessNodes() " + node.getName());
        }
        _subProcessNodes.remove(node);
        deleteObserver(node);
    }

    public void notifyPostInserted(FlexoPostCondition<?, ?> post) {
        setChanged();
        notifyObservers(new PostInserted(post));
    }

    public void notifyAssociationInserted(WKFAssociation association) {
        setChanged();
        notifyObservers(new AssociationInserted(association));
    }

    /**
     * We finalize here serialization since port and port registery definitions are inter-procedural !
     */
    public void finalizeProcessBindings() {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("finalizeProcessBindings() " + getName());
        }
        for (Enumeration e = getAllSubProcessNodes().elements(); e.hasMoreElements();) {
            SubProcessNode node = (SubProcessNode) e.nextElement();
            if (node.getSubProcess() != null) {
                if (logger.isLoggable(Level.FINE)) {
                    logger.finer("Finalize linking " + getName() + " with " + node.getSubProcess().getName());
                }
                if (!node.getSubProcess().isImported()) {
                    node.getPortMapRegistery().lookupServiceInterface();
                }
            } else if (node.getSubProcessName() != null) {
                if (logger.isLoggable(Level.WARNING)) {
                    logger.warning("Undefined sub-process " + node.getSubProcessName() + " referenced in process "
                            + getName());
                }
                node.setSubProcessName(null);
            }
            if (node.getSubProcess() == null && node.getPortMapRegistery() != null) {
                if (logger.isLoggable(Level.WARNING)) {
                    logger.warning(
                            "Inconsistent data : PortMapRegistery defined while no sub-process is defined: remove it");
                }
                node.getPortMapRegistery().delete();
                node.setSubProcessName(null);
            }
        }
        // Now do it with message edges
        // Vector<MessageEdge> unboundMessageEdgesToRemove = new
        // Vector<MessageEdge>();
        for (MessageEdge messageEdge : getAllMessageEdges()) {
            messageEdge.lookupMessageDefinition();
        }
    }

    @Override
    public synchronized void setIsModified() {
        if (ignoreNotifications()) {
            return;
        }
        if (nameForNodeMap != null) {
            nameForNodeMap.clear();// Any modification is capable of modify the
        }
        // names of the objects.
        lastUpdate = null; // Reset the last update date so that it will be
        // recomputed according to the new lastMemoryUpdate!
        super.setIsModified();
    }

    /**
     * This date is use to perform fine tuning resource dependancies computing
     * 
     * @return
     */
    @Override
    public Date getLastUpdate() {
        if (lastUpdate == null) {
            lastUpdate = lastMemoryUpdate();
        }
        if (lastUpdate == null) {
            lastUpdate = super.getLastUpdate();
        }
        return lastUpdate;
    }

    public void setLastUpdate(Date lastUpdate) {
        this.lastUpdate = lastUpdate;
    }

    public String getAcronym() {
        return acronym;
    }

    public void setAcronym(String acronym) {
        this.acronym = acronym;
    }

    public static final String getTypeName() {
        return "PROCESS";
    }

    private static final Vector<WKFObject> EMPTY_VECTOR = EmptyVector.EMPTY_VECTOR(WKFObject.class);

    public void addStatus() {
        if (addStatusActionizer != null) {
            addStatusActionizer.run(this, EMPTY_VECTOR);
        }
    }

    public void deleteStatus(Status object) {
        if (deleteActionizer != null) {
            deleteActionizer.run(object, EMPTY_VECTOR);
        }
    }

    /**
     * @return
     * @deprecated
     */
    @Deprecated
    public Enumeration<Role> getSortedRoles() {
        return getWorkflow().getSortedRoles();
    }

    public Enumeration<Status> getSortedStatuses() {
        if (getStatusList() == null) {
            return ToolBox.getEnumeration(new Status[0]);
        }
        disableObserving();
        Status[] o = FlexoIndexManager.sortArray(getStatusList().getStatus().toArray(new Status[0]));
        enableObserving();
        return ToolBox.getEnumeration(o);
    }

    public Enumeration<EventNode> getSortedEvents() {
        disableObserving();
        EventNode[] o = FlexoIndexManager.sortArray(getAllEventNodes().toArray(new EventNode[0]));
        enableObserving();
        return ToolBox.getEnumeration(o);
    }

    // =========================================================
    // ============= Control graph management ==================
    // =========================================================

    private static ControlGraphFactory<FlexoProcess> _executionComputingFactory;

    public static void setExecutionComputingFactory(ControlGraphFactory<FlexoProcess> factory) {
        _executionComputingFactory = factory;
    }

    public WorkflowControlGraph<FlexoProcess> getExecution() {
        if (_executionComputingFactory != null) {
            return _executionComputingFactory.getControlGraph(this);
        }
        return null;
    }

    @Override
    public void setProgrammingLanguageForControlGraphComputation(ProgrammingLanguage language) {
        if (getExecution() != null) {
            getExecution().setProgrammingLanguage(language);
        }
    }

    @Override
    public void setInterproceduralForControlGraphComputation(boolean interprocedural) {
        if (getExecution() != null) {
            getExecution().setInterprocedural(interprocedural);
        }
    }

    @Override
    public String getExecutableElementName() {
        return FlexoLocalization.localizedForKeyWithParams("process_($0)", getName());
    }

    public String getExecutionClassName() {
        return ToolBox.capitalize(ToolBox.getJavaName(getName()) + "Processor");
    }

    public String getExecutionGroupName() {
        return "org.openflexo.controlgraph." + getProject().getPrefix().toLowerCase();
    }

    public synchronized BidiMap getNameForNodeMap() {
        if (nameForNodeMap.size() == 0) {
            buildNameForNodeMap();
        }
        return nameForNodeMap;
    }

    public synchronized String getUniqueNameForNode(AbstractNode node) {
        if (getNameForNodeMap().getKey(node) != null) {
            return (String) getNameForNodeMap().getKey(node);
        }
        if (logger.isLoggable(Level.WARNING)) {
            logger.warning("Node " + node
                    + " had no computed name meaning that it was probably not properly embedded in the FlexoProcess."
                    + "I will compute its name now, but this can be source of instability in the names of the nodes. You should try to find why that node was not embedded.");
        }
        return computeAndStoreNameForNode(node);
    }

    private synchronized String computeAndStoreNameForNode(AbstractNode node) {
        String base = ToolBox.uncapitalize(node.getNiceName());
        String attempt = base;
        if (nameForNodeMap.get(attempt) != null || ReservedKeyword.contains(attempt)) {
            String nodeType = node.getNodeTypeName();
            if (base.toLowerCase().indexOf(nodeType.toLowerCase()) == -1) {
                base = base + nodeType;
            }
            base = ToolBox.uncapitalize(base);
            int i = 1;
            attempt = base;
            while (nameForNodeMap.get(attempt) != null || ReservedKeyword.contains(attempt)) {
                i++;
                attempt = base + String.valueOf(i);
            }
        }
        nameForNodeMap.put(attempt, node);
        return attempt;
    }

    private void buildNameForNodeMap() {
        Vector<AbstractNode> nodes = getActivityPetriGraph().getAllEmbeddedNodesOfClass(AbstractNode.class);
        nodes.addAll(getPortRegistery().getAllPorts());
        Collections.sort(nodes, new Comparator<FlexoModelObject>() {

            @Override
            public int compare(FlexoModelObject o1, FlexoModelObject o2) {
                return o1.compareTo(o2);
            }

        });
        for (FlexoProcess process : getWorkflow().getAllLocalFlexoProcesses()) {
            nameForNodeMap.put(ToolBox.uncapitalize(ToolBox.getJavaName(process.getName())), process);
        }
        for (FlexoProcess process : getWorkflow().getAllImportedFlexoProcesses()) {
            nameForNodeMap.put(ToolBox.uncapitalize(ToolBox.getJavaName(process.getName())), process);
        }
        if (getProcessDMEntity() != null) {
            for (DMObject obj : getProcessDMEntity().getOrderedChildren()) {
                nameForNodeMap.put(ToolBox.uncapitalize(ToolBox.getJavaName(obj.getName())), obj);
            }
        }
        for (AbstractNode node : nodes) {
            computeAndStoreNameForNode(node);
        }
    }

    // ============================================================
    // ==================== Validation ============================
    // ============================================================

    public static class NonRootProcessShouldBeUsed
            extends ValidationRule<NonRootProcessShouldBeUsed, FlexoProcess> {
        public NonRootProcessShouldBeUsed() {
            super(FlexoProcess.class, "non_root_process_should_be_used");
        }

        @Override
        public ValidationIssue<NonRootProcessShouldBeUsed, FlexoProcess> applyValidation(
                final FlexoProcess process) {
            if (!process.isRootProcess() && process.getSubProcessNodes().size() == 0
                    && (!process.isImported() || process.isTopLevelProcess())) {
                return new ValidationWarning<NonRootProcessShouldBeUsed, FlexoProcess>(this, process,
                        "process_($object.name)_is_used_nowhere");
            }
            return null;
        }
    }

    public static class FlexoProcessMustHaveADefaultStatus
            extends ValidationRule<FlexoProcessMustHaveADefaultStatus, FlexoProcess> {
        public FlexoProcessMustHaveADefaultStatus() {
            super(FlexoProcess.class, "process_must_have_a_default_status");
        }

        @Override
        public ValidationIssue<FlexoProcessMustHaveADefaultStatus, FlexoProcess> applyValidation(
                FlexoProcess process) {
            if (process.getStatusList() != null && process.getStatusList().getDefaultStatus() == null) {
                Vector<FixProposal<FlexoProcessMustHaveADefaultStatus, FlexoProcess>> v = new Vector<FixProposal<FlexoProcessMustHaveADefaultStatus, FlexoProcess>>();
                Enumeration<Status> en = process.getStatusList().getStatus().elements();
                while (en.hasMoreElements()) {
                    Status s = en.nextElement();
                    v.add(new SetDefaultStatus(s));
                }
                v.add(new CreateAndSetDefaultStatus());
                return new ValidationError<FlexoProcessMustHaveADefaultStatus, FlexoProcess>(this, process,
                        "process_($object.name)_has_no_default_status", v);
            }
            return null;
        }

        protected static class CreateAndSetDefaultStatus
                extends FixProposal<FlexoProcessMustHaveADefaultStatus, FlexoProcess> {

            public CreateAndSetDefaultStatus() {
                super("create_and_set_default_status");
                // TODO Auto-generated constructor stub
            }

            @Override
            protected void fixAction() {
                FlexoProcess p = getObject();
                Status s = p.getStatusList().createNewStatus();
                p.getStatusList().setDefaultStatus(s);
            }

        }

        protected static class SetDefaultStatus
                extends FixProposal<FlexoProcessMustHaveADefaultStatus, FlexoProcess> {

            private Status status;

            public SetDefaultStatus(Status status) {
                super("set_default_status_to_($status.name)");
                this.status = status;
            }

            // Used by KVC for message
            public Status getStatus() {
                return status;
            }

            @Override
            protected void fixAction() {
                FlexoProcess p = getObject();
                p.getStatusList().setDefaultStatus(status);
            }

        }
    }

    public static class ProcessHierarchyIsConsistent
            extends ValidationRule<ProcessHierarchyIsConsistent, FlexoProcess> {
        public ProcessHierarchyIsConsistent() {
            super(FlexoProcess.class, "process_hierarchy_must_be_consistent");
        }

        @Override
        public ValidationIssue<ProcessHierarchyIsConsistent, FlexoProcess> applyValidation(
                final FlexoProcess process) {
            if (!process.isImported() && !process.isAcceptableAsParentProcess(process.getParentProcess())) {
                return new ValidationError<ProcessHierarchyIsConsistent, FlexoProcess>(this, process,
                        "process_hierarchy_for_($object.name)_is_inconsistant");
            }
            return null;
        }
    }

    public static class ImportedProcessShouldExistOnServer
            extends ValidationRule<ImportedProcessShouldExistOnServer, FlexoProcess> {
        public ImportedProcessShouldExistOnServer() {
            super(FlexoProcess.class, "imported_process_should_exist_on_server");
        }

        @Override
        public ValidationIssue<ImportedProcessShouldExistOnServer, FlexoProcess> applyValidation(
                final FlexoProcess process) {
            if (process.isImported() && process.isDeletedOnServer()) {
                return new ValidationWarning<ImportedProcessShouldExistOnServer, FlexoProcess>(this, process,
                        "process_($object.name)_no_longer_exists_on_server", new DeleteProcess());
            }
            return null;
        }

        public static class DeleteProcess extends FixProposal<ImportedProcessShouldExistOnServer, FlexoProcess> {
            public DeleteProcess() {
                super("delete_process_($object.name)");
            }

            @Override
            protected void fixAction() {
                getObject().delete();
            }
        }
    }

    public static class ProcessMustDefineBusinessDataClass
            extends ValidationRule<ProcessMustDefineBusinessDataClass, FlexoProcess> {

        /**
         * @param objectType
         * @param ruleName
         */
        public ProcessMustDefineBusinessDataClass() {
            super(FlexoProcess.class, "process_must_define_business_data_class");
        }

        /**
         * Overrides applyValidation
         * 
         * @see org.openflexo.foundation.validation.ValidationRule#applyValidation(org.openflexo.foundation.validation.Validable)
         */
        @Override
        public ValidationIssue<ProcessMustDefineBusinessDataClass, FlexoProcess> applyValidation(
                FlexoProcess process) {
            if (process.getBusinessDataType() == null && !process.isRootProcess()) {
                return new ValidationError<ProcessMustDefineBusinessDataClass, FlexoProcess>(this, process,
                        "process_must_define_a_business_data_type", new SetTypeProposal());
            }
            if (!process.isRootProcess() && (process.getBusinessDataVariableName() == null
                    || process.getBusinessDataVariableName().trim().length() == 0)) {
                return new ValidationError<ProcessMustDefineBusinessDataClass, FlexoProcess>(this, process,
                        "process_must_define_a_business_data_variable", new SetVariableNameProposal());
            }
            return null;
        }

        /**
         * Overrides isValidForTarget
         * 
         * @see org.openflexo.foundation.validation.ValidationRule#isValidForTarget(TargetType)
         */
        @Override
        public boolean isValidForTarget(TargetType targetType) {
            return targetType != CodeType.PROTOTYPE;
        }

        public static class SetTypeProposal
                extends ParameteredFixProposal<ProcessMustDefineBusinessDataClass, FlexoProcess> {

            private static final ParameterDefinition[] parameters = new ParameterDefinition[] {
                    new DMEntityParameter("type", "type", null) };

            /**
             * @param aMessage
             */
            public SetTypeProposal() {
                super("set_type", parameters);
            }

            /**
             * Overrides fixAction
             * 
             * @see org.openflexo.foundation.validation.FixProposal#fixAction()
             */
            @Override
            protected void fixAction() {
                DMEntity e = (DMEntity) getValueForParameter("type");
                if (e != null) {
                    getObject().setBusinessDataType(e);
                }
            }

        }

        public static class SetVariableNameProposal
                extends ParameteredFixProposal<ProcessMustDefineBusinessDataClass, FlexoProcess> {

            private static final ParameterDefinition[] parameters = new ParameterDefinition[] {
                    new TextFieldParameter("name", "name", null) };

            /**
             * @param aMessage
             */
            public SetVariableNameProposal() {
                super("set_variable", parameters);
            }

            /**
             * Overrides fixAction
             * 
             * @see org.openflexo.foundation.validation.FixProposal#fixAction()
             */
            @Override
            protected void fixAction() {
                String s = (String) getValueForParameter("name");
                if (s != null && s.trim().length() == 0) {
                    try {
                        getObject().setBusinessDataVariableName(s);
                    } catch (InvalidNameException e) {
                        if (logger.isLoggable(Level.WARNING)) {
                            logger.warning(e.getMessage());
                        }
                    } catch (DuplicatePropertyNameException e) {
                        if (logger.isLoggable(Level.WARNING)) {
                            logger.warning(e.getMessage());
                        }
                    }
                }
            }

        }

    }

    public static class BusinessDataClassMustHaveStatusProperty
            extends ValidationRule<BusinessDataClassMustHaveStatusProperty, FlexoProcess> {

        /**
         * @param objectType
         * @param ruleName
         */
        public BusinessDataClassMustHaveStatusProperty() {
            super(FlexoProcess.class, "business_data_class_must_have_status_property");
        }

        /**
         * Overrides applyValidation
         * 
         * @see org.openflexo.foundation.validation.ValidationRule#applyValidation(org.openflexo.foundation.validation.Validable)
         */
        @Override
        public ValidationIssue<BusinessDataClassMustHaveStatusProperty, FlexoProcess> applyValidation(
                FlexoProcess process) {

            if (process._processDMEntity != null) {
                if (process.getBusinessDataType().getProperty("status") == null) {
                    if (process.getBusinessDataType() instanceof DMEOEntity) {
                        return new ValidationError<BusinessDataClassMustHaveStatusProperty, FlexoProcess>(this,
                                process, "business_data_class_must_have_status_property",
                                process.getBusinessDataType().getIsReadOnly() ? null
                                        : new AddPropertyStatus((DMEOEntity) process.getBusinessDataType()));
                    } else {
                        return new ValidationError<BusinessDataClassMustHaveStatusProperty, FlexoProcess>(this,
                                process, "business_data_class_must_have_status_property");
                    }

                }
            }
            return null;
        }

        /**
         * Overrides isValidForTarget
         * 
         * @see org.openflexo.foundation.validation.ValidationRule#isValidForTarget(TargetType)
         */
        @Override
        public boolean isValidForTarget(TargetType targetType) {
            return targetType != CodeType.PROTOTYPE;
        }

        public static class AddPropertyStatus
                extends FixProposal<BusinessDataClassMustHaveStatusProperty, FlexoProcess> {

            private DMEOEntity _businessDataClass;

            /**
             * @param aMessage
             */
            public AddPropertyStatus(DMEOEntity businessDataClass) {
                super("create_status_property");
                _businessDataClass = businessDataClass;
            }

            /**
             * Overrides fixAction
             * 
             * @see org.openflexo.foundation.validation.FixProposal#fixAction()
             */
            @Override
            protected void fixAction() {
                try {
                    DMEOAttribute statusAttribute = DMEOAttribute.createsNewDMEOAttribute(
                            _businessDataClass.getDMModel(), _businessDataClass, "status", false, true,
                            DMPropertyImplementationType.PUBLIC_ACCESSORS_PRIVATE_FIELD);
                    statusAttribute.setPrototype(_businessDataClass.getDMModel().getPrototypeNamed("str100"));
                    statusAttribute.setColumnName("PROCESS_STATUS");
                    _businessDataClass.registerProperty(statusAttribute);
                } catch (EOAccessException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }

            }

        }
    }

    public void notifyOperationChange(OperationNode node) {
        setChanged();
        notifyObservers(new OperationChange(node));
    }

    /**
     * Overrides getClassNameKey
     * 
     * @see org.openflexo.foundation.FlexoModelObject#getClassNameKey()
     */
    @Override
    public String getClassNameKey() {
        return "flexo_process";
    }

    /**
     * Wheter there is within all the operations of this process at least one operation associated to a component
     * 
     * @return
     */
    public boolean hasWOComponent() {
        for (AbstractActivityNode act : getAllEmbeddedAbstractActivityNodes()) {
            if (act.hasWOComponent()) {
                return true;
            }
        }
        return false;
    }

    public int getIndex() {
        if (getProcessNode() != null) {
            return getProcessNode().getIndex();
        }

        logger.warning("Process node is null for flexo process " + this.getName());
        return -1;
    }

    public void setIndex(int index) {
        if (getProcessNode() != null) {
            getProcessNode().setIndex(index);

            if (getIndex() != index) {
                setChanged(false);
                AttributeDataModification dm = new AttributeDataModification("index", null, getIndex());
                dm.setReentrant(true);
                notifyObservers(dm);
            }
        } else {
            logger.warning("Process node is null for flexo process " + this.getName());
        }
    }

    public int getVectorIndex() {
        if (getProcessNode() != null) {
            return getProcessNode().getVectorIndex();
        }

        logger.warning("Process node is null for flexo process " + this.getName());
        return -1;
    }

    public void setVectorIndex(int index) {
        if (getProcessNode() != null) {
            getProcessNode().setVectorIndex(index);

            if (getVectorIndex() != index) {
                setChanged(false);
                AttributeDataModification dm = new AttributeDataModification("vectorIndex", null, getIndex());
                dm.setReentrant(true);
                notifyObservers(dm);
            }
        } else {
            logger.warning("Process node is null for flexo process " + this.getName());
        }
    }

    /**
     * Returns a sorted vector of all the abstract activity nodes that are in the underlying activity petrigraph and the ones embedded by
     * LOOPOperator and SelfExecutableNode. This is done recursively on all nodes.
     * 
     * @return a sorted vector of all the abstract activity nodes embedded in the petri graph.
     */
    public Vector<AbstractActivityNode> getAllEmbeddedSortedAbstractActivityNodes() {
        if (_petriGraph != null) {
            return _petriGraph.getAllEmbeddedSortedAbstractActivityNodes();
        }
        return new Vector<AbstractActivityNode>();
    }

    public Enumeration<AbstractActivityNode> getSortedActivities() {
        disableObserving();
        AbstractActivityNode[] o = FlexoIndexManager
                .sortArray(getAllAbstractActivityNodes().toArray(new AbstractActivityNode[0]));
        enableObserving();
        return ToolBox.getEnumeration(o);
    }

    public Enumeration<AbstractActivityNode> getSortedMeaningFullActivities() {
        disableObserving();
        AbstractActivityNode[] o = FlexoIndexManager
                .sortArray(getAllMeaningFullActivityNodes().toArray(new AbstractActivityNode[0]));
        enableObserving();
        return ToolBox.getEnumeration(o);
    }

    public List<SubProcessNode> getSortedSubProcessNode() {
        disableObserving();
        SubProcessNode[] o = FlexoIndexManager
                .sortArray(getAllMeaningSubProcessNodes().toArray(new SubProcessNode[0]));
        enableObserving();
        return Arrays.asList(o);
    }

    public List<AbstractActivityNode> getSortedMeaningFullActivitiesAndSubProcessNode() {
        disableObserving();
        AbstractActivityNode[] o = FlexoIndexManager
                .sortArray(getAllMeaningFullActivityNodes().toArray(new AbstractActivityNode[0]));
        enableObserving();
        return Arrays.asList(o);
    }

    public Enumeration<PetriGraphNode> getSortedActivitiesAndOperators() {
        disableObserving();
        PetriGraphNode[] o = FlexoIndexManager
                .sortArray(getAllAbstractActivityNodesAndActivityOperators().toArray(new PetriGraphNode[0]));
        enableObserving();
        return ToolBox.getEnumeration(o);
    }

    public Enumeration<PetriGraphNode> getSortedActivitiesAndOperatorsWithEvents() {
        disableObserving();
        PetriGraphNode[] o = FlexoIndexManager.sortArray(
                getAllAbstractActivityNodesAndActivityOperatorsWithEvents().toArray(new PetriGraphNode[0]));
        enableObserving();
        return ToolBox.getEnumeration(o);
    }

    public Vector<Status> getSortedStatusesVector() {
        if (getStatusList() == null) {
            return new Vector<Status>();
        }
        disableObserving();
        Vector<Status> v = new Vector<Status>(getStatusList().getStatus());
        Collections.sort(v, FlexoIndexManager.INDEX_COMPARATOR);
        enableObserving();
        return v;
    }

    public boolean hasAtLeastOneStatusToDocument() {
        if (getStatusList() == null) {
            return false;
        }
        Enumeration<Status> en = getStatusList().elements();
        while (en.hasMoreElements()) {
            if (!en.nextElement().getDontGenerate()) {
                return true;
            }
        }
        return false;
    }

    public boolean hasAtLeastOneEventToDocument() {
        Enumeration<EventNode> en = getAllEventNodes().elements();
        while (en.hasMoreElements()) {
            if (!en.nextElement().getDontGenerate()) {
                return true;
            }
        }
        return false;
    }

    public ProcessStatistics getStatistics() {
        if (statistics == null) {
            statistics = new ProcessStatistics(this);
        }
        return statistics;
    }

    @Override
    public ApplicationHelpEntryPoint getParentHelpEntry() {
        return getParentProcess();
    }

    @Override
    public List<ApplicationHelpEntryPoint> getChildsHelpObjects() {
        Vector<ApplicationHelpEntryPoint> reply = new Vector<ApplicationHelpEntryPoint>();
        reply.addAll(getAllActivityNodes());
        return reply;
    }

    @Override
    public String getShortHelpLabel() {
        return getName();
    }

    @Override
    public String getTypedHelpLabel() {
        return "Process : " + getName();
    }

    public void resolveObjectReferences() {
        for (ActionNode node : getAllEmbeddedActionNodes()) {
            node.getDisplayProcess();
            node.getDisplayOperation();
        }
    }

    public boolean oneAncestorIsNotGenerated() {
        if (getDontGenerate()) {
            return true;
        }
        if (getParentProcess() == null) {
            return getDontGenerate();
        }
        return getParentProcess().oneAncestorIsNotGenerated();
    }

    public String getProcessDictionaryKey() {
        return ToolBox.cleanStringForProcessDictionaryKey(getName());
    }

    public String getBusinessDataDictionaryKey() {
        if (getBusinessDataType() != null) {
            return ToolBox.cleanStringForProcessDictionaryKey(getBusinessDataType().getName());
        }

        return AutoGeneratedProcessBusinessDataDMEntity.getProcessBusinessDataEntityNameForProcess(this);
    }

    public static final String PROCESSINSTANCE_STATUS_KEY = ToolBox.cleanStringForProcessDictionaryKey("status");
    public static final String PROCESSINSTANCE_CREATIONDATE_KEY = ToolBox
            .cleanStringForProcessDictionaryKey("creationDate");
    public static final String PROCESSINSTANCE_LASTUPDATEDATE_KEY = ToolBox
            .cleanStringForProcessDictionaryKey("lastUpdateDate");

    /**
     * Return a map containing the sample value list for each key used for this process (prototype).
     * 
     * @return a map containing the sample value list for each key used for this process (prototype)..
     */
    public Map<String, List<Object>> getProcessInstanceDictionaryPrototypeSamples() {
        Map<String, List<Object>> keysTable = new HashMap<String, List<Object>>();

        for (IEWidget widget : getWidgetsForProcessInstanceDictionary()) {
            String key = widget.getProcessInstanceDictionaryKey();
            List<Object> sampleValues = new ArrayList<Object>();
            if (widget instanceof IEWidgetWithValueList) {
                sampleValues = ((IEWidgetWithValueList) widget).getValueList(this);
            }

            if (!keysTable.containsKey(key) || keysTable.get(key).size() < sampleValues.size()) {
                keysTable.put(widget.getProcessInstanceDictionaryKey(), sampleValues);
            }
        }

        if (getStatusList().size() > 0) {
            // Always add status list if any
            List<Object> statuses = new ArrayList<Object>();
            keysTable.put(PROCESSINSTANCE_STATUS_KEY, statuses);
            for (Status status : getStatusList().getStatus()) {
                statuses.add(status.getName());
            }
        }

        if (keysTable.get(PROCESSINSTANCE_CREATIONDATE_KEY) == null) {
            keysTable.put(PROCESSINSTANCE_CREATIONDATE_KEY, new ArrayList<Object>());
        }

        if (keysTable.get(PROCESSINSTANCE_LASTUPDATEDATE_KEY) == null) {
            keysTable.put(PROCESSINSTANCE_LASTUPDATEDATE_KEY, new ArrayList<Object>());
        }

        return keysTable;
    }

    /**
     * Return a map with all keys found for this process with their type. Keys are created based on the screen components.
     * 
     * @return a map with all keys found for this process with their type. Keys are created based on the screen components.
     */
    public Map<String, Class<? extends Object>> getProcessInstanceDictionaryKeys() {
        Map<String, Class<? extends Object>> result = new HashMap<String, Class<? extends Object>>();
        for (IEWidget widget : getWidgetsForProcessInstanceDictionary()) {
            String key = widget.getProcessInstanceDictionaryKey();
            if (key != null) {
                Class<? extends Object> type = getProcessInstanceDictionaryType(widget);

                if (result.containsKey(key) && result.get(key) != type) {
                    type = Object.class;
                }

                result.put(key, type);
            }
        }

        if (getStatusList().size() > 0) {
            result.put(PROCESSINSTANCE_STATUS_KEY, String.class);
        }

        result.put(PROCESSINSTANCE_CREATIONDATE_KEY, Date.class);
        result.put(PROCESSINSTANCE_LASTUPDATEDATE_KEY, Date.class);

        return result;
    }

    private List<IEWidget> getWidgetsForProcessInstanceDictionary() {
        Map<FlexoProcess, Set<IEWOComponent>> componentsByProcess = new HashMap<FlexoProcess, Set<IEWOComponent>>();

        for (OperationComponentInstance ci : getProject().getFlexoWorkflow().getAllComponentInstances()) {
            OperationNode operationNode = ci.getOperationNode();
            if (operationNode != null && operationNode.hasWOComponent()) {
                if (componentsByProcess.get(operationNode.getProcess()) == null) {
                    componentsByProcess.put(operationNode.getProcess(), new HashSet<IEWOComponent>());
                }

                componentsByProcess.get(operationNode.getProcess()).add(operationNode.getWOComponent());
            }
        }

        List<IEWidget> allWidgets = new ArrayList<IEWidget>();
        for (Map.Entry<FlexoProcess, Set<IEWOComponent>> entry : componentsByProcess.entrySet()) {
            for (IEWOComponent woComponent : entry.getValue()) {
                allWidgets.addAll(getWidgetsForProcessInstanceFromComponent(woComponent, entry.getKey()));
            }
        }

        return allWidgets;
    }

    private List<IEWidget> getWidgetsForProcessInstanceFromComponent(IEWOComponent component,
            FlexoProcess componentProcess) {
        List<IEWidget> allWidgets = new ArrayList<IEWidget>();

        for (IEWidget widget : component.getAllEmbeddedIEWidgets(IEWidget.class)) {
            if (widget.getIsAcceptableForProcessInstanceDictionary(componentProcess, this)) {
                allWidgets.add(widget);
            }

            if (widget instanceof IETabWidget) {
                allWidgets.addAll(getWidgetsForProcessInstanceFromComponent(
                        ((IETabWidget) widget).getTabComponent(), componentProcess));
            }

        }

        return allWidgets;
    }

    /**
     * Return the type used in the process instance dictionary for the specified IEWidget.
     * 
     * @param widget
     * @return the type used in the process instance dictionary for the specified IEWidget.
     */
    public Class<? extends Object> getProcessInstanceDictionaryType(IEWidget widget) {
        if (widget instanceof IECheckBoxWidget) {
            return Boolean.class;
        }
        if (widget instanceof IEDropDownWidget) {
            return String.class;
        }
        if (widget instanceof IERadioButtonWidget) {
            return Boolean.class;
        }
        if (widget instanceof IETextAreaWidget) {
            return String.class;
        }
        if (widget instanceof IEWysiwygWidget) {
            return String.class;
        }

        TextFieldType fieldType = null;
        if (widget instanceof IEHyperlinkWidget) {
            fieldType = ((IEHyperlinkWidget) widget).getFieldType();
        } else if (widget instanceof IEStringWidget) {
            fieldType = ((IEStringWidget) widget).getFieldType();
        } else if (widget instanceof IETextFieldWidget) {
            fieldType = ((IETextFieldWidget) widget).getFieldType();
        }

        if (fieldType == null) {
            return String.class;
        }

        switch (fieldType) {
        case DATE:
            return Date.class;
        case DOUBLE:
            return Double.class;
        case FLOAT:
            return Float.class;
        case INTEGER:
            return Integer.class;
        case KEYVALUE:
        case STATUS_LIST:
        case TEXT:
        default:
            return String.class;
        }
    }
}