Java tutorial
/* * JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. * * This is free software; you can redistribute it and/or modify it * under the terms of the JBPM BPEL PUBLIC LICENSE AGREEMENT as * published by JBoss Inc.; either version 1.0 of the License, or * (at your option) any later version. * * This software 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. */ package org.jbpm.bpel.xml; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import javax.wsdl.Definition; import javax.wsdl.Message; import javax.wsdl.Operation; import javax.wsdl.OperationType; import javax.wsdl.PortType; import javax.wsdl.WSDLException; import javax.wsdl.xml.WSDLReader; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import org.apache.commons.collections.Predicate; import org.apache.commons.collections.iterators.FilterIterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.jbpm.JbpmConfiguration; import org.jbpm.bpel.BpelException; import org.jbpm.bpel.alarm.AlarmAction; import org.jbpm.bpel.graph.basic.Empty; import org.jbpm.bpel.graph.def.Activity; import org.jbpm.bpel.graph.def.BpelProcessDefinition; import org.jbpm.bpel.graph.def.CompositeActivity; import org.jbpm.bpel.graph.def.Import; import org.jbpm.bpel.graph.def.ImportDefinition; import org.jbpm.bpel.graph.scope.Catch; import org.jbpm.bpel.graph.scope.Handler; import org.jbpm.bpel.graph.scope.OnAlarm; import org.jbpm.bpel.graph.scope.OnEvent; import org.jbpm.bpel.graph.scope.Scope; import org.jbpm.bpel.integration.def.Correlation; import org.jbpm.bpel.integration.def.CorrelationSetDefinition; import org.jbpm.bpel.integration.def.Correlations; import org.jbpm.bpel.integration.def.PartnerLinkDefinition; import org.jbpm.bpel.integration.def.ReceiveAction; import org.jbpm.bpel.integration.def.Correlation.Initiate; import org.jbpm.bpel.sublang.def.Expression; import org.jbpm.bpel.sublang.def.PropertyQuery; import org.jbpm.bpel.variable.def.ElementType; import org.jbpm.bpel.variable.def.MessageType; import org.jbpm.bpel.variable.def.SchemaType; import org.jbpm.bpel.variable.def.VariableDefinition; import org.jbpm.bpel.variable.def.VariableType; import org.jbpm.bpel.wsdl.PartnerLinkType; import org.jbpm.bpel.wsdl.Property; import org.jbpm.bpel.wsdl.PropertyAlias; import org.jbpm.bpel.wsdl.PartnerLinkType.Role; import org.jbpm.bpel.wsdl.xml.WsdlConstants; import org.jbpm.bpel.wsdl.xml.WsdlUtil; import org.jbpm.bpel.xml.util.DatatypeUtil; import org.jbpm.bpel.xml.util.NodeIterator; import org.jbpm.bpel.xml.util.XmlUtil; import org.jbpm.jpdl.par.ProcessArchive; import org.jbpm.jpdl.xml.Problem; import org.jbpm.util.ClassLoaderUtil; /** * Converts a process document in XML format to a * {@linkplain BpelProcessDefinition process definition}. * @author Juan Cantu * @author Alejandro Guizar * @version $Revision$ $Date: 2007/11/29 10:16:30 $ */ public class BpelReader { private Map activityReaders = createActivityReaders(); private ProblemHandler problemHandler = new ProblemCounter(); public static final String RESOURCE_ACTIVITY_READERS = "resource.activity.readers"; private static final Log log = LogFactory.getLog(BpelReader.class); private static final Map activityReaderClasses = readActivityReaderClasses(); private static Templates bpelUpgradeTemplates; /** * Reads a BPEL document into a process definition. * @param processDefinition the definition to read into * @param source an input source pointing to the BPEL document */ public void read(BpelProcessDefinition processDefinition, InputSource source) { DocumentBuilder documentBuilder = XmlUtil.getDocumentBuilder(); // capture parse errors in our problem handler documentBuilder.setErrorHandler(problemHandler.asSaxErrorHandler()); // save the document location String location = source.getSystemId(); processDefinition.setLocation(location); try { // parse content Document document = documentBuilder.parse(source); // halt on parse errors if (problemHandler.getProblemCount() > 0) return; // prepare a locator of imported documents, relative to the process document location ProcessWsdlLocator wsdlLocator = null; if (location != null) { try { wsdlLocator = new ProcessWsdlLocator(new URI(location)); wsdlLocator.setProblemHandler(problemHandler); } catch (URISyntaxException e) { problemHandler.add(new Problem(Problem.LEVEL_ERROR, "source system identifier is invalid: " + location, e)); } } // read process definition read(processDefinition, document.getDocumentElement(), wsdlLocator); } catch (SAXException e) { problemHandler .add(new Problem(Problem.LEVEL_ERROR, "bpel document contains invalid xml: " + location, e)); } catch (IOException e) { problemHandler.add(new Problem(Problem.LEVEL_ERROR, "bpel document is not readable: " + location, e)); } finally { // reset error handling behavior documentBuilder.setErrorHandler(null); } } /** * Reads a process archive containing a BPEL document into a process definition. * @param processDefinition the definition to read into; its <code>location</code> property * specifies the process document entry within the archive * @param archive the archive to read */ public void read(BpelProcessDefinition processDefinition, ProcessArchive archive) { String location = processDefinition.getLocation(); byte[] bpelEntry = archive.getEntry(location); // check whether the bpel document exists in the archive if (bpelEntry == null) { problemHandler.add(new Problem(Problem.LEVEL_ERROR, "process document entry not found")); return; } DocumentBuilder documentBuilder = XmlUtil.getDocumentBuilder(); // capture parse errors in our problem handler documentBuilder.setErrorHandler(problemHandler.asSaxErrorHandler()); try { // parse content Document document = documentBuilder.parse(new ByteArrayInputStream(bpelEntry)); // halt on parse errors if (problemHandler.getProblemCount() > 0) return; /* * prepare a locator of imported documents, relative to the process document location within * the archive */ ProcessWsdlLocator wsdlLocator = new ProcessArchiveWsdlLocator(new URI(location), archive); wsdlLocator.setProblemHandler(problemHandler); // read process definition read(processDefinition, document.getDocumentElement(), wsdlLocator); } catch (SAXException e) { problemHandler .add(new Problem(Problem.LEVEL_ERROR, "bpel document contains invalid xml: " + location, e)); } catch (IOException e) { problemHandler.add(new Problem(Problem.LEVEL_ERROR, "bpel document is not readable: " + location, e)); } catch (URISyntaxException e) { problemHandler.add( new Problem(Problem.LEVEL_ERROR, "process definition location is invalid: " + location, e)); } finally { // reset error handling behavior documentBuilder.setErrorHandler(null); } } public void read(BpelProcessDefinition processDefinition, DOMSource source) { // save the document location String location = source.getSystemId(); processDefinition.setLocation(location); // prepare a locator of imported documents, relative to the process document location ProcessWsdlLocator wsdlLocator = null; if (location != null) { try { wsdlLocator = new ProcessWsdlLocator(new URI(location)); wsdlLocator.setProblemHandler(problemHandler); } catch (URISyntaxException e) { problemHandler.add(new Problem(Problem.LEVEL_ERROR, "source system id is invalid")); } } Element processElem; Node node = source.getNode(); switch (node.getNodeType()) { case Node.DOCUMENT_NODE: processElem = ((Document) node).getDocumentElement(); break; case Node.ELEMENT_NODE: processElem = (Element) node; break; default: problemHandler.add(new Problem(Problem.LEVEL_ERROR, "source node must be either an element or a document: " + node)); return; } // read process definition read(processDefinition, processElem, wsdlLocator); } protected void read(BpelProcessDefinition processDefinition, Element processElem, ProcessWsdlLocator wsdlLocator) { // see if the bpel document requires updating if (BpelConstants.NS_BPEL_1_1.equals(processElem.getNamespaceURI())) { try { // create bpel upgrader Transformer bpelUpgrader = getBpelUpgradeTemplates().newTransformer(); // install our problem handler as transformer's error listener bpelUpgrader.setErrorListener(problemHandler.asTraxErrorListener()); // upgrade into dom document Document resultDocument = XmlUtil.createDocument(); bpelUpgrader.transform(new DOMSource(processElem.getOwnerDocument()), new DOMResult(resultDocument)); processElem = resultDocument.getDocumentElement(); log.debug("upgraded bpel document: " + processDefinition.getLocation()); } catch (TransformerException e) { Problem problem = new Problem(Problem.LEVEL_ERROR, "bpel upgrade failed", e); problem.setResource(processDefinition.getLocation()); problemHandler.add(problem); } // halt on transform errors if (problemHandler.getProblemCount() > 0) return; } // read attributes in the process element readProcessAttributes(processElem, processDefinition); // read imported documents ImportDefinition importDefinition = processDefinition.getImportDefinition(); readImports(processElem, importDefinition, wsdlLocator); // halt on import parse errors if (problemHandler.getProblemCount() > 0) return; try { // registration gets the query language from the process definition registerPropertyAliases(importDefinition); // finally read the global scope readScope(processElem, processDefinition.getGlobalScope()); log.debug("read bpel document: " + processDefinition.getLocation()); } catch (BpelException e) { problemHandler.add(new Problem(Problem.LEVEL_ERROR, "bpel process is invalid", e)); } } static synchronized Templates getBpelUpgradeTemplates() throws TransformerException { if (bpelUpgradeTemplates == null) bpelUpgradeTemplates = XmlUtil.createTemplates(BpelReader.class.getResource("bpel-1-1-converter.xslt")); return bpelUpgradeTemplates; } public void registerPropertyAliases(ImportDefinition importDefinition) { // register property aliases in each wsdl document List imports = importDefinition.getImports(); for (int i = 0, n = imports.size(); i < n; i++) { Import _import = (Import) imports.get(i); if (Import.Type.WSDL.equals(_import.getType())) registerPropertyAliases(importDefinition, (Definition) _import.getDocument()); } } private void registerPropertyAliases(ImportDefinition importDefinition, Definition wsdlDef) { BpelProcessDefinition processDefinition = (BpelProcessDefinition) importDefinition.getProcessDefinition(); // first deal with local extensibility elements for (Iterator i = WsdlUtil.getExtensions(wsdlDef.getExtensibilityElements(), WsdlConstants.Q_PROPERTY_ALIAS); i.hasNext();) { PropertyAlias alias = (PropertyAlias) i.next(); // property Property property = alias.getProperty(); if (!property.isUndefined()) importDefinition.addProperty(property); else { Problem problem = new Problem(Problem.LEVEL_ERROR, "property not found: " + property.getQName()); problem.setResource(wsdlDef.getDocumentBaseURI()); problemHandler.add(problem); } // message Message message = alias.getMessage(); if (message != null) { // check the message definition exists if (!message.isUndefined()) { // register property alias in message type MessageType type = importDefinition.getMessageType(message.getQName()); type.addPropertyAlias(alias); } else { Problem problem = new Problem(Problem.LEVEL_ERROR, "message not found: " + message.getQName()); problem.setResource(wsdlDef.getDocumentBaseURI()); problemHandler.add(problem); } } else { QName element = alias.getElement(); if (element != null) importDefinition.getElementType(element).addPropertyAlias(alias); else { QName type = alias.getType(); if (type != null) importDefinition.getSchemaType(type).addPropertyAlias(alias); else { Problem problem = new Problem(Problem.LEVEL_ERROR, "neither message, element nor type specified in property alias"); problem.setResource(wsdlDef.getDocumentBaseURI()); problemHandler.add(problem); } } } // query PropertyQuery query = alias.getQuery(); if (query != null) { // namespaces query.setNamespaces(processDefinition.addNamespaces(query.getNamespaces())); // language if (query.getLanguage() == null) query.setLanguage(processDefinition.getQueryLanguage()); // syntax try { query.parse(); } catch (BpelException e) { Problem problem = new Problem(Problem.LEVEL_ERROR, "could not parse query: " + query.getText(), e); problem.setResource(wsdlDef.getDocumentBaseURI()); problemHandler.add(problem); } } } // deal with imported definitions for (Iterator l = wsdlDef.getImports().values().iterator(); l.hasNext();) { List imports = (List) l.next(); for (int i = 0, n = imports.size(); i < n; i++) { javax.wsdl.Import _import = (javax.wsdl.Import) imports.get(i); registerPropertyAliases(importDefinition, _import.getDefinition()); } } } // process properties // ////////////////////////////////////////////////////////////// protected void readProcessAttributes(Element processElem, BpelProcessDefinition processDefinition) { // name & namespace processDefinition.setName(processElem.getAttribute(BpelConstants.ATTR_NAME)); processDefinition.setTargetNamespace(processElem.getAttribute(BpelConstants.ATTR_TARGET_NAMESPACE)); // query & expression language processDefinition.setQueryLanguage(XmlUtil.getAttribute(processElem, BpelConstants.ATTR_QUERY_LANGUAGE)); processDefinition .setExpressionLanguage(XmlUtil.getAttribute(processElem, BpelConstants.ATTR_EXPRESSION_LANGUAGE)); // suppress join failure Attr suppressAttr = processElem.getAttributeNode(BpelConstants.ATTR_SUPPRESS_JOIN_FAILURE); processDefinition.getGlobalScope().setSuppressJoinFailure(readTBoolean(suppressAttr, Boolean.FALSE)); } protected void readImports(Element processElem, ImportDefinition importDefinition, ProcessWsdlLocator wsdlLocator) { Iterator importElemIt = XmlUtil.getElements(processElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_IMPORT); if (importElemIt.hasNext()) { // process document explicitly imports documents // read only those documents do { Element importElem = (Element) importElemIt.next(); Import _import = readImport(importElem); importDefinition.addImport(_import); if (Import.Type.WSDL.equals(_import.getType())) { // read wsdl document readImportWsdlDefinition(_import, wsdlLocator); // verify the wsdl target namespace matches the import namespace Definition def = (Definition) _import.getDocument(); if (!_import.getNamespace().equals(def.getTargetNamespace())) { problemHandler.add( new ParseProblem("namespace does not match wsdl target namespace", importElem)); } } } while (importElemIt.hasNext()); } else if (importDefinition.getImports().isEmpty()) { /* * process document has no explicit imports and no imports were supplied by the definition * descriptor; fall back to master wsdl definition */ Import masterImport = createMasterWsdlImport(wsdlLocator); importDefinition.addImport(masterImport); // read wsdl document readImportWsdlDefinition(masterImport, wsdlLocator); // set the import namespace to the wsdl target namespace Definition masterWsdl = (Definition) masterImport.getDocument(); masterImport.setNamespace(masterWsdl.getTargetNamespace()); } } protected Import readImport(Element importElem) { Import _import = new Import(); _import.setNamespace(importElem.getAttribute(BpelConstants.ATTR_NAMESPACE)); _import.setLocation(importElem.getAttribute(BpelConstants.ATTR_LOCATION)); _import.setType(Import.Type.valueOf(importElem.getAttribute(BpelConstants.ATTR_IMPORT_TYPE))); return _import; } protected Import createMasterWsdlImport(ProcessWsdlLocator wsdlLocator) { // determine master wsdl location String processPath = wsdlLocator.getProcessURI().getPath(); int beginIndex = processPath.lastIndexOf('/'); if (beginIndex != -1) ++beginIndex; else beginIndex = 0; int endIndex = processPath.lastIndexOf('.'); if (endIndex == -1 || beginIndex >= endIndex) { problemHandler.add( new Problem(Problem.LEVEL_ERROR, "cannot extract file name from process path: " + processPath)); return new Import(); } String wsdlFile = processPath.substring(beginIndex, endIndex) + ".wsdl"; // create import for master wsdl Import masterImport = new Import(); masterImport.setLocation(wsdlFile); masterImport.setType(Import.Type.WSDL); return masterImport; } public void readImportWsdlDefinition(Import _import, ProcessWsdlLocator wsdlLocator) { String location = _import.getLocation(); Definition definition; try { // set import location as the base URI of the given WSDL locator wsdlLocator.resolveBaseURI(location); // read imported WSDL document WSDLReader reader = WsdlUtil.getFactory().newWSDLReader(); definition = reader.readWSDL(wsdlLocator); log.debug("read wsdl document: " + location); } catch (WSDLException e) { problemHandler.add(new Problem(Problem.LEVEL_ERROR, "could not read wsdl document", e)); // patch missing definition definition = WsdlUtil.getFactory().newDefinition(); definition.setDocumentBaseURI(location); if (_import.getNamespace() != null) definition.setTargetNamespace(_import.getNamespace()); } _import.setDocument(definition); } public Boolean readTBoolean(Attr attribute, Boolean defaultValue) { if (attribute == null) return defaultValue; String text = attribute.getValue(); return BpelConstants.YES.equals(text) ? Boolean.TRUE : BpelConstants.NO.equals(text) ? Boolean.FALSE : defaultValue; } public Expression readExpression(Element enclosingElem, CompositeActivity parent) { Expression expression = new Expression(); readExpression(enclosingElem, parent, expression); return expression; } protected void readExpression(Element enclosingElem, CompositeActivity parent, Expression expression) { // text content expression.setText(DatatypeUtil.toString(enclosingElem)); // namespaces BpelProcessDefinition processDefinition = parent.getBpelProcessDefinition(); expression.setNamespaces(processDefinition.addNamespaces(XmlUtil.findNamespaceDeclarations(enclosingElem))); // language String language = XmlUtil.getAttribute(enclosingElem, BpelConstants.ATTR_EXPRESSION_LANGUAGE); if (language == null) language = processDefinition.getExpressionLanguage(); expression.setLanguage(language); // parsing try { expression.parse(); } catch (BpelException e) { problemHandler.add(new ParseProblem("could not parse expression", enclosingElem, e)); } } // scope definition properties // ////////////////////////////////////////////////////////////// public void readScope(Element scopeElem, Scope scope) { scope.installFaultExceptionHandler(); // partner links Element partnerLinksElem = XmlUtil.getElement(scopeElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_PARTNER_LINKS); if (partnerLinksElem != null) scope.setPartnerLinks(readPartnerLinks(partnerLinksElem, scope)); // variables Element variablesElem = XmlUtil.getElement(scopeElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_VARIABLES); if (variablesElem != null) scope.setVariables(readVariables(variablesElem, scope)); // correlation sets Element setsElem = XmlUtil.getElement(scopeElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_CORRELATION_SETS); if (setsElem != null) scope.setCorrelationSets(readCorrelationSets(setsElem, scope)); /* * read activity before FCT handlers; compensateScope requires the activity be present in order * to locate the nested scope */ Element activityElem = getActivityElement(scopeElem); readActivity(activityElem, scope); // fault handlers Element faultHandlersElem = XmlUtil.getElement(scopeElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_FAULT_HANDLERS); if (faultHandlersElem != null) readFaultHandlers(faultHandlersElem, scope); // compensation handler Element compensationHandlerElem = XmlUtil.getElement(scopeElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_COMPENSATION_HANDLER); if (compensationHandlerElem != null) readCompensationHandler(compensationHandlerElem, scope); // termination handler Element terminationHandlerElem = XmlUtil.getElement(scopeElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_TERMINATION_HANDLER); if (terminationHandlerElem != null) { readTerminationHandler(terminationHandlerElem, scope); } else { // install BPEL4WS 1.1 forced termination handler Catch forcedTerminationHandler = scope.selectCatch(BpelConstants.FAULT_FORCED_TERMINATION); if (forcedTerminationHandler != null) scope.setTerminationHandler(forcedTerminationHandler); } // event handlers Element eventHandlersElem = XmlUtil.getElement(scopeElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_EVENT_HANDLERS); if (eventHandlersElem != null) readEventHandlers(eventHandlersElem, scope); } public void readCompensationHandler(Element handlerElem, Scope scope) { Handler handler = new Handler(); // register handler before reading activity so that scope definitions are // available scope.setCompensationHandler(handler); // read handler activity Activity activity = readActivity(getActivityElement(handlerElem), handler); handler.setActivity(activity); } protected void readTerminationHandler(Element handlerElem, Scope scope) { Handler handler = new Handler(); // register handler before reading activity so that scope definitions are // available scope.setTerminationHandler(handler); // read handler activity Activity activity = readActivity(getActivityElement(handlerElem), handler); handler.setActivity(activity); } public void readFaultHandlers(Element faultHandlersElem, Scope scope) { // catch elements Iterator catchElemIt = XmlUtil.getElements(faultHandlersElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_CATCH); while (catchElemIt.hasNext()) { Element catchElem = (Element) catchElemIt.next(); readCatch(catchElem, scope); } // catchAll element Element catchAllElem = XmlUtil.getElement(faultHandlersElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_CATCH_ALL); if (catchAllElem != null) readCatchAll(catchAllElem, scope); } protected void readCatch(Element catchElem, Scope scope) { // the valid configuration for a catch is: // faultName OR (faultVariable AND (elementType XOR messageType)) Catch catcher = new Catch(); // fault name QName faultName = getFaultName(catchElem); catcher.setFaultName(faultName); // fault variable VariableDefinition faultVariable = getFaultVariable(catchElem, scope); if (faultVariable != null) { catcher.setFaultVariable(faultVariable); } else if (faultName == null) { problemHandler.add(new ParseProblem("catch must specify faultName, faultVariable or both", catchElem)); } // register handler before reading activity so that variable, partnerLink // and correlationSet definitions are available scope.addCatch(catcher); // activity Activity activity = readActivity(getActivityElement(catchElem), catcher); catcher.setActivity(activity); } private QName getFaultName(Element catchElem) { Attr faultName = catchElem.getAttributeNode(BpelConstants.ATTR_FAULT_NAME); return faultName != null ? XmlUtil.getQNameValue(faultName) : null; } private VariableDefinition getFaultVariable(Element catchElem, Scope scope) { VariableDefinition faultVariable = null; String faultVariableAttr = XmlUtil.getAttribute(catchElem, BpelConstants.ATTR_FAULT_VARIABLE); if (faultVariableAttr != null) { VariableType faultType = getFaultType(catchElem, scope.getBpelProcessDefinition().getImportDefinition()); if (faultType != null) { // create variable local to handler faultVariable = new VariableDefinition(); faultVariable.setName(faultVariableAttr); faultVariable.setType(faultType); } // BPEL-199 parse BPEL4WS 1.1 fault handler else { // retrieve variable from enclosing scope faultVariable = scope.findVariable(faultVariableAttr); // check variable exists if (faultVariable == null) { problemHandler.add(new ParseProblem("variable not found", catchElem)); } // check variable is of message type else if (!faultVariable.getType().isMessage()) { problemHandler.add(new ParseProblem("catch must reference a message variable", catchElem)); } } } return faultVariable; } private VariableType getFaultType(Element catchElem, ImportDefinition importDefinition) { VariableType type = null; Attr messageType = catchElem.getAttributeNode(BpelConstants.ATTR_FAULT_MESSAGE_TYPE); Attr elementName = catchElem.getAttributeNode(BpelConstants.ATTR_FAULT_ELEMENT); if (messageType != null) { if (elementName != null) problemHandler.add(new ParseProblem("found more than one fault type specifier", catchElem)); type = getMessageType(catchElem, messageType, importDefinition); } else if (elementName != null) type = getElementType(catchElem, elementName, importDefinition); return type; } protected void readCatchAll(Element catchAllElem, Scope scope) { Handler handler = new Handler(); // register handler before reading activity so that in-scope definitions are available scope.setCatchAll(handler); // read handler activity Activity activity = readActivity(getActivityElement(catchAllElem), handler); handler.setActivity(activity); } protected void readEventHandlers(Element eventHandlersElem, Scope scope) { // onEvents for (Iterator i = XmlUtil.getElements(eventHandlersElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_ON_EVENT); i.hasNext();) { OnEvent onEvent = new OnEvent(); scope.addOnEvent(onEvent); readOnEvent((Element) i.next(), onEvent); } // onAlarms for (Iterator i = XmlUtil.getElements(eventHandlersElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_ON_ALARM); i.hasNext();) { OnAlarm onAlarm = new OnAlarm(); scope.addOnAlarm(onAlarm); readOnAlarm((Element) i.next(), onAlarm); } } protected void readOnEvent(Element onEventElem, OnEvent onEvent) { // the attribute messageType indicates a variable declaration Attr messageType = onEventElem.getAttributeNode(BpelConstants.ATTR_MESSAGE_TYPE); if (messageType != null) { VariableDefinition variable = new VariableDefinition(); // name String name = XmlUtil.getAttribute(onEventElem, BpelConstants.ATTR_VARIABLE); variable.setName(name); // type VariableType type = getMessageType(onEventElem, messageType, onEvent.getBpelProcessDefinition().getImportDefinition()); variable.setType(type); // onEvent onEvent.setVariableDefinition(variable); } // receiver ReceiveAction receiveAction = readReceiveAction(onEventElem, onEvent); onEvent.setAction(receiveAction); // activity Element activityElem = getActivityElement(onEventElem); onEvent.setActivity(readActivity(activityElem, onEvent)); } protected OnAlarm readOnAlarm(Element onAlarmElem, OnAlarm onAlarm) { // alarm onAlarm.setAction(readAlarmAction(onAlarmElem, onAlarm)); // activity Element activityElem = getActivityElement(onAlarmElem); onAlarm.setActivity(readActivity(activityElem, onAlarm)); return onAlarm; } protected Map readVariables(Element variablesElem, CompositeActivity parent) { Map variables = new HashMap(); ImportDefinition importDefinition = parent.getBpelProcessDefinition().getImportDefinition(); for (Iterator i = XmlUtil.getElements(variablesElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_VARIABLE); i .hasNext();) { Element variableElem = (Element) i.next(); VariableDefinition variable = readVariable(variableElem, importDefinition); String variableName = variable.getName(); if (!variables.containsKey(variableName)) variables.put(variableName, variable); else problemHandler.add(new ParseProblem("duplicate local name", variableElem)); } return variables; } protected VariableDefinition readVariable(Element variableElem, ImportDefinition importDefinition) { VariableDefinition variable = new VariableDefinition(); // name variable.setName(variableElem.getAttribute(BpelConstants.ATTR_NAME)); // type variable.setType(getVariableType(variableElem, importDefinition)); return variable; } private VariableType getVariableType(Element variableElem, ImportDefinition importDefinition) { VariableType type; Attr schemaType = variableElem.getAttributeNode(BpelConstants.ATTR_TYPE); Attr elementName = variableElem.getAttributeNode(BpelConstants.ATTR_ELEMENT); Attr messageType = variableElem.getAttributeNode(BpelConstants.ATTR_MESSAGE_TYPE); if (messageType != null) { if (schemaType != null || elementName != null) problemHandler.add(new ParseProblem("more than one type specifier present", variableElem)); type = getMessageType(variableElem, messageType, importDefinition); } else if (schemaType != null) { if (elementName != null) problemHandler.add(new ParseProblem("more than one type specifier present", variableElem)); type = getSchemaType(variableElem, schemaType, importDefinition); } else if (elementName != null) { type = getElementType(variableElem, elementName, importDefinition); } else { problemHandler.add(new ParseProblem("no type specifier present", variableElem)); type = null; } return type; } private MessageType getMessageType(Element contextElem, Attr typeAttr, ImportDefinition importDefinition) { QName typeName = XmlUtil.getQNameValue(typeAttr); MessageType type = importDefinition.getMessageType(typeName); if (type == null) { // patch missing type Message message = WsdlUtil.getSharedDefinition().createMessage(); message.setQName(typeName); type = new MessageType(message); problemHandler.add(new ParseProblem("message type not found", contextElem)); } return type; } private ElementType getElementType(Element contextElem, Attr elementAttr, ImportDefinition importDefinition) { QName elementName = XmlUtil.getQNameValue(elementAttr); ElementType type = importDefinition.getElementType(elementName); if (type == null) { // patch missing type type = new ElementType(elementName); problemHandler.add(new ParseProblem("element not found", contextElem)); } return type; } private SchemaType getSchemaType(Element contextElem, Attr typeAttr, ImportDefinition importDefinition) { QName typeName = XmlUtil.getQNameValue(typeAttr); SchemaType type = importDefinition.getSchemaType(typeName); if (type == null) { // patch missing type type = new SchemaType(typeName); problemHandler.add(new ParseProblem("schema type not found", contextElem)); } return type; } // service properties // ////////////////////////////////////////////////////////////// protected Map readCorrelationSets(Element setsElem, CompositeActivity superState) { Map correlationSets = new HashMap(); ImportDefinition importDefinition = superState.getBpelProcessDefinition().getImportDefinition(); for (Iterator i = XmlUtil.getElements(setsElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_CORRELATION_SET); i.hasNext();) { Element setElem = (Element) i.next(); CorrelationSetDefinition set = readCorrelationSet(setElem, importDefinition); String setName = set.getName(); if (!correlationSets.containsKey(setName)) correlationSets.put(setName, set); else problemHandler.add(new ParseProblem("duplicate local name", setElem)); } return correlationSets; } protected CorrelationSetDefinition readCorrelationSet(Element setElem, ImportDefinition importDefinition) { CorrelationSetDefinition set = new CorrelationSetDefinition(); // properties String[] propertyNames = setElem.getAttribute(BpelConstants.ATTR_PROPERTIES).split("\\s"); for (int p = 0; p < propertyNames.length; p++) { QName propertyName = XmlUtil.parseQName(propertyNames[p], setElem); Property property = importDefinition.getProperty(propertyName); if (property == null) { problemHandler.add(new ParseProblem("property not found: " + propertyName, setElem)); // patch the missing property try { property = (Property) WsdlUtil.getSharedExtensionRegistry().createExtension(Definition.class, WsdlConstants.Q_PROPERTY); property.setQName(propertyName); } catch (WSDLException e) { // should not happen throw new AssertionError(e); } } set.addProperty(property); } // name set.setName(setElem.getAttribute(BpelConstants.ATTR_NAME)); return set; } protected Map readPartnerLinks(Element partnerLinksElem, CompositeActivity parent) { Map partnerLinks = new HashMap(); for (Iterator i = XmlUtil.getElements(partnerLinksElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_PARTNER_LINK); i.hasNext();) { Element partnerLinkElem = (Element) i.next(); PartnerLinkDefinition partnerLink = readPartnerLink(partnerLinkElem, parent); String plinkName = partnerLink.getName(); if (!partnerLinks.containsKey(plinkName)) partnerLinks.put(plinkName, partnerLink); else problemHandler.add(new ParseProblem("duplicate local name", partnerLinkElem)); } return partnerLinks; } protected PartnerLinkDefinition readPartnerLink(Element partnerLinkElem, CompositeActivity parent) { PartnerLinkDefinition partnerLink = new PartnerLinkDefinition(); partnerLink.setName(partnerLinkElem.getAttribute(BpelConstants.ATTR_NAME)); // partner link type QName typeName = XmlUtil .getQNameValue(partnerLinkElem.getAttributeNode(BpelConstants.ATTR_PARTNER_LINK_TYPE)); PartnerLinkType type = parent.getBpelProcessDefinition().getImportDefinition().getPartnerLinkType(typeName); if (type == null) { problemHandler.add(new ParseProblem("partner link type not found", partnerLinkElem)); return partnerLink; } partnerLink.setPartnerLinkType(type); String myRoleName = XmlUtil.getAttribute(partnerLinkElem, BpelConstants.ATTR_MY_ROLE); String partnerRoleName = XmlUtil.getAttribute(partnerLinkElem, BpelConstants.ATTR_PARTNER_ROLE); boolean partnerFirst = false; // first role Role role = type.getFirstRole(); String roleName = role.getName(); if (roleName.equals(myRoleName)) { partnerLink.setMyRole(role); } else if (roleName.equals(partnerRoleName)) { partnerLink.setPartnerRole(role); partnerFirst = true; } else { problemHandler.add(new ParseProblem( "neither my role nor partner role match the first partner link type role", partnerLinkElem)); return partnerLink; } PortType portType = role.getPortType(); if (portType.isUndefined()) { problemHandler.add(new ParseProblem("port type not found: " + portType.getQName(), partnerLinkElem)); } // second role role = type.getSecondRole(); if (role != null) { roleName = role.getName(); if (partnerFirst) { if (!roleName.equals(myRoleName)) { problemHandler.add(new ParseProblem("my role does not match the second partner link type role", partnerLinkElem)); } partnerLink.setMyRole(role); } else { if (!roleName.equals(partnerRoleName)) { problemHandler.add(new ParseProblem( "partner role does not match the second partner link type role", partnerLinkElem)); } partnerLink.setPartnerRole(role); } portType = role.getPortType(); if (portType.isUndefined()) { problemHandler .add(new ParseProblem("port type not found: " + portType.getQName(), partnerLinkElem)); } } else if (partnerFirst ? myRoleName != null : partnerRoleName != null) problemHandler.add(new ParseProblem("partner link type has one role only", partnerLinkElem)); return partnerLink; } public ReceiveAction readReceiveAction(Element receiveElem, CompositeActivity parent) { ReceiveAction receiveAction = new ReceiveAction(); // partner link String partnerLinkName = receiveElem.getAttribute(BpelConstants.ATTR_PARTNER_LINK); PartnerLinkDefinition partnerLink = parent.findPartnerLink(partnerLinkName); if (partnerLink == null) { problemHandler.add(new ParseProblem("partner link not found", receiveElem)); return receiveAction; } receiveAction.setPartnerLink(partnerLink); // port type Role myRole = partnerLink.getMyRole(); // BPEL-181 detect absence of my role if (myRole == null) { problemHandler.add(new ParseProblem("my role not found", receiveElem)); return receiveAction; } PortType portType = getMessageActivityPortType(receiveElem, myRole); // operation Operation operation = getMessageActivityOperation(receiveElem, portType); receiveAction.setOperation(operation); // message exchange // BPEL-74: map the empty message exchange to null for compatibility with Oracle receiveAction.setMessageExchange(XmlUtil.getAttribute(receiveElem, BpelConstants.ATTR_MESSAGE_EXCHANGE)); // variable VariableDefinition variable = getMessageActivityVariable(receiveElem, BpelConstants.ATTR_VARIABLE, parent, operation.getInput().getMessage()); receiveAction.setVariable(variable); // correlations Element correlationsElem = XmlUtil.getElement(receiveElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_CORRELATIONS); if (correlationsElem != null) receiveAction.setCorrelations(readCorrelations(correlationsElem, parent, variable)); return receiveAction; } public Correlations readCorrelations(Element correlationsElem, CompositeActivity parent, VariableDefinition variable) { Correlations correlations = new Correlations(); Iterator correlationElemIt = XmlUtil.getElements(correlationsElem, BpelConstants.NS_BPEL, BpelConstants.ELEM_CORRELATION); while (correlationElemIt.hasNext()) { Element correlationElem = (Element) correlationElemIt.next(); Correlation correlation = readCorrelation(correlationElem, parent); checkVariableProperties(variable, correlation.getSet(), correlationElem); correlations.addCorrelation(correlation); } return correlations; } public Correlation readCorrelation(Element correlationElem, CompositeActivity parent) { Correlation correlation = new Correlation(); // correlation set String setName = correlationElem.getAttribute(BpelConstants.ATTR_SET); CorrelationSetDefinition set = parent.findCorrelationSet(setName); if (set == null) { problemHandler.add(new ParseProblem("correlation set not found", correlationElem)); set = new CorrelationSetDefinition(); set.setName(setName); } correlation.setSet(set); // initiate mode correlation .setInitiate(Initiate.valueOf(XmlUtil.getAttribute(correlationElem, BpelConstants.ATTR_INITIATE))); return correlation; } PortType getMessageActivityPortType(Element serviceElem, Role role) { PortType effectivePortType = role.getPortType(); // validate port type attribute, if present Attr portTypeAttr = serviceElem.getAttributeNode(BpelConstants.ATTR_PORT_TYPE); if (portTypeAttr != null) { QName portTypeName = XmlUtil.getQNameValue(portTypeAttr); if (!effectivePortType.getQName().equals(portTypeName)) { problemHandler.add(new ParseProblem("port type mismatch between message activity and partner link", serviceElem)); } } return effectivePortType; } Operation getMessageActivityOperation(Element serviceElem, PortType portType) { String operationName = serviceElem.getAttribute(BpelConstants.ATTR_OPERATION); Operation operation = portType.getOperation(operationName, null, null); if (operation == null) { problemHandler.add(new ParseProblem("operation not found", serviceElem)); // patch missing operation operation = WsdlUtil.getSharedDefinition().createOperation(); operation.setName(operationName); } else { OperationType style = operation.getStyle(); if (style == OperationType.SOLICIT_RESPONSE || style == OperationType.NOTIFICATION) problemHandler.add(new ParseProblem("operation style not supported", serviceElem)); } return operation; } VariableDefinition getMessageActivityVariable(Element serviceElem, String variableAttr, CompositeActivity parent, Message activityMessage) { VariableDefinition variable; // get variable name String variableName = XmlUtil.getAttribute(serviceElem, variableAttr); if (variableName == null) { problemHandler.add(new ParseProblem(variableAttr + " attribute is missing", serviceElem)); // patch missing variable variable = new VariableDefinition(); variable.setName("unnamed"); return variable; } // find variable definition variable = parent.findVariable(variableName); if (variable == null) { problemHandler.add(new ParseProblem(variableAttr + " not found", serviceElem)); // create a variable stub variable = new VariableDefinition(); variable.setName(variableName); variable.setType(parent.getBpelProcessDefinition().getImportDefinition() .getMessageType(activityMessage.getQName())); } // validate type else if (!variable.getType().getName().equals(activityMessage.getQName())) { problemHandler .add(new ParseProblem(variableAttr + " type is not applicable for the operation", serviceElem)); } return variable; } void checkVariableProperties(VariableDefinition variable, CorrelationSetDefinition set, Element correlationElem) { Map variableProperties = variable.getType().getPropertyAliases(); for (Iterator i = set.getProperties().iterator(); i.hasNext();) { Property property = (Property) i.next(); QName propertyName = property.getQName(); if (!variableProperties.containsKey(propertyName)) { problemHandler.add(new ParseProblem( "property '" + propertyName + "' does not appear in variable '" + variable.getName() + "'", correlationElem)); } } } // alarm properties // ////////////////////////////////////////////////////////////// public AlarmAction readAlarmAction(Element element, CompositeActivity parent) { AlarmAction alarmAction = new AlarmAction(); // for Element forElem = XmlUtil.getElement(element, BpelConstants.NS_BPEL, BpelConstants.ELEM_FOR); if (forElem != null) { alarmAction.setFor(readExpression(forElem, parent)); } else { // until Element untilElem = XmlUtil.getElement(element, BpelConstants.NS_BPEL, BpelConstants.ELEM_UNTIL); if (untilElem != null) alarmAction.setUntil(readExpression(untilElem, parent)); } // repeat every Element repeatEveryElem = XmlUtil.getElement(element, BpelConstants.NS_BPEL, BpelConstants.ELEM_REPEAT_EVERY); if (repeatEveryElem != null) alarmAction.setRepeatEvery(readExpression(repeatEveryElem, parent)); return alarmAction; } // child activities // ////////////////////////////////////////////////////////////// public Activity readActivity(Element activityElem, CompositeActivity parent) { if (activityElem == null) { // patch the missing activity return new Empty(); } ActivityReader parser = (ActivityReader) activityReaders.get(activityElem.getLocalName()); return parser.read(activityElem, parent); } protected Element getActivityElement(Element parent) { for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { if (ActivityElementPredicate.evaluate(child)) return (Element) child; } problemHandler.add(new ParseProblem("activity not found", parent)); return null; } protected Iterator getActivityElements(Element parent) { return new FilterIterator(new NodeIterator(parent), ActivityElementPredicate.INSTANCE); } protected ActivityReader getActivityReader(String name) { return (ActivityReader) activityReaders.get(name); } private Map createActivityReaders() { HashMap activityReaders = new HashMap(); // walk through registered reader classes Iterator readerClassIt = activityReaderClasses.entrySet().iterator(); while (readerClassIt.hasNext()) { Entry readerClassEntry = (Entry) readerClassIt.next(); Object activityName = readerClassEntry.getKey(); Class readerClass = (Class) readerClassEntry.getValue(); try { // instantiate activity reader ActivityReader reader = (ActivityReader) readerClass.newInstance(); // associate activity reader with this bpel reader reader.setBpelReader(this); activityReaders.put(activityName, reader); } catch (InstantiationException e) { log.warn("reader class not instantiable: " + readerClass.getName(), e); } catch (IllegalAccessException e) { log.warn("reader class or constructor not public: " + readerClass.getName(), e); } } return activityReaders; } public ProblemHandler getProblemHandler() { return problemHandler; } public void setProblemHandler(ProblemHandler problemHandler) { this.problemHandler = problemHandler; } private static Map readActivityReaderClasses() { // get activity readers resource name String resource = JbpmConfiguration.Configs.getString(RESOURCE_ACTIVITY_READERS); // parse activity readers document Element readersElem; try { readersElem = XmlUtil.parseResource(resource); } catch (SAXException e) { log.error("activity readers document contains invalid xml: " + resource, e); return Collections.EMPTY_MAP; } catch (IOException e) { log.error("could not read activity readers document: " + resource, e); return Collections.EMPTY_MAP; } // walk through activityReader elements HashMap activityReaderClasses = new HashMap(); Iterator readerElemIt = XmlUtil.getElements(readersElem, null, "activityReader"); while (readerElemIt.hasNext()) { Element readerElem = (Element) readerElemIt.next(); String activityName = readerElem.getAttribute("name"); // load reader class String readerClassName = readerElem.getAttribute("class"); Class readerClass = ClassLoaderUtil.loadClass(readerClassName); // validate reader class if (!ActivityReader.class.isAssignableFrom(readerClass)) { log.warn("not an activity reader: " + readerClassName); continue; } // register reader class activityReaderClasses.put(activityName, readerClass); log.debug("registered activity reader: name=" + activityName + ", class=" + readerClassName); } return activityReaderClasses; } private static class ActivityElementPredicate implements Predicate { private static String[] BPEL_2_ACTIVITIES = { BpelConstants.ELEM_EMPTY, BpelConstants.ELEM_RECEIVE, BpelConstants.ELEM_REPLY, BpelConstants.ELEM_INVOKE, BpelConstants.ELEM_ASSIGN, BpelConstants.ELEM_THROW, BpelConstants.ELEM_EXIT, BpelConstants.ELEM_WAIT, BpelConstants.ELEM_SEQUENCE, BpelConstants.ELEM_IF, "switch", BpelConstants.ELEM_WHILE, BpelConstants.ELEM_PICK, BpelConstants.ELEM_FLOW, BpelConstants.ELEM_SCOPE, BpelConstants.ELEM_COMPENSATE, BpelConstants.ELEM_COMPENSATE_SCOPE, BpelConstants.ELEM_RETHROW, BpelConstants.ELEM_VALIDATE }; private static final Set activityNames = new HashSet( Arrays.asList(ActivityElementPredicate.BPEL_2_ACTIVITIES)); static final Predicate INSTANCE = new ActivityElementPredicate(); private ActivityElementPredicate() { } public boolean evaluate(Object arg) { return evaluate((Node) arg); } static boolean evaluate(Node node) { /* * the node is an activity if (1) it is an element, (2) its namespace URI matches the BPEL * namespace and (3) the set of activity names contains its local name */ return node.getNodeType() == Node.ELEMENT_NODE && BpelConstants.NS_BPEL.equals(node.getNamespaceURI()) && activityNames.contains(node.getLocalName()); } } }