1/* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.xml.internal.ws.api.addressing; 27 28import com.sun.istack.internal.NotNull; 29import com.sun.istack.internal.Nullable; 30import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer; 31import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; 32import com.sun.xml.internal.stream.buffer.XMLStreamBufferResult; 33import com.sun.xml.internal.stream.buffer.XMLStreamBufferSource; 34import com.sun.xml.internal.stream.buffer.sax.SAXBufferProcessor; 35import com.sun.xml.internal.stream.buffer.stax.StreamReaderBufferProcessor; 36import com.sun.xml.internal.stream.buffer.stax.StreamWriterBufferCreator; 37import com.sun.xml.internal.ws.addressing.EndpointReferenceUtil; 38import com.sun.xml.internal.ws.addressing.W3CAddressingMetadataConstants; 39import com.sun.xml.internal.ws.addressing.WSEPRExtension; 40import com.sun.xml.internal.ws.addressing.model.InvalidAddressingHeaderException; 41import com.sun.xml.internal.ws.addressing.v200408.MemberSubmissionAddressingConstants; 42import com.sun.xml.internal.ws.api.message.Header; 43import com.sun.xml.internal.ws.api.message.HeaderList; 44import com.sun.xml.internal.ws.api.message.Message; 45import com.sun.xml.internal.ws.api.message.MessageHeaders; 46import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; 47import com.sun.xml.internal.ws.api.model.wsdl.WSDLExtension; 48import com.sun.xml.internal.ws.resources.AddressingMessages; 49import com.sun.xml.internal.ws.resources.ClientMessages; 50import com.sun.xml.internal.ws.spi.ProviderImpl; 51import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; 52import com.sun.xml.internal.ws.util.DOMUtil; 53import com.sun.xml.internal.ws.util.xml.XMLStreamWriterFilter; 54import com.sun.xml.internal.ws.util.xml.XmlUtil; 55import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; 56import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; 57import org.w3c.dom.Element; 58import org.xml.sax.*; 59import org.xml.sax.helpers.XMLFilterImpl; 60 61import javax.xml.bind.JAXBContext; 62import javax.xml.namespace.QName; 63import javax.xml.stream.XMLStreamException; 64import javax.xml.stream.XMLStreamReader; 65import javax.xml.stream.XMLStreamWriter; 66import javax.xml.transform.Source; 67import javax.xml.transform.TransformerException; 68import javax.xml.transform.sax.SAXSource; 69import javax.xml.transform.stream.StreamResult; 70import javax.xml.transform.stream.StreamSource; 71import javax.xml.ws.Dispatch; 72import javax.xml.ws.EndpointReference; 73import javax.xml.ws.Service; 74import javax.xml.ws.WebServiceException; 75import javax.xml.ws.WebServiceFeature; 76import java.io.InputStream; 77import java.io.StringWriter; 78import java.net.URI; 79import java.net.URL; 80import java.util.*; 81 82/** 83 * Internal representation of the EPR. 84 * 85 * <p> 86 * Instances of this class are immutable and thread-safe. 87 * 88 * @author Kohsuke Kawaguchi 89 * @author Rama Pulavarthi 90 * 91 * @see AddressingVersion#anonymousEpr 92 */ 93public final class WSEndpointReference implements WSDLExtension { 94 private final XMLStreamBuffer infoset; 95 /** 96 * Version of the addressing spec. 97 */ 98 private final AddressingVersion version; 99 100 /** 101 * Marked Reference parameters inside this EPR. 102 * 103 * Parsed when the object is created. can be empty but never null. 104 * @see #parse() 105 */ 106 private @NotNull Header[] referenceParameters; 107 private @NotNull String address; 108 109 private @NotNull QName rootElement; 110 /** 111 * Creates from the spec version of {@link EndpointReference}. 112 * 113 * <p> 114 * This method performs the data conversion, so it's slow. 115 * Do not use this method in a performance critical path. 116 */ 117 public WSEndpointReference(EndpointReference epr, AddressingVersion version) { 118 try { 119 MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); 120 epr.writeTo(new XMLStreamBufferResult(xsb)); 121 this.infoset = xsb; 122 this.version = version; 123 this.rootElement = new QName("EndpointReference", version.nsUri); 124 parse(); 125 } catch (XMLStreamException e) { 126 throw new WebServiceException(ClientMessages.FAILED_TO_PARSE_EPR(epr),e); 127 } 128 } 129 130 /** 131 * Creates from the spec version of {@link EndpointReference}. 132 * 133 * <p> 134 * This method performs the data conversion, so it's slow. 135 * Do not use this method in a performance critical path. 136 */ 137 public WSEndpointReference(EndpointReference epr) { 138 this(epr,AddressingVersion.fromSpecClass(epr.getClass())); 139 } 140 141 /** 142 * Creates a {@link WSEndpointReference} that wraps a given infoset. 143 */ 144 public WSEndpointReference(XMLStreamBuffer infoset, AddressingVersion version) { 145 try { 146 this.infoset = infoset; 147 this.version = version; 148 this.rootElement = new QName("EndpointReference", version.nsUri); 149 parse(); 150 } catch (XMLStreamException e) { 151 // this can never happen because XMLStreamBuffer never has underlying I/O error. 152 throw new AssertionError(e); 153 } 154 } 155 156 /** 157 * Creates a {@link WSEndpointReference} by parsing an infoset. 158 */ 159 public WSEndpointReference(InputStream infoset, AddressingVersion version) throws XMLStreamException { 160 this(XMLStreamReaderFactory.create(null,infoset,false),version); 161 } 162 163 /** 164 * Creates a {@link WSEndpointReference} from the given infoset. 165 * The {@link XMLStreamReader} must point to either a document or an element. 166 */ 167 public WSEndpointReference(XMLStreamReader in, AddressingVersion version) throws XMLStreamException { 168 this(XMLStreamBuffer.createNewBufferFromXMLStreamReader(in), version); 169 } 170 171 /** 172 * @see #WSEndpointReference(String, AddressingVersion) 173 */ 174 public WSEndpointReference(URL address, AddressingVersion version) { 175 this(address.toExternalForm(), version); 176 } 177 178 /** 179 * @see #WSEndpointReference(String, AddressingVersion) 180 */ 181 public WSEndpointReference(URI address, AddressingVersion version) { 182 this(address.toString(), version); 183 } 184 185 /** 186 * Creates a {@link WSEndpointReference} that only has an address. 187 */ 188 public WSEndpointReference(String address, AddressingVersion version) { 189 this.infoset = createBufferFromAddress(address,version); 190 this.version = version; 191 this.address = address; 192 this.rootElement = new QName("EndpointReference", version.nsUri); 193 this.referenceParameters = EMPTY_ARRAY; 194 } 195 196 private static XMLStreamBuffer createBufferFromAddress(String address, AddressingVersion version) { 197 try { 198 MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); 199 StreamWriterBufferCreator w = new StreamWriterBufferCreator(xsb); 200 w.writeStartDocument(); 201 w.writeStartElement(version.getPrefix(), 202 "EndpointReference", version.nsUri); 203 w.writeNamespace(version.getPrefix(), version.nsUri); 204 w.writeStartElement(version.getPrefix(),version.eprType.address, version.nsUri); 205 w.writeCharacters(address); 206 w.writeEndElement(); 207 w.writeEndElement(); 208 w.writeEndDocument(); 209 w.close(); 210 return xsb; 211 } catch (XMLStreamException e) { 212 // can never happen because we are writing to XSB 213 throw new AssertionError(e); 214 } 215 } 216 217 /** 218 * Creates an EPR from individual components. 219 * 220 * <p> 221 * This version takes various information about metadata, and creates an EPR that has 222 * the necessary embedded WSDL. 223 */ 224 public WSEndpointReference(@NotNull AddressingVersion version, 225 @NotNull String address, 226 @Nullable QName service, 227 @Nullable QName port, 228 @Nullable QName portType, 229 @Nullable List<Element> metadata, 230 @Nullable String wsdlAddress, 231 @Nullable List<Element> referenceParameters) { 232 this(version, address, service, port, portType, metadata, wsdlAddress, null, referenceParameters, null, null); 233 } 234 235 /** 236 * Creates an EPR from individual components. 237 * 238 * <p> 239 * This version takes various information about metadata, and creates an EPR that has 240 * the necessary embedded WSDL. 241 */ 242 public WSEndpointReference(@NotNull AddressingVersion version, 243 @NotNull String address, 244 @Nullable QName service, 245 @Nullable QName port, 246 @Nullable QName portType, 247 @Nullable List<Element> metadata, 248 @Nullable String wsdlAddress, 249 @Nullable List<Element> referenceParameters, 250 @Nullable Collection<EPRExtension> extns,@Nullable Map<QName, String> attributes) { 251 this(createBufferFromData(version, address, referenceParameters, service, port, portType, metadata, wsdlAddress, null, extns, attributes), 252 version ); 253 } 254 255 /** 256 * Creates an EPR from individual components. 257 * 258 * <p> 259 * This version takes various information about metadata, and creates an EPR that has 260 * the necessary embedded WSDL. 261 * @since JAX-WS 2.2 262 */ 263 public WSEndpointReference(@NotNull AddressingVersion version, 264 @NotNull String address, 265 @Nullable QName service, 266 @Nullable QName port, 267 @Nullable QName portType, 268 @Nullable List<Element> metadata, 269 @Nullable String wsdlAddress, 270 @Nullable String wsdlTargetNamepsace, 271 @Nullable List<Element> referenceParameters, 272 @Nullable List<Element> elements, @Nullable Map<QName, String> attributes) { 273 this( 274 createBufferFromData(version, address, referenceParameters, service, port, portType, metadata, wsdlAddress,wsdlTargetNamepsace, elements, attributes), 275 version ); 276 } 277 278 private static XMLStreamBuffer createBufferFromData(AddressingVersion version, String address, List<Element> referenceParameters, QName service, QName port, QName portType, 279 List<Element> metadata, String wsdlAddress, String wsdlTargetNamespace, @Nullable List<Element> elements, @Nullable Map<QName, String> attributes) { 280 281 StreamWriterBufferCreator writer = new StreamWriterBufferCreator(); 282 283 try { 284 writer.writeStartDocument(); 285 writer.writeStartElement(version.getPrefix(),"EndpointReference", version.nsUri); 286 writer.writeNamespace(version.getPrefix(),version.nsUri); 287 288 writePartialEPRInfoset(writer, version, address, referenceParameters, service, port, portType, 289 metadata,wsdlAddress, wsdlTargetNamespace, attributes); 290 291 //write extensibility elements in the EPR element 292 if (elements != null) { 293 for (Element e : elements) { 294 DOMUtil.serializeNode(e, writer); 295 } 296 } 297 298 writer.writeEndElement(); 299 writer.writeEndDocument(); 300 writer.flush(); 301 302 return writer.getXMLStreamBuffer(); 303 } catch (XMLStreamException e) { 304 throw new WebServiceException(e); 305 } 306 } 307 308 private static XMLStreamBuffer createBufferFromData(AddressingVersion version, String address, List<Element> referenceParameters, QName service, QName port, QName portType, 309 List<Element> metadata, String wsdlAddress, String wsdlTargetNamespace, @Nullable Collection<EPRExtension> extns, @Nullable Map<QName, String> attributes) { 310 311 StreamWriterBufferCreator writer = new StreamWriterBufferCreator(); 312 313 try { 314 writer.writeStartDocument(); 315 writer.writeStartElement(version.getPrefix(),"EndpointReference", version.nsUri); 316 writer.writeNamespace(version.getPrefix(),version.nsUri); 317 318 writePartialEPRInfoset(writer, version, address, referenceParameters, service, port, portType, 319 metadata,wsdlAddress, wsdlTargetNamespace, attributes); 320 321 //write extensibility elements in the EPR element 322 if (extns != null) { 323 for (EPRExtension e : extns) { 324 XMLStreamReaderToXMLStreamWriter c = new XMLStreamReaderToXMLStreamWriter(); 325 XMLStreamReader r = e.readAsXMLStreamReader(); 326 c.bridge(r, writer); 327 XMLStreamReaderFactory.recycle(r); 328 } 329 } 330 331 writer.writeEndElement(); 332 writer.writeEndDocument(); 333 writer.flush(); 334 335 return writer.getXMLStreamBuffer(); 336 } catch (XMLStreamException e) { 337 throw new WebServiceException(e); 338 } 339 } 340 341 private static void writePartialEPRInfoset(StreamWriterBufferCreator writer, AddressingVersion version, String address, List<Element> referenceParameters, QName service, QName port, QName portType, 342 List<Element> metadata, String wsdlAddress, String wsdlTargetNamespace, @Nullable Map<QName, String> attributes) throws XMLStreamException { 343 //add extensibile attributes on the EPR element 344 if (attributes != null) { 345 for (Map.Entry<QName, String> entry : attributes.entrySet()) { 346 QName qname = entry.getKey(); 347 writer.writeAttribute(qname.getPrefix(), qname.getNamespaceURI(), qname.getLocalPart(), entry.getValue()); 348 } 349 } 350 351 writer.writeStartElement(version.getPrefix(), version.eprType.address, version.nsUri); 352 writer.writeCharacters(address); 353 writer.writeEndElement(); 354 //When the size of ReferenceParametes is zero, the ReferenceParametes element will not be written. 355 if(referenceParameters != null && referenceParameters.size() > 0) { 356 writer.writeStartElement(version.getPrefix(), version.eprType.referenceParameters, version.nsUri); 357 for (Element e : referenceParameters) { 358 DOMUtil.serializeNode(e, writer); 359 } 360 writer.writeEndElement(); 361 } 362 363 switch (version) { 364 case W3C: 365 writeW3CMetaData(writer, service, port, portType, metadata, wsdlAddress, wsdlTargetNamespace); 366 break; 367 368 case MEMBER: 369 writeMSMetaData(writer, service, port, portType, metadata); 370 if (wsdlAddress != null) { 371 //Inline the wsdl as extensibility element 372 //Write mex:Metadata wrapper 373 writer.writeStartElement(MemberSubmissionAddressingConstants.MEX_METADATA.getPrefix(), 374 MemberSubmissionAddressingConstants.MEX_METADATA.getLocalPart(), 375 MemberSubmissionAddressingConstants.MEX_METADATA.getNamespaceURI()); 376 writer.writeStartElement(MemberSubmissionAddressingConstants.MEX_METADATA_SECTION.getPrefix(), 377 MemberSubmissionAddressingConstants.MEX_METADATA_SECTION.getLocalPart(), 378 MemberSubmissionAddressingConstants.MEX_METADATA_SECTION.getNamespaceURI()); 379 writer.writeAttribute(MemberSubmissionAddressingConstants.MEX_METADATA_DIALECT_ATTRIBUTE, 380 MemberSubmissionAddressingConstants.MEX_METADATA_DIALECT_VALUE); 381 382 writeWsdl(writer, service, wsdlAddress); 383 384 writer.writeEndElement(); 385 writer.writeEndElement(); 386 } 387 388 break; 389 } 390 } 391 392 private static boolean isEmty(QName qname) { 393 return qname == null || qname.toString().trim().length()== 0; 394 } 395 396 private static void writeW3CMetaData(StreamWriterBufferCreator writer, 397 QName service, 398 QName port, 399 QName portType, List<Element> metadata, 400 String wsdlAddress, String wsdlTargetNamespace) throws XMLStreamException { 401 402 403 //.NET treate empty metaData element as bad request. 404 if (isEmty(service) && isEmty(port) && isEmty(portType) && metadata == null/* && wsdlAddress == null*/) { 405 return; 406 } 407 408 writer.writeStartElement(AddressingVersion.W3C.getPrefix(), 409 AddressingVersion.W3C.eprType.wsdlMetadata.getLocalPart(), AddressingVersion.W3C.nsUri); 410 writer.writeNamespace(AddressingVersion.W3C.getWsdlPrefix(), 411 AddressingVersion.W3C.wsdlNsUri); 412 //write wsdliLication as defined in WS-Addressing 1.0 Metadata spec 413 if(wsdlAddress != null) { 414 writeWsdliLocation(writer, service, wsdlAddress, wsdlTargetNamespace); 415 } 416 417 //Write Interface info 418 if (portType != null) { 419 writer.writeStartElement(W3CAddressingMetadataConstants.WSAM_PREFIX_NAME, 420 AddressingVersion.W3C.eprType.portTypeName, 421 W3CAddressingMetadataConstants.WSAM_NAMESPACE_NAME); 422 writer.writeNamespace(W3CAddressingMetadataConstants.WSAM_PREFIX_NAME, 423 W3CAddressingMetadataConstants.WSAM_NAMESPACE_NAME); 424 String portTypePrefix = portType.getPrefix(); 425 if (portTypePrefix == null || portTypePrefix.equals("")) { 426 //TODO check prefix again 427 portTypePrefix = "wsns"; 428 } 429 writer.writeNamespace(portTypePrefix, portType.getNamespaceURI()); 430 writer.writeCharacters(portTypePrefix + ":" + portType.getLocalPart()); 431 writer.writeEndElement(); 432 } 433 if (service != null) { 434 //Write service and Port info 435 if (!(service.getNamespaceURI().equals("") || service.getLocalPart().equals(""))) { 436 writer.writeStartElement(W3CAddressingMetadataConstants.WSAM_PREFIX_NAME, 437 AddressingVersion.W3C.eprType.serviceName, 438 W3CAddressingMetadataConstants.WSAM_NAMESPACE_NAME); 439 writer.writeNamespace(W3CAddressingMetadataConstants.WSAM_PREFIX_NAME, 440 W3CAddressingMetadataConstants.WSAM_NAMESPACE_NAME); 441 String servicePrefix = service.getPrefix(); 442 if (servicePrefix == null || servicePrefix.equals("")) { 443 //TODO check prefix again 444 servicePrefix = "wsns"; 445 } 446 writer.writeNamespace(servicePrefix, service.getNamespaceURI()); 447 if (port != null) { 448 writer.writeAttribute(AddressingVersion.W3C.eprType.portName, port.getLocalPart()); 449 } 450 writer.writeCharacters(servicePrefix + ":" + service.getLocalPart()); 451 writer.writeEndElement(); 452 } 453 } 454 /* 455 //Inline the wsdl 456 if (wsdlAddress != null) { 457 writeWsdl(writer, service, wsdlAddress); 458 } 459 */ 460 //Add the extra metadata Elements 461 if (metadata != null) { 462 for (Element e : metadata) { 463 DOMUtil.serializeNode(e, writer); 464 } 465 } 466 writer.writeEndElement(); 467 468 } 469 470 /** 471 * @param writer the writer should be at the start of element. 472 * @param service Namespace URI of servcie is used as targetNamespace of wsdl if wsdlTargetNamespace is not null 473 * @param wsdlAddress wsdl location 474 * @param wsdlTargetNamespace targetnamespace of wsdl to be put in wsdliLocation 475 * 476 */ 477 private static void writeWsdliLocation(StreamWriterBufferCreator writer, QName service,String wsdlAddress,String wsdlTargetNamespace) throws XMLStreamException { 478 String wsdliLocation = ""; 479 if(wsdlTargetNamespace != null) { 480 wsdliLocation = wsdlTargetNamespace + " "; 481 } else if (service != null) { 482 wsdliLocation = service.getNamespaceURI() + " "; 483 } else { 484 throw new WebServiceException("WSDL target Namespace cannot be resolved"); 485 } 486 wsdliLocation += wsdlAddress; 487 writer.writeNamespace(W3CAddressingMetadataConstants.WSAM_WSDLI_ATTRIBUTE_PREFIX, 488 W3CAddressingMetadataConstants.WSAM_WSDLI_ATTRIBUTE_NAMESPACE); 489 writer.writeAttribute(W3CAddressingMetadataConstants.WSAM_WSDLI_ATTRIBUTE_PREFIX, 490 W3CAddressingMetadataConstants.WSAM_WSDLI_ATTRIBUTE_NAMESPACE, 491 W3CAddressingMetadataConstants.WSAM_WSDLI_ATTRIBUTE_LOCALNAME, 492 wsdliLocation); 493 494 } 495 private static void writeMSMetaData(StreamWriterBufferCreator writer, 496 QName service, 497 QName port, 498 QName portType, List<Element> metadata) throws XMLStreamException { 499 // TODO: write ReferenceProperties 500 //TODO: write ReferenceParameters 501 if (portType != null) { 502 //Write Interface info 503 writer.writeStartElement(AddressingVersion.MEMBER.getPrefix(), 504 AddressingVersion.MEMBER.eprType.portTypeName, 505 AddressingVersion.MEMBER.nsUri); 506 507 508 String portTypePrefix = portType.getPrefix(); 509 if (portTypePrefix == null || portTypePrefix.equals("")) { 510 //TODO check prefix again 511 portTypePrefix = "wsns"; 512 } 513 writer.writeNamespace(portTypePrefix, portType.getNamespaceURI()); 514 writer.writeCharacters(portTypePrefix + ":" + portType.getLocalPart()); 515 writer.writeEndElement(); 516 } 517 //Write service and Port info 518 if (service != null) { 519 if (!(service.getNamespaceURI().equals("") || service.getLocalPart().equals(""))) { 520 writer.writeStartElement(AddressingVersion.MEMBER.getPrefix(), 521 AddressingVersion.MEMBER.eprType.serviceName, 522 AddressingVersion.MEMBER.nsUri); 523 String servicePrefix = service.getPrefix(); 524 if (servicePrefix == null || servicePrefix.equals("")) { 525 //TODO check prefix again 526 servicePrefix = "wsns"; 527 } 528 writer.writeNamespace(servicePrefix, service.getNamespaceURI()); 529 if (port != null) { 530 writer.writeAttribute(AddressingVersion.MEMBER.eprType.portName, 531 port.getLocalPart()); 532 } 533 writer.writeCharacters(servicePrefix + ":" + service.getLocalPart()); 534 writer.writeEndElement(); 535 } 536 } 537 } 538 539 private static void writeWsdl(StreamWriterBufferCreator writer, QName service, String wsdlAddress) throws XMLStreamException { 540 // Inline-wsdl 541 writer.writeStartElement(WSDLConstants.PREFIX_NS_WSDL, 542 WSDLConstants.QNAME_DEFINITIONS.getLocalPart(), 543 WSDLConstants.NS_WSDL); 544 writer.writeNamespace(WSDLConstants.PREFIX_NS_WSDL, WSDLConstants.NS_WSDL); 545 writer.writeStartElement(WSDLConstants.PREFIX_NS_WSDL, 546 WSDLConstants.QNAME_IMPORT.getLocalPart(), 547 WSDLConstants.NS_WSDL); 548 writer.writeAttribute("namespace", service.getNamespaceURI()); 549 writer.writeAttribute("location", wsdlAddress); 550 writer.writeEndElement(); 551 writer.writeEndElement(); 552 } 553 554 555 556 /** 557 * Converts from {@link EndpointReference}. 558 * 559 * This handles null {@link EndpointReference} correctly. 560 * Call {@link #WSEndpointReference(EndpointReference)} directly 561 * if you know it's not null. 562 */ 563 public static @Nullable 564 WSEndpointReference create(@Nullable EndpointReference epr) { 565 if (epr != null) { 566 return new WSEndpointReference(epr); 567 } else { 568 return null; 569 } 570 } 571 572 /** 573 * @see #createWithAddress(String) 574 */ 575 public @NotNull WSEndpointReference createWithAddress(@NotNull URI newAddress) { 576 return createWithAddress(newAddress.toString()); 577 } 578 579 /** 580 * @see #createWithAddress(String) 581 */ 582 public @NotNull WSEndpointReference createWithAddress(@NotNull URL newAddress) { 583 return createWithAddress(newAddress.toString()); 584 } 585 586 /** 587 * Creates a new {@link WSEndpointReference} by replacing the address of this EPR 588 * to the new one. 589 * 590 * <p> 591 * The following example shows how you can use this to force an HTTPS EPR, 592 * when the endpoint can serve both HTTP and HTTPS requests. 593 * <pre> 594 * if(epr.getAddress().startsWith("http:")) 595 * epr = epr.createWithAddress("https:"+epr.getAddress().substring(5)); 596 * </pre> 597 * 598 * @param newAddress 599 * This is a complete URL to be written inside <Adress> element of the EPR, 600 * such as "http://foo.bar/abc/def" 601 */ 602 public @NotNull WSEndpointReference createWithAddress(@NotNull final String newAddress) { 603 MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); 604 XMLFilterImpl filter = new XMLFilterImpl() { 605 private boolean inAddress = false; 606 @Override 607 public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { 608 if (localName.equals("Address") && uri.equals(version.nsUri)) { 609 inAddress = true; 610 } 611 super.startElement(uri,localName,qName,atts); 612 } 613 614 @Override 615 public void characters(char ch[], int start, int length) throws SAXException { 616 if (!inAddress) { 617 super.characters(ch, start, length); 618 } 619 } 620 621 @Override 622 public void endElement(String uri, String localName, String qName) throws SAXException { 623 if (inAddress) { 624 super.characters(newAddress.toCharArray(),0,newAddress.length()); 625 } 626 inAddress = false; 627 super.endElement(uri, localName, qName); 628 } 629 }; 630 filter.setContentHandler(xsb.createFromSAXBufferCreator()); 631 try { 632 infoset.writeTo(filter,false); 633 } catch (SAXException e) { 634 throw new AssertionError(e); // impossible since we are writing from XSB to XSB. 635 } 636 637 return new WSEndpointReference(xsb,version); 638 } 639 640 /** 641 * Convert the EPR to the spec version. The actual type of 642 * {@link EndpointReference} to be returned depends on which version 643 * of the addressing spec this EPR conforms to. 644 * 645 * @throws WebServiceException 646 * if the conversion fails, which can happen if the EPR contains 647 * invalid infoset (wrong namespace URI, etc.) 648 */ 649 public @NotNull EndpointReference toSpec() { 650 return ProviderImpl.INSTANCE.readEndpointReference(asSource("EndpointReference")); 651 } 652 653 /** 654 * Converts the EPR to the specified spec version. 655 * 656 * If the {@link #getVersion() the addressing version in use} and 657 * the given class is different, then this may involve version conversion. 658 */ 659 public @NotNull <T extends EndpointReference> T toSpec(Class<T> clazz) { 660 return EndpointReferenceUtil.transform(clazz,toSpec()); 661 } 662 663 /** 664 * Creates a proxy that can be used to talk to this EPR. 665 * 666 * <p> 667 * All the normal WS-Addressing processing happens automatically, 668 * such as setting the endpoint address to {@link #getAddress() the address}, 669 * and sending the reference parameters associated with this EPR as 670 * headers, etc. 671 */ 672 public @NotNull <T> T getPort(@NotNull Service jaxwsService, 673 @NotNull Class<T> serviceEndpointInterface, 674 WebServiceFeature... features) { 675 // TODO: implement it in a better way 676 return jaxwsService.getPort(toSpec(),serviceEndpointInterface,features); 677 } 678 679 /** 680 * Creates a {@link Dispatch} that can be used to talk to this EPR. 681 * 682 * <p> 683 * All the normal WS-Addressing processing happens automatically, 684 * such as setting the endpoint address to {@link #getAddress() the address}, 685 * and sending the reference parameters associated with this EPR as 686 * headers, etc. 687 */ 688 public @NotNull <T> Dispatch<T> createDispatch( 689 @NotNull Service jaxwsService, 690 @NotNull Class<T> type, 691 @NotNull Service.Mode mode, 692 WebServiceFeature... features) { 693 694 // TODO: implement it in a better way 695 return jaxwsService.createDispatch(toSpec(),type,mode,features); 696 } 697 698 /** 699 * Creates a {@link Dispatch} that can be used to talk to this EPR. 700 * 701 * <p> 702 * All the normal WS-Addressing processing happens automatically, 703 * such as setting the endpoint address to {@link #getAddress() the address}, 704 * and sending the reference parameters associated with this EPR as 705 * headers, etc. 706 */ 707 public @NotNull Dispatch<Object> createDispatch( 708 @NotNull Service jaxwsService, 709 @NotNull JAXBContext context, 710 @NotNull Service.Mode mode, 711 WebServiceFeature... features) { 712 713 // TODO: implement it in a better way 714 return jaxwsService.createDispatch(toSpec(),context,mode,features); 715 } 716 717 /** 718 * Gets the addressing version of this EPR. 719 */ 720 public @NotNull AddressingVersion getVersion() { 721 return version; 722 } 723 724 /** 725 * The value of the <wsa:address> header. 726 */ 727 public @NotNull String getAddress() { 728 return address; 729 } 730 731 /** 732 * Returns true if this has anonymous URI as the {@link #getAddress() address}. 733 */ 734 public boolean isAnonymous() { 735 return address.equals(version.anonymousUri); 736 } 737 738 /** 739 * Returns true if this has {@link AddressingVersion#noneUri none URI} 740 * as the {@link #getAddress() address}. 741 */ 742 public boolean isNone() { 743 return address.equals(version.noneUri); 744 } 745 746 /** 747 * Parses inside EPR and mark all reference parameters. 748 */ 749 private void parse() throws XMLStreamException { 750 // TODO: validate the EPR structure. 751 // check for non-existent Address, that sort of things. 752 753 StreamReaderBufferProcessor xsr = infoset.readAsXMLStreamReader(); 754 755 // parser should be either at the start element or the start document 756 if (xsr.getEventType()==XMLStreamReader.START_DOCUMENT) { 757 xsr.nextTag(); 758 } 759 assert xsr.getEventType()==XMLStreamReader.START_ELEMENT; 760 761 String rootLocalName = xsr.getLocalName(); 762 if(!xsr.getNamespaceURI().equals(version.nsUri)) { 763 throw new WebServiceException(AddressingMessages.WRONG_ADDRESSING_VERSION( 764 version.nsUri, xsr.getNamespaceURI())); 765 } 766 767 this.rootElement = new QName(xsr.getNamespaceURI(), rootLocalName); 768 769 // since often EPR doesn't have a reference parameter, create array lazily 770 List<Header> marks=null; 771 772 while(xsr.nextTag()==XMLStreamReader.START_ELEMENT) { 773 String localName = xsr.getLocalName(); 774 if(version.isReferenceParameter(localName)) { 775 XMLStreamBuffer mark; 776 while((mark = xsr.nextTagAndMark())!=null) { 777 if (marks==null) { 778 marks = new ArrayList<Header>(); 779 } 780 781 // TODO: need a different header for member submission version 782 marks.add(version.createReferenceParameterHeader( 783 mark, xsr.getNamespaceURI(), xsr.getLocalName())); 784 XMLStreamReaderUtil.skipElement(xsr); 785 } 786 } else 787 if(localName.equals("Address")) { 788 if (address!=null) { 789 throw new InvalidAddressingHeaderException(new QName(version.nsUri,rootLocalName),AddressingVersion.fault_duplicateAddressInEpr); 790 } 791 address = xsr.getElementText().trim(); 792 } else { 793 XMLStreamReaderUtil.skipElement(xsr); 794 } 795 } 796 797 // hit to </EndpointReference> by now 798 799 if (marks==null) { 800 this.referenceParameters = EMPTY_ARRAY; 801 } else { 802 this.referenceParameters = marks.toArray(new Header[marks.size()]); 803 } 804 805 if (address==null) { 806 throw new InvalidAddressingHeaderException(new QName(version.nsUri,rootLocalName),version.fault_missingAddressInEpr); 807 } 808 } 809 810 811 /** 812 * Reads this EPR as {@link XMLStreamReader}. 813 * 814 * @param localName 815 * EPR uses a different root tag name depending on the context. 816 * The returned {@link XMLStreamReader} will use the given local name 817 * for the root element name. 818 */ 819 public XMLStreamReader read(final @NotNull String localName) throws XMLStreamException { 820 return new StreamReaderBufferProcessor(infoset) { 821 @Override 822 protected void processElement(String prefix, String uri, String _localName, boolean inScope) { 823 if (_depth == 0) { 824 _localName = localName; 825 } 826 super.processElement(prefix, uri, _localName, isInscope(infoset,_depth)); 827 } 828 }; 829 } 830 831 private boolean isInscope(XMLStreamBuffer buffer, int depth) { 832 return buffer.getInscopeNamespaces().size() > 0 && depth ==0; 833 } 834 835 /** 836 * Returns a {@link Source} that represents this EPR. 837 * 838 * @param localName 839 * EPR uses a different root tag name depending on the context. 840 * The returned {@link Source} will use the given local name 841 * for the root element name. 842 */ 843 public Source asSource(@NotNull String localName) { 844 return new SAXSource(new SAXBufferProcessorImpl(localName),new InputSource()); 845 } 846 847 /** 848 * Writes this EPR to the given {@link ContentHandler}. 849 * 850 * @param localName 851 * EPR uses a different root tag name depending on the context. 852 * The returned {@link Source} will use the given local name 853 * for the root element name. 854 * @param fragment 855 * If true, generate a fragment SAX events without start/endDocument callbacks. 856 * If false, generate a full XML document event. 857 */ 858 public void writeTo(@NotNull String localName, ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { 859 SAXBufferProcessorImpl p = new SAXBufferProcessorImpl(localName); 860 p.setContentHandler(contentHandler); 861 p.setErrorHandler(errorHandler); 862 p.process(infoset,fragment); 863 } 864 865 /** 866 * Writes this EPR into the given writer. 867 * 868 * @param localName 869 * EPR uses a different root tag name depending on the context. 870 * The returned {@link Source} will use the given local name 871 */ 872 public void writeTo(final @NotNull String localName, @NotNull XMLStreamWriter w) throws XMLStreamException { 873 infoset.writeToXMLStreamWriter(new XMLStreamWriterFilter(w) { 874 private boolean root=true; 875 876 @Override 877 public void writeStartDocument() throws XMLStreamException { 878 } 879 880 @Override 881 public void writeStartDocument(String encoding, String version) throws XMLStreamException { 882 } 883 884 @Override 885 public void writeStartDocument(String version) throws XMLStreamException { 886 } 887 888 @Override 889 public void writeEndDocument() throws XMLStreamException { 890 } 891 892 private String override(String ln) { 893 if(root) { 894 root = false; 895 return localName; 896 } 897 return ln; 898 } 899 900 @Override 901 public void writeStartElement(String localName) throws XMLStreamException { 902 super.writeStartElement(override(localName)); 903 } 904 905 @Override 906 public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { 907 super.writeStartElement(namespaceURI, override(localName)); 908 } 909 910 @Override 911 public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { 912 super.writeStartElement(prefix, override(localName), namespaceURI); 913 } 914 },true/*write as fragment*/); 915 } 916 917 /** 918 * Returns a {@link Header} that wraps this {@link WSEndpointReference}. 919 * 920 * <p> 921 * The returned header is immutable too, and can be reused with 922 * many {@link Message}s. 923 * 924 * @param rootTagName 925 * The header tag name to be used, such as <ReplyTo> or <FaultTo>. 926 * (It's bit ugly that this method takes {@link QName} and not just local name, 927 * unlike other methods. If it's making the caller's life miserable, then 928 * we can talk.) 929 */ 930 public Header createHeader(QName rootTagName) { 931 return new EPRHeader(rootTagName,this); 932 } 933 934 /** 935 * Copies all the reference parameters in this EPR as headers 936 * to the given {@link HeaderList}. 937 * @deprecated - use addReferenceParametersToList(MessageHeaders) 938 */ 939 @SuppressWarnings("ManualArrayToCollectionCopy") 940 public void addReferenceParametersToList(HeaderList outbound) { 941 // implemented through iteration because of unsupportedoperation exception thrown from addAll method on headerlist 942 // do not change 943 for (Header header : referenceParameters) { 944 outbound.add(header); 945 } 946 } 947 948 /** 949 * Copies all the reference parameters in this EPR as headers 950 * to the given {@link MessageHeaders}. 951 */ 952 public void addReferenceParametersToList(MessageHeaders outbound) { 953 for (Header header : referenceParameters) { 954 outbound.add(header); 955 } 956 } 957 /** 958 * Copies all the reference parameters from the given {@link HeaderList} 959 * to this EPR 960 */ 961 public void addReferenceParameters(HeaderList headers) { 962 if (headers != null) { 963 Header[] hs = new Header[referenceParameters.length + headers.size()]; 964 System.arraycopy(referenceParameters, 0, hs, 0, referenceParameters.length); 965 int i = referenceParameters.length; 966 for (Header h : headers) { 967 hs[i++] = h; 968 } 969 referenceParameters = hs; 970 } 971 } 972 973 /** 974 * Dumps the EPR infoset in a human-readable string. 975 */ 976 @Override 977 public String toString() { 978 try { 979 // debug convenience 980 StringWriter sw = new StringWriter(); 981 XmlUtil.newTransformer().transform(asSource("EndpointReference"),new StreamResult(sw)); 982 return sw.toString(); 983 } catch (TransformerException e) { 984 return e.toString(); 985 } 986 } 987 988 /** 989 * Gets the QName of the EndpointReference element. 990 * @return 991 */ 992 @Override 993 public QName getName() { 994 return rootElement; 995 } 996 997 /** 998 * Filtering {@link SAXBufferProcessor} that replaces the root tag name. 999 */ 1000 class SAXBufferProcessorImpl extends SAXBufferProcessor { 1001 private final String rootLocalName; 1002 private boolean root=true; 1003 1004 public SAXBufferProcessorImpl(String rootLocalName) { 1005 super(infoset,false); 1006 this.rootLocalName = rootLocalName; 1007 } 1008 1009 @Override 1010 protected void processElement(String uri, String localName, String qName, boolean inscope) throws SAXException { 1011 if(root) { 1012 root = false; 1013 1014 if(qName.equals(localName)) { 1015 qName = localName = rootLocalName; 1016 } else { 1017 localName = rootLocalName; 1018 int idx = qName.indexOf(':'); 1019 qName = qName.substring(0,idx+1)+rootLocalName; 1020 } 1021 } 1022 super.processElement(uri, localName, qName, inscope); 1023 } 1024 } 1025 1026 private static final OutboundReferenceParameterHeader[] EMPTY_ARRAY = new OutboundReferenceParameterHeader[0]; 1027 1028 private Map<QName, EPRExtension> rootEprExtensions; 1029 1030 /** 1031 * Represents an extensibility element inside an EndpointReference 1032 */ 1033 public static abstract class EPRExtension { 1034 public abstract XMLStreamReader readAsXMLStreamReader() throws XMLStreamException; 1035 1036 public abstract QName getQName(); 1037 } 1038 1039 /** 1040 * Returns the first extensibility element inside EPR root element with input QName. 1041 */ 1042 public @Nullable 1043 EPRExtension getEPRExtension(final QName extnQName) throws XMLStreamException { 1044 if (rootEprExtensions == null) { 1045 parseEPRExtensions(); 1046 } 1047 return rootEprExtensions.get(extnQName); 1048 } 1049 1050 public @NotNull Collection<EPRExtension> getEPRExtensions() throws XMLStreamException { 1051 if (rootEprExtensions == null) { 1052 parseEPRExtensions(); 1053 } 1054 return rootEprExtensions.values(); 1055 } 1056 1057 private void parseEPRExtensions() throws XMLStreamException { 1058 1059 rootEprExtensions = new HashMap<QName, EPRExtension>(); 1060 1061 1062 StreamReaderBufferProcessor xsr = infoset.readAsXMLStreamReader(); 1063 1064 // parser should be either at the start element or the start document 1065 if (xsr.getEventType() == XMLStreamReader.START_DOCUMENT) { 1066 xsr.nextTag(); 1067 } 1068 assert xsr.getEventType() == XMLStreamReader.START_ELEMENT; 1069 1070 if (!xsr.getNamespaceURI().equals(version.nsUri)) { 1071 throw new WebServiceException(AddressingMessages.WRONG_ADDRESSING_VERSION( 1072 version.nsUri, xsr.getNamespaceURI())); 1073 } 1074 1075 // since often EPR doesn't have extensions, create array lazily 1076 XMLStreamBuffer mark; 1077 String localName; 1078 String ns; 1079 while ((mark = xsr.nextTagAndMark()) != null) { 1080 localName = xsr.getLocalName(); 1081 ns = xsr.getNamespaceURI(); 1082 if (version.nsUri.equals(ns)) { 1083 //EPR extensions do not use the same namespace of the Addressing Version. 1084 //Not an extension - SKIP 1085 XMLStreamReaderUtil.skipElement(xsr); 1086 } else { 1087 QName qn = new QName(ns, localName); 1088 rootEprExtensions.put(qn, new WSEPRExtension(mark,qn)); 1089 XMLStreamReaderUtil.skipElement(xsr); 1090 } 1091 } 1092 // hit to </EndpointReference> by now 1093 } 1094 1095 /** 1096 * Parses the metadata inside this EPR and obtains it in a easy-to-process form. 1097 * 1098 * <p> 1099 * See {@link Metadata} class for what's avaliable as "metadata". 1100 */ 1101 public @NotNull Metadata getMetaData() { 1102 return new Metadata(); 1103 } 1104 1105 /** 1106 * Parses the Metadata in an EPR and provides convenience methods to access 1107 * the metadata. 1108 * 1109 */ 1110 public class Metadata { 1111 private @Nullable QName serviceName; 1112 private @Nullable QName portName; 1113 private @Nullable QName portTypeName; //interfaceName 1114 private @Nullable Source wsdlSource; 1115 private @Nullable String wsdliLocation; 1116 1117 public @Nullable QName getServiceName(){ 1118 return serviceName; 1119 } 1120 public @Nullable QName getPortName(){ 1121 return portName; 1122 } 1123 public @Nullable QName getPortTypeName(){ 1124 return portTypeName; 1125 } 1126 public @Nullable Source getWsdlSource(){ 1127 return wsdlSource; 1128 } 1129 public @Nullable String getWsdliLocation(){ 1130 return wsdliLocation; 1131 } 1132 1133 private Metadata() { 1134 try { 1135 parseMetaData(); 1136 } catch (XMLStreamException e) { 1137 throw new WebServiceException(e); 1138 } 1139 } 1140 1141 /** 1142 * Parses the Metadata section of the EPR. 1143 */ 1144 private void parseMetaData() throws XMLStreamException { 1145 StreamReaderBufferProcessor xsr = infoset.readAsXMLStreamReader(); 1146 1147 // parser should be either at the start element or the start document 1148 if (xsr.getEventType() == XMLStreamReader.START_DOCUMENT) { 1149 xsr.nextTag(); 1150 } 1151 assert xsr.getEventType() == XMLStreamReader.START_ELEMENT; 1152 String rootElement = xsr.getLocalName(); 1153 if (!xsr.getNamespaceURI().equals(version.nsUri)) { 1154 throw new WebServiceException(AddressingMessages.WRONG_ADDRESSING_VERSION( 1155 version.nsUri, xsr.getNamespaceURI())); 1156 } 1157 String localName; 1158 String ns; 1159 if (version == AddressingVersion.W3C) { 1160 do { 1161 //If the current element is metadata enclosure, look inside 1162 if (xsr.getLocalName().equals(version.eprType.wsdlMetadata.getLocalPart())) { 1163 String wsdlLoc = xsr.getAttributeValue("http://www.w3.org/ns/wsdl-instance","wsdlLocation"); 1164 if (wsdlLoc != null) { 1165 wsdliLocation = wsdlLoc.trim(); 1166 } 1167 XMLStreamBuffer mark; 1168 while ((mark = xsr.nextTagAndMark()) != null) { 1169 localName = xsr.getLocalName(); 1170 ns = xsr.getNamespaceURI(); 1171 if (localName.equals(version.eprType.serviceName)) { 1172 String portStr = xsr.getAttributeValue(null, version.eprType.portName); 1173 if (serviceName != null) { 1174 throw new RuntimeException("More than one "+ version.eprType.serviceName +" element in EPR Metadata"); 1175 } 1176 serviceName = getElementTextAsQName(xsr); 1177 if (serviceName != null && portStr != null) { 1178 portName = new QName(serviceName.getNamespaceURI(), portStr); 1179 } 1180 } else if (localName.equals(version.eprType.portTypeName)) { 1181 if (portTypeName != null) { 1182 throw new RuntimeException("More than one "+ version.eprType.portTypeName +" element in EPR Metadata"); 1183 } 1184 portTypeName = getElementTextAsQName(xsr); 1185 } else if (ns.equals(WSDLConstants.NS_WSDL) 1186 && localName.equals(WSDLConstants.QNAME_DEFINITIONS.getLocalPart())) { 1187 wsdlSource = new XMLStreamBufferSource(mark); 1188 } else { 1189 XMLStreamReaderUtil.skipElement(xsr); 1190 } 1191 } 1192 } else { 1193 //Skip is it is not root element 1194 if (!xsr.getLocalName().equals(rootElement)) { 1195 XMLStreamReaderUtil.skipElement(xsr); 1196 } 1197 } 1198 } while (XMLStreamReaderUtil.nextElementContent(xsr) == XMLStreamReader.START_ELEMENT); 1199 1200 if(wsdliLocation != null) { 1201 String wsdlLocation = wsdliLocation.trim(); 1202 wsdlLocation = wsdlLocation.substring(wsdliLocation.lastIndexOf(" ")); 1203 wsdlSource = new StreamSource(wsdlLocation); 1204 } 1205 } else if (version == AddressingVersion.MEMBER) { 1206 do { 1207 localName = xsr.getLocalName(); 1208 ns = xsr.getNamespaceURI(); 1209 //If the current element is metadata enclosure, look inside 1210 if (localName.equals(version.eprType.wsdlMetadata.getLocalPart()) && 1211 ns.equals(version.eprType.wsdlMetadata.getNamespaceURI())) { 1212 while (xsr.nextTag() == XMLStreamReader.START_ELEMENT) { 1213 XMLStreamBuffer mark; 1214 while ((mark = xsr.nextTagAndMark()) != null) { 1215 localName = xsr.getLocalName(); 1216 ns = xsr.getNamespaceURI(); 1217 if (ns.equals(WSDLConstants.NS_WSDL) 1218 && localName.equals(WSDLConstants.QNAME_DEFINITIONS.getLocalPart())) { 1219 wsdlSource = new XMLStreamBufferSource(mark); 1220 } else { 1221 XMLStreamReaderUtil.skipElement(xsr); 1222 } 1223 } 1224 } 1225 } else if (localName.equals(version.eprType.serviceName)) { 1226 String portStr = xsr.getAttributeValue(null, version.eprType.portName); 1227 serviceName = getElementTextAsQName(xsr); 1228 if (serviceName != null && portStr != null) { 1229 portName = new QName(serviceName.getNamespaceURI(), portStr); 1230 } 1231 } else if (localName.equals(version.eprType.portTypeName)) { 1232 portTypeName = getElementTextAsQName(xsr); 1233 } else { 1234 //Skip is it is not root element 1235 if (!xsr.getLocalName().equals(rootElement)) { 1236 XMLStreamReaderUtil.skipElement(xsr); 1237 } 1238 } 1239 } while (XMLStreamReaderUtil.nextElementContent(xsr) == XMLStreamReader.START_ELEMENT); 1240 } 1241 } 1242 1243 private QName getElementTextAsQName(StreamReaderBufferProcessor xsr) throws XMLStreamException { 1244 String text = xsr.getElementText().trim(); 1245 String prefix = XmlUtil.getPrefix(text); 1246 String name = XmlUtil.getLocalPart(text); 1247 if (name != null) { 1248 if (prefix != null) { 1249 String ns = xsr.getNamespaceURI(prefix); 1250 if (ns != null) { 1251 return new QName(ns, name, prefix); 1252 } 1253 } else { 1254 return new QName(null, name); 1255 } 1256 } 1257 return null; 1258 } 1259 } 1260} 1261