All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cristalise.kernel.lifecycle.CompositeActivityDef Maven / Gradle / Ivy

/**
 * This file is part of the CRISTAL-iSE kernel.
 * Copyright (c) 2001-2015 The CRISTAL Consortium. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * http://www.fsf.org/licensing/licenses/lgpl.html
 */
package org.cristalise.kernel.lifecycle;

import static org.cristalise.kernel.collection.BuiltInCollections.ACTIVITY;
import static org.cristalise.kernel.graph.model.BuiltInVertexProperties.ABORTABLE;
import static org.cristalise.kernel.graph.model.BuiltInVertexProperties.REPEAT_WHEN;
import static org.cristalise.kernel.graph.model.BuiltInVertexProperties.STATE_MACHINE_NAME;
import static org.cristalise.kernel.process.resource.BuiltInResources.COMP_ACT_DESC_RESOURCE;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import org.cristalise.kernel.collection.CollectionArrayList;
import org.cristalise.kernel.collection.Dependency;
import org.cristalise.kernel.common.InvalidDataException;
import org.cristalise.kernel.common.ObjectNotFoundException;
import org.cristalise.kernel.entity.proxy.ItemProxy;
import org.cristalise.kernel.graph.model.BuiltInVertexProperties;
import org.cristalise.kernel.graph.model.GraphModel;
import org.cristalise.kernel.graph.model.GraphPoint;
import org.cristalise.kernel.graph.model.GraphableVertex;
import org.cristalise.kernel.graph.model.TypeNameAndConstructionInfo;
import org.cristalise.kernel.graph.model.Vertex;
import org.cristalise.kernel.lifecycle.instance.CompositeActivity;
import org.cristalise.kernel.lifecycle.instance.Next;
import org.cristalise.kernel.lifecycle.instance.WfVertex;
import org.cristalise.kernel.lookup.ItemPath;
import org.cristalise.kernel.persistency.outcome.Outcome;
import org.cristalise.kernel.process.Gateway;
import org.cristalise.kernel.utils.CastorHashMap;
import org.cristalise.kernel.utils.FileStringUtility;
import org.cristalise.kernel.utils.LocalObjectLoader;
import org.cristalise.kernel.utils.Logger;
import org.w3c.dom.NodeList;

/**
 * 
 */
public class CompositeActivityDef extends ActivityDef {
    private ArrayList refChildActDef = new ArrayList();

    public CompositeActivityDef() {
        super();
        setBuiltInProperty(ABORTABLE, false);
        setBuiltInProperty(REPEAT_WHEN, false);
        setBuiltInProperty(STATE_MACHINE_NAME, "CompositeActivity");

        try {
            setChildrenGraphModel(new GraphModel(new LifecycleVertexOutlineCreator()));
        }
        catch (InvalidDataException e) {
        } // shouldn't happen with an empty one

        setIsComposite(true);
    }

    public ArrayList getRefChildActDef() {
        return refChildActDef;
    }

    public void setRefChildActDef(ArrayList refChildActDef) {
        this.refChildActDef = refChildActDef;
    }

    private final TypeNameAndConstructionInfo[] mVertexTypeNameAndConstructionInfo = {
            new TypeNameAndConstructionInfo("Activity",         "Atomic"),
            new TypeNameAndConstructionInfo("Local Activity",   "AtomicLocal"),
            new TypeNameAndConstructionInfo("Composite",        "Composite"),
            new TypeNameAndConstructionInfo("Sub-workflow",     "CompositeLocal"),
            new TypeNameAndConstructionInfo("AND Split",        "And"), 
            new TypeNameAndConstructionInfo("OR Split",         "Or"),
            new TypeNameAndConstructionInfo("XOR Split",        "XOr"),
            new TypeNameAndConstructionInfo("Join",             "Join"),
            new TypeNameAndConstructionInfo("Loop",             "Loop"),
    };

    private final TypeNameAndConstructionInfo[] mEdgeTypeNameAndConstructionInfo  = { new TypeNameAndConstructionInfo("Next Edge", "Next") };

    public TypeNameAndConstructionInfo[] getVertexTypeNameAndConstructionInfo() {
        return mVertexTypeNameAndConstructionInfo;
    }

    public TypeNameAndConstructionInfo[] getEdgeTypeNameAndConstructionInfo() {
        return mEdgeTypeNameAndConstructionInfo;
    }

    public NextDef addNextDef(WfVertexDef origin, WfVertexDef terminus) {
        NextDef returnNxt = new NextDef(origin, terminus);
        getChildrenGraphModel().addEdgeAndCreateId(returnNxt, origin, terminus);
        return returnNxt;
    }

    public ActivitySlotDef addExistingActivityDef(String name, ActivityDef actDef, GraphPoint point) throws InvalidDataException {
        changed = true;
        boolean newActDef = true;

        for (ActivityDef existingActDef : refChildActDef) {
            if (existingActDef.getName().equals(actDef.getName())) {
                if (existingActDef.getVersion().equals(actDef.getVersion())) {
                    actDef = existingActDef;
                    newActDef = false;
                    break;
                }
                else {
                    throw new InvalidDataException("Cannot use same activity def with different version in the same composite activity");
                }
            }
        }
        if (newActDef) refChildActDef.add(actDef);
        
        ActivitySlotDef child = new ActivitySlotDef(name, actDef);
        addChild(child, point);

        return child;
    }

    public ActivityDef addLocalActivityDef(String name, String type, GraphPoint point) {
        changed = true;
        ActivityDef child = type.startsWith("Composite") ? new CompositeActivityDef() : new ActivityDef();
        child.setName(name);
        child.setIsLayoutable(true);
        addChild(child, point);
        return child;
    }

    public WfVertexDef newChild(String Name, String Type, Integer version, GraphPoint location)
            throws ObjectNotFoundException, InvalidDataException
    {
        changed = true;
        boolean wasAdded = false;
        WfVertexDef child;
        
        if (Type.equals("Or"))        child = new OrSplitDef();
        else if (Type.equals("XOr"))  child = new XOrSplitDef();
        else if (Type.equals("And"))  child = new AndSplitDef();
        else if (Type.equals("Loop")) child = new LoopDef();
        else if (Type.equals("Join") || Type.equals("Route")) {
            child = new JoinDef();
            child.getProperties().put("Type", Type);
        }
        else if (Type.equals("Atomic") || Type.equals("Composite")) {
            ActivityDef act = Type.equals("Atomic") ? LocalObjectLoader.getElemActDef(Name, version) : LocalObjectLoader.getCompActDef(Name, version);
            child = addExistingActivityDef(act.getActName(), act, location);
            wasAdded = true;
        }
        else if (Type.equals("AtomicLocal") || Type.equals("CompositeLocal")) {
            child = addLocalActivityDef(Name, Type, location);
            wasAdded = true;
        }
        else {
            throw new InvalidDataException("Unknown child type: " + Type);
        }

        if(!wasAdded) addChild(child, location);

        Logger.msg(5, "CompositeActivityDef.newChild() - Type:"+Type + " ID:" + child.getID() + " added to ID:" + this.getID());

        return child;
    }

    /**
     * 
     * @return CompositeActivity
     */
    @Override
    public WfVertex instantiate() throws ObjectNotFoundException, InvalidDataException {
        return instantiate(getName());
    }

    @Override
    public WfVertex instantiate(String name) throws ObjectNotFoundException, InvalidDataException {
        CompositeActivity caInstance = new CompositeActivity();

        Logger.msg(1, "CompositeActivityDef.instantiate(name:"+name+") - Starting.");

        caInstance.setName(name);

        configureInstance(caInstance);

        if (getItemPath() != null) caInstance.setType(getItemID());

        caInstance.getChildrenGraphModel().setStartVertexId( getChildrenGraphModel().getStartVertexId() );
        caInstance.getChildrenGraphModel().setVertices(      intantiateVertices(caInstance)             );
        caInstance.getChildrenGraphModel().setEdges(         instantiateEdges(caInstance)               );
        caInstance.getChildrenGraphModel().setNextId(        getChildrenGraphModel().getNextId()        );

        caInstance.getChildrenGraphModel().resetVertexOutlines();

        propagateCollectionProperties(caInstance);

        return caInstance;
    }

    /**
     * Reading collections during configureInstance() the properties of CAInstance can be updated to
     * contain CastorHashMaps, which contain properties to be propagated to the Vertices of CAInstance.
     * 
     * @param caInstance the CompAct instance beeing instantiated
     * @throws InvalidDataException 
     */
    private void propagateCollectionProperties(CompositeActivity caInstance) throws InvalidDataException {
        //Propagate now properties to Vertices 
        CastorHashMap caProps = caInstance.getProperties();
        List keysToDelete = new ArrayList();

        for (Entry aCAProp: caProps.entrySet()) {
            if(aCAProp.getValue() instanceof CastorHashMap) {
                for (Vertex vertex : caInstance.getChildrenGraphModel().getVertices()) {
                    CastorHashMap propsToPropagate = (CastorHashMap)aCAProp.getValue();
                    propsToPropagate.dump(8);
                    BuiltInVertexProperties builtInProp = BuiltInVertexProperties.getValue(aCAProp.getKey());

                    if(builtInProp == null) {
                        ((GraphableVertex)vertex).updatePropertiesFromCollection(Integer.parseInt(aCAProp.getKey()), propsToPropagate);
                    }
                    else {
                        ((GraphableVertex)vertex).updatePropertiesFromCollection(builtInProp, propsToPropagate);
                    }
                }
                keysToDelete.add(aCAProp.getKey());
            }
        }

        for(String key : keysToDelete) caProps.remove(key);
    }

    /**
     * Loops through the edges of children graph model and calls their instantiate method
     * 
     * @param ca the parent CompositeActivity instance which will be set as a Parent
     * @return the instantiated array of edge instances called Next
     */
    public Next[] instantiateEdges(CompositeActivity ca) {
        Next[] nexts = new Next[getChildrenGraphModel().getEdges().length];
        
        for (int i = 0; i < getChildrenGraphModel().getEdges().length; i++) {
            NextDef nextDef = (NextDef) getChildrenGraphModel().getEdges()[i];

            nexts[i] = nextDef.instantiate();

            nexts[i].setParent(ca);
        }
        return nexts;
    }

    /**
     * Loops through the vertices of children graph model and calls their instantiate method
     * 
     * @param ca the parent CompositeActivity instance which will be set as a Parent
     * @return the instantiated array of WfVertex instances
     */
    public WfVertex[] intantiateVertices(CompositeActivity ca) throws ObjectNotFoundException, InvalidDataException {
        GraphableVertex[] vertexDefs = getLayoutableChildren();
        WfVertex[]        wfVertices = new WfVertex[vertexDefs.length];

        for (int i = 0; i < vertexDefs.length; i++) {
            WfVertexDef vertDef = (WfVertexDef) vertexDefs[i];

            wfVertices[i] = vertDef.instantiate();

            wfVertices[i].setParent(ca);
        }
        return wfVertices;
    }

    @Override
    public CollectionArrayList makeDescCollections() throws InvalidDataException, ObjectNotFoundException {
        CollectionArrayList retArr = super.makeDescCollections();
        retArr.put(makeActDefCollection());
        return retArr;
    }

    /**
     * Used in Script CompositeActivityDefCollSetter
     * 
     * @return the Dependency collection created from the list of child ActDefs of this class
     * @throws InvalidDataException there was a problem creating the collections
     */
    public Dependency makeActDefCollection() throws InvalidDataException {
        return makeDescCollection(ACTIVITY, refChildActDef.toArray(new ActivityDef[refChildActDef.size()]));
    }

    public ArrayList findRefActDefs(GraphModel graph) throws ObjectNotFoundException, InvalidDataException {
        ArrayList graphActDefs = new ArrayList();
        for (Vertex elem : graph.getVertices()) {
            if (elem instanceof ActivitySlotDef) {
                ActivityDef actDef = ((ActivitySlotDef) elem).getTheActivityDef();
                if (!graphActDefs.contains(actDef)) graphActDefs.add(actDef);
            }
        }
        return graphActDefs;
    }

    /**
     *
     * @return boolean
     */
    public boolean hasGoodNumberOfActivity() {
        int endingAct = 0;
        GraphableVertex[] graphableVertices = this.getLayoutableChildren();
        
        if (graphableVertices != null) for (GraphableVertex graphableVertice : graphableVertices) {
            WfVertexDef vertex = (WfVertexDef) graphableVertice;
            if (getChildrenGraphModel().getOutEdges(vertex).length == 0) endingAct++;
        }
        
        if (endingAct > 1) return false;
        
        return true;
    }

    /**
     * @see org.cristalise.kernel.graph.model.GraphableVertex#getPath()
     */
    @Override
    public String getPath() {
        if (getParent() == null) return getName();
        return super.getPath();
    }

    @Override
    public void setChildrenGraphModel(GraphModel childrenGraph) throws InvalidDataException {
        super.setChildrenGraphModel(childrenGraph);
        childrenGraph.setVertexOutlineCreator(new LifecycleVertexOutlineCreator());
        
        try {
            setRefChildActDef(findRefActDefs(childrenGraph));
        }
        catch (ObjectNotFoundException e) {
            throw new InvalidDataException(e.getMessage());
        }
    }

    @Deprecated
    public String[] getCastorNonLayoutableChildren() {
        return new String[0];
    }

    @Deprecated
    public void setCastorNonLayoutableChildren(String[] dummy) {
    }

    @Override
    public boolean verify() {
        boolean err = super.verify();
        GraphableVertex[] vChildren = getChildren();
        
        for (int i = 0; i < vChildren.length; i++) {
            WfVertexDef wfvChild = (WfVertexDef) vChildren[i];
            if (!(wfvChild.verify())) {
                mErrors.add(wfvChild.getName() + ": " + wfvChild.getErrors());
                err = false;
            }
        }
        return err;
    }

    @Override
    public void export(Writer imports, File dir, boolean shallow) throws InvalidDataException, ObjectNotFoundException, IOException {
        // rebuild the child refs in case any slots have been removed
        setRefChildActDef(findRefActDefs(getChildrenGraphModel()));

        // TODO: property include routing scripts in another dependency collection

        if (!shallow) {
            //export child activitz defs, routing scripts and schemas
            for (GraphableVertex vert: getChildren()) {
                if (vert instanceof AndSplitDef) {
                    try {
                        ((AndSplitDef) vert).getRoutingScript().export(imports, dir, shallow);
                    }
                    catch (ObjectNotFoundException ex) {}
                }
                else if (vert instanceof ActivitySlotDef) {
                    ActivityDef refAct = ((ActivitySlotDef) vert).getTheActivityDef();
                    refAct.export(imports, dir, shallow);
                }
            }
        }

        String tc = COMP_ACT_DESC_RESOURCE.getTypeCode();

        try {
            NodeList nodeList = null;
            Outcome outcome = null;
            // export marshalled compAct
            String compactXML = Gateway.getMarshaller().marshall(this);
            if (Gateway.getProperties().getBoolean("Export.replaceActivitySlotDefUUIDWithName", false)) {
               outcome = new Outcome(compactXML);
               nodeList = outcome.getNodesByXPath("/CompositeActivityDef/childrenGraphModel/GraphModelCastorData/ActivitySlotDef/activityDef/text()");
               for (int i = 0; i < nodeList.getLength(); i++) {					 
                    try {
                        ItemPath itemPath = Gateway.getLookup().getItemPath(nodeList.item(i).getNodeValue());
                        ItemProxy itemProxy = Gateway.getProxyManager().getProxy(itemPath);
                        nodeList.item(i).setNodeValue(itemProxy.getName());
                    }
                    catch(Exception e) {
                         Logger.error(e);
                         throw new ObjectNotFoundException("Cannot find item with UIID: "+nodeList.item(i).getNodeValue());
                    }
               }
               compactXML = outcome.getData();
            }            
            FileStringUtility.string2File(new File(new File(dir, tc), getActName() + (getVersion() == null ? "" : "_" + getVersion()) + ".xml"), compactXML);
        }
        catch (Exception e) {
            Logger.error(e);
            throw new InvalidDataException("Couldn't marshall composite activity def " + getActName());
        }

        if (imports != null) {
            imports.write("" + getExportCollections());

            for (ActivityDef childActDef : refChildActDef) {
                imports.write("");
            }
            imports.write("\n");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy