com.twinsoft.convertigo.beans.core.StepWithExpressions.java Source code

Java tutorial

Introduction

Here is the source code for com.twinsoft.convertigo.beans.core.StepWithExpressions.java

Source

/*
 * Copyright (c) 2001-2011 Convertigo SA.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see<http://www.gnu.org/licenses/>.
 *
 * $URL$
 * $Author$
 * $Revision$
 * $Date$
 */

package com.twinsoft.convertigo.beans.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpState;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.apache.ws.commons.schema.XmlSchemaComplexType;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaGroupBase;
import org.apache.ws.commons.schema.XmlSchemaParticle;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.twinsoft.convertigo.beans.common.XMLVector;
import com.twinsoft.convertigo.beans.steps.BranchStep;
import com.twinsoft.convertigo.beans.steps.ParallelStep;
import com.twinsoft.convertigo.engine.Engine;
import com.twinsoft.convertigo.engine.EngineException;
import com.twinsoft.convertigo.engine.enums.SchemaMeta;
import com.twinsoft.convertigo.engine.util.TwsCachedXPathAPI;
import com.twinsoft.convertigo.engine.util.XmlSchemaUtils;

public abstract class StepWithExpressions extends Step
        implements IContextMaintainer, IContainerOrdered, ISchemaParticleGenerator {
    private static final long serialVersionUID = 6835033841635158551L;

    /**
      * The vector of ordered step objects which can be applied on the StepWithExpressions.
      */
    private XMLVector<XMLVector<Long>> orderedSteps = null;

    transient private List<Step> vSteps = new ArrayList<Step>();

    transient private List<Step> vAllSteps = null;

    transient private String transactionSessionId = null;

    transient protected Map<String, Long> childrenSteps = null;

    transient protected int nbAsyncThreadRunning = 0;

    transient protected Boolean haveToWait = Boolean.FALSE;

    transient protected int currentChildStep;

    transient public boolean bContinue = true;

    transient public boolean handlePriorities = true;

    transient public long[] asyncCounters = null;

    public StepWithExpressions() {
        super();

        orderedSteps = new XMLVector<XMLVector<Long>>();
        orderedSteps.add(new XMLVector<Long>());
    }

    @Override
    public StepWithExpressions clone() throws CloneNotSupportedException {
        StepWithExpressions clonedObject = (StepWithExpressions) super.clone();
        clonedObject.nbAsyncThreadRunning = 0;
        clonedObject.haveToWait = Boolean.FALSE;
        clonedObject.currentChildStep = 0;
        clonedObject.childrenSteps = null;
        clonedObject.vSteps = new ArrayList<Step>();
        clonedObject.vAllSteps = null;
        clonedObject.bContinue = true;
        clonedObject.handlePriorities = handlePriorities;
        clonedObject.transactionSessionId = null;
        clonedObject.asyncCounters = null;
        return clonedObject;
    }

    @Override
    public Object copy() throws CloneNotSupportedException {
        StepWithExpressions copiedObject = (StepWithExpressions) super.copy();
        copiedObject.childrenSteps = new HashMap<String, Long>(10);
        copiedObject.vSteps = vSteps;
        return copiedObject;
    }

    public String getInheritedContextName() {
        return null;
    }

    public String getContextName() {
        return "Container-" + executeTimeID;
    }

    public String getTransactionSessionId() {
        return transactionSessionId;
    }

    public void setTransactionSessionId(String sessionId) {
        if ((transactionSessionId == null) && (sessionId != null)) {
            transactionSessionId = sessionId;
            if (Engine.logBeans.isTraceEnabled())
                Engine.logBeans.trace("(StepWithExpression) setting transactionSessionId: " + transactionSessionId);
        } else if (transactionSessionId != null) {
            if (Engine.logBeans.isTraceEnabled())
                Engine.logBeans.trace("(StepWithExpression) transactionSessionId/JSESSIONID: "
                        + transactionSessionId + "/" + sessionId);
        }
    }

    public void setTransactionSessionId(HttpState state) {
        if ((transactionSessionId == null) && (state != null)) {
            if (state != null) {
                Cookie[] httpCookies = state.getCookies();
                int len = httpCookies.length;
                Cookie cookie = null;
                for (int i = 0; i < len; i++) {
                    cookie = httpCookies[i];
                    if (cookie.getName().equalsIgnoreCase("JSESSIONID")) {
                        transactionSessionId = cookie.getValue();
                        if (Engine.logBeans.isTraceEnabled())
                            Engine.logBeans.trace(
                                    "(StepWithExpression) setting transactionSessionId: " + transactionSessionId);
                        break;
                    }
                }
            }
        } else if (transactionSessionId != null) {
            if (Engine.logBeans.isTraceEnabled()) {
                if (state != null) {
                    Cookie[] httpCookies = state.getCookies();
                    int len = httpCookies.length;
                    Cookie cookie = null;
                    for (int i = 0; i < len; i++) {
                        cookie = httpCookies[i];
                        if (cookie.getName().equalsIgnoreCase("JSESSIONID")) {
                            Engine.logBeans.trace("(StepWithExpression) transactionSessionId/JSESSIONID: "
                                    + transactionSessionId + "/" + cookie.getValue());
                            break;
                        }
                    }
                }
            }
        }
    }

    protected void cleanChildren() {
        if (childrenSteps != null) {
            //Enumeration e = childrenSteps.elements();
            Enumeration<String> e = Collections.enumeration(childrenSteps.keySet());
            while (e.hasMoreElements()) {
                String timeID = (String) e.nextElement();
                if (timeID != null) {
                    Long stepPriority = null;
                    Step step = sequence.getCopy(timeID);
                    if (step != null) {
                        stepPriority = new Long(step.priority);
                        step.cleanCopy();
                    }
                    sequence.removeCopy(timeID, stepPriority);
                }
            }
            childrenSteps.clear();
        }
    }

    @Override
    protected void cleanCopy() {
        //System.out.println("Start Clean copy of step " + name + "("+executeTimeID+")");
        cleanChildren();
        if (childrenSteps != null) {
            childrenSteps.clear();
            childrenSteps = null;
        }
        super.cleanCopy();
        vSteps = null; // ! Do not clear()!
        if (vAllSteps != null) {
            vAllSteps.clear();
            vAllSteps = null;
        }
        //System.out.println("End Clean copy of step " + name + "("+executeTimeID+")");
    }

    @Override
    public void add(DatabaseObject databaseObject) throws EngineException {
        if (databaseObject instanceof Step) {
            addStep((Step) databaseObject);
        } else {
            super.add(databaseObject);
        }
    }

    @Override
    public void remove(DatabaseObject databaseObject) throws EngineException {
        if (databaseObject instanceof Step) {
            removeStep((Step) databaseObject);
        } else {
            super.remove(databaseObject);
        }
    }

    public void addStep(Step step) throws EngineException {
        checkSubLoaded();

        String newDatabaseObjectName = getChildBeanName(vSteps, step.getName(), step.bNew);
        step.setName(newDatabaseObjectName);

        vSteps.add(step);
        step.setParent(this);// do not call super.add otherwise it will generate an exception
        step.sequence = getSequence();

        sequence.loadedSteps.put(new Long(step.priority), step);
        sequence.addStepListener(step);

        insertOrderedStep(step, null);
    }

    public void insertOrderedStep(Step step, Long after) {
        XMLVector<Long> ordered = orderedSteps.get(0);
        int size = ordered.size();

        Long value = new Long(step.priority);

        if (ordered.contains(value))
            return;

        if (after == null) {
            after = new Long(0);
            if (size > 0)
                after = (Long) ordered.lastElement();
        }

        int order = ordered.indexOf(after);
        ordered.add(order + 1, value);
        hasChanged = true;
    }

    public void removeStep(Step step) {
        checkSubLoaded();

        vSteps.remove(step);
        step.setParent(null); // Do not call super.remove otherwise it will generate an exception
        step.sequence = null;

        Long value = new Long(step.priority);
        removeOrderedStep(value);

        sequence.loadedSteps.remove(new Long(step.priority));
        sequence.removeStepListener(step);
    }

    public void removeOrderedStep(Long value) {
        XMLVector<Long> ordered = orderedSteps.get(0);
        ordered.remove(value);
        hasChanged = true;
    }

    public List<Step> getSteps(boolean reset) {
        if (reset)
            vAllSteps = null;
        return getSteps();
    }

    public List<Step> getSteps() {
        checkSubLoaded();

        if ((vAllSteps == null) || hasChanged)
            vAllSteps = getAllSteps();
        return vAllSteps;
    }

    public List<Step> getAllSteps() {
        checkSubLoaded();

        debugSteps();
        return sort(vSteps);
    }

    /**
     * Get representation of order for quick sort of a given database object.
     */
    @Override
    public Object getOrder(Object object) throws EngineException {
        if (object instanceof Step) {
            List<Long> ordered = orderedSteps.get(0);
            long time = ((Step) object).priority;
            if (ordered.contains(time))
                return (long) ordered.indexOf(time);
            else
                throw new EngineException("Corrupted step for StepWithExpressions \"" + getName() + "\". Step \""
                        + ((Step) object).getName() + "\" with priority \"" + time
                        + "\" isn't referenced anymore.");
        } else
            return super.getOrder(object);
    }

    public boolean hasSteps() {
        checkSubLoaded();

        return (vSteps.size() > 0) ? true : false;
    }

    public int numberOfSteps() {
        checkSubLoaded();

        return vSteps.size();
    }

    /**
    * @return the orderedSteps
    */
    public XMLVector<XMLVector<Long>> getOrderedSteps() {
        return orderedSteps;
    }

    /**
     * @param orderedSteps the orderedSteps to set
     */
    public void setOrderedSteps(XMLVector<XMLVector<Long>> orderedSteps) {
        this.orderedSteps = orderedSteps;
    }

    public void increasePriority(DatabaseObject databaseObject) throws EngineException {
        if (databaseObject instanceof Step)
            increaseOrder(databaseObject, null);
    }

    public void decreasePriority(DatabaseObject databaseObject) throws EngineException {
        if (databaseObject instanceof Step)
            decreaseOrder(databaseObject, null);
    }

    public void insertAtOrder(DatabaseObject databaseObject, long priority) throws EngineException {
        increaseOrder(databaseObject, new Long(priority));
    }

    private void increaseOrder(DatabaseObject databaseObject, Long before) throws EngineException {
        XMLVector<Long> ordered = orderedSteps.get(0);
        Long value = new Long(databaseObject.priority);

        if (!ordered.contains(value))
            return;
        int pos = ordered.indexOf(value);
        if (pos == 0)
            return;

        if (before == null)
            before = (Long) ordered.get(pos - 1);
        int pos1 = ordered.indexOf(before);

        ordered.add(pos1, value);
        ordered.remove(pos + 1);
        hasChanged = true;
    }

    private void decreaseOrder(DatabaseObject databaseObject, Long after) throws EngineException {
        XMLVector<Long> ordered = orderedSteps.get(0);
        Long value = new Long(databaseObject.priority);

        if (!ordered.contains(value))
            return;
        int pos = ordered.indexOf(value);
        if (pos + 1 == ordered.size())
            return;

        if (after == null)
            after = (Long) ordered.get(pos + 1);
        int pos1 = ordered.indexOf(after);

        ordered.add(pos1 + 1, value);
        ordered.remove(pos);
        hasChanged = true;
    }

    public void debugSteps() {
        if (Engine.logBeans.isTraceEnabled()) {
            String steps = "";
            if (orderedSteps.size() > 0) {
                XMLVector<Long> ordered = orderedSteps.get(0);
                steps = Arrays.asList(ordered.toArray()).toString();
            }
            Engine.logBeans.trace("[" + getName() + "] Ordered Steps [" + steps + "]");
        }
    }

    public String toJsString() {
        List<Step> v = getSteps();
        String code = "";
        if (hasSteps()) {
            for (int i = 0; i < v.size(); i++) {
                Step step = (Step) v.get(i);
                code += step.toJsString() + "\n";
            }
        }
        return code;
    }

    @Override
    protected boolean stepExecute(Context javascriptContext, Scriptable scope) throws EngineException {
        if (isEnable()) {
            if (bContinue && sequence.isRunning()) {
                if (super.stepExecute(javascriptContext, scope)) {
                    return executeNextStep(javascriptContext, scope);
                }
            }
        }
        return false;
    }

    @Override
    protected void stepInit() throws EngineException {
        super.stepInit();
        currentChildStep = 0;
    }

    @Override
    protected void reset() throws EngineException {
        super.reset();
        bContinue = true;
    }

    @Override
    protected void stepDone() {
        if (isSynchronous()) {
            try {
                boolean hasWait = false;
                while (nbAsyncThreadRunning > 0) {
                    // If contains ParallelSteps, waits until child's threads finish
                    if (Engine.logBeans.isTraceEnabled())
                        Engine.logBeans.trace("Step " + getName() + " (" + executeTimeID + ") waiting...");
                    Thread.sleep(500);
                    hasWait = true;
                }
                if (hasWait) {
                    if (Engine.logBeans.isTraceEnabled())
                        Engine.logBeans.trace("Step " + getName() + " (" + executeTimeID + ") ends wait");
                }
            } catch (InterruptedException e) {
                if (Engine.logBeans.isTraceEnabled())
                    Engine.logBeans.trace("Step " + getName() + " (" + executeTimeID + ") has been interrupted");
            }
        }

        // Remove transaction's context if needed
        removeTransactionContext();

        super.stepDone();
    }

    protected void removeTransactionContext() {
        if (Engine.isEngineMode()) {
            if (parent instanceof ParallelStep) {
                if (sequence.useSameJSessionForSteps()) {
                    // TODO ??
                } else {
                    if (Engine.logBeans.isDebugEnabled())
                        Engine.logBeans.debug(
                                "Executing deletion of transaction's context for step \"" + getName() + "\"");

                    Engine.theApp.contextManager.removeAll(transactionSessionId);

                    if (Engine.logBeans.isDebugEnabled())
                        Engine.logBeans
                                .debug("Deletion of transaction's context for step \"" + getName() + "\" done");
                }
            }
        }
    }

    protected void waitForAvailableThread() {
        // does nothing
    }

    protected void notifyForAvailableThread() {
        // does nothing
    }

    public synchronized void increaseAsyncThreadRunning() {
        nbAsyncThreadRunning++;
        //System.out.println("Incr step "+ name + " ("+executeTimeID+") threads :" + nbAsyncThreadRunning);
    }

    public synchronized void decreaseAsyncThreadRunning() {
        if (nbAsyncThreadRunning > 0)
            nbAsyncThreadRunning--;
        //System.out.println("Decr step "+ name + " ("+executeTimeID+") threads : " + nbAsyncThreadRunning);
    }

    //protected synchronized void invokeNextStep(Step step, Context javascriptContext, Scriptable scope) throws EngineException {
    protected void invokeNextStep(Step step, Context javascriptContext, Scriptable scope) throws EngineException {
        Step stepToInvoke = getStepCopyToInvoke(step);
        if (stepToInvoke != null) {
            // Stack scope
            // Note: variable must be declared with the 'var' keyword
            Scriptable curScope = javascriptContext.initStandardObjects();
            curScope.setParentScope(scope);
            invokeStep(stepToInvoke, javascriptContext, curScope);
        }
        currentChildStep++;

        performSynchronisation();
    }

    protected void invokeStep(Step step, Context javascriptContext, Scriptable scope) {
        if (Engine.logBeans.isDebugEnabled())
            Engine.logBeans.debug("Invoquing step named '" + step + "' (" + step.getName() + ")");

        AsynchronousStepThread connectionStepThread = new AsynchronousStepThread(step, scope);
        increaseAsyncThreadRunning();
        connectionStepThread.setDaemon(true);
        connectionStepThread.start();
    }

    class AsynchronousStepThread extends Thread {
        private org.mozilla.javascript.Context javascriptContext = null;
        private Scriptable scope = null;
        private Sequence refSequence = null;
        public boolean bContinue = false;
        private Step step = null;
        private long asyncNum;

        public AsynchronousStepThread(Step step, Scriptable scope) {
            this.step = step;
            this.scope = scope;
            this.refSequence = sequence;
            asyncNum = asyncCounters[0]++;
            setName("AsynchronousStep #" + step.hashCode());
        }

        @Override
        public void run() {
            bContinue = true;
            try {
                javascriptContext = org.mozilla.javascript.Context.enter();
                if (step != null) {
                    if (Engine.logBeans.isDebugEnabled())
                        Engine.logBeans.debug("(AsynchronousStepThread) \"" + AsynchronousStepThread.this.getName()
                                + "\" executing step : " + step.getName());
                    if (step.execute(javascriptContext, scope)) {
                        //childrenSteps.put(step.executeTimeID, new Long(step.priority));
                        //executedSteps.putAll(step.executedSteps);
                        if (step instanceof ParallelStep) {
                            try {
                                while (((ParallelStep) step).nbAsyncThreadRunning > 0) {
                                    Thread.sleep(500);
                                }
                            } catch (InterruptedException e) {
                                if (Engine.logBeans.isDebugEnabled())
                                    Engine.logBeans.debug("(AsynchronousStepThread) \""
                                            + AsynchronousStepThread.this.getName() + "\" has been interrupted");
                            }
                        }
                    }
                }

            } catch (Exception e) {
                Engine.logBeans.error("An error occured while invoking connection step \""
                        + AsynchronousStepThread.this.getName() + "\"", e);
            } finally {
                bContinue = false;
                org.mozilla.javascript.Context.exit();
                javascriptContext = null;
                decreaseAsyncThreadRunning();
                if (step.xpathApi != null) {
                    step.xpathApi.release();
                }
                step.cleanCopy();
                refSequence.removeCopy(step.executeTimeID, new Long(step.priority));
                if (Engine.logBeans.isDebugEnabled())
                    Engine.logBeans.debug(
                            "(AsynchronousStepThread) \"" + AsynchronousStepThread.this.getName() + "\" done");
            }
        }

        public void wakeTurn(Step step) {
            if (asyncCounters != null) {
                synchronized (asyncCounters) {
                    long next = asyncCounters[1];

                    if (Engine.logBeans.isTraceEnabled())
                        Engine.logBeans.trace("(AsynchronousStepThread) \"" + AsynchronousStepThread.this.getName()
                                + "\" (" + step.getName() + ") wakeTurn : is " + asyncNum + " and current is "
                                + next);

                    while (asyncNum > next && bContinue && sequence.isRunning()) {
                        try {
                            asyncCounters.wait(5000);
                        } catch (InterruptedException e) {
                        }
                        next = asyncCounters[1];
                        if (Engine.logBeans.isDebugEnabled())
                            Engine.logBeans.debug("(AsynchronousStepThread) \""
                                    + AsynchronousStepThread.this.getName() + "\" (" + step.getName()
                                    + ") wakeTurn retry : is " + asyncNum + " and current is " + next);
                    }
                    if (asyncNum == asyncCounters[1]) {
                        asyncCounters[1]++;
                        if (Engine.logBeans.isDebugEnabled())
                            Engine.logBeans.debug("(AsynchronousStepThread) \""
                                    + AsynchronousStepThread.this.getName() + "\" (" + step.getName()
                                    + ") wakeTurn inc : next value is " + asyncCounters[1]);
                    }
                    asyncCounters.notifyAll();
                }
            }
        }
    }

    protected boolean executeNextStep(Context javascriptContext, Scriptable scope) throws EngineException {
        if (isEnable()) {
            if (hasSteps()) {
                for (int i = 0; i < numberOfSteps(); i++) {
                    if (bContinue && sequence.isRunning())
                        executeNextStep((Step) getSteps().get(i), javascriptContext, scope);
                    else
                        break;
                }
            }
            return true;
        }
        return false;
    }

    private Step getStepCopy(Step step) throws EngineException {
        step.checkSubLoaded();

        Step stepCopy = null;
        if (step.isEnable()) {
            Object ob = null;
            try {
                ob = step.copy();
            } catch (CloneNotSupportedException e) {
                throw new EngineException("Unable to get a copy of step \"" + step.getName() + "\" (" + step + ")",
                        e);
            }
            stepCopy = (Step) ob;
        }
        return stepCopy;
    }

    private Step getStepCopyToExecute(Step step) throws EngineException {
        Step stepToExecute = getStepCopy(step);
        if (stepToExecute != null) {
            stepToExecute.parent = this;
            stepToExecute.transactionContextMaintainer = ((this.parent instanceof ParallelStep) ? this
                    : transactionContextMaintainer);
            stepToExecute.xpathApi = xpathApi;
            stepToExecute.httpState = ((stepToExecute instanceof BranchStep) ? sequence.getNewHttpState()
                    : this.httpState);
            stepToExecute.executedSteps.putAll(executedSteps);
            if (Engine.logBeans.isTraceEnabled())
                Engine.logBeans.trace("(StepWithExpression) " + step + " [" + step.hashCode()
                        + "] has been copied into " + stepToExecute + " [" + stepToExecute.hashCode() + "]");
        }
        return stepToExecute;
    }

    private Step getStepCopyToInvoke(Step step) throws EngineException {
        Step stepToInvoke = getStepCopy(step);
        if (stepToInvoke != null) {
            stepToInvoke.parent = this;
            stepToInvoke.transactionContextMaintainer = ((sequence.useSameJSessionForSteps()) ? this : null);
            stepToInvoke.xpathApi = new TwsCachedXPathAPI(getProject());
            stepToInvoke.httpState = sequence.getNewHttpState(); // require new HttpState!
            stepToInvoke.executedSteps.putAll(executedSteps);
            if (Engine.logBeans.isTraceEnabled())
                Engine.logBeans.trace("(StepWithExpression) " + step + " [" + step.hashCode()
                        + "] has been copied into " + stepToInvoke + " [" + stepToInvoke.hashCode() + "]");
        }
        return stepToInvoke;
    }

    protected void executeNextStep(Step step, org.mozilla.javascript.Context javascriptContext, Scriptable scope)
            throws EngineException {
        Step stepToExecute = getStepCopyToExecute(step);
        if (stepToExecute != null) {
            // Execute step
            if (stepToExecute.execute(javascriptContext, scope)) {
                childrenSteps.put(stepToExecute.executeTimeID, new Long(stepToExecute.priority));
                executedSteps.putAll(stepToExecute.executedSteps);
            } else {
                stepToExecute.cleanCopy();
            }
        }
        currentChildStep++;

        // Makes current thread wait if needed
        // (case maxNumberOfThread for a parallel step has been reached)
        performSynchronisation();
    }

    private synchronized void performSynchronisation() {
        try {
            if (haveToWait.equals(Boolean.TRUE)) {
                if (bContinue && sequence.isRunning()) {
                    if (Engine.logBeans.isTraceEnabled())
                        Engine.logBeans.trace("Step '" + getName() + "' (" + executeTimeID + ") waiting...");

                    wait();

                    if (Engine.logBeans.isTraceEnabled())
                        Engine.logBeans.trace("Step '" + getName() + "' (" + executeTimeID + ") going through...");
                }
            }
        } catch (InterruptedException e) {
            if (Engine.logBeans.isDebugEnabled())
                Engine.logBeans.debug("Step '" + getName() + "' (" + executeTimeID + ") has been interrupted");
        }
    }

    public synchronized void shouldWait(boolean bWait) {
        if (bWait) {
            if (haveToWait.equals(Boolean.FALSE))
                haveToWait = Boolean.TRUE;
        } else {
            if (haveToWait.equals(Boolean.TRUE)) {
                if (Engine.logBeans.isTraceEnabled())
                    Engine.logBeans.trace("Step '" + getName() + "' (" + executeTimeID + ") has been notified");
                haveToWait = Boolean.FALSE;
                notify();
            }
        }
    }

    /* (non-Javadoc)
     * @see com.twinsoft.convertigo.beans.core.DatabaseObject#toXml(org.w3c.dom.Document)
     */
    @Override
    public Element toXml(Document document) throws EngineException {
        Element element = super.toXml(document);

        // Storing the transaction "handlePriorities" flag
        element.setAttribute("handlePriorities", new Boolean(handlePriorities).toString());

        return element;
    }

    @Override
    public List<DatabaseObject> getAllChildren() {
        List<DatabaseObject> rep = super.getAllChildren();
        List<Step> steps = getSteps();
        for (Step step : steps) {
            rep.add(step);
        }
        return rep;
    }

    protected XmlSchemaParticle getXmlSchemaParticle(XmlSchemaCollection collection, XmlSchema schema,
            XmlSchemaGroupBase group) {
        XmlSchemaParticle particle = group;
        if (isOutput()) {
            XmlSchemaElement element = (XmlSchemaElement) super.getXmlSchemaObject(collection, schema);
            XmlSchemaComplexType cType = XmlSchemaUtils.makeDynamic(this, new XmlSchemaComplexType(schema));
            SchemaMeta.setContainerXmlSchemaGroupBase(element, group);
            element.setType(cType);
            cType.setParticle(group);
            particle = element;
        }
        return particle;
    }

    @Override
    public XmlSchemaParticle getXmlSchemaObject(XmlSchemaCollection collection, XmlSchema schema) {
        return (XmlSchemaParticle) super.getXmlSchemaObject(collection, schema);
    }

    public boolean isGenerateElement() {
        return isOutput();
    }
}