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

src.openwfe.org.engine.impl.launch.SimpleXmlLauncher Maven / Gradle / Ivy

There is a newer version: 1.7.2
Show newest version
/*
 * Copyright (c) 2001-2006, John Mettraux, OpenWFE.org
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 * . Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.  
 * 
 * . Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 * 
 * . Neither the name of the "OpenWFE" nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without
 *   specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: SimpleXmlLauncher.java 2947 2006-07-17 08:04:50Z jmettraux $
 */

//
// SimpleXmlLauncher.java
//
// [email protected]
//
// generated with 
// jtmpl 1.1.01 2004/05/19 ([email protected])
//

package openwfe.org.engine.impl.launch;

import openwfe.org.Utils;
import openwfe.org.ReflectionUtils;
import openwfe.org.AbstractService;
import openwfe.org.xml.XmlUtils;
import openwfe.org.engine.Definitions;
import openwfe.org.engine.launch.Launcher;
import openwfe.org.engine.launch.LaunchException;
import openwfe.org.engine.launch.ProcessLibrary;
import openwfe.org.engine.expool.ExpressionPool;
import openwfe.org.engine.workitem.Attribute;
import openwfe.org.engine.workitem.XmlAttribute;
import openwfe.org.engine.workitem.LaunchItem;
import openwfe.org.engine.workitem.InFlowWorkItem;
import openwfe.org.engine.workitem.AttributeUtils;
import openwfe.org.engine.dispatch.DispatchingException;
import openwfe.org.engine.expressions.ValueUtils;
import openwfe.org.engine.expressions.Environment;
import openwfe.org.engine.expressions.WithChildren;
import openwfe.org.engine.expressions.ApplyException;
import openwfe.org.engine.expressions.BuildException;
import openwfe.org.engine.expressions.FlowExpression;
import openwfe.org.engine.expressions.FlowExpressionId;
import openwfe.org.engine.expressions.DefineExpression;
import openwfe.org.engine.expressions.ProcessDefinition;
import openwfe.org.engine.expressions.AbstractFlowExpression;
import openwfe.org.engine.expressions.SubProcessRefExpression;
import openwfe.org.engine.expressions.raw.RawExpression;
import openwfe.org.engine.participants.Participant;
import openwfe.org.engine.participants.ParticipantMap;


/**
 * The vanilla XML openwfe launcher.
 *
 * 

CVS Info : *
$Author: jmettraux $ *
$Id: SimpleXmlLauncher.java 2947 2006-07-17 08:04:50Z jmettraux $
* * @author [email protected] */ public class SimpleXmlLauncher extends AbstractService implements Launcher { private final static org.apache.log4j.Logger log = org.apache.log4j.Logger .getLogger(SimpleXmlLauncher.class.getName()); // // CONSTANTS & co /** * This constant is the name of a system property, when it has a value * of 'true', 'ok' or 'yes', XML schema validation will be used * against process definitions. */ public final static String VALIDATE = "openwfe.org.engine.launcher.validate"; // // FIELDS //private XmlResourceLoader loader = new XmlResourceLoader(); // caching documents // // CONSTRUCTORS // // METHODS from Launcher public FlowExpressionId launch (final LaunchItem li, final boolean async) throws LaunchException { final InFlowWorkItem wi = new InFlowWorkItem(li); //Definitions.getXmlCoder(getContext()).dump("launch", wi); return launch(wi, li.getReplyTo(), li.getWorkflowDefinitionUrl(), async); } private org.jdom.Element parseXmlDefinition (final String url, final InFlowWorkItem wi, final boolean shouldValidate) throws Exception { if (log.isDebugEnabled()) log.debug("parseXmlDefinition() from "+url); if (url.startsWith(URL_FIELD_PREFIX)) // // the process definition seems to be embedded in a field // of the workitem { final String fieldName = url.substring(URL_FIELD_PREFIX.length()); //final Attribute a = wi.getAttribute(fieldName); final Attribute a = wi.getAttributes().getField(fieldName); wi.getAttributes().unsetField(fieldName); if (a == null) { throw new IllegalArgumentException ("Field '"+fieldName+ "' is not present, cannot launch flow defined in it"); } if (a instanceof XmlAttribute) { org.jdom.Content content = ((XmlAttribute)a).getContent(); return (org.jdom.Element)content; } final String sXmlDefinition = a.toString(); //log.debug("parseXmlDefinition()\n"+sXmlDefinition); org.jdom.Element elt = XmlUtils.extractXmlElement(sXmlDefinition); return elt; } // // classical case : the process definition is pointed at // through an HTTP URL or something like that return XmlUtils.extractXml(url, shouldValidate); } /** * Returns the workflowInstanceId of the newly launched flow. */ public FlowExpressionId launch (final InFlowWorkItem wi, final FlowExpressionId parentId, final String wfdUrl, final boolean async) throws LaunchException { // // remote launch ? if (wfdUrl.indexOf(SubProcessRefExpression.ENGINE_SEPARATOR) > -1) // engine separator is "::" { final String wfid = launchExternalProcess(wi, wfdUrl, parentId); final FlowExpressionId result = new FlowExpressionId(); result.setOwfeVersion(Definitions.OPENWFE_VERSION); result.setWorkflowInstanceId(wfid); return result; } // // local launch final String url = Utils.expandUrl(wfdUrl); if (log.isDebugEnabled()) log.debug("launch() request for "+url); try { final org.jdom.Element elt = parseXmlDefinition(url, wi, shouldValidate()); final RawExpression rootExpression = RawExpression.getEmptyRawExpression(getContext()); // // misc data final String wfdName = elt.getAttributeValue("name"); final String wfdRevision = elt.getAttributeValue("revision"); if (wfdName == null || wfdRevision == null) { throw new LaunchException ("Process definition is missing a 'name' "+ "and/or a 'revision' attribute."); } // // determine root expression ids if (parentId == null) // // brand new flow { FlowExpressionId pid = new FlowExpressionId(); pid.setOwfeVersion(Definitions.OPENWFE_VERSION); pid.setEngineId(getContext().getApplicationName()); pid.setInitialEngineId(getContext().getApplicationName()); pid.setWorkflowDefinitionUrl(url); pid.setWorkflowDefinitionName(wfdName); pid.setWorkflowDefinitionRevision(wfdRevision); // expression name and id remain to null !! pid.setWorkflowInstanceId (RawExpression.determineNewWorkflowInstanceId()); // // init the expression rootExpression.init (getContext(), null, pid, 0, elt); // // starting at expressionId '0' // envId : null } else // // determine root expression id manually { final FlowExpressionId id = new FlowExpressionId(); id.setOwfeVersion(Definitions.OPENWFE_VERSION); id.setEngineId(getContext().getApplicationName()); id.setInitialEngineId(getContext().getApplicationName()); id.setWorkflowDefinitionUrl(url); id.setWorkflowDefinitionName(wfdName); id.setWorkflowDefinitionRevision(wfdRevision); id.setExpressionName(elt.getName()); id.setExpressionId("0"); id.setWorkflowInstanceId (RawExpression.determineNewWorkflowInstanceId()); // // init the expression rootExpression.init (getContext(), null, // envId parentId, id, elt); } getExpressionPool().add(rootExpression); final java.util.Map vars = new java.util.HashMap(1); vars.put(wfdName, rootExpression.clone()); if (log.isDebugEnabled()) log.debug("launch() '"+wfdName+"' -> "+rootExpression.getId()); // // do the launch final FlowExpressionId fei = launchSub (wi, parentId, rootExpression.getId(), vars, async); if (log.isDebugEnabled()) { log.debug ("launch() launched as sub : "+fei); log.debug ("launch() returning : "+fei.getWorkflowInstanceId()); } return fei; } catch (final Throwable t) { throw new LaunchException("launch failed", t); } } /** * Launches an inner subflow (for example for 'iterator' or 'when'). * * @param variables the set of variables that have to be put in the new * environment of the expression. If this param is null, no new environment * will be created and the expression will use the environment of the * parent expression (if there is one). */ public FlowExpressionId launchSub (final InFlowWorkItem wi, final FlowExpressionId parentId, final FlowExpressionId templateId, final java.util.Map variables, final boolean async) throws LaunchException { loadLibrary(); if (log.isDebugEnabled()) { log.debug("launchSub() for template "+templateId); log.debug("launchSub() parentId is "+parentId); } RawExpression rawExp = (RawExpression)getExpressionPool() .fetch(templateId); try { rawExp = rawExp.newInstance(parentId); // // this method adds the new expression to the expool if (log.isDebugEnabled()) log.debug("launchSub() rawExp.parent was "+rawExp.getParent()); rawExp.setParent(parentId); // // especially if it's null //log.debug("launchSub() rawExp.parent is "+rawExp.getParent()); if (variables != null || parentId == null) // // build new environment // // variables != null : the launching exp requests explicitely // a new environment // parent == null : the launched, being an orphan, must have // a new environment { log.debug("launchSub() generating a new env for self"); final Environment env = Environment.generateEnvironment(rawExp); //rawExp.storeItself(); // // it's better here : it fixes bug #1453357 as well if (log.isDebugEnabled()) log.debug("launchSub() generated env : "+env.getId()); if (variables != null) // // subprocess 'parameters' // { env.putAll(variables); //env.storeItself(); // // already done in putAll() } } else // (parentId != null) // // else : variables is null and parent id is not null { log.debug("launchSub() using parent's env"); FlowExpression parent = getExpressionPool().fetch(parentId); rawExp.setEnvironmentId(parent.getEnvironmentId()); } rawExp.storeItself(); final FlowExpressionId id = rawExp.getId(); //addChildToParent(parentId, id); // // Was previously done in the Iterator. // Is only necessary of SynchableExpression parents. // // applying final InFlowWorkItem subwi = (InFlowWorkItem)wi.clone(); //Definitions.getXmlCoder(getContext()).dump("launchsub1_", subwi); if (log.isDebugEnabled()) { log.debug("launchSub() rawExp.id is "+id); log.debug("launchSub() rawExp.parent is "+rawExp.getParent()); //log.debug("launchSub() applying "+id); log.debug("launchSub() launching "+id); log.debug("launchSub() async ? "+async); } if (async) { (new Thread() { public void run () { try { log.debug("launchSub() (now in async thread)"); //getExpressionPool().apply(id, subwi); getExpressionPool().launch(id, subwi); if (log.isDebugEnabled()) log.debug("launchSub() launched "+id); } catch (final Throwable t) { log.warn("launchSub() failure", t); } } }).start(); } else { //getExpressionPool().apply(id, subwi); getExpressionPool().launch(id, subwi); } if (log.isDebugEnabled()) { log.debug ("launchSub() launched "+id.getWorkflowInstanceId()); } return id; } catch (final Exception e) { log.debug ("Failed to 'launch' RawExpression", e); throw new LaunchException ("Failed to 'launch' RawExpression", e); } } /** * Fetches the attributes from the uninterpreted raw version of a flow * expression. * If rawExpression is an instance of java.util.Map, it will be * returned straight away. */ public java.util.Map fetchAttributes (final FlowExpression fe, final Object rawExpression) throws BuildException { if (rawExpression instanceof java.util.Map) return (java.util.Map)rawExpression; final org.jdom.Element e = (org.jdom.Element)rawExpression; final java.util.Map result = XmlUtils.fetchAttributes(e); if (fe instanceof WithChildren) { final String text = e.getTextTrim(); if (text != null && text.length() > 0 && e.getChildren().size() < 1) // // truc // { result.put(WithChildren.A_VALUE, e.getTextTrim()); result.put(WithChildren.A_CONTENT, XmlUtils.xmlToString(e)); } else if (e.getContent().size() > 0) // // // // true // // // { result.put(WithChildren.A_CONTENT, XmlUtils.xmlToString(e)); } } return result; } /** * This method is used by droflo to load completety a workflow * definition for display or edition. */ public ProcessDefinition loadProcessDefinition (final String wfdUrl) throws BuildException { //log.debug("loadProcessDefinition(u)"); final String url = Utils.expandUrl(wfdUrl); org.jdom.Element elt = null; try { elt = XmlUtils.extractXml(url, shouldValidate()); } catch (final Throwable t) { throw new BuildException("Failed to load "+url, t); } return loadProcessDefinition(url, null, elt); } /** * Loads a sub process definition. */ public ProcessDefinition loadProcessDefinition (final FlowExpressionId parentId, final Object rawExpression) throws BuildException { //log.debug("loadProcessDefinition(p, e)"); org.jdom.Element xmlBranch = null; if (rawExpression instanceof org.jdom.Element) { xmlBranch = (org.jdom.Element)rawExpression; } else if (rawExpression instanceof RawExpression) { xmlBranch = (org.jdom.Element) ((RawExpression)rawExpression).getRaw(); } if (xmlBranch == null) { throw new BuildException ("Cannot turn an instance of class "+ rawExpression.getClass().getName()+ " into a process definition"); } return loadProcessDefinition(null, parentId, xmlBranch); } /* * Either wfdUrl is null, either elt is null, not both should be null * at the same time. */ private ProcessDefinition loadProcessDefinition (final String wfdUrl, final FlowExpressionId parentId, final org.jdom.Element elt) throws BuildException { //log.debug("loadProcessDefinition(u, p, e)"); String wfdName = null; String wfdRevision = null; FlowExpressionId pId = parentId; if (pId == null) { pId = new FlowExpressionId(); // // misc data wfdName = elt.getAttributeValue("name"); wfdRevision = elt.getAttributeValue("revision"); // // tweak parent id pId.setOwfeVersion(Definitions.OPENWFE_VERSION); pId.setWorkflowDefinitionUrl(wfdUrl); pId.setWorkflowDefinitionName(wfdName); pId.setWorkflowDefinitionRevision(wfdRevision); } else { wfdName = pId.getWorkflowDefinitionName(); wfdRevision = pId.getWorkflowDefinitionRevision(); } try { final RawExpression rootExpression = RawExpression.getEmptyRawExpression(getContext()); // // inits the root expression rootExpression.init (getContext(), null, pId, 0, elt); //log.debug // ("loadProcessDefinition(d, e) root exp is "+ // rootExpression.getId()); final ProcessDefinition result = new ProcessDefinition (getContext(), wfdUrl, wfdName, wfdRevision); final FlowExpression fe = rootExpression.resolveExpression(result); if (log.isDebugEnabled()) { log.debug ("loadProcessDefinition() "+ "found something of class >"+fe.getClass().getName()+"<"); } result.setSelf((DefineExpression)fe); //log.debug // ("loadProcessDefinition(d, e) result is \n"+ // result.toString()); return result; } catch (final Throwable t) { throw new BuildException("Failed to load "+wfdUrl, t); } } /** * This method is used by droflo to load completety a workflowd * definition for display or edition. */ public ProcessDefinition loadProcessDefinitionFromString (final String xmlDefinition) throws BuildException { try { return loadProcessDefinition (null, // wfdUrl XmlUtils .extractXmlDocument(xmlDefinition, shouldValidate()) .getRootElement()); } catch (final BuildException be) { throw be; } catch (final Exception e) { throw new BuildException ("Failed to extract xml from string xml definition", e); } } /** * This is used by the EvalExpression and also by the * SubProcessRefExpression when evaluating nested children. * This method doesn't apply the newly created tree of expressions, * it simply returns it. * * @param caller the FlowExpression calling this eval method. * @param rawScript the snippet of POOL (Process Oriented OpenWFE Lisp) * that has to be evaluated. * * @return the newly created RawExpression, ready to be applied. */ public RawExpression eval (final FlowExpression caller, final Object rawScript, final InFlowWorkItem wi) throws Exception { if (rawScript == null) { log.debug("eval() nothing to eval."); return null; } // // is a Text (CDATA element) ? if (rawScript instanceof org.jdom.Text) // // trying to return what's behind the variable name { final String varName = ((org.jdom.Text)rawScript).getTextTrim(); final Object o = caller.lookupVariable(varName); if (o != null) ValueUtils.setResult(wi, AttributeUtils.java2owfe(o)); log.debug("eval() just some text."); return null; } if ( ! (rawScript instanceof org.jdom.Element)) { throw new ApplyException ("cannot handle XML fragment of class "+ rawScript.getClass().getName()); } if (log.isDebugEnabled()) { log.debug ("eval() xml is \n"+ XmlUtils.xmlToString((org.jdom.Content)rawScript)); } // // prepare the evaluation work final RawExpression evalResult = RawExpression.getEmptyRawExpression(caller.context()); //final FlowExpressionId evalId = caller.getId().copy(); //evalId.setExpressionName(((org.jdom.Element)rawScript).getName()); evalResult.init (caller.context(), caller.getEnvironmentId(), caller.getId(), //evalId, 0, rawScript); getExpressionPool().add(evalResult); return evalResult; } // // METHODS protected ExpressionPool getExpressionPool () { return Definitions.getExpressionPool(getContext()); } protected ParticipantMap getParticipantMap () { return Definitions.getParticipantMap(getContext()); } /** * This method is called when the process referenced is an * external process (not defined as a subprocess of the current * process definition). */ protected String launchExternalProcess (final InFlowWorkItem wi, final String ref, final FlowExpressionId parentId) throws LaunchException { final String[] ss = ref.split("::"); final String engineId = ss[0]; final String processUrl = ss[1]; if (log.isDebugEnabled()) { log.debug("launchExternalProcess() engineId >"+engineId+"<"); log.debug("launchExternalProcess() processUrl >"+processUrl+"<"); } // // prepare target engine final Participant participant = getParticipantMap().get(engineId); // // prepare launchitem final LaunchItem li = new LaunchItem (processUrl, parentId, wi); // // launch try { final Object o = participant.dispatch(getContext(), li); return o.toString(); } catch (final DispatchingException de) { throw new LaunchException ("Dispatching (launch) to engine '"+engineId+"' failed", de); } catch (final Throwable t) { log.warn("launchExternalProcess() unexpected exception", t); log.warn("launchExternalProcess() returning flowInstanceId = null"); } return null; } /* * Ensures the library processes got loaded and interpreted. */ private void loadLibrary () throws LaunchException { ProcessLibrary lib = (ProcessLibrary)getContext() .get(Definitions.S_PROCESS_LIBRARY); if (lib == null) return; lib.load(); // // if the interpretation has already been done, this method call // returns immediately } // // STATIC METHODS /** * Returns true if the VM property 'openwfe.org.launcher.validate' is * set to true. */ public static boolean shouldValidate () { String s = System.getProperty(VALIDATE); if (s == null) return false; s = s.toLowerCase(); return s.equals("true") || s.equals("yes") || s.equals("ok") || s.equals("validate"); } /** * Returns a mapping between language codes and the description of * the workflow definition in that language. */ public static java.util.Map extractXmlDescription (final String processDefinitionUrl) { try { java.util.Map result = new java.util.HashMap(); org.jdom.Element root = XmlUtils .extractXml(new java.net.URL(processDefinitionUrl), false); result.put("root.element.name", root.getName()); // a small trick useful for Launchable instances java.util.Iterator it = root.getChildren("description").iterator(); while (it.hasNext()) { org.jdom.Element description = (org.jdom.Element)it.next(); String dLanguage = description.getAttributeValue("language"); String descriptionText = description.getTextNormalize(); if (dLanguage == null) result.put("default", descriptionText); else result.put(dLanguage, descriptionText); } return result; } catch (Exception e) { log.info ("Failed to load description from "+processDefinitionUrl, e); return new java.util.HashMap(0); } } /** * Returns the description of the process in the default language. */ public static String extractXmlDescription (final String processDefinitionUrl, final String language) { java.util.Map descriptionMap = extractXmlDescription(processDefinitionUrl); if (language == null) return (String)descriptionMap.get("default"); String description = (String)descriptionMap.get(language); if (description != null) return description; return (String)descriptionMap.get("default"); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy