/** * Copyright 2010 JBoss Inc * * Licensed 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.drools.bpel.instance; import java.io.ByteArrayInputStream; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPathConstants; import org.apache.ode.utils.DOMUtils; import org.drools.bpel.core.BPELAssign; import org.drools.bpel.core.BPELAssign.Copy; import org.drools.bpel.core.BPELAssign.Expression; import org.drools.bpel.core.BPELAssign.From; import org.drools.bpel.core.BPELAssign.Literal; import org.drools.bpel.core.BPELAssign.VariableRef; import org.drools.bpel.xpath.XMLDataType; import org.drools.bpel.xpath.XPathReturnValueEvaluator; import org.drools.process.core.context.variable.VariableScope; import org.drools.process.core.datatype.DataType; import org.drools.process.instance.ProcessInstance; import org.drools.process.instance.context.variable.VariableScopeInstance; import org.drools.runtime.process.NodeInstance; import org.drools.spi.ProcessContext; import org.drools.workflow.core.Node; import org.drools.workflow.instance.impl.NodeInstanceImpl; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NodeList; /** * * @author <a href="mailto:kris_verlaenen@hotmail.com">Kris Verlaenen</a> */ public class BPELAssignInstance extends NodeInstanceImpl { private static final long serialVersionUID = 510l; public BPELAssign getBPELAssign() { return (BPELAssign) getNode(); } public void internalTrigger(NodeInstance from, String type) { if (BPELLinkManager.checkActivityEnabled(this)) { BPELAssign assign = getBPELAssign(); for (Copy copy: assign.getCopies()) { From fromPart = copy.getFrom(); VariableRef toPart = (VariableRef) copy.getTo(); Object fromValue = getValue(fromPart); if (toPart.getPart() == null) { if (fromValue instanceof String) { setVariableValue(toPart.getVariable(), (String) fromValue); } else if (fromValue instanceof Element) { String value = DOMUtils.domToString(((Element) fromValue).getFirstChild()); setVariableValue(toPart.getVariable(), value); } else { throw new IllegalArgumentException( "Cannot set variable of this type " + fromValue); } } else { String toValue = getVariableValue(toPart.getVariable()); if (toValue == null) { toValue = initializeVariable(toPart.getVariable()); } toValue = copy(fromValue, toValue, toPart.getPart()); setVariableValue(toPart.getVariable(), toValue); } } triggerCompleted(Node.CONNECTION_DEFAULT_TYPE, true); } } private Object getValue(From from) { if (from instanceof VariableRef) { VariableRef fromPart = (VariableRef) from; String fromValue = getVariableValue(fromPart.getVariable()); if (fromPart.getPart() == null) { return fromValue; } try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document fromDocument = factory.newDocumentBuilder().parse(new ByteArrayInputStream(fromValue.getBytes())); return DOMUtils.findChildByName((Element) fromDocument.getDocumentElement(), new QName(fromPart.getPart())); } catch (Throwable t) { throw new IllegalArgumentException("Could not get value", t); } } else if (from instanceof Literal) { String literal = ((Literal) from).getValue(); if (literal.startsWith("<?xml")) { int index = literal.indexOf("?>"); literal = "<message>" + literal.substring(index + 3) + "</message>"; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document document = factory.newDocumentBuilder().parse(new ByteArrayInputStream(literal.getBytes())); return document.getDocumentElement(); } catch (Throwable t) { throw new IllegalArgumentException("Could not get value", t); } } return literal; } else if (from instanceof Expression) { String expression = ((Expression) from).getExpression(); try { XPathReturnValueEvaluator evaluator = new XPathReturnValueEvaluator(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document document = factory.newDocumentBuilder().parse(new ByteArrayInputStream(expression.getBytes())); org.w3c.dom.Node node = document.getFirstChild().getFirstChild(); if (node == null) { throw new IllegalStateException(); } if (node.getNodeType() != org.w3c.dom.Node.TEXT_NODE) { throw new IllegalArgumentException("Unexpected node type for XPath"); } String xpathString = node.getNodeValue(); evaluator.setExpression(xpathString); ProcessContext processContext = new ProcessContext(); processContext.setNodeInstance(this); return (String) evaluator.evaluate( ((ProcessInstance) getProcessInstance()).getWorkingMemory(), processContext, XPathConstants.STRING); } catch (Throwable t) { throw new IllegalArgumentException("Could not evaluate expression " + expression, t); } } else { throw new UnsupportedOperationException(); } } private String copy(Object fromValue, String toValue, String toPart) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document toDocument = factory.newDocumentBuilder().parse(new ByteArrayInputStream(toValue.getBytes())); Element to = DOMUtils.findChildByName((Element) toDocument.getDocumentElement(), new QName(toPart)); if (fromValue instanceof Element) { Element from = (Element) fromValue; Element replacement = toDocument.createElementNS(null, toPart); NodeList nl = from.getChildNodes(); for (int i = 0; i < nl.getLength(); ++i) replacement.appendChild(toDocument.importNode(nl.item(i), true)); NamedNodeMap attrs = from.getAttributes(); for (int i = 0; i < attrs.getLength(); ++i) { if (!((Attr)attrs.item(i)).getName().startsWith("xmlns")) { replacement.setAttributeNodeNS((Attr) toDocument.importNode(attrs.item(i), true)); } } if (to == null) { toDocument.getDocumentElement().appendChild(replacement); } else { to.getParentNode().replaceChild(replacement, to); } } else { Element replacement = toDocument.createElementNS(null, toPart); replacement.setTextContent((String) fromValue); if (to == null) { toDocument.getDocumentElement().appendChild(replacement); } else { to.getParentNode().replaceChild(replacement, to); } } return DOMUtils.domToString(toDocument.getDocumentElement()); } catch (Throwable t) { throw new IllegalArgumentException("Could not copy value", t); } } private String initializeVariable(String variable) { VariableScopeInstance variableScopeInstance = (VariableScopeInstance) resolveContextInstance(VariableScope.VARIABLE_SCOPE, variable); if (variableScopeInstance != null) { DataType dataType = ((VariableScope) variableScopeInstance.getContext()).findVariable(variable).getType(); if (dataType instanceof XMLDataType) { String type = ((XMLDataType) dataType).getTypeDefinition(); type = type.substring(type.lastIndexOf("}") + 1); return "<" + type + "></" + type + ">"; } } return ""; } private String getVariableValue(String variable) { VariableScopeInstance variableScopeInstance = (VariableScopeInstance) resolveContextInstance(VariableScope.VARIABLE_SCOPE, variable); if (variableScopeInstance != null) { return (String) variableScopeInstance.getVariable(variable); } else { System.err.println("Could not find variable scope for variable " + variable); System.err.println("when trying assign"); System.err.println("Continuing without setting variable."); } return null; } private void setVariableValue(String variable, String value) { VariableScopeInstance variableScopeInstance = (VariableScopeInstance) resolveContextInstance(VariableScope.VARIABLE_SCOPE, variable); if (variableScopeInstance != null) { variableScopeInstance.setVariable(variable, value); } else { System.err.println("Could not find variable scope for variable " + variable); System.err.println("when trying assign"); System.err.println("Continuing without setting variable."); } } public void triggerCompleted(String type, boolean remove) { super.triggerCompleted(type, remove); BPELLinkManager.activateTargetLinks(this); } }