Java tutorial
/* * 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.rtrep.v2; import java.util.List; import javax.xml.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ode.bpel.common.FaultException; import org.apache.ode.bpel.evar.ExternalVariableModuleException; import org.apache.ode.bpel.rapi.ContextData; import org.apache.ode.bpel.rtrep.v2.OScope.Variable; import org.apache.ode.utils.DOMUtils; import org.apache.ode.utils.msg.MessageBundle; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; /** * Helper class that shares common code * for ASSIGN activity and SCOPE activity (used by in-line variable * initialization) * * NOTE: This will extend ACTIVITY class, but it is not * meant to be activity, it reuses methods provided * by superclass. * * @author madars.vitolins _at gmail.com (University of Latvia) */ public class AssignHelper extends ACTIVITY { private static final long serialVersionUID = 1L; private static final Log __log = LogFactory.getLog(AssignHelper.class); private static final ASSIGNMessages __msgs = MessageBundle.getMessages(ASSIGNMessages.class); public AssignHelper(ActivityInfo self, ScopeFrame scopeFrame, LinkFrame linkFrame) { super(self, scopeFrame, linkFrame); } /** * This method is stub, it is not meant to run */ @Override public void run() { String errMsg = "AssignHelper cannot be ran as ACTIVITY"; __log.error(errMsg); _self.parent.failure(errMsg, null); } /** * Moved from ASSIGN here */ @Override Node fetchVariableData(VariableInstance variable, boolean forWriting) throws FaultException { try { return super.fetchVariableData(variable, forWriting); } catch (FaultException fe) { if (forWriting) { fe = new FaultException(fe.getQName(), fe.getMessage(), new Throwable("throwUninitializedToVariable")); } throw fe; } } private OActivity getOActivity() { return _self.o; } /** * Initializes single variable by using it's 'from-spec' * @param var * @author madars.vitolins _at gmail.com, 2009.04.17 */ public void initVar(Variable var) throws FaultException, ExternalVariableModuleException { __log.info("Initializing variable [" + var.name + "]"); // Init variable from another variable if (var.type instanceof OMessageVarType && var.from instanceof OAssign.VariableRef && ((OAssign.VariableRef) var.from).isMessageRef()) { final VariableInstance lval = _scopeFrame.resolve(var); final VariableInstance rval = _scopeFrame.resolve(((OAssign.VariableRef) var.from).getVariable()); Element lvalue = (Element) fetchVariableData(rval, false); initializeVariable(lval, lvalue); } else { Node rvalue = evalRValue(var.from); Node lvalue = evalLValue(var); // Dump r-value if (__log.isDebugEnabled()) { __log.debug("rvalue after eval " + rvalue); if (rvalue != null) __log.debug("content " + DOMUtils.domToString(rvalue)); } // Dump l-value if (__log.isDebugEnabled()) { __log.debug("lvalue after eval " + rvalue); if (lvalue != null) __log.debug("content " + DOMUtils.domToString(lvalue)); } Node lvaluePtr = lvalue; // Sneakily converting the EPR if it's not the format expected by // the lvalue if (var.from instanceof OAssign.PartnerLinkRef) { rvalue = getBpelRuntime().convertEndpointReference((Element) rvalue, lvaluePtr); if (rvalue.getNodeType() == Node.DOCUMENT_NODE) rvalue = ((Document) rvalue).getDocumentElement(); } if (rvalue.getNodeType() == Node.ELEMENT_NODE && lvaluePtr.getNodeType() == Node.ELEMENT_NODE) { lvalue = replaceElement((Element) lvalue, (Element) lvaluePtr, (Element) rvalue, true); } else { lvalue = replaceContent(lvalue, lvaluePtr, rvalue.getTextContent()); } final VariableInstance lval = _scopeFrame.resolve(var); if (__log.isDebugEnabled()) __log.debug("SCOPE initialized variable '" + lval.declaration.name + "' value '" + DOMUtils.domToString(lvalue) + "'"); // Commit changes! commitChanges(lval, lvalue); } }// initVar() /** * Assumes that variable is variable not kind of partner links. * * @param var * @return * @throws FaultException * @throws ExternalVariableModuleException * @author madars.vitolins _at gmail.com */ public Node evalLValue(Variable var) throws FaultException, ExternalVariableModuleException { final OdeInternalInstance napi = getBpelRuntime(); Node lval = null; VariableInstance lvar = _scopeFrame.resolve(var); if (!napi.isVariableInitialized(lvar)) { Document doc = DOMUtils.newDocument(); Node val = var.type.newInstance(doc); if (val.getNodeType() == Node.TEXT_NODE) { Element tempwrapper = doc.createElementNS(null, "temporary-simple-type-wrapper"); doc.appendChild(tempwrapper); tempwrapper.appendChild(val); val = tempwrapper; } else doc.appendChild(val); // Only external variables need to be initialized, others are new // and going to be overwritten if (lvar.declaration.extVar != null) lval = initializeVariable(lvar, val); else lval = val; } else lval = fetchVariableData(lvar, true); return lval; } /** * madars.vitolins _at gmail.com - 2009.04.17 - Moved from ASSIGN here * @param to * @return * @throws FaultException * @throws ExternalVariableModuleException */ public Node evalLValue(OAssign.LValue to) throws FaultException, ExternalVariableModuleException { final OdeInternalInstance napi = getBpelRuntime(); Node lval = null; if (!(to instanceof OAssign.PartnerLinkRef) && !(to instanceof OAssign.ContextRef)) { VariableInstance lvar; try { lvar = _scopeFrame.resolve(to.getVariable()); } catch (RuntimeException e) { __log.error("iid: " + napi.getInstanceId() + " error evaluating lvalue"); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, e.getMessage()); } if (!napi.isVariableInitialized(lvar)) { Document doc = DOMUtils.newDocument(); Node val = to.getVariable().type.newInstance(doc); if (val.getNodeType() == Node.TEXT_NODE) { Element tempwrapper = doc.createElementNS(null, "temporary-simple-type-wrapper"); doc.appendChild(tempwrapper); tempwrapper.appendChild(val); val = tempwrapper; } else doc.appendChild(val); // Only external variables need to be initialized, others are new and going to be overwritten if (lvar.declaration.extVar != null) lval = initializeVariable(lvar, val); else lval = val; } else lval = fetchVariableData(lvar, true); } return lval; } /** * Get the r-value. There are several possibilities: * <ul> * <li>a message is selected - an element representing the whole message is * returned.</li> * <li>a (element) message part is selected - the element is returned. * </li> * <li>a (typed) message part is select - a wrapper element is returned. * </li> * <li>an attribute is selected - an attribute node is returned. </li> * <li>a text node/string expression is selected - a text node is returned. * </li> * </ul> * (madars.vitolins _at gmail.com - 2009.04.17 - moved from ASSIGN here) * @param from * * @return Either {@link Element}, {@link org.w3c.dom.Text}, or * {@link org.w3c.dom.Attr} node representing the r-value. * * @throws FaultException * DOCUMENTME * @throws UnsupportedOperationException * DOCUMENTME * @throws IllegalStateException * DOCUMENTME */ public Node evalRValue(OAssign.RValue from) throws FaultException, ExternalVariableModuleException { if (__log.isDebugEnabled()) __log.debug("Evaluating FROM expression \"" + from + "\"."); Node retVal; if (from instanceof OAssign.DirectRef) { OAssign.DirectRef dref = (OAssign.DirectRef) from; sendVariableReadEvent(_scopeFrame.resolve(dref.variable)); Node data = fetchVariableData(_scopeFrame.resolve(dref.variable), false); retVal = DOMUtils.findChildByName((Element) data, dref.elName); } else if (from instanceof OAssign.VariableRef) { OAssign.VariableRef varRef = (OAssign.VariableRef) from; sendVariableReadEvent(_scopeFrame.resolve(varRef.variable)); Node data = fetchVariableData(_scopeFrame.resolve(varRef.variable), false); retVal = evalQuery(data, varRef.part != null ? varRef.part : varRef.headerPart, varRef.location, getEvaluationContext()); } else if (from instanceof OAssign.PropertyRef) { OAssign.PropertyRef propRef = (OAssign.PropertyRef) from; sendVariableReadEvent(_scopeFrame.resolve(propRef.variable)); Node data = fetchVariableData(_scopeFrame.resolve(propRef.variable), false); retVal = evalQuery(data, propRef.propertyAlias.part, propRef.propertyAlias.location, getEvaluationContext()); } else if (from instanceof OAssign.PartnerLinkRef) { OAssign.PartnerLinkRef pLinkRef = (OAssign.PartnerLinkRef) from; PartnerLinkInstance pLink = _scopeFrame.resolve(pLinkRef.partnerLink); Node tempVal = pLinkRef.isMyEndpointReference ? getBpelRuntime().fetchMyRoleEndpointReferenceData(pLink) : getBpelRuntime().fetchPartnerRoleEndpointReferenceData(pLink); if (__log.isDebugEnabled()) __log.debug("RValue is a partner link, corresponding endpoint " + tempVal.getClass().getName() + " has value " + DOMUtils.domToString(tempVal)); retVal = tempVal; } else if (from instanceof OAssign.ContextRef) { OAssign.ContextRef ctxRef = (OAssign.ContextRef) from; ContextData cdata = getBpelRuntime().fetchContextData(_scopeFrame.resolve(ctxRef.partnerLink)); retVal = evalQuery(cdata.toXML(ctxRef.contexts), null, ctxRef.location, getEvaluationContext()); } else if (from instanceof OAssign.Expression) { OExpression expr = ((OAssign.Expression) from).expression; List<Node> l = getBpelRuntime().getExpLangRuntime().evaluate(expr, getEvaluationContext()); if (l.size() == 0) { String msg = __msgs.msgRValueNoNodesSelected(expr.toString()); if (__log.isDebugEnabled()) __log.debug(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg, new Throwable("ignoreMissingFromData")); } else if (l.size() > 1) { String msg = __msgs.msgRValueMultipleNodesSelected(expr.toString()); if (__log.isDebugEnabled()) __log.debug(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } retVal = l.get(0); } else if (from instanceof OAssign.Literal) { Element literalRoot = ((OAssign.Literal) from).getXmlLiteral().getDocumentElement(); assert literalRoot.getLocalName().equals("literal"); // We'd like a single text node... literalRoot.normalize(); retVal = literalRoot.getFirstChild(); // Adjust for whitespace before an element. if (retVal != null && retVal.getNodeType() == Node.TEXT_NODE && retVal.getTextContent().trim().length() == 0 && retVal.getNextSibling() != null) { retVal = retVal.getNextSibling(); } if (retVal == null) { // Special case, no children --> empty TII retVal = literalRoot.getOwnerDocument().createTextNode(""); } else if (retVal.getNodeType() == Node.ELEMENT_NODE) { // Make sure there is no more elements. Node x = retVal.getNextSibling(); while (x != null) { if (x.getNodeType() == Node.ELEMENT_NODE) { String msg = __msgs.msgLiteralContainsMultipleEIIs(); if (__log.isDebugEnabled()) __log.debug(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } x = x.getNextSibling(); } } else if (retVal.getNodeType() == Node.TEXT_NODE) { // Make sure there are no elements following this text node. Node x = retVal.getNextSibling(); while (x != null) { if (x.getNodeType() == Node.ELEMENT_NODE) { String msg = __msgs.msgLiteralContainsMixedContent(); if (__log.isDebugEnabled()) __log.debug(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } x = x.getNextSibling(); } } if (retVal == null) { String msg = __msgs.msgLiteralMustContainTIIorEII(); if (__log.isDebugEnabled()) __log.debug(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } } else { String msg = __msgs.msgInternalError("Unknown RVALUE type: " + from); if (__log.isErrorEnabled()) __log.error(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } // Now verify we got something. if (retVal == null) { String msg = __msgs.msgEmptyRValue(); if (__log.isDebugEnabled()) __log.debug(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } // Now check that we got the right thing. switch (retVal.getNodeType()) { case Node.TEXT_NODE: case Node.ATTRIBUTE_NODE: case Node.ELEMENT_NODE: case Node.CDATA_SECTION_NODE: break; default: String msg = __msgs.msgInvalidRValue(); if (__log.isDebugEnabled()) __log.debug(from + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } return retVal; } /** * madars.vitolins _at gmail.com - 2009.04.17 - moved from ASSIGN here */ public Element replaceElement(Element lval, Element ptr, Element src, boolean keepSrcElement) { Document doc = ptr.getOwnerDocument(); Node parent = ptr.getParentNode(); if (keepSrcElement) { Element replacement = (Element) doc.importNode(src, true); parent.replaceChild(replacement, ptr); return (lval == ptr) ? replacement : lval; } Element replacement = doc.createElementNS(ptr.getNamespaceURI(), ptr.getLocalName()); NodeList nl = src.getChildNodes(); for (int i = 0; i < nl.getLength(); ++i) replacement.appendChild(doc.importNode(nl.item(i), true)); NamedNodeMap attrs = src.getAttributes(); for (int i = 0; i < attrs.getLength(); ++i) { Attr attr = (Attr) attrs.item(i); if (!attr.getName().startsWith("xmlns")) { replacement.setAttributeNodeNS((Attr) doc.importNode(attrs.item(i), true)); // Case of qualified attribute values, we're forced to add corresponding namespace declaration manually int colonIdx = attr.getValue().indexOf(":"); if (colonIdx > 0) { String prefix = attr.getValue().substring(0, colonIdx); String attrValNs = src.lookupPrefix(prefix); if (attrValNs != null) replacement.setAttributeNS(DOMUtils.NS_URI_XMLNS, "xmlns:" + prefix, attrValNs); } } } parent.replaceChild(replacement, ptr); DOMUtils.copyNSContext(ptr, replacement); return (lval == ptr) ? replacement : lval; } /** * isInsert flag desginates this as an 'element' type insertion, which * requires insert the actual element value, rather than it's children * (madars.vitolins _at gmail.com - 2009.04.17 - moved from ASSIGN here) * @return * @throws FaultException */ public Node replaceContent(Node lvalue, Node lvaluePtr, String rvalue) throws FaultException { Document d = lvaluePtr.getOwnerDocument(); if (__log.isDebugEnabled()) { __log.debug("lvaluePtr type " + lvaluePtr.getNodeType()); __log.debug("lvaluePtr " + DOMUtils.domToString(lvaluePtr)); __log.debug("lvalue " + lvalue); __log.debug("rvalue " + rvalue); } switch (lvaluePtr.getNodeType()) { case Node.ELEMENT_NODE: // Remove all the children. while (lvaluePtr.hasChildNodes()) lvaluePtr.removeChild(lvaluePtr.getFirstChild()); // Append a new text node. lvaluePtr.appendChild(d.createTextNode(rvalue)); // If lvalue is a text, removing all lvaluePtr children had just removed it // so we need to rebuild it as a child of lvaluePtr if (lvalue instanceof Text) lvalue = lvaluePtr.getFirstChild(); break; case Node.TEXT_NODE: Node newval = d.createTextNode(rvalue); // Replace ourselves . lvaluePtr.getParentNode().replaceChild(newval, lvaluePtr); // A little kludge, let our caller know that the root element has changed. // (used for assignment to a simple typed variable) if (lvalue.getNodeType() == Node.ELEMENT_NODE) { // No children, adding an empty text children to point to if (lvalue.getFirstChild() == null) { Text txt = lvalue.getOwnerDocument().createTextNode(""); lvalue.appendChild(txt); } if (lvalue.getFirstChild().getNodeType() == Node.TEXT_NODE) lvalue = lvalue.getFirstChild(); } if (lvalue.getNodeType() == Node.TEXT_NODE && ((Text) lvalue).getWholeText().equals(((Text) lvaluePtr).getWholeText())) lvalue = lvaluePtr = newval; break; case Node.ATTRIBUTE_NODE: ((Attr) lvaluePtr).setValue(rvalue); break; default: // This could occur if the expression language selects something // like // a PI or a CDATA. String msg = __msgs.msgInvalidLValue(); if (__log.isDebugEnabled()) __log.debug(lvaluePtr + ": " + msg); throw new FaultException(getOActivity().getOwner().constants.qnSelectionFailure, msg); } return lvalue; } /** * madars.vitolins _at gmail.com - 2009.04.17 moved from ASSIGN here * @param data * @param part * @param expression * @param ec * @return * @throws FaultException */ private Node evalQuery(Node data, OMessageVarType.Part part, OExpression expression, EvaluationContext ec) throws FaultException { assert data != null; if (part != null) { QName partName = new QName(null, part.name); Node qualLVal = DOMUtils.findChildByName((Element) data, partName); if (part.type instanceof OElementVarType) { QName elName = ((OElementVarType) part.type).elementType; qualLVal = DOMUtils.findChildByName((Element) qualLVal, elName); } else if (part.type == null) { // Special case of header parts never referenced in the WSDL def if (qualLVal != null && qualLVal.getNodeType() == Node.ELEMENT_NODE && ((Element) qualLVal).getAttribute("headerPart") != null && DOMUtils.getTextContent(qualLVal) == null) qualLVal = DOMUtils.getFirstChildElement((Element) qualLVal); // The needed part isn't there, dynamically creating it if (qualLVal == null) { qualLVal = data.getOwnerDocument().createElementNS(null, part.name); ((Element) qualLVal).setAttribute("headerPart", "true"); data.appendChild(qualLVal); } } data = qualLVal; } if (expression != null) { // Neat little trick.... data = ec.evaluateQuery(data, expression); } return data; } }