/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.ode.bpel.engine; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.net.URI; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import javax.wsdl.Operation; import javax.xml.namespace.QName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.ode.bpel.common.CorrelationKey; import org.apache.ode.bpel.common.CorrelationKeySet; import org.apache.ode.bpel.common.FaultException; import org.apache.ode.bpel.common.ProcessState; import org.apache.ode.bpel.dao.CorrelationSetDAO; import org.apache.ode.bpel.dao.CorrelatorDAO; import org.apache.ode.bpel.dao.MessageDAO; import org.apache.ode.bpel.dao.MessageExchangeDAO; import org.apache.ode.bpel.dao.MessageRouteDAO; import org.apache.ode.bpel.dao.PartnerLinkDAO; import org.apache.ode.bpel.dao.ProcessDAO; import org.apache.ode.bpel.dao.ProcessInstanceDAO; import org.apache.ode.bpel.dao.ScopeDAO; import org.apache.ode.bpel.dao.ScopeStateEnum; import org.apache.ode.bpel.dao.XmlDataDAO; import org.apache.ode.bpel.evar.ExternalVariableModule.Value; import org.apache.ode.bpel.evar.ExternalVariableModuleException; import org.apache.ode.bpel.evt.CorrelationSetWriteEvent; import org.apache.ode.bpel.evt.ProcessCompletionEvent; import org.apache.ode.bpel.evt.ProcessInstanceEvent; import org.apache.ode.bpel.evt.ProcessInstanceStateChangeEvent; import org.apache.ode.bpel.evt.ProcessMessageExchangeEvent; import org.apache.ode.bpel.evt.ProcessTerminationEvent; import org.apache.ode.bpel.evt.ScopeCompletionEvent; import org.apache.ode.bpel.evt.ScopeEvent; import org.apache.ode.bpel.evt.ScopeFaultEvent; import org.apache.ode.bpel.evt.ScopeStartEvent; import org.apache.ode.bpel.iapi.BpelEngineException; import org.apache.ode.bpel.iapi.ContextException; import org.apache.ode.bpel.iapi.Endpoint; import org.apache.ode.bpel.iapi.EndpointReference; import org.apache.ode.bpel.iapi.Message; import org.apache.ode.bpel.iapi.MessageExchange; import org.apache.ode.bpel.iapi.MessageExchange.FailureType; import org.apache.ode.bpel.iapi.MessageExchange.MessageExchangePattern; import org.apache.ode.bpel.iapi.MyRoleMessageExchange; import org.apache.ode.bpel.iapi.ProcessConf.CLEANUP_CATEGORY; import org.apache.ode.bpel.iapi.ProcessConf.PartnerRoleConfig; import org.apache.ode.bpel.iapi.Scheduler; import org.apache.ode.bpel.iapi.Scheduler.JobDetails; import org.apache.ode.bpel.iapi.Scheduler.JobType; import org.apache.ode.bpel.memdao.ProcessInstanceDaoImpl; import org.apache.ode.bpel.obj.OMessageVarType; import org.apache.ode.bpel.obj.OPartnerLink; import org.apache.ode.bpel.obj.OProcess; import org.apache.ode.bpel.obj.OScope; import org.apache.ode.bpel.obj.OScope.Variable; import org.apache.ode.bpel.runtime.BpelJacobRunnable; import org.apache.ode.bpel.runtime.BpelRuntimeContext; import org.apache.ode.bpel.runtime.CorrelationSetInstance; import org.apache.ode.bpel.runtime.ExpressionLanguageRuntimeRegistry; import org.apache.ode.bpel.runtime.PROCESS; import org.apache.ode.bpel.runtime.PartnerLinkInstance; import org.apache.ode.bpel.runtime.Selector; import org.apache.ode.bpel.runtime.VariableInstance; import org.apache.ode.bpel.runtime.channels.ActivityRecovery; import org.apache.ode.bpel.runtime.channels.FaultData; import org.apache.ode.bpel.runtime.channels.InvokeResponse; import org.apache.ode.bpel.runtime.channels.PickResponse; import org.apache.ode.bpel.runtime.channels.TimerResponse; import org.apache.ode.jacob.JacobRunnable; import org.apache.ode.jacob.ProcessUtil; import org.apache.ode.jacob.vpu.ExecutionQueueImpl; import org.apache.ode.jacob.vpu.JacobVPU; import org.apache.ode.utils.DOMUtils; import org.apache.ode.utils.GUID; import org.apache.ode.utils.Namespaces; import org.apache.ode.utils.ObjectPrinter; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class BpelRuntimeContextImpl implements BpelRuntimeContext { private static final Logger __log = LoggerFactory.getLogger(BpelRuntimeContextImpl.class); /** Data-access object for process instance. */ protected ProcessInstanceDAO _dao; /** Process Instance ID */ private final Long _iid; /** JACOB VPU */ protected JacobVPU _vpu; /** JACOB ExecutionQueue (state) */ protected ExecutionQueueImpl _soup; private MyRoleMessageExchangeImpl _instantiatingMessageExchange; protected OutstandingRequestManager _outstandingRequests; protected IMAManager2 _imaManager; protected BpelProcess _bpelProcess; private Date _currentEventDateTime; private boolean _forceFlush; /** Five second maximum for continous execution. */ private long _maxReductionTimeMs = 2000000; public BpelRuntimeContextImpl(BpelProcess bpelProcess, ProcessInstanceDAO dao, PROCESS PROCESS, MyRoleMessageExchangeImpl instantiatingMessageExchange) { _bpelProcess = bpelProcess; _dao = dao; _iid = dao.getInstanceId(); _instantiatingMessageExchange = instantiatingMessageExchange; _vpu = new JacobVPU(); _vpu.registerExtension(BpelRuntimeContext.class, this); _soup = new ExecutionQueueImpl(null); _soup.setReplacementMap(_bpelProcess.getReplacementMap(dao.getProcess().getProcessId())); _outstandingRequests = null; _imaManager = new IMAManager2(); _vpu.setContext(_soup); if (bpelProcess.isInMemory()) { ProcessInstanceDaoImpl inmem = (ProcessInstanceDaoImpl) _dao; if (inmem.getSoup() != null) { _soup = (ExecutionQueueImpl) inmem.getSoup(); _imaManager = (IMAManager2) _soup.getGlobalData(); _vpu.setContext(_soup); } } else { byte[] daoState = dao.getExecutionState(); if (daoState != null) { ByteArrayInputStream iis = new ByteArrayInputStream(daoState); try { _soup.read(iis); } catch (Exception ex) { throw new RuntimeException(ex); } _imaManager = (IMAManager2) _soup.getGlobalData(); } } if (PROCESS != null) { _vpu.inject(PROCESS); } if (BpelProcess.__log.isDebugEnabled()) { __log.debug("BpelRuntimeContextImpl created for instance " + _iid + ". INDEXED STATE=" + _soup.getIndex()); } } public Long getPid() { return _iid; } public long genId() { return _dao.genMonotonic(); } /** * @see BpelRuntimeContext#isCorrelationInitialized(org.apache.ode.bpel.runtime.CorrelationSetInstance) */ public boolean isCorrelationInitialized(CorrelationSetInstance correlationSet) { ScopeDAO scopeDAO = _dao.getScope(correlationSet.scopeInstance); CorrelationSetDAO cs = scopeDAO.getCorrelationSet(correlationSet.declaration.getName()); return cs.getValue() != null; } /** * @see BpelRuntimeContext#isVariableInitialized(org.apache.ode.bpel.runtime.VariableInstance) */ public boolean isVariableInitialized(VariableInstance var) { if (var == null) { return false; } ScopeDAO scopeDAO = _dao.getScope(var.scopeInstance); XmlDataDAO dataDAO = scopeDAO.getVariable(var.declaration.getName()); return !dataDAO.isNull(); } public boolean isPartnerRoleEndpointInitialized(PartnerLinkInstance pLink) { PartnerLinkDAO spl = fetchPartnerLinkDAO(pLink); return spl.getPartnerEPR() != null || _bpelProcess.getInitialPartnerRoleEPR(pLink.partnerLink) != null; } /** * @see BpelRuntimeContext#completedFault(org.apache.ode.bpel.runtime.channels.FaultData) */ public void completedFault(FaultData faultData) { BpelProcess.__log.warn("Instance " + _dao.getInstanceId() + " of " + _bpelProcess.getPID() + " has completed with fault: " + faultData); _dao.setFault(faultData.getFaultName(), faultData.getExplanation(), faultData.getFaultLineNo(), faultData .getActivityId(), faultData.getFaultMessage()); // send event ProcessInstanceStateChangeEvent evt = new ProcessInstanceStateChangeEvent(); evt.setOldState(_dao.getState()); _dao.setState(ProcessState.STATE_COMPLETED_WITH_FAULT); evt.setNewState(ProcessState.STATE_COMPLETED_WITH_FAULT); sendEvent(evt); sendEvent(new ProcessCompletionEvent(faultData.getFaultName())); _dao.finishCompletion(); faultOutstandingMessageExchanges(faultData); _bpelProcess._engine._contexts.scheduler.registerSynchronizer(new Scheduler.Synchronizer() { public void afterCompletion(boolean success) { } public void beforeCompletion() { _dao.delete(_bpelProcess.getCleanupCategories(false), false); } }); } /** * @see BpelRuntimeContext#completedOk() */ public void completedOk() { if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("ProcessImpl " + _bpelProcess.getPID() + " completed OK."); } // send event ProcessInstanceStateChangeEvent evt = new ProcessInstanceStateChangeEvent(); evt.setOldState(_dao.getState()); _dao.setState(ProcessState.STATE_COMPLETED_OK); evt.setNewState(ProcessState.STATE_COMPLETED_OK); sendEvent(evt); sendEvent(new ProcessCompletionEvent(null)); _dao.finishCompletion(); completeOutstandingMessageExchanges(); _bpelProcess._engine._contexts.scheduler.registerSynchronizer(new Scheduler.Synchronizer() { public void afterCompletion(boolean success) { } public void beforeCompletion() { _dao.delete(_bpelProcess.getCleanupCategories(true), false); } }); } /** * @see BpelRuntimeContext#createScopeInstance(Long, * org.apache.ode.bpel.obj.OScope) */ public Long createScopeInstance(Long parentScopeId, OScope scope) { if (BpelProcess.__log.isTraceEnabled()) { BpelProcess.__log.trace(ObjectPrinter.stringifyMethodEnter("createScopeInstance", new Object[] { "parentScopeId", parentScopeId, "scope", scope })); } ScopeDAO parent = null; if (parentScopeId != null) { parent = _dao.getScope(parentScopeId); } ScopeDAO scopeDao = _dao.createScope(parent, scope.getName(), scope.getId()); return scopeDao.getScopeInstanceId(); } public void initializePartnerLinks(Long parentScopeId, Collection<OPartnerLink> partnerLinks) { if (BpelProcess.__log.isTraceEnabled()) { BpelProcess.__log.trace(ObjectPrinter.stringifyMethodEnter("initializeEndpointReferences", new Object[] { "parentScopeId", parentScopeId, "partnerLinks", partnerLinks })); } ScopeDAO parent = _dao.getScope(parentScopeId); for (OPartnerLink partnerLink : partnerLinks) { PartnerLinkDAO pdao = parent.createPartnerLink(partnerLink.getId(), partnerLink.getName(), partnerLink.getMyRoleName(), partnerLink.getPartnerRoleName()); // If there is a myrole on the link, initialize the session id so it // is always // available for opaque correlations. The myrole session id should // never be changed. if (partnerLink.hasMyRole()) pdao.setMySessionId(new GUID().toString()); } } public void select(PickResponse pickResponseChannel, Date timeout, boolean createInstance, Selector[] selectors) throws FaultException { if (BpelProcess.__log.isTraceEnabled()) BpelProcess.__log.trace(ObjectPrinter.stringifyMethodEnter("select", new Object[] { "pickResponseChannel", pickResponseChannel, "timeout", timeout, "createInstance", createInstance, "selectors", selectors })); ProcessDAO processDao = _dao.getProcess(); // check if this is first pick if (_dao.getState() == ProcessState.STATE_NEW) { assert createInstance; // send event ProcessInstanceStateChangeEvent evt = new ProcessInstanceStateChangeEvent(); evt.setOldState(ProcessState.STATE_NEW); _dao.setState(ProcessState.STATE_READY); evt.setNewState(ProcessState.STATE_READY); sendEvent(evt); } final String pickResponseChannelStr = ProcessUtil.exportChannel(pickResponseChannel); List<CorrelatorDAO> correlators = new ArrayList<CorrelatorDAO>(selectors.length); for (Selector selector : selectors) { String correlatorId = BpelProcess.genCorrelatorId(selector.plinkInstance.partnerLink, selector.opName); if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("SELECT: " + pickResponseChannel + ": USING CORRELATOR " + correlatorId); } correlators.add(processDao.getCorrelator(correlatorId)); } // Checking conflicts int conflict = _imaManager.findConflict(selectors); if (conflict != -1) throw new FaultException(_bpelProcess.getOProcess().getConstants().getQnConflictingReceive(), selectors[conflict] .toString()); // Check for ambiguous receive for (int i = 0; i < selectors.length; ++i) { CorrelatorDAO correlator = correlators.get(i); Selector selector = selectors[i]; if (!correlator.checkRoute(selector.correlationKeySet)) { throw new FaultException(_bpelProcess.getOProcess().getConstants().qnAmbiguousReceive(), selector.toString()); } } //Registering _imaManager.register(pickResponseChannelStr, selectors); // First check if we match to a new instance. if (_instantiatingMessageExchange != null && _dao.getState() == ProcessState.STATE_READY) { if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("SELECT: " + pickResponseChannel + ": CHECKING for NEW INSTANCE match"); } for (int i = 0; i < correlators.size(); ++i) { CorrelatorDAO ci = correlators.get(i); if (ci.equals(_dao.getInstantiatingCorrelator())) { inputMsgMatch(pickResponseChannelStr, i, _instantiatingMessageExchange); if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("SELECT: " + pickResponseChannel + ": FOUND match for NEW instance mexRef=" + _instantiatingMessageExchange); } return; } } } if (timeout != null) { registerTimer(pickResponseChannel, timeout); if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("SELECT: " + pickResponseChannel + "REGISTERED TIMEOUT for " + timeout); } } for (int i = 0; i < selectors.length; ++i) { CorrelatorDAO correlator = correlators.get(i); Selector selector = selectors[i]; correlator.addRoute(ProcessUtil.exportChannel(pickResponseChannel), _dao, i, selector.correlationKeySet, selector.route); scheduleCorrelatorMatcher(correlator.getCorrelatorId(), selector.correlationKeySet); if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("SELECT: " + pickResponseChannel + ": ADDED ROUTE " + correlator.getCorrelatorId() + ": " + selector.correlationKeySet + " --> " + _dao.getInstanceId()); } } } /** * @see BpelRuntimeContext#readCorrelation(org.apache.ode.bpel.runtime.CorrelationSetInstance) */ public CorrelationKey readCorrelation(CorrelationSetInstance cset) { ScopeDAO scopeDAO = _dao.getScope(cset.scopeInstance); CorrelationSetDAO cs = scopeDAO.getCorrelationSet(cset.declaration.getName()); return cs.getValue(); } public Element fetchPartnerRoleEndpointReferenceData(PartnerLinkInstance pLink) throws FaultException { PartnerLinkDAO pl = fetchPartnerLinkDAO(pLink); Element epr = pl.getPartnerEPR(); if (epr == null) { EndpointReference e = _bpelProcess.getInitialPartnerRoleEPR(pLink.partnerLink); if (e != null) epr = e.toXML().getDocumentElement(); } if (epr == null) { throw new FaultException(_bpelProcess.getOProcess().getConstants().getQnUninitializedPartnerRole()); } return epr; } public Element fetchMyRoleEndpointReferenceData(PartnerLinkInstance pLink) { return _bpelProcess.getInitialMyRoleEPR(pLink.partnerLink).toXML().getDocumentElement(); } protected PartnerLinkDAO fetchPartnerLinkDAO(PartnerLinkInstance pLink) { ScopeDAO scopeDAO = _dao.getScope(pLink.scopeInstanceId); return scopeDAO.getPartnerLink(pLink.partnerLink.getId()); } /** * Evaluate a property alias query expression against a variable, returning * the normalized {@link String} representation of the property value. * * @param variable * variable to read * @param property * property to read * @return value of property for variable, in String form * @throws org.apache.ode.bpel.common.FaultException * in case of selection or other fault */ public String readProperty(VariableInstance variable, OProcess.OProperty property) throws FaultException { Node varData = readVariable(variable.scopeInstance, variable.declaration.getName(), false); OProcess.OPropertyAlias alias = property.getAlias(variable.declaration.getType()); String val = _bpelProcess.extractProperty((Element) varData, Collections.EMPTY_MAP, alias, variable.declaration.getDescription()); if (BpelProcess.__log.isTraceEnabled()) { BpelProcess.__log.trace("readPropertyAlias(variable=" + variable + ", alias=" + alias + ") = " + val.toString()); } return val; } public void writeEndpointReference(PartnerLinkInstance variable, Element data) throws FaultException { if (__log.isDebugEnabled()) { __log.debug("Writing endpoint reference " + variable.partnerLink.getName() + " with value " + DOMUtils.domToString(data)); } PartnerLinkDAO eprDAO = fetchPartnerLinkDAO(variable); eprDAO.setPartnerEPR(data); } public String fetchEndpointSessionId(PartnerLinkInstance pLink, boolean isMyEPR) throws FaultException { PartnerLinkDAO dao = fetchPartnerLinkDAO(pLink); return isMyEPR ? dao.getMySessionId() : dao.getPartnerSessionId(); } public Node convertEndpointReference(Element sourceNode, Node targetNode) { QName nodeQName; if (targetNode.getNodeType() == Node.TEXT_NODE) { nodeQName = new QName(Namespaces.XML_SCHEMA, "string"); } else { // We have an element nodeQName = new QName(targetNode.getNamespaceURI(), targetNode.getLocalName()); } return _bpelProcess._engine._contexts.eprContext.convertEndpoint(nodeQName, sourceNode).toXML(); } public Node readVariable(Long scopeInstanceId, String varname, boolean forWriting) throws FaultException { ScopeDAO scopedao = _dao.getScope(scopeInstanceId); XmlDataDAO var = scopedao.getVariable(varname); return (var == null || var.isNull()) ? null : var.get(); } public Node writeVariable(VariableInstance variable, Node changes) { ScopeDAO scopeDAO = _dao.getScope(variable.scopeInstance); XmlDataDAO dataDAO = scopeDAO.getVariable(variable.declaration.getName()); dataDAO.set(changes); writeProperties(variable, changes, dataDAO); return dataDAO.get(); } public void cancelOutstandingRequests(String channelId) { _imaManager.cancel(channelId, false); } public void processOutstandingRequest(PartnerLinkInstance partnerLink, String opName, String bpelMexId, String odeMexId) throws FaultException { String mexRef = _imaManager.processOutstandingRequest(partnerLink, opName, bpelMexId, odeMexId); if (mexRef != null) { reply2(partnerLink, opName, bpelMexId, null, _bpelProcess.getOProcess().getConstants().getQnConflictingRequest(), false, mexRef); throw new FaultException(_bpelProcess.getOProcess().getConstants().getQnConflictingRequest()); } } public void reply(final PartnerLinkInstance plinkInstnace, final String opName, final String mexId, Element msg, QName fault) throws FaultException { String mexRef = _imaManager.release(plinkInstnace, opName, mexId); reply2(plinkInstnace, opName, mexId, msg, fault, false, mexRef); } public void reply2(final PartnerLinkInstance plinkInstnace, final String opName, final String mexId, Element msg, QName fault, boolean failure, final String mexRef) throws FaultException { // prepare event ProcessMessageExchangeEvent evt = new ProcessMessageExchangeEvent(); evt.setMexId(mexId); evt.setOperation(opName); evt.setPortType(plinkInstnace.partnerLink.getMyRolePortType().getQName()); MessageExchangeDAO mex = _dao.getConnection().getMessageExchange(mexRef); MessageDAO message = mex.createMessage(plinkInstnace.partnerLink.getMyRoleOperation(opName).getOutput() .getMessage().getQName()); buildOutgoingMessage(message, msg); MyRoleMessageExchangeImpl m = new MyRoleMessageExchangeImpl(_bpelProcess, _bpelProcess._engine, mex); _bpelProcess.initMyRoleMex(m); m.setResponse(new MessageImpl(message)); if (failure) { mex.setStatus(MessageExchange.Status.FAILURE.toString()); } else if (fault != null) { mex.setStatus(MessageExchange.Status.FAULT.toString()); mex.setFault(fault); evt.setAspect(ProcessMessageExchangeEvent.PROCESS_FAULT); } else { mex.setStatus(MessageExchange.Status.RESPONSE.toString()); evt.setAspect(ProcessMessageExchangeEvent.PROCESS_OUTPUT); } _bpelProcess.doAsyncReply(m, this); // send event sendEvent(evt); } /** * @see BpelRuntimeContext#writeCorrelation(org.apache.ode.bpel.runtime.CorrelationSetInstance, * org.apache.ode.bpel.common.CorrelationKey) */ public void writeCorrelation(CorrelationSetInstance cset, CorrelationKey correlation) { ScopeDAO scopeDAO = _dao.getScope(cset.scopeInstance); CorrelationSetDAO cs = scopeDAO.getCorrelationSet(cset.declaration.getName()); QName[] propNames = new QName[cset.declaration.getProperties().size()]; for (int m = 0; m < cset.declaration.getProperties().size(); m++) { OProcess.OProperty oProperty = cset.declaration.getProperties().get(m); propNames[m] = oProperty.getName(); } cs.setValue(propNames, correlation); CorrelationSetWriteEvent cswe = new CorrelationSetWriteEvent(cset.declaration.getName(), correlation); cswe.setScopeId(cset.scopeInstance); sendEvent(cswe); } /** * Common functionality to initialize a correlation set based on data * available in a variable. * * @param cset * the correlation set instance * @param variable * variable instance * * @throws IllegalStateException * DOCUMENTME */ public void initializeCorrelation(CorrelationSetInstance cset, VariableInstance variable) throws FaultException { if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("Initializing correlation set " + cset.declaration.getName()); } // if correlation set is already initialized, then skip if (isCorrelationInitialized(cset)) { // if already set, we ignore if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("OCorrelation set " + cset + " is already set: ignoring"); } return; } String[] propNames = new String[cset.declaration.getProperties().size()]; String[] propValues = new String[cset.declaration.getProperties().size()]; for (int i = 0; i < cset.declaration.getProperties().size(); ++i) { OProcess.OProperty property = cset.declaration.getProperties().get(i); propValues[i] = readProperty(variable, property); propNames[i] = property.getName().toString(); } CorrelationKey ckeyVal = new CorrelationKey(cset.declaration.getName(), propValues); writeCorrelation(cset, ckeyVal); } public ExpressionLanguageRuntimeRegistry getExpLangRuntime() { return _bpelProcess._expLangRuntimeRegistry; } /** * @see BpelRuntimeContext#terminate() */ public void terminate() { // send event ProcessInstanceStateChangeEvent evt = new ProcessInstanceStateChangeEvent(); evt.setOldState(_dao.getState()); _dao.setState(ProcessState.STATE_TERMINATED); evt.setNewState(ProcessState.STATE_TERMINATED); sendEvent(evt); sendEvent(new ProcessTerminationEvent()); _dao.finishCompletion(); failOutstandingMessageExchanges(); _bpelProcess._engine._contexts.scheduler.registerSynchronizer(new Scheduler.Synchronizer() { public void afterCompletion(boolean success) { } public void beforeCompletion() { _dao.delete(_bpelProcess.getCleanupCategories(false), false); } }); } public void registerTimer(TimerResponse timerChannel, Date timeToFire) { JobDetails we = new JobDetails(); we.setInstanceId(_dao.getInstanceId()); we.setChannel(ProcessUtil.exportChannel(timerChannel)); we.setType(JobType.TIMER); we.setInMem(_bpelProcess.isInMemory()); if(_bpelProcess.isInMemory()){ _bpelProcess._engine._contexts.scheduler.scheduleVolatileJob(true, we, timeToFire); }else{ _bpelProcess._engine._contexts.scheduler.schedulePersistedJob(we, timeToFire); } } private void scheduleCorrelatorMatcher(String correlatorId, CorrelationKeySet keySet) { JobDetails we = new JobDetails(); we.setInstanceId(_dao.getInstanceId()); we.setType(JobType.MATCHER); we.setCorrelatorId(correlatorId); we.setCorrelationKeySet(keySet); we.setInMem(_bpelProcess.isInMemory()); if(_bpelProcess.isInMemory()){ _bpelProcess._engine._contexts.scheduler.scheduleVolatileJob(true, we); }else{ _bpelProcess._engine._contexts.scheduler.schedulePersistedJob(we, null); } } public void checkInvokeExternalPermission() {} /** * Called back when the process executes an invokation. * * @param activityId The activity id in the process definition (id of OInvoke) * @param partnerLinkInstance The partner link variable instance * @param operation The wsdl operation. * @param outboundMsg The message sent outside as a DOM * @param invokeResponseChannel Object called back when the response is received. * @return The instance id of the message exchange. * @throws FaultException When the response is a fault or when the invoke could not be executed * in which case it is one of the bpel standard fault. */ public String invoke(int aid, PartnerLinkInstance partnerLink, Operation operation, Element outgoingMessage, InvokeResponse channel) throws FaultException { PartnerLinkDAO plinkDAO = fetchPartnerLinkDAO(partnerLink); // The target (partner endpoint) -- if it has not been explicitly // initialized // then use the value from bthe deployment descriptor .. Element partnerEPR = plinkDAO.getPartnerEPR(); EndpointReference partnerEpr; if (partnerEPR == null) { partnerEpr = _bpelProcess.getInitialPartnerRoleEPR(partnerLink.partnerLink); // In this case, the partner link has not been initialized. if (partnerEpr == null) throw new FaultException(partnerLink.partnerLink.getOwner().getConstants().getQnUninitializedPartnerRole()); } else { partnerEpr = _bpelProcess._engine._contexts.eprContext.resolveEndpointReference(partnerEPR); } if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("INVOKING PARTNER: partnerLink=" + partnerLink + ", op=" + operation.getName() + " channel=" + channel + ")"); } // prepare event ProcessMessageExchangeEvent evt = new ProcessMessageExchangeEvent(); evt.setOperation(operation.getName()); evt.setPortType(partnerLink.partnerLink.getPartnerRolePortType().getQName()); evt.setAspect(ProcessMessageExchangeEvent.PARTNER_INPUT); MessageExchangeDAO mexDao = _dao.getConnection().createMessageExchange( MessageExchangeDAO.DIR_BPEL_INVOKES_PARTNERROLE); mexDao.setCreateTime(getCurrentEventDateTime()); mexDao.setStatus(MessageExchange.Status.NEW.toString()); mexDao.setOperation(operation.getName()); mexDao.setPortType(partnerLink.partnerLink.getPartnerRolePortType().getQName()); mexDao.setPartnerLinkModelId(partnerLink.partnerLink.getId()); mexDao.setPartnerLink(plinkDAO); mexDao.setProcess(_dao.getProcess()); mexDao.setInstance(_dao); mexDao.setPattern((operation.getOutput() != null ? MessageExchangePattern.REQUEST_RESPONSE : MessageExchangePattern.REQUEST_ONLY).toString()); mexDao.setChannel(channel == null ? null : ProcessUtil.exportChannel(channel)); // Properties used by stateful-exchange protocol. String mySessionId = plinkDAO.getMySessionId(); String partnerSessionId = plinkDAO.getPartnerSessionId(); if ( mySessionId != null ) mexDao.setProperty(MessageExchange.PROPERTY_SEP_MYROLE_SESSIONID, mySessionId); if ( partnerSessionId != null ) mexDao.setProperty(MessageExchange.PROPERTY_SEP_PARTNERROLE_SESSIONID, partnerSessionId); if (__log.isDebugEnabled()) __log.debug("INVOKE PARTNER (SEP): sessionId=" + mySessionId + " partnerSessionId=" + partnerSessionId); MessageDAO message = null; if (operation.getInput() != null) message = mexDao.createMessage(operation.getInput().getMessage().getQName()); else message = mexDao.createMessage(null); mexDao.setRequest(message); if (operation.getInput() != null) message.setType(operation.getInput().getMessage().getQName()); else message.setType(null); buildOutgoingMessage(message, outgoingMessage); // Get he my-role EPR (if myrole exists) for optional use by partner // (for callback mechanism). EndpointReference myRoleEndpoint = partnerLink.partnerLink.hasMyRole() ? _bpelProcess .getInitialMyRoleEPR(partnerLink.partnerLink) : null; PartnerRoleMessageExchangeImpl mex = createPartnerRoleMessageExchangeImpl(mexDao, partnerLink, operation, partnerEpr, myRoleEndpoint); mex.setProperty("activityId", ""+aid); List<BpelProcess> p2pProcesses = null; Endpoint partnerEndpoint = _bpelProcess.getInitialPartnerRoleEndpoint(partnerLink.partnerLink); if (getConfigForPartnerLink(partnerLink.partnerLink).usePeer2Peer && partnerEndpoint != null) p2pProcesses = _bpelProcess.getEngine().route(partnerEndpoint.serviceName, mex.getRequest()); if (p2pProcesses != null && !p2pProcesses.isEmpty()) { // Creating a my mex using the same message id as partner mex to "pipe" them MyRoleMessageExchange myRoleMex = _bpelProcess.getEngine().createMessageExchange( mex.getMessageExchangeId(), partnerEndpoint.serviceName, operation.getName(), mex.getMessageExchangeId()); if (myRoleMex instanceof BrokeredMyRoleMessageExchangeImpl) { mex.setSubscriberCount(((BrokeredMyRoleMessageExchangeImpl) myRoleMex).getSubscriberCount()); } if (BpelProcess.__log.isDebugEnabled()) { __log.debug("Invoking in a p2p interaction, partnerrole " + mex + " - myrole " + myRoleMex); } Message odeRequest = myRoleMex.createMessage(operation.getInput().getMessage().getQName()); odeRequest.setMessage(outgoingMessage); ((MessageImpl)odeRequest)._dao.setHeader(message.getHeader()); if (BpelProcess.__log.isDebugEnabled()) { __log.debug("Setting myRoleMex session ids for p2p interaction, mySession " + partnerSessionId + " - partnerSess " + mySessionId); } if ( partnerSessionId != null ) myRoleMex.setProperty(MessageExchange.PROPERTY_SEP_MYROLE_SESSIONID, partnerSessionId); if ( mySessionId != null ) myRoleMex.setProperty(MessageExchange.PROPERTY_SEP_PARTNERROLE_SESSIONID, mySessionId); mex.setStatus(MessageExchange.Status.REQUEST); myRoleMex.invoke(odeRequest); // Can't expect any sync response scheduleInvokeCheck(mex, partnerLink.partnerLink, true); mex.replyAsync(); } else { // If we couldn't find the endpoint, then there is no sense // in asking the IL to invoke. if (partnerEpr != null) { checkInvokeExternalPermission(); mexDao.setEPR(partnerEpr.toXML().getDocumentElement()); mex.setStatus(MessageExchange.Status.REQUEST); // Assuming an unreliable protocol, we schedule a task to check if recovery mode will be needed scheduleInvokeCheck(mex, partnerLink.partnerLink, false); _bpelProcess._engine._contexts.mexContext.invokePartner(mex); } else { __log.error("Couldn't find endpoint for partner EPR " + DOMUtils.domToString(partnerEPR)); mex.setFailure(FailureType.UNKNOWN_ENDPOINT, "UnknownEndpoint", partnerEPR); } } evt.setMexId(mexDao.getMessageExchangeId()); sendEvent(evt); // MEX pattern is request only, at this point the status can only be a one way if (mexDao.getPattern().equals(MessageExchangePattern.REQUEST_ONLY.toString())) { mexDao.setStatus(MessageExchange.Status.ASYNC.toString()); // This mex can now be released boolean succeeded = mex.getStatus() != MessageExchange.Status.FAILURE && mex.getStatus() != MessageExchange.Status.FAULT; mexDao.release(_bpelProcess.isCleanupCategoryEnabled(succeeded, CLEANUP_CATEGORY.MESSAGES)); } // Check if there is a synchronous response, if so, we need to inject the // message on the response channel. switch (mex.getStatus()) { case NEW: throw new AssertionError("Impossible!"); case ASYNC: break; case RESPONSE: case FAULT: case FAILURE: invocationResponse(mex); break; default: __log.error("Partner did not acknowledge message exchange: " + mex); mex.setFailure(FailureType.NO_RESPONSE, "Partner did not acknowledge.", null); invocationResponse(mex); } return mexDao.getMessageExchangeId(); } // enable extensibility protected PartnerRoleMessageExchangeImpl createPartnerRoleMessageExchangeImpl(MessageExchangeDAO mexDao, PartnerLinkInstance partnerLink, Operation operation, EndpointReference partnerEpr, EndpointReference myRoleEndpoint) { return new PartnerRoleMessageExchangeImpl(getBpelProcess().getEngine(), mexDao, partnerLink.partnerLink.getPartnerRolePortType(), operation, partnerEpr, myRoleEndpoint, getBpelProcess().getPartnerRoleChannel(partnerLink.partnerLink)); } protected BpelProcess getBpelProcess() { return _bpelProcess; } private void scheduleInvokeCheck(PartnerRoleMessageExchangeImpl mex, OPartnerLink partnerLink, boolean p2p) { boolean isTwoWay = mex.getMessageExchangePattern() == org.apache.ode.bpel.iapi.MessageExchange.MessageExchangePattern.REQUEST_RESPONSE; if (!_bpelProcess.isInMemory() && isTwoWay) { JobDetails event = new JobDetails(); event.setMexId(mex.getMessageExchangeId()); event.setProcessId(_bpelProcess.getPID()); event.setInMem(false); event.setType(JobType.INVOKE_CHECK); // use a greater timeout to make sure the check job does not get executed while the service invocation is still waiting for a response long timeout = getBpelProcess().getTimeout(partnerLink, p2p); if (__log.isDebugEnabled()) __log.debug("Creating invocation check event in "+timeout+"ms for mexid " + mex.getMessageExchangeId()); Date future = new Date(System.currentTimeMillis() + timeout); String jobId = _bpelProcess._engine._contexts.scheduler.schedulePersistedJob(event, future); mex.setProperty("invokeCheckJobId", jobId); } } protected void buildOutgoingMessage(MessageDAO message, Element outgoingElmt) { if (outgoingElmt == null) return; Document doc = DOMUtils.newDocument(); Element header = doc.createElement("header"); NodeList parts = outgoingElmt.getChildNodes(); for (int m = 0; m < parts.getLength(); m++) { if (parts.item(m).getNodeType() == Node.ELEMENT_NODE) { Element part = (Element) parts.item(m); if (part.getAttribute("headerPart") != null && part.getAttribute("headerPart").length() > 0) { header.appendChild(doc.importNode(part, true)); // remove the element from the list AND decrement the index to avoid skipping the next element!! outgoingElmt.removeChild(part); m--; } } } message.setData(outgoingElmt); message.setHeader(header); } public void execute() { long maxTime = System.currentTimeMillis() + _maxReductionTimeMs; boolean canReduce = true; assert _outstandingRequests == null && _imaManager != null; while (ProcessState.canExecute(_dao.getState()) && System.currentTimeMillis() < maxTime && canReduce && !_forceFlush) { canReduce = _vpu.execute(); } _dao.setLastActiveTime(new Date()); if (!ProcessState.isFinished(_dao.getState())) { if (__log.isDebugEnabled()) __log.debug("Setting execution state on instance " + _iid); _soup.setGlobalData(_imaManager); if (_bpelProcess.isInMemory()) { // don't serialize in-memory processes ((ProcessInstanceDaoImpl) _dao).setSoup(_soup); } else { ByteArrayOutputStream bos = new ByteArrayOutputStream(10000); try { _soup.write(bos); bos.close(); } catch (Exception ex) { throw new RuntimeException(ex); } _dao.setExecutionState(bos.toByteArray()); } if (ProcessState.canExecute(_dao.getState()) && canReduce) { // Max time exceeded (possibly an infinite loop). if (__log.isDebugEnabled()) __log.debug("MaxTime exceeded for instance # " + _iid); try { JobDetails we = new JobDetails(); we.setInstanceId(_iid); we.setType(JobType.RESUME); we.setInMem(_bpelProcess.isInMemory()); if (_bpelProcess.isInMemory()) _bpelProcess._engine._contexts.scheduler.scheduleVolatileJob(true, we); else _bpelProcess._engine._contexts.scheduler.schedulePersistedJob(we, new Date()); } catch (ContextException e) { __log.error("Failed to schedule resume task.", e); throw new BpelEngineException(e); } } } } public void inputMsgMatch(final String responsechannel, final int idx, MyRoleMessageExchangeImpl mex) { // if we have a message match, this instance should be marked // active if it isn't already if (_dao.getState() == ProcessState.STATE_READY) { if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("INPUTMSGMATCH: Changing process instance state from ready to active"); } _dao.setState(ProcessState.STATE_ACTIVE); // send event ProcessInstanceStateChangeEvent evt = new ProcessInstanceStateChangeEvent(); evt.setOldState(ProcessState.STATE_READY); evt.setNewState(ProcessState.STATE_ACTIVE); sendEvent(evt); } final String mexId = mex.getMessageExchangeId(); _vpu.inject(new JacobRunnable() { private static final long serialVersionUID = 3168964409165899533L; public void run() { PickResponse pickResponse = importChannel(responsechannel, PickResponse.class); pickResponse.onRequestRcvd(idx, mexId); } }); } protected void timerEvent(final String timerResponseChannel) { // In case this is a pick event, we remove routes, // and cancel the outstanding requests. _dao.getProcess().removeRoutes(timerResponseChannel, _dao); _imaManager.cancel(timerResponseChannel, true); // Ignore timer events after the process is finished. if (ProcessState.isFinished(_dao.getState())) { return; } _vpu.inject(new JacobRunnable() { private static final long serialVersionUID = -7767141033611036745L; public void run() { TimerResponse responseChannel = importChannel(timerResponseChannel, TimerResponse.class); responseChannel.onTimeout(); } }); execute(); } public void cancel(final TimerResponse timerResponseChannel) { // In case this is a pick response channel, we need to cancel routes and // receive/reply association. final String id = ProcessUtil.exportChannel(timerResponseChannel); _dao.getProcess().removeRoutes(id, _dao); _imaManager.cancel(id, true); _vpu.inject(new JacobRunnable() { private static final long serialVersionUID = 6157913683737696396L; public void run() { TimerResponse timerResponse = importChannel(id, TimerResponse.class); timerResponse.onCancel(); } }); } void invocationResponse(PartnerRoleMessageExchangeImpl mex) { invocationResponse(mex.getDAO().getMessageExchangeId(), mex.getDAO().getChannel()); } public void invocationResponse(final String mexid, final String responseChannelId) { if (responseChannelId == null) throw new NullPointerException("Null responseChannelId"); if (mexid == null) throw new NullPointerException("Null mexId"); if (BpelProcess.__log.isDebugEnabled()) { __log.debug("Invoking message response for mexid " + mexid + " and channel " + responseChannelId); } _vpu.inject(new BpelJacobRunnable() { private static final long serialVersionUID = -1095444335740879981L; public void run() { ((BpelRuntimeContextImpl) getBpelRuntimeContext()).invocationResponse2( mexid, importChannel(responseChannelId, InvokeResponse.class)); } }); } /** * Continuation of the above. * * @param mexid * @param responseChannel */ private void invocationResponse2(String mexid, InvokeResponse responseChannel) { __log.debug("Triggering response"); MessageExchangeDAO mex = _dao.getConnection().getMessageExchange(mexid); ProcessMessageExchangeEvent evt = new ProcessMessageExchangeEvent(); evt.setPortType(mex.getPortType()); evt.setMexId(mexid); evt.setOperation(mex.getOperation()); MessageExchange.Status status = MessageExchange.Status.valueOf(mex.getStatus()); switch (status) { case FAULT: evt.setAspect(ProcessMessageExchangeEvent.PARTNER_FAULT); responseChannel.onFault(); break; case RESPONSE: evt.setAspect(ProcessMessageExchangeEvent.PARTNER_OUTPUT); responseChannel.onResponse(); break; case FAILURE: evt.setAspect(ProcessMessageExchangeEvent.PARTNER_FAILURE); responseChannel.onFailure(); break; default: __log.error("Invalid response state for mex " + mexid + ": " + status); } sendEvent(evt); } private void saveScopeState(Long scopeId, ScopeStateEnum scopeState) { ScopeDAO scope = _dao.getScope(scopeId); scope.setState(scopeState); } /** * @see BpelRuntimeContext#sendEvent(org.apache.ode.bpel.evt.ProcessInstanceEvent) */ public void sendEvent(ProcessInstanceEvent event) { // fill in missing pieces event.setProcessId(_dao.getProcess().getProcessId()); event.setProcessName(_dao.getProcess().getType()); event.setProcessInstanceId(_dao.getInstanceId()); _bpelProcess._debugger.onEvent(event); // filter scopes List<String> scopeNames = null; if (event instanceof ScopeEvent) { ScopeEvent sevent = (ScopeEvent) event; scopeNames = sevent.getParentScopesNames(); if (sevent instanceof ScopeStartEvent) { saveScopeState(sevent.getScopeId(), ScopeStateEnum.ACTIVE); } else if (sevent instanceof ScopeCompletionEvent) { saveScopeState(sevent.getScopeId(), ScopeStateEnum.COMPLETED); } else if (sevent instanceof ScopeFaultEvent) { saveScopeState(sevent.getScopeId(), ScopeStateEnum.FAULT); } } // saving _bpelProcess.saveEvent(event, _dao, scopeNames); } public static String debugInfoToString(org.apache.ode.bpel.obj.DebugInfo debugInfo) { if (debugInfo == null) return ""; else return " at " + debugInfo.getSourceURI() + ":" + debugInfo.getStartLine(); } /** * We record all values of properties of a 'MessageType' variable for * efficient lookup. */ private void writeProperties(VariableInstance variable, Node value, XmlDataDAO dao) { if (variable.declaration.getType() instanceof OMessageVarType) { for (OProcess.OProperty property : variable.declaration.getOwner().getProperties()) { OProcess.OPropertyAlias alias = property.getAlias(variable.declaration.getType()); if (alias != null) { try { String val = _bpelProcess.extractProperty((Element) value, Collections.EMPTY_MAP, alias, variable.declaration .getDescription()); if (val != null) { dao.setProperty(property.getName().toString(), val); } } catch (FaultException e) { // This will fail as we're basically trying to extract properties on all // received messages for optimization purposes. if (__log.isWarnEnabled()) __log.warn("Couldn't extract property '" + property.toString() + "' and variable " + variable.declaration + debugInfoToString(variable.declaration.getDebugInfo()) + " in property pre-extraction: " + e.toString()); } } } } } private void completeOutstandingMessageExchanges() { String[] mexRefs = _imaManager.releaseAll(); for (String mexId : mexRefs) { MessageExchangeDAO mexDao = _dao.getConnection().getMessageExchange(mexId); if (mexDao != null) { MyRoleMessageExchangeImpl mex = new MyRoleMessageExchangeImpl(_bpelProcess, _bpelProcess._engine, mexDao); switch (mex.getStatus()) { case ASYNC: case RESPONSE: mex.setStatus(MessageExchange.Status.COMPLETED_OK); break; case REQUEST: if (mex.getPattern().equals(MessageExchange.MessageExchangePattern.REQUEST_ONLY)) { mex.setStatus(MessageExchange.Status.COMPLETED_OK); break; } default: mex.setFailure(FailureType.OTHER, "No response.", null); _bpelProcess.doAsyncReply(mex, this); } } } } private void faultOutstandingMessageExchanges(FaultData faultData) { String[] mexRefs = _imaManager.releaseAll(); for (String mexId : mexRefs) { MessageExchangeDAO mexDao = _dao.getConnection().getMessageExchange(mexId); if (mexDao != null) { MyRoleMessageExchangeImpl mex = new MyRoleMessageExchangeImpl(_bpelProcess, _bpelProcess._engine, mexDao); _bpelProcess.initMyRoleMex(mex); Message message = mex.createMessage(faultData.getFaultName()); if (faultData.getFaultMessage() != null) message.setMessage(faultData.getFaultMessage()); mex.setResponse(message); mex.setFault(faultData.getFaultName(), message); mex.setFaultExplanation(faultData.getExplanation()); _bpelProcess.doAsyncReply(mex, this); } } } private void failOutstandingMessageExchanges() { String[] mexRefs = _imaManager.releaseAll(); for (String mexId : mexRefs) { MessageExchangeDAO mexDao = _dao.getConnection().getMessageExchange(mexId); if (mexDao != null) { MyRoleMessageExchangeImpl mex = new MyRoleMessageExchangeImpl(_bpelProcess, _bpelProcess._engine, mexDao); _bpelProcess.initMyRoleMex(mex); mex.setFailure(FailureType.OTHER, "No response.", null); _bpelProcess.doAsyncReply(mex, this); } } } public Element getPartnerResponse(String mexId) { return mergeHeaders(_getPartnerResponse(mexId)); } public Element getMyRequest(String mexId) { MessageExchangeDAO dao = _dao.getConnection().getMessageExchange(mexId); if (dao == null) { // this should not happen.... String msg = "Engine requested non-existent message exchange: " + mexId; __log.error(msg); throw new BpelEngineException(msg); } if (dao.getDirection() != MessageExchangeDAO.DIR_PARTNER_INVOKES_MYROLE) { // this should not happen.... String msg = "Engine requested my-role request for a partner-role mex: " + mexId; __log.error(msg); throw new BpelEngineException(msg); } MessageExchange.Status status = MessageExchange.Status.valueOf(dao.getStatus()); switch (status) { case ASYNC: case REQUEST: // In the case of pub-sub, the status may already be OK. case COMPLETED_OK: MessageDAO request = dao.getRequest(); if (request == null) { // this also should not happen String msg = "Engine requested request for message exchange that did not have one: " + mexId; __log.error(msg); throw new BpelEngineException(msg); } return mergeHeaders(request); default: // We should not be in any other state when requesting this. String msg = "Engine requested response while the message exchange " + mexId + " was in the state " + status; __log.error(msg); throw new BpelEngineException(msg); } } private Element mergeHeaders(MessageDAO msg) { if(msg==null) return null; // Merging header data, it's all stored in the same variable Element data = msg.getData(); if (msg.getHeader() != null) { if (data == null) { Document doc = DOMUtils.newDocument(); data = doc.createElement("message"); doc.appendChild(data); } NodeList headerParts = msg.getHeader().getChildNodes(); for (int m = 0; m < headerParts.getLength(); m++) { if (headerParts.item(m).getNodeType() == Node.ELEMENT_NODE) { Element headerPart = (Element) headerParts.item(m); headerPart.setAttribute("headerPart", "true"); data.appendChild(data.getOwnerDocument().importNode(headerPart, true)); } } } return data; } public QName getPartnerFault(String mexId) { MessageExchangeDAO mex = _getPartnerResponse(mexId).getMessageExchange(); return mex.getFault(); } public QName getPartnerResponseType(String mexId) { return _getPartnerResponse(mexId).getType(); } public String getPartnerFaultExplanation(String mexId) { MessageExchangeDAO dao = _dao.getConnection().getMessageExchange(mexId); return dao != null ? dao.getFaultExplanation() : null; } private MessageDAO _getPartnerResponse(String mexId) { MessageExchangeDAO dao = _dao.getConnection().getMessageExchange(mexId); if (dao == null) { // this should not happen.... String msg = "Engine requested non-existent message exchange: " + mexId; __log.error(msg); throw new BpelEngineException(msg); } if (dao.getDirection() != MessageExchangeDAO.DIR_BPEL_INVOKES_PARTNERROLE) { // this should not happen.... String msg = "Engine requested partner response for a my-role mex: " + mexId; __log.error(msg); throw new BpelEngineException(msg); } MessageDAO response; MessageExchange.Status status = MessageExchange.Status.valueOf(dao.getStatus()); switch (status) { case FAULT: case RESPONSE: response = dao.getResponse(); if (response == null) { // this also should not happen String msg = "Engine requested response for message exchange that did not have one: " + mexId; __log.error(msg); throw new BpelEngineException(msg); } break; case FAILURE: response = dao.getResponse(); break; default: // We should not be in any other state when requesting this. String msg = "Engine requested response while the message exchange " + mexId + " was in the state " + status; __log.error(msg); throw new BpelEngineException(msg); } return response; } public void releasePartnerMex(String mexId, boolean instanceSucceeded) { MessageExchangeDAO dao = _dao.getConnection().getMessageExchange(mexId); dao.release(_bpelProcess.isCleanupCategoryEnabled(instanceSucceeded, CLEANUP_CATEGORY.MESSAGES) ); // We used to cancel the invoke check job here but it turns out // it creates more contention on the ODE_JOB table. It's better // just to let the job get scheduled and discarded quietly /* String jobId = dao.getProperty("invokeCheckJobId"); if (jobId != null) _bpelProcess._engine._contexts.scheduler.cancelJob(jobId); */ } public Element getSourceEPR(String mexId) { MessageExchangeDAO dao = _dao.getConnection().getMessageExchange(mexId); String epr = dao.getProperty(MessageExchange.PROPERTY_SEP_PARTNERROLE_EPR); if (epr == null) return null; try { Element eepr = DOMUtils.stringToDOM(epr); return eepr; } catch (Exception ex) { __log.error("Invalid value for SEP property " + MessageExchange.PROPERTY_SEP_PARTNERROLE_EPR + ": " + epr); } return null; } public String getSourceSessionId(String mexId) { MessageExchangeDAO dao = _dao.getConnection().getMessageExchange(mexId); return dao.getProperty(MessageExchange.PROPERTY_SEP_PARTNERROLE_SESSIONID); } public void registerActivityForRecovery(ActivityRecovery channel, long activityId, String reason, Date dateTime, Element details, String[] actions, int retries) { if (reason == null) reason = "Unspecified"; if (dateTime == null) dateTime = new Date(); __log.info("ActivityRecovery: Registering activity " + activityId + ", failure reason: " + reason + " on channel " + ProcessUtil.exportChannel(channel)); _dao.createActivityRecovery(ProcessUtil.exportChannel(channel), (int) activityId, reason, dateTime, details, actions, retries); } public void unregisterActivityForRecovery(ActivityRecovery channel) { _dao.deleteActivityRecovery(ProcessUtil.exportChannel(channel)); } public void recoverActivity(final String channel, final long activityId, final String action, final FaultData fault) { _vpu.inject(new JacobRunnable() { private static final long serialVersionUID = 3168964409165899533L; public void run() { ActivityRecovery recovery = importChannel(channel, ActivityRecovery.class); __log.info("ActivityRecovery: Recovering activity " + activityId + " with action " + action + " on channel " + recovery); if (recovery != null) { if ("cancel".equals(action)) recovery.cancel(); else if ("retry".equals(action)) recovery.retry(); else if ("fault".equals(action)) recovery.fault(fault); } } }); //_dao.deleteActivityRecovery(channel); execute(); } /** * Fetch the session-identifier for the partner link from the database. */ public String fetchMySessionId(PartnerLinkInstance pLink) { String sessionId = fetchPartnerLinkDAO(pLink).getMySessionId(); assert sessionId != null : "Session ID should always be set!"; return sessionId; } public String fetchPartnersSessionId(PartnerLinkInstance pLink) { return fetchPartnerLinkDAO(pLink).getPartnerSessionId(); } public void initializePartnersSessionId(PartnerLinkInstance pLink, String session) { if (__log.isDebugEnabled()) __log.debug("initializing partner " + pLink + " sessionId to " + session); fetchPartnerLinkDAO(pLink).setPartnerSessionId(session); } /** * Attempt to match message exchanges on a correlator. * */ public void matcherEvent(String correlatorId, CorrelationKeySet ckeySet) { if (BpelProcess.__log.isDebugEnabled()) { __log.debug("MatcherEvent handling: correlatorId=" + correlatorId + ", ckeySet=" + ckeySet); } CorrelatorDAO correlator = _dao.getProcess().getCorrelator(correlatorId); // Find the route first, this is a SELECT FOR UPDATE on the "selector" row, // So we want to acquire the lock before we do anthing else. List<MessageRouteDAO> mroutes = correlator.findRoute(ckeySet); if (mroutes == null || mroutes.size() == 0) { // Ok, this means that a message arrived before we did, so nothing to do. __log.debug("MatcherEvent handling: nothing to do, route no longer in DB"); return; } // Now see if there is a message that matches this selector. MessageExchangeDAO mexdao = correlator.dequeueMessage(ckeySet); if (mexdao != null) { __log.debug("MatcherEvent handling: found matching message in DB (i.e. message arrived before <receive>)"); if( MessageExchangePattern.REQUEST_RESPONSE.toString().equals(mexdao.getPattern())) { __log.warn("A message arrived before a receive is ready for a request/response pattern. This may be processed to success. However, you should consider revising your process since a TCP port and a container thread will be held for a longer time and the process will not scale under heavy load."); } for (MessageRouteDAO mroute : mroutes) { // We have a match, so we can get rid of the routing entries. correlator.removeRoutes(mroute.getGroupId(), _dao); } // Selecting first route to proceed, other matching entries are ignored MessageRouteDAO mroute = mroutes.get(0); // Found message matching one of our selectors. if (BpelProcess.__log.isDebugEnabled()) { BpelProcess.__log.debug("SELECT: " + mroute.getGroupId() + ": matched to MESSAGE " + mexdao + " on CKEYSET " + ckeySet); } MyRoleMessageExchangeImpl mex = new MyRoleMessageExchangeImpl(_bpelProcess, _bpelProcess._engine, mexdao); inputMsgMatch(mroute.getGroupId(), mroute.getIndex(), mex); execute(); // Do not release yet if the process is suspended, the mex will be used again if (_dao.getState() != ProcessState.STATE_SUSPENDED) mexdao.releasePremieMessages(); } else { __log.debug("MatcherEvent handling: nothing to do, no matching message in DB"); } } public Node readExtVar(Variable variable, Node reference) throws ExternalVariableModuleException { Value val = _bpelProcess.getEVM().read(variable, reference, _iid); return val.value; } public ValueReferencePair writeExtVar(Variable variable, Node reference, Node value) throws ExternalVariableModuleException { ValueReferencePair vrp = new ValueReferencePair(); Value val = _bpelProcess.getEVM().write(variable, reference, value, _iid); vrp.reference = val.locator.reference; vrp.value = val.value; return vrp; } public URI getBaseResourceURI() { return _bpelProcess.getBaseResourceURI(); } public Node getProcessProperty(QName propertyName) { return _bpelProcess.getProcessProperty(propertyName); } public QName getProcessQName() { return _bpelProcess.getProcessType(); } public Date getCurrentEventDateTime() { if (_currentEventDateTime == null) return Calendar.getInstance().getTime(); else return _currentEventDateTime; } public void setCurrentEventDateTime(Date eventDateTime) { _currentEventDateTime = eventDateTime; } public ClassLoader getProcessClassLoader() { return _bpelProcess._classLoader; } public PartnerRoleConfig getConfigForPartnerLink(OPartnerLink pLink) { PartnerRoleConfig c = _bpelProcess.getConf().getPartnerRoleConfig().get(pLink.getName()); if (c == null) { return new PartnerRoleConfig(null, true); } else { return c; } } public void forceFlush() { _forceFlush = true; } }