1 package org.jbpm.bpel.xml.util; 2 3 import java.io.IOException ; 4 import java.io.InputStream ; 5 import java.io.StringReader ; 6 import java.net.URL ; 7 import java.util.ArrayList ; 8 import java.util.HashMap ; 9 import java.util.Iterator ; 10 import java.util.Map ; 11 import java.util.NoSuchElementException ; 12 13 import javax.xml.namespace.QName ; 14 import javax.xml.parsers.DocumentBuilder ; 15 import javax.xml.parsers.DocumentBuilderFactory ; 16 import javax.xml.parsers.ParserConfigurationException ; 17 import javax.xml.soap.SOAPElement ; 18 import javax.xml.soap.SOAPException ; 19 import javax.xml.transform.Transformer ; 20 import javax.xml.transform.TransformerConfigurationException ; 21 import javax.xml.transform.TransformerFactory ; 22 import javax.xml.transform.stream.StreamSource ; 23 24 import org.apache.commons.collections.Predicate; 25 import org.apache.commons.collections.iterators.FilterIterator; 26 import org.apache.commons.logging.Log; 27 import org.apache.commons.logging.LogFactory; 28 import org.jaxen.JaxenException; 29 import org.jaxen.Navigator; 30 import org.jaxen.SimpleNamespaceContext; 31 import org.jaxen.UnsupportedAxisException; 32 import org.jaxen.XPath; 33 import org.jaxen.dom.DOMXPath; 34 import org.jaxen.dom.DocumentNavigator; 35 import org.w3c.dom.Attr ; 36 import org.w3c.dom.Document ; 37 import org.w3c.dom.Element ; 38 import org.w3c.dom.NamedNodeMap ; 39 import org.w3c.dom.Node ; 40 import org.w3c.dom.NodeList ; 41 import org.xml.sax.InputSource ; 42 import org.xml.sax.SAXException ; 43 44 import org.jbpm.bpel.xml.BpelConstants; 45 46 import com.ibm.wsdl.util.xml.DOMUtils; 47 48 52 public class NodeUtil { 53 54 private static ThreadLocal documentBuilderLocal = new ThreadLocal () { 55 56 protected Object initialValue() { 57 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 58 factory.setNamespaceAware(true); 59 factory.setValidating(true); 60 factory.setCoalescing(true); 61 factory.setIgnoringElementContentWhitespace(true); 62 try { 63 factory.setAttribute(JAXP_SCHEMA_LANGUAGE, BpelConstants.NS_XML_SCHEMA); 65 } 66 catch (IllegalArgumentException e) { 67 log.fatal("The JAXP implementation does not support XML Schema validation. " + 68 " BPEL readers will not work properly.", e); 69 throw new AssertionError (e); 70 } 71 try { 72 factory.setAttribute("http://apache.org/xml/features/validation/schema-full-checking", Boolean.TRUE); 74 factory.setAttribute("http://apache.org/xml/features/validation/dynamic", Boolean.TRUE); 76 } 77 catch (IllegalArgumentException e) { 78 log.warn("The JAXP implementation is not Xerces. Cannot enable dynamic schema validation." + 79 " XML documents without xsi:schemaLocation in their root element will not parse."); 80 } 81 try { 82 DocumentBuilder documentBuilder = factory.newDocumentBuilder(); 83 documentBuilder.setEntityResolver(new LocalEntityResolver()); 84 return documentBuilder; 85 } 86 catch (ParserConfigurationException e) { 87 throw new RuntimeException ("could not create document builder", e); 88 } 89 } 90 }; 91 92 private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; 93 static final Log log = LogFactory.getLog(NodeUtil.class); 94 95 96 private NodeUtil() { 97 } 98 99 public static Element getElement(Node parentElem, String localName) { 100 return getElement(parentElem, null, localName); 101 } 102 103 public static Element getElement(Node parentElem, String namespaceURI, String localName) { 104 for (Node child = parentElem.getFirstChild(); child != null; child = child.getNextSibling()) { 105 if (QNameElementPredicate.evaluate(child, namespaceURI, localName)) { 106 return (Element ) child; 107 } 108 } 109 return null; 110 } 111 112 public static Iterator getElements(Node parentNode, String namespaceURI) { 113 return new FilterIterator(new NodeIterator(parentNode), new NamespaceElementPredicate(namespaceURI)); 114 } 115 116 public static Iterator getElements(Node parentNode, String namespaceURI, String localName) { 117 return new FilterIterator(new NodeIterator(parentNode), new QNameElementPredicate(namespaceURI, localName)); 118 } 119 120 public static Iterator getNodes(Node parentNode) { 121 return new NodeIterator(parentNode); 122 } 123 124 public static String getAttribute(Element ownerElem, String attrName) { 125 Attr attribute = ownerElem.getAttributeNode(attrName); 126 return attribute != null ? attribute.getValue() : null; 127 } 128 129 public static QName getQName(String prefixedName, Element contextElement) { 130 String prefix; 131 String namespaceURI; 132 String localPart; 133 134 int index = prefixedName.indexOf(':'); 135 if (index == -1) { 136 localPart = prefixedName; 137 prefix = ""; 138 namespaceURI = ""; 139 } 140 else { 141 localPart = prefixedName.substring(index + 1); 142 prefix = prefixedName.substring(0, index); 143 namespaceURI = DOMUtils.getNamespaceURIFromPrefix(contextElement, prefix); 144 } 145 return new QName (namespaceURI, localPart, prefix); 146 } 147 148 public static Object getValue(Node node) { 149 Object value = null; 150 switch (node.getNodeType()) { 151 case Node.ELEMENT_NODE: 152 value = getValue((Element ) node); 153 break; 154 default: 155 value = node.getNodeValue(); 156 } 157 return value; 158 } 159 160 public static Object getValue(Element elem) { 161 Object value; 162 Node firstChild = elem.getFirstChild(); 163 if (firstChild != null) { 164 switch (firstChild.getNodeType()) { 165 case Node.TEXT_NODE: 166 case Node.CDATA_SECTION_NODE: 167 case Node.COMMENT_NODE: 168 value = firstChild.getNodeValue(); 171 break; 172 default: { 173 Node child = firstChild.getNextSibling(); 174 if (child != null) { 176 ArrayList childNodes = new ArrayList (); 177 childNodes.add(firstChild); 178 do { 179 childNodes.add(child); 180 child = child.getNextSibling(); 181 } while (child != null); 182 value = childNodes; 184 } 185 else { 186 value = firstChild; 188 } 189 } 190 } 191 } 192 else { 193 value = null; 195 } 196 return value; 197 } 198 199 public static void setValue(Node node, Object value) { 200 switch (node.getNodeType()) { 201 case Node.ELEMENT_NODE: 202 setValue((Element ) node, value); 203 break; 204 case Node.ATTRIBUTE_NODE: 205 setValue((Attr ) node, value); 206 break; 207 default: 208 node.setNodeValue(value.toString()); 209 } 210 } 211 212 public static void setValue(Attr attr, Object value) { 213 if (value instanceof Node ) { 214 Node source = (Node ) value; 215 switch (source.getNodeType()) { 216 case Node.ELEMENT_NODE: 217 attr.setValue(getValue((Element ) source).toString()); 218 break; 219 default: 220 attr.setValue(source.getNodeValue()); 221 } 222 } 223 else { 224 attr.setValue(value.toString()); 225 } 226 } 227 228 public static void setValue(Element elem, Object value) { 229 if (value instanceof Node ) { 230 Node source = (Node ) value; 231 switch (source.getNodeType()) { 232 case Node.ELEMENT_NODE: { 233 copy(elem, (Element ) source); 234 break; 235 } 236 default: 237 setValue(elem, source.getNodeValue()); 238 } 239 } 240 else { 241 setValue(elem, value.toString()); 243 } 244 } 245 246 public static void setValue(Element elem, String value) { 247 Node firstChild = elem.getFirstChild(); 248 if (firstChild != null) { 249 switch (firstChild.getNodeType()) { 250 case Node.TEXT_NODE: 251 case Node.CDATA_SECTION_NODE: 252 case Node.COMMENT_NODE: 253 firstChild.setNodeValue(value); 255 break; 256 default: 257 removeChildNodes(elem); 258 elem.appendChild(elem.getOwnerDocument().createTextNode(value)); 259 } 260 } 261 else { 262 elem.appendChild(elem.getOwnerDocument().createTextNode(value)); 263 } 264 } 265 266 public static void copy(Element target, Element source) { 267 removeAttributes(target); 269 if (source.hasAttributes()) { 270 NamedNodeMap attributes = source.getAttributes(); 271 for (int i = 0, n = attributes.getLength(); i < n; i++) { 272 Attr attribute = (Attr ) attributes.item(i); 273 String namespaceURI = attribute.getNamespaceURI(); 274 if (namespaceURI == null) 275 target.setAttribute(attribute.getName(), attribute.getValue()); 276 else 277 target.setAttributeNS(namespaceURI, attribute.getName(), attribute.getValue()); 278 } 279 } 280 removeChildNodes(target); 282 Document document = target.getOwnerDocument(); 283 if (source.hasChildNodes()) { 284 for (Node child = source.getFirstChild(); child != null; child = child.getNextSibling()) { 285 Node newChild; 286 switch (child.getNodeType()) { 287 case Node.ELEMENT_NODE: { 288 Element newElem = document.createElementNS(child.getNamespaceURI(), child.getNodeName()); 289 copy(newElem, (Element ) child); 290 newChild = newElem; 291 break; 292 } 293 case Node.TEXT_NODE: 294 newChild = document.createTextNode(child.getNodeValue()); 295 break; 296 case Node.CDATA_SECTION_NODE: 297 newChild = document.createCDATASection(child.getNodeValue()); 298 break; 299 case Node.COMMENT_NODE: 300 newChild = document.createComment(child.getNodeValue()); 301 break; 302 default: 303 newChild = document.importNode(child, true); 304 } 305 target.appendChild(newChild); 306 } 307 } 308 } 309 310 public static void copy(SOAPElement target, Element source) throws SOAPException { 311 removeAttributes(target); 313 if (source.hasAttributes()) { 314 NamedNodeMap attributes = source.getAttributes(); 315 for (int i = 0, n = attributes.getLength(); i < n; i++) { 316 Attr attribute = (Attr ) attributes.item(i); 317 String namespaceURI = attribute.getNamespaceURI(); 318 if (namespaceURI == null) 319 target.setAttribute(attribute.getName(), attribute.getValue()); 320 else if (namespaceURI.equals(BpelConstants.NS_XMLNS)) 321 target.addNamespaceDeclaration(attribute.getLocalName(), attribute.getValue()); 322 else 323 target.setAttributeNS(namespaceURI, attribute.getName(), attribute.getValue()); 324 } 325 } 326 target.removeContents(); 327 if (source.hasChildNodes()) { 328 for (Node child = source.getFirstChild(); child != null; child = child.getNextSibling()) { 329 switch (child.getNodeType()) { 330 case Node.ELEMENT_NODE: { 331 String namespaceURI = child.getNamespaceURI(); 332 SOAPElement newElem = namespaceURI != null ? 333 target.addChildElement(child.getLocalName(), child.getPrefix(), namespaceURI) : 334 target.addChildElement(child.getLocalName(), ""); 335 copy(newElem, (Element ) child); 336 break; 337 } 338 case Node.COMMENT_NODE: 339 case Node.TEXT_NODE: 340 case Node.CDATA_SECTION_NODE: 341 target.addTextNode(child.getNodeValue()); 342 break; 343 } 345 } 346 } 347 } 348 349 public static Node appendForeignChild(Node node, Node importedChild) { 350 return node.appendChild(node.getOwnerDocument().importNode(importedChild, true)); 351 } 352 353 public static void addNamespace(Element elem, String namespaceURI, String prefix) { 354 elem.setAttributeNS(BpelConstants.NS_XMLNS, "xmlns:" + prefix, namespaceURI); 355 } 356 357 public static void removeAttributes(Element elem) { 358 if (elem.hasAttributes()) { 359 NamedNodeMap attributes = elem.getAttributes(); 360 for (int i = 0, n = attributes.getLength(); i < n; i++) { 361 elem.removeAttributeNode((Attr ) attributes.item(i)); 362 } 363 } 364 } 365 366 public static void removeChildNodes(Node node) { 367 if (node.hasChildNodes()) { 368 NodeList children = node.getChildNodes(); 369 for (int i = 0, n = children.getLength(); i < n; i++) { 370 node.removeChild(children.item(i)); 371 } 372 } 373 } 374 375 public static Document createDocument() { 376 return getDocumentBuilder().newDocument(); 377 } 378 379 385 public static Element parseElement(String text) throws SAXException { 386 try { 387 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 388 factory.setNamespaceAware(true); 389 DocumentBuilder builder = factory.newDocumentBuilder(); 390 return builder.parse(new InputSource (new StringReader (text))).getDocumentElement(); 391 } 392 catch (IOException e) { 393 log.error(e); 394 throw new RuntimeException ("i/o operation failed on a string reader", e); 395 } 396 catch (ParserConfigurationException e) { 397 throw new RuntimeException ("could not create document builder", e); 398 } 399 } 400 401 405 public static DocumentBuilder getDocumentBuilder() { 406 DocumentBuilder builder = (DocumentBuilder ) documentBuilderLocal.get(); 407 return builder; 408 } 409 410 public static Map getNamespaceDeclarations(Element elem) { 411 Map namespaceDeclarations = new HashMap (); 412 try { 413 Navigator nav = DocumentNavigator.getInstance(); 414 Iterator namespaceAxis = nav.getNamespaceAxisIterator(elem); 415 while (namespaceAxis.hasNext()) { 416 Object namespace = namespaceAxis.next(); 417 String prefix = nav.getNamespacePrefix(namespace); 418 String uri = nav.getNamespaceStringValue(namespace); 419 if (!namespaceDeclarations.containsKey(prefix)) { 420 namespaceDeclarations.put(prefix, uri); 421 } 422 } 423 namespaceDeclarations.remove(""); 425 } 426 catch (UnsupportedAxisException e) { 427 log.fatal("The Jaxen DOM navigator does not support the namespace axis." + 428 " Cannot determine the namespace declarations of DOM elements."); 429 throw new AssertionError (e); 430 } 431 return namespaceDeclarations; 432 } 433 434 public static Object evaluateXPath(String text, Object context, Map namespaces) { 435 try { 436 XPath xpath = new DOMXPath(text); 437 if (namespaces != null) { 438 xpath.setNamespaceContext(new SimpleNamespaceContext(namespaces)); 439 } 440 return xpath.evaluate(context); 441 } 442 catch (JaxenException e) { 443 log.error(e); 444 throw new RuntimeException ("could not evaluate xpath", e); 445 } 446 } 447 448 private static class NodeIterator implements Iterator { 449 450 private Node currentNode; 451 private Node lastReturned; 452 453 NodeIterator(Node parentNode) { 454 currentNode = parentNode.getFirstChild(); 455 } 456 457 public boolean hasNext() { 458 return currentNode != null; 459 } 460 461 public Object next() { 462 if (currentNode == null) throw new NoSuchElementException (); 463 lastReturned = currentNode; 464 currentNode = lastReturned.getNextSibling(); 465 return lastReturned; 466 } 467 468 public void remove() { 469 if (lastReturned == null) throw new IllegalStateException (); 470 Node parentNode = lastReturned.getParentNode(); 471 if (parentNode != null) 472 parentNode.removeChild(lastReturned); 473 lastReturned = null; 474 } 475 } 476 477 private static class NamespaceElementPredicate implements Predicate { 478 479 private String namespaceURI; 480 481 public NamespaceElementPredicate(String namespaceURI) { 482 this.namespaceURI = namespaceURI; 483 } 484 485 public boolean evaluate(Object arg) { 486 return evaluate((Node ) arg, namespaceURI); 487 } 488 489 static boolean evaluate(Node node, String namespaceURI) { 490 return node.getNodeType() == Node.ELEMENT_NODE 491 && (namespaceURI != null ? 492 namespaceURI.equals(node.getNamespaceURI()) 493 : node.getNamespaceURI() == null); 494 } 495 } 496 497 private static class QNameElementPredicate implements Predicate { 498 499 private String namespaceURI; 500 private String localName; 501 502 QNameElementPredicate(String namespaceURI, String localName) { 503 this.namespaceURI = namespaceURI; 504 this.localName = localName; 505 } 506 507 public boolean evaluate(Object arg) { 508 return evaluate((Node ) arg, namespaceURI, localName); 509 } 510 511 static boolean evaluate(Node node, String namespaceURI, String localName) { 512 return node.getNodeType() == Node.ELEMENT_NODE 513 && (namespaceURI != null ? 514 namespaceURI.equals(node.getNamespaceURI()) 515 : node.getNamespaceURI() == null) 516 && localName.equals(node.getLocalName()); 517 } 518 } 519 520 public static Transformer createUpgrader(URL upgraderURL) { 521 TransformerFactory factory = TransformerFactory.newInstance(); 522 Transformer upgrader = null; 523 InputStream stream = null; 524 try { 525 stream = upgraderURL.openStream(); 526 upgrader = factory.newTransformer(new StreamSource (stream)); 527 } 528 catch (TransformerConfigurationException e) { 529 log.error("unable to create upgrader " + upgraderURL, e); 530 } 531 catch (IOException e) { 532 log.error("unable to read upgrader " + upgraderURL, e); 533 } 534 finally { 535 try { 536 stream.close(); 537 } catch (IOException e) { 538 log.error("unable to close xsl template " + upgraderURL, e); 539 } 540 } 541 542 return upgrader; 543 } 544 } 545 | Popular Tags |