com.twinsoft.convertigo.beans.steps.SequenceStep.java Source code

Java tutorial

Introduction

Here is the source code for com.twinsoft.convertigo.beans.steps.SequenceStep.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.steps;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.twinsoft.convertigo.beans.core.IContextMaintainer;
import com.twinsoft.convertigo.beans.core.ITagsProperty;
import com.twinsoft.convertigo.beans.core.Project;
import com.twinsoft.convertigo.beans.core.RequestableStep;
import com.twinsoft.convertigo.beans.core.Sequence;
import com.twinsoft.convertigo.beans.sequences.GenericSequence;
import com.twinsoft.convertigo.engine.Engine;
import com.twinsoft.convertigo.engine.EngineException;
import com.twinsoft.convertigo.engine.EnginePropertiesManager;
import com.twinsoft.convertigo.engine.EnginePropertiesManager.PropertyName;
import com.twinsoft.convertigo.engine.EngineStatistics;
import com.twinsoft.convertigo.engine.enums.MimeType;
import com.twinsoft.convertigo.engine.enums.Parameter;
import com.twinsoft.convertigo.engine.enums.Visibility;
import com.twinsoft.convertigo.engine.util.ProjectUtils;
import com.twinsoft.convertigo.engine.util.StringUtils;
import com.twinsoft.convertigo.engine.util.VersionUtils;
import com.twinsoft.convertigo.engine.util.XMLUtils;

public class SequenceStep extends RequestableStep implements ITagsProperty {
    private static final long serialVersionUID = -8066934224685627694L;

    private transient String sequenceName;

    private String sourceSequence = "";

    // Specify if transaction's context should be inherited from mother sequence's one
    private boolean inheritTransactionCtx = false;

    public SequenceStep() {
        super();
    }

    public SequenceStep(boolean synchronous) {
        super();
    }

    @Override
    public SequenceStep clone() throws CloneNotSupportedException {
        SequenceStep clonedObject = (SequenceStep) super.clone();
        clonedObject.setSourceSequence(sourceSequence);
        return clonedObject;
    }

    @Override
    public SequenceStep copy() throws CloneNotSupportedException {
        SequenceStep copiedObject = (SequenceStep) super.copy();
        copiedObject.setSourceSequence(sourceSequence);
        return copiedObject;
    }

    @Override
    public String getStepNodeName() {
        return "sequence";
    }

    public String getSequenceName() {
        return sequenceName;
    }

    public boolean isInheritTransactionCtx() {
        return inheritTransactionCtx;
    }

    public void setInheritTransactionCtx(boolean inheritTransactionCtx) {
        this.inheritTransactionCtx = inheritTransactionCtx;
    }

    @Override
    protected void stepDone() {
        super.stepDone();
    }

    protected void prepareForRequestable(Context javascriptContext, Scriptable scope)
            throws MalformedURLException, EngineException {
        Sequence targetSequence = getTargetSequence();

        if (Engine.isStudioMode()) {
            if (targetSequence != null) {
                if (sequence.getOriginal().equals(targetSequence.getOriginal())) {
                    throw new EngineException("Execution of recursive sequence is not allowed in Studio mode!");
                }
            }
        }

        String ctxName = getContextName(javascriptContext, scope);
        boolean useSequenceJSession = sequence.useSameJSessionForSteps();
        boolean maintainContext = useSequenceJSession && !ctxName.startsWith("Container-");
        boolean maintainSession = useSequenceJSession;

        boolean inheritContex = inheritTransactionCtx && sequence.equals(getTransactionContextMaintainer());
        String inheritedCxtName = sequence.getInheritedContextName();
        inheritedCxtName = (inheritContex && (inheritedCxtName == null)) ? sequence.getContextName()
                : inheritedCxtName;
        inheritedCxtName = (inheritedCxtName == null) ? "" : inheritedCxtName;

        if (isInternalInvoke()) {
            request.put(Parameter.Project.getName(), new String[] { projectName });
            request.put(Parameter.MotherSequenceContext.getName(), new String[] { sequence.context.contextID });
            request.put(Parameter.Sequence.getName(), new String[] { targetSequence.getName() });
            request.put(Parameter.Context.getName(), new String[] { sequence.addStepContextName(ctxName) });
            request.put(Parameter.SequenceInheritedTransactionContext.getName(),
                    inheritContex ? new String[] { inheritedCxtName } : new String[] { "" });
            if (!maintainContext)
                request.put(Parameter.RemoveContext.getName(), new String[] { "" });
            if (!maintainSession)
                request.put(Parameter.RemoveSession.getName(), new String[] { "" });
            getPostQuery(scope);
        } else {
            targetUrl = EnginePropertiesManager.getProperty(PropertyName.APPLICATION_SERVER_CONVERTIGO_URL);
            targetUrl += "/projects/" + projectName + "/.xml?";

            URL url = new URL(targetUrl);
            String host = url.getHost();
            int port = url.getPort();

            Engine.logBeans.trace("(SequenceStep) Host: " + host + ":" + port);
            hostConfiguration.setHost(host, port);

            // Retrieves new HttpState!!
            // This will force a new http session on convertigo server : new context for sequence
            httpState = sequence.getNewHttpState();

            method = new PostMethod(targetUrl);
            method.setRequestHeader("Content-Type", MimeType.WwwForm.value());

            // Set transaction sessionId from context maintainer
            String sessionId = getTransactionSessionId();
            if (useSequenceJSession) {
                Engine.logBeans.trace("(SequenceStep) JSESSIONID required : " + sessionId);
                if (sessionId != null) {
                    method.setRequestHeader("Cookie", "JSESSIONID=" + sessionId + ";");
                    Engine.logBeans.trace("(SequenceStep) JSESSIONID used : " + sessionId);
                } else {
                    Engine.logBeans.trace("(SequenceStep) JSESSIONID is null");
                }
            } else {
                if (sessionId != null) {
                    method.addRequestHeader("Transaction-JSessionId", sessionId);
                    Engine.logBeans.trace("(SequenceStep) Transaction JSESSIONID used : " + sessionId);
                } else {
                    Engine.logBeans.trace("(SequenceStep) Transaction JSESSIONID is null");
                }
            }

            String postQuery = getPostQuery(scope);
            if (!maintainContext && (postQuery.indexOf(Parameter.RemoveContext.getName()) == -1))
                postQuery = addParamToPostQuery(Parameter.RemoveContext.getName(), "", postQuery);
            if (!maintainSession && (postQuery.indexOf(Parameter.RemoveSession.getName()) == -1))
                postQuery = addParamToPostQuery(Parameter.RemoveSession.getName(), "", postQuery);
            if (postQuery.indexOf(Parameter.SequenceInheritedTransactionContext.getName()) == -1)
                postQuery = addParamToPostQuery(Parameter.SequenceInheritedTransactionContext.getName(),
                        inheritContex ? inheritedCxtName : "", postQuery);
            if (postQuery.indexOf(Parameter.Sequence.getName()) == -1)
                postQuery = addParamToPostQuery(Parameter.Sequence.getName(), targetSequence.getName(), postQuery);
            if (postQuery.indexOf(Parameter.Context.getName()) == -1)
                postQuery = addParamToPostQuery(Parameter.Context.getName(), sequence.addStepContextName(ctxName),
                        postQuery);
            if (postQuery.indexOf(Parameter.MotherSequenceContext.getName()) == -1)
                postQuery = addParamToPostQuery(Parameter.MotherSequenceContext.getName(),
                        sequence.context.contextID, postQuery);

            if (Engine.logBeans.isTraceEnabled())
                Engine.logBeans.trace(
                        "(SequenceStep) postQuery :" + Visibility.Logs.replaceVariables(getVariables(), postQuery));

            try {
                method.setRequestEntity(new StringRequestEntity(postQuery, null, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                throw new EngineException("Encoding error", e);
            }
        }
    }

    private String getContextName(Context javascriptContext, Scriptable scope) {
        boolean useSameJSessionForSteps = sequence.useSameJSessionForSteps();
        String ctxName = getStepContextName();

        // Auto context name
        if (ctxName.equals("")) {
            ctxName = useSameJSessionForSteps ? "error_" + priority : "default";
            IContextMaintainer transactionContextMaintainer = getTransactionContextMaintainer();
            if (transactionContextMaintainer != null) {
                ctxName = transactionContextMaintainer.getContextName();
                if (useSameJSessionForSteps) {
                    // Sequence always requires new context
                    ctxName += "-" + priority;
                }
            }
        }
        // Defined context name
        else {
            try {
                evaluate(javascriptContext, scope, ctxName, "ctxName", true);
            } catch (Exception e) {
                evaluated = null;
                Engine.logBeans.trace("(SequenceStep) " + e.getMessage());
            }
            ctxName = (evaluated != null) ? evaluated.toString()
                    : (useSameJSessionForSteps ? "error_" + priority : "default");
        }
        return ctxName;
    }

    private String getTransactionSessionId() {
        if (sequence.useSameJSessionForSteps()) {
            return sequence.getSessionId();
        } else {
            IContextMaintainer transactionContextMaintainer = getTransactionContextMaintainer();
            if (transactionContextMaintainer != null) {
                return transactionContextMaintainer.getTransactionSessionId();
            }
            return null;
        }
    }

    private void setTransactionSessionId(String sessionId) {
        if (sequence.useSameJSessionForSteps())
            return;

        IContextMaintainer transactionContextMaintainer = getTransactionContextMaintainer();
        if (transactionContextMaintainer != null) {
            transactionContextMaintainer.setTransactionSessionId(sessionId);
        }
    }

    public void importVariableDefinition() throws EngineException {
        Sequence targetSequence = getTargetSequence();
        if (targetSequence != null && targetSequence instanceof GenericSequence) {
            importVariableDefinition(targetSequence);
        }
    }

    public Sequence getTargetSequence() throws EngineException {
        Project p = getTargetProject(projectName);
        List<Sequence> v = p.getSequencesList();
        Sequence targetSequence = (sequenceName.equals("") ? (v.isEmpty() ? null : (Sequence) v.get(0))
                : p.getSequenceByName(sequenceName));
        return targetSequence;
    }

    protected byte[] executeMethod() throws IOException, URIException, MalformedURLException, EngineException {
        Header[] requestHeaders, responseHeaders = null;
        byte[] result = null;
        String contents = null;
        int statuscode = -1;

        if (sequence.isRunning()) {
            Engine.logBeans
                    .debug("(SequenceStep) Executing method - " + method.getName() + "(" + method.getPath() + ")");

            String ts = sequence.context.statistics.start(EngineStatistics.EXECUTE_SEQUENCE_CALLS);

            try {
                requestHeaders = method.getRequestHeaders();
                if (Engine.logBeans.isTraceEnabled())
                    Engine.logBeans
                            .trace("(SequenceStep) Request headers :\n" + Arrays.asList(requestHeaders).toString());

                statuscode = doExecuteMethod();

                Engine.logBeans.debug("(SequenceStep) Status: " + method.getStatusLine().toString());

                // stores transaction sessionId in context maintainer
                Header h = method.getResponseHeader("Transaction-JSessionId");
                if (h != null)
                    setTransactionSessionId(h.getValue());

                responseHeaders = method.getResponseHeaders();
                if (Engine.logBeans.isTraceEnabled())
                    Engine.logBeans.trace(
                            "(SequenceStep) Response headers:\n" + Arrays.asList(responseHeaders).toString());

                if (statuscode != -1) {
                    InputStream in = method.getResponseBodyAsStream();
                    if (in != null) {
                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
                        byte[] buf = new byte[1024];
                        int len;
                        while ((len = in.read(buf)) > 0) {
                            bos.write(buf, 0, len);
                        }
                        result = bos.toByteArray();
                        in.close();
                        bos.close();
                    }

                    if (Engine.logBeans.isTraceEnabled()) {
                        contents = new String((result != null) ? result : new byte[] {});
                        Engine.logBeans.trace("(SequenceStep) Response content:\n" + contents);
                    }

                }
                if (statuscode >= 300) {
                    throw new EngineException("(SequenceStep) HTTP response returned status :"
                            + ((method != null) ? method.getStatusLine().toString() : String.valueOf(statuscode)));
                }
            } finally {
                if (method != null)
                    method.releaseConnection();

                sequence.context.statistics.stop(ts, sequence.getCurrentChildStep() != 0);
            }
        }
        return result;
    }

    @Override
    public void configure(Element element) throws Exception {
        super.configure(element);

        String version = element.getAttribute("version");

        if (version == null) {
            String s = XMLUtils.prettyPrintDOM(element);
            EngineException ee = new EngineException(
                    "Unable to find version number for the database object \"" + getName() + "\".\nXML data: " + s);
            throw ee;
        }

        try {
            if (VersionUtils.compare(version, "6.0.3") < 0) {
                String projectName = (String) XMLUtils.findPropertyValue(element, "projectName");
                // Handle wrong project name
                if (projectName.equals("")) {
                    projectName = "unknown_project";
                }

                String sequenceName = (String) XMLUtils.findPropertyValue(element, "sequenceName");
                // Handle wrong sequence name
                if (sequenceName.equals("")) {
                    sequenceName = "unknown_sequence";
                }

                String sourceSequence = projectName + SequenceStep.SOURCE_SEPARATOR + sequenceName;

                setSourceSequence(sourceSequence);

                hasChanged = true;
                Engine.logBeans.warn("[SequenceStpe] The object \"" + getName()
                        + "\" has been updated to version 6.0.3; source sequence: " + sourceSequence);
            }
        } catch (Exception e) {
            throw new EngineException(
                    "Unable to migrate the source definition for CallSequence step \"" + getName() + "\".", e);
        }
    }

    @Override
    public Element toXml(Document document) throws EngineException {
        Element element = super.toXml(document);

        // Storing the sequence WSDL type
        try {
            Element wsdlTypeElement = document.createElement("wsdltype");
            if (wsdlType != null) {
                CDATASection cDATASection = document.createCDATASection(wsdlType);
                wsdlTypeElement.appendChild(cDATASection);
                element.appendChild(wsdlTypeElement);
            }
        } catch (NullPointerException e) {
            // Silently ignore
        }

        return element;
    }

    @Override
    public String[] getTagsForProperty(String propertyName) {
        if (propertyName.equals("sourceSequence")) {
            List<String> sequencesList = new ArrayList<String>();

            try {
                List<String> projectNames = Engine.theApp.databaseObjectsManager.getAllProjectNamesList();
                for (String projectName : projectNames) {
                    Project project = Engine.theApp.databaseObjectsManager.getProjectByName(projectName);
                    List<Sequence> sequences = project.getSequencesList();

                    for (Sequence sequence : sequences) {
                        sequencesList.add(projectName + SOURCE_SEPARATOR + sequence.getName());
                    }
                }
            } catch (EngineException e) {
                // Just ignore, should never happen
            }

            return sequencesList.toArray(new String[] {});
        }
        return super.getTagsForProperty(propertyName);
    }

    /* (non-Javadoc)
     * @see com.twinsoft.convertigo.beans.core.RequestableStep#getSpecificLabel()
     */
    @Override
    protected String getSpecificLabel() throws EngineException {
        String label = super.getSpecificLabel();
        if (label.equals("")) {// normal case
            // Check for project
            if (projectName.equals("")) {
                label = "! broken project !";
            } else {
                // Check for project
                try {
                    if (ProjectUtils.existProjectSchemaReference(getProject(), projectName)) {
                        Project p = getTargetProject(projectName);
                        if (p == null) {
                            label = "! broken project !";
                        } else {
                            //Check for sequence
                            List<Sequence> v = p.getSequencesList();
                            Sequence seq = (sequenceName.equals("") ? (v.isEmpty() ? null : (Sequence) v.get(0))
                                    : p.getSequenceByName(sequenceName));
                            if (seq == null) {
                                label = "! broken sequence !";
                            }
                        }
                    } else {
                        label = "! broken reference !";
                    }
                } catch (Exception e) {
                    label = "! broken project !";
                }
            }
        }
        return label;
    }

    @Override
    public String toString() {
        String label = "";
        try {
            label += getLabel();
        } catch (EngineException e) {
        }
        return StringUtils.normalize("Call_" + getSourceSequence()) + (label.equals("") ? "" : " ") + label;
    }

    public String getSourceSequence() {
        return sourceSequence;
    }

    public void setSourceSequence(String sourceSequence) {
        this.sourceSequence = sourceSequence;
        StringTokenizer st = new StringTokenizer(sourceSequence, SequenceStep.SOURCE_SEPARATOR);
        try {
            projectName = st.nextToken();
            sequenceName = st.nextToken();
        } catch (Exception e) {
        }
    }

    protected String getRequestableName() {
        return sequenceName;
    }
}