/* * 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.runtime; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ode.bpel.common.FaultException; import org.apache.ode.bpel.evt.ScopeEvent; import org.apache.ode.bpel.iapi.BpelEngineException; import org.apache.ode.bpel.o.OElementVarType; import org.apache.ode.bpel.o.OMessageVarType; import org.apache.ode.bpel.o.OPartnerLink; import org.apache.ode.bpel.o.OScope; import org.apache.ode.bpel.o.OMessageVarType.Part; import org.apache.ode.bpel.runtime.BpelRuntimeContext.ValueReferencePair; import org.apache.ode.bpel.runtime.channels.FaultData; import org.apache.ode.utils.DOMUtils; import org.apache.ode.bpel.evar.ExternalVariableModuleException; import org.apache.ode.bpel.evar.IncompleteKeyException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import java.io.Serializable; import java.util.ArrayList; import java.util.Set; import javax.xml.namespace.QName; /** * N-tuple representing a scope "frame" (as in stack frame). */ class ScopeFrame implements Serializable { private static final long serialVersionUID = 1L; private static final Log __log = LogFactory.getLog(ScopeFrame.class); /** The compiled scope representation. */ final OScope oscope; /** The parent scope frame. */ final ScopeFrame parent; /** Database scope instance identifier. */ final Long scopeInstanceId; Set<CompensationHandler> availableCompensations; /** The fault context for this scope. */ private FaultData _faultData; /** Constructor used to create "fault" scopes. */ ScopeFrame( OScope scopeDef, Long scopeInstanceId, ScopeFrame parent, Set<CompensationHandler> visibleCompensationHandlers, FaultData fault) { this(scopeDef,scopeInstanceId,parent,visibleCompensationHandlers); _faultData = fault; } public ScopeFrame( OScope scopeDef, Long scopeInstanceId, ScopeFrame parent, Set<CompensationHandler> visibleCompensationHandlers) { this.oscope = scopeDef; this.scopeInstanceId = scopeInstanceId; this.parent = parent; this.availableCompensations = visibleCompensationHandlers; } public ScopeFrame find(OScope scope) { if (oscope.name.equals(scope.name)) { return this; } return (parent != null) ? parent.find(scope) : null; } public VariableInstance resolve(OScope.Variable variable) { ScopeFrame scopeFrame = find(variable.declaringScope); if (scopeFrame == null) return null; return new VariableInstance(scopeFrame.scopeInstanceId, variable); } public CorrelationSetInstance resolve(OScope.CorrelationSet cset) { return new CorrelationSetInstance(find(cset.declaringScope).scopeInstanceId, cset); } public PartnerLinkInstance resolve(OPartnerLink partnerLink) { return new PartnerLinkInstance(find(partnerLink.declaringScope).scopeInstanceId, partnerLink); } public String toString() { StringBuffer buf= new StringBuffer("{ScopeFrame: o="); buf.append(oscope); buf.append(", id="); buf.append(scopeInstanceId); if (availableCompensations != null) { buf.append(", avComps="); buf.append(availableCompensations); } if (_faultData != null) { buf.append(", fault="); buf.append(_faultData); } buf.append('}'); return buf.toString(); } public FaultData getFault() { if (_faultData != null) return _faultData; if (parent != null) return parent.getFault(); return null; } public void fillEventInfo(ScopeEvent event) { ScopeFrame currentScope = this; ArrayList<String> parentNames = new ArrayList<String>(); while (currentScope != null) { parentNames.add(currentScope.oscope.name); currentScope = currentScope.parent; } event.setParentScopesNames(parentNames); if (parent != null) event.setParentScopeId(parent.scopeInstanceId); event.setScopeId(scopeInstanceId); event.setScopeName(oscope.name); event.setScopeDeclerationId(oscope.getId()); if (event.getLineNo() == -1 && oscope.debugInfo != null) event.setLineNo(oscope.debugInfo.startLine); } // // Move all the external variable stuff in here so that it can be used by the expr-lang evaluation // context. // Node fetchVariableData(BpelRuntimeContext brc, VariableInstance variable, boolean forWriting) throws FaultException { // Special case of messageType variables with no part if (variable.declaration.type instanceof OMessageVarType) { OMessageVarType msgType = (OMessageVarType) variable.declaration.type; if (msgType.parts.size() == 0) { Document doc = DOMUtils.newDocument(); Element root = doc.createElement("message"); doc.appendChild(root); return root; } } if (variable.declaration.extVar != null) { // Note, that when using external variables, the database will not contain the value of the // variable, instead we need to go the external variable subsystems. Element reference = (Element) fetchVariableData(brc, resolve(variable.declaration.extVar.related), false); try { Node ret = brc.readExtVar(variable.declaration, reference ); if (ret == null) { throw new FaultException(oscope.getOwner().constants.qnUninitializedVariable, "The external variable \"" + variable.declaration.name + "\" has not been initialized."); } return ret; } catch (IncompleteKeyException ike) { // This indicates that the external variable needed to be written do, put has not been. __log.error("External variable could not be read due to incomplete key; the following key " + "components were missing: " + ike.getMissing()); throw new FaultException(oscope.getOwner().constants.qnUninitializedVariable, "The extenral variable \"" + variable.declaration.name + "\" has not been properly initialized;" + "the following key compoenents were missing:" + ike.getMissing()); } catch (ExternalVariableModuleException e) { throw new BpelEngineException(e); } } else /* not external */ { Node data = brc.readVariable(variable.scopeInstance,variable.declaration.name, forWriting); if (data == null) { throw new FaultException(oscope.getOwner().constants.qnUninitializedVariable, "The variable " + variable.declaration.name + " isn't properly initialized."); } return data; } } Node fetchVariableData(BpelRuntimeContext brc, VariableInstance var, OMessageVarType.Part part, boolean forWriting) throws FaultException { Node container = fetchVariableData(brc, var, forWriting); // If we want a specific part, we will need to navigate through the // message/part structure if (var.declaration.type instanceof OMessageVarType && part != null) { container = getPartData((Element) container, part); } return container; } Node initializeVariable(BpelRuntimeContext context, VariableInstance var, Node value) throws ExternalVariableModuleException { if (var.declaration.extVar != null) /* external variable */ { if (__log.isDebugEnabled()) __log.debug("Initialize external variable: name="+var.declaration + " value="+DOMUtils.domToString(value)); VariableInstance related = resolve(var.declaration.extVar.related); Node reference = null; try { reference = fetchVariableData(context, related, true); } catch (FaultException fe) { // In this context this is not necessarily a problem, since the assignment may re-init the related var } if (reference != null) value = context.readExtVar(var.declaration, reference); return value; } else /* normal variable */ { if (__log.isDebugEnabled()) __log.debug("Initialize variable: name="+var.declaration + " value="+DOMUtils.domToString(value)); return context.writeVariable(var, value); } } Node commitChanges(BpelRuntimeContext context, VariableInstance var, Node value) throws ExternalVariableModuleException { return writeVariable(context, var, value); } Node writeVariable(BpelRuntimeContext context, VariableInstance var, Node value) throws ExternalVariableModuleException { if (var.declaration.extVar != null) /* external variable */ { __log.debug("Write external variable: name="+var.declaration + " value="+DOMUtils.domToString(value)); VariableInstance related = resolve(var.declaration.extVar.related); Node reference = null; try { reference = fetchVariableData(context, related, true); } catch (FaultException fe) { // In this context this is not necessarily a problem, since the assignment may re-init the related var } ValueReferencePair vrp = context.writeExtVar(var.declaration, reference, value); writeVariable(context, related, vrp.reference); return vrp.value; } else /* normal variable */ { __log.debug("Write variable: name="+var.declaration + " value="+DOMUtils.domToString(value)); return context.writeVariable(var, value); } } Node getPartData(Element message, Part part) { // borrowed from ASSIGN.evalQuery() QName partName = new QName(null, part.name); Node ret = DOMUtils.findChildByName(message, partName); if (part.type instanceof OElementVarType) { QName elName = ((OElementVarType) part.type).elementType; ret = DOMUtils.findChildByName((Element) ret, elName); } return ret; } }