0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common Development
0008: * and Distribution License("CDDL") (collectively, the "License"). You
0009: * may not use this file except in compliance with the License. You can obtain
0010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
0011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
0012: * language governing permissions and limitations under the License.
0013: *
0014: * When distributing the software, include this License Header Notice in each
0015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
0016: * Sun designates this particular file as subject to the "Classpath" exception
0017: * as provided by Sun in the GPL Version 2 section of the License file that
0018: * accompanied this code. If applicable, add the following below the License
0019: * Header, with the fields enclosed by brackets [] replaced by your own
0020: * identifying information: "Portions Copyrighted [year]
0021: * [name of copyright owner]"
0022: *
0023: * Contributor(s):
0024: *
0025: * If you wish your version of this file to be governed by only the CDDL or
0026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
0027: * elects to include this software in this distribution under the [CDDL or GPL
0028: * Version 2] license." If you don't indicate a single choice of license, a
0029: * recipient has the option to distribute your version of this file under
0030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
0031: * its licensees as provided above. However, if you add GPL Version 2 code
0032: * and therefore, elected the GPL Version 2 license, then the option applies
0033: * only if the new code is made subject to such option by the copyright
0034: * holder.
0035: */
0036:
0037: package com.sun.xml.ws.api.addressing;
0038:
0039: import com.sun.istack.NotNull;
0040: import com.sun.istack.Nullable;
0041: import com.sun.xml.stream.buffer.MutableXMLStreamBuffer;
0042: import com.sun.xml.stream.buffer.XMLStreamBuffer;
0043: import com.sun.xml.stream.buffer.XMLStreamBufferResult;
0044: import com.sun.xml.stream.buffer.XMLStreamBufferSource;
0045: import com.sun.xml.stream.buffer.sax.SAXBufferProcessor;
0046: import com.sun.xml.stream.buffer.stax.StreamReaderBufferProcessor;
0047: import com.sun.xml.stream.buffer.stax.StreamWriterBufferCreator;
0048: import com.sun.xml.ws.addressing.EndpointReferenceUtil;
0049: import com.sun.xml.ws.addressing.W3CAddressingConstants;
0050: import com.sun.xml.ws.addressing.model.InvalidMapException;
0051: import com.sun.xml.ws.addressing.v200408.MemberSubmissionAddressingConstants;
0052: import com.sun.xml.ws.api.message.Header;
0053: import com.sun.xml.ws.api.message.HeaderList;
0054: import com.sun.xml.ws.api.message.Message;
0055: import com.sun.xml.ws.api.streaming.XMLStreamReaderFactory;
0056: import com.sun.xml.ws.resources.AddressingMessages;
0057: import com.sun.xml.ws.resources.ClientMessages;
0058: import com.sun.xml.ws.spi.ProviderImpl;
0059: import com.sun.xml.ws.streaming.XMLStreamReaderUtil;
0060: import com.sun.xml.ws.util.DOMUtil;
0061: import com.sun.xml.ws.util.xml.XMLStreamWriterFilter;
0062: import com.sun.xml.ws.util.xml.XmlUtil;
0063: import com.sun.xml.ws.wsdl.parser.WSDLConstants;
0064: import org.w3c.dom.Element;
0065: import org.xml.sax.Attributes;
0066: import org.xml.sax.ContentHandler;
0067: import org.xml.sax.ErrorHandler;
0068: import org.xml.sax.InputSource;
0069: import org.xml.sax.SAXException;
0070: import org.xml.sax.helpers.XMLFilterImpl;
0071:
0072: import javax.xml.bind.JAXBContext;
0073: import javax.xml.namespace.QName;
0074: import javax.xml.stream.XMLStreamException;
0075: import javax.xml.stream.XMLStreamReader;
0076: import javax.xml.stream.XMLStreamWriter;
0077: import javax.xml.transform.Source;
0078: import javax.xml.transform.TransformerException;
0079: import javax.xml.transform.sax.SAXSource;
0080: import javax.xml.transform.stream.StreamResult;
0081: import javax.xml.ws.Dispatch;
0082: import javax.xml.ws.EndpointReference;
0083: import javax.xml.ws.Service;
0084: import javax.xml.ws.WebServiceException;
0085: import javax.xml.ws.WebServiceFeature;
0086: import java.io.InputStream;
0087: import java.io.StringWriter;
0088: import java.net.URI;
0089: import java.net.URL;
0090: import java.util.ArrayList;
0091: import java.util.List;
0092:
0093: /**
0094: * Internal representation of the EPR.
0095: *
0096: * <p>
0097: * Instances of this class are immutable and thread-safe.
0098: *
0099: * @author Kohsuke Kawaguchi
0100: * @see AddressingVersion#anonymousEpr
0101: */
0102: public final class WSEndpointReference {
0103: private final XMLStreamBuffer infoset;
0104: /**
0105: * Version of the addressing spec.
0106: */
0107: private final AddressingVersion version;
0108:
0109: /**
0110: * Marked Reference parameters inside this EPR.
0111: *
0112: * Parsed when the object is created. can be empty but never null.
0113: * @see #parse()
0114: */
0115: private @NotNull
0116: Header[] referenceParameters;
0117: private @NotNull
0118: String address;
0119:
0120: /**
0121: * Creates from the spec version of {@link EndpointReference}.
0122: *
0123: * <p>
0124: * This method performs the data conversion, so it's slow.
0125: * Do not use this method in a performance critical path.
0126: */
0127: public WSEndpointReference(EndpointReference epr,
0128: AddressingVersion version) {
0129: try {
0130: MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer();
0131: epr.writeTo(new XMLStreamBufferResult(xsb));
0132: this .infoset = xsb;
0133: this .version = version;
0134: parse();
0135: } catch (XMLStreamException e) {
0136: throw new WebServiceException(ClientMessages
0137: .FAILED_TO_PARSE_EPR(epr), e);
0138: }
0139: }
0140:
0141: /**
0142: * Creates from the spec version of {@link EndpointReference}.
0143: *
0144: * <p>
0145: * This method performs the data conversion, so it's slow.
0146: * Do not use this method in a performance critical path.
0147: */
0148: public WSEndpointReference(EndpointReference epr) {
0149: this (epr, AddressingVersion.fromSpecClass(epr.getClass()));
0150: }
0151:
0152: /**
0153: * Creates a {@link WSEndpointReference} that wraps a given infoset.
0154: */
0155: public WSEndpointReference(XMLStreamBuffer infoset,
0156: AddressingVersion version) {
0157: try {
0158: this .infoset = infoset;
0159: this .version = version;
0160: parse();
0161: } catch (XMLStreamException e) {
0162: // this can never happen because XMLStreamBuffer never has underlying I/O error.
0163: throw new AssertionError(e);
0164: }
0165: }
0166:
0167: /**
0168: * Creates a {@link WSEndpointReference} by parsing an infoset.
0169: */
0170: public WSEndpointReference(InputStream infoset,
0171: AddressingVersion version) throws XMLStreamException {
0172: this (XMLStreamReaderFactory.create(null, infoset, false),
0173: version);
0174: }
0175:
0176: /**
0177: * Creates a {@link WSEndpointReference} from the given infoset.
0178: * The {@link XMLStreamReader} must point to either a document or an element.
0179: */
0180: public WSEndpointReference(XMLStreamReader in,
0181: AddressingVersion version) throws XMLStreamException {
0182: this (XMLStreamBuffer.createNewBufferFromXMLStreamReader(in),
0183: version);
0184: }
0185:
0186: /**
0187: * @see #WSEndpointReference(String, AddressingVersion)
0188: */
0189: public WSEndpointReference(URL address, AddressingVersion version) {
0190: this (address.toExternalForm(), version);
0191: }
0192:
0193: /**
0194: * @see #WSEndpointReference(String, AddressingVersion)
0195: */
0196: public WSEndpointReference(URI address, AddressingVersion version) {
0197: this (address.toString(), version);
0198: }
0199:
0200: /**
0201: * Creates a {@link WSEndpointReference} that only has an address.
0202: */
0203: public WSEndpointReference(String address, AddressingVersion version) {
0204: this .infoset = createBufferFromAddress(address, version);
0205: this .version = version;
0206: this .address = address;
0207: this .referenceParameters = EMPTY_ARRAY;
0208: }
0209:
0210: private static XMLStreamBuffer createBufferFromAddress(
0211: String address, AddressingVersion version) {
0212: try {
0213: MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer();
0214: StreamWriterBufferCreator w = new StreamWriterBufferCreator(
0215: xsb);
0216: w.writeStartDocument();
0217: w.writeStartElement(version.getPrefix(),
0218: "EndpointReference", version.nsUri);
0219: w.writeNamespace(version.getPrefix(), version.nsUri);
0220: w.writeStartElement(version.getPrefix(),
0221: W3CAddressingConstants.WSA_ADDRESS_NAME,
0222: version.nsUri);
0223: w.writeCharacters(address);
0224: w.writeEndElement();
0225: w.writeEndElement();
0226: w.writeEndDocument();
0227: w.close();
0228: return xsb;
0229: } catch (XMLStreamException e) {
0230: // can never happen because we are writing to XSB
0231: throw new AssertionError(e);
0232: }
0233: }
0234:
0235: /**
0236: * Creates an EPR from individual components.
0237: *
0238: * <p>
0239: * This version takes various information about metadata, and creates an EPR that has
0240: * the necessary embedded WSDL.
0241: */
0242: public WSEndpointReference(@NotNull
0243: AddressingVersion version, @NotNull
0244: String address, @Nullable
0245: QName service, @Nullable
0246: QName port, @Nullable
0247: QName portType, @Nullable
0248: List<Element> metadata, @Nullable
0249: String wsdlAddress, @Nullable
0250: List<Element> referenceParameters) {
0251: this (createBufferFromData(version, address,
0252: referenceParameters, service, port, portType, metadata,
0253: wsdlAddress), version);
0254: }
0255:
0256: private static XMLStreamBuffer createBufferFromData(
0257: AddressingVersion version, String address,
0258: List<Element> referenceParameters, QName service,
0259: QName port, QName portType, List<Element> metadata,
0260: String wsdlAddress) {
0261:
0262: StreamWriterBufferCreator writer = new StreamWriterBufferCreator();
0263:
0264: try {
0265: writer.writeStartDocument();
0266: writer.writeStartElement(version.getPrefix(),
0267: "EndpointReference", version.nsUri);
0268: writer.writeNamespace(version.getPrefix(), version.nsUri);
0269: writer.writeStartElement(version.getPrefix(), "Address",
0270: version.nsUri);
0271: writer.writeCharacters(address);
0272: writer.writeEndElement();
0273: if (referenceParameters != null) {
0274: writer.writeStartElement(version.getPrefix(),
0275: "ReferenceParameters", version.nsUri);
0276: for (Element e : referenceParameters)
0277: DOMUtil.serializeNode(e, writer);
0278: writer.writeEndElement();
0279: }
0280:
0281: switch (version) {
0282: case W3C:
0283: writeW3CMetaData(writer, service, port, portType,
0284: metadata, wsdlAddress);
0285: break;
0286:
0287: case MEMBER:
0288: writeMSMetaData(writer, service, port, portType,
0289: metadata);
0290: if (wsdlAddress != null) {
0291: //Inline the wsdl as extensibility element
0292: //Write mex:Metadata wrapper
0293: writer
0294: .writeStartElement(
0295: MemberSubmissionAddressingConstants.MEX_METADATA
0296: .getPrefix(),
0297: MemberSubmissionAddressingConstants.MEX_METADATA
0298: .getLocalPart(),
0299: MemberSubmissionAddressingConstants.MEX_METADATA
0300: .getNamespaceURI());
0301: writer
0302: .writeStartElement(
0303: MemberSubmissionAddressingConstants.MEX_METADATA_SECTION
0304: .getPrefix(),
0305: MemberSubmissionAddressingConstants.MEX_METADATA_SECTION
0306: .getLocalPart(),
0307: MemberSubmissionAddressingConstants.MEX_METADATA_SECTION
0308: .getNamespaceURI());
0309: writer
0310: .writeAttribute(
0311: MemberSubmissionAddressingConstants.MEX_METADATA_DIALECT_ATTRIBUTE,
0312: MemberSubmissionAddressingConstants.MEX_METADATA_DIALECT_VALUE);
0313:
0314: writeWsdl(writer, service, wsdlAddress);
0315:
0316: writer.writeEndElement();
0317: writer.writeEndElement();
0318: }
0319:
0320: break;
0321: }
0322: writer.writeEndElement();
0323: writer.writeEndDocument();
0324: writer.flush();
0325:
0326: return writer.getXMLStreamBuffer();
0327: } catch (XMLStreamException e) {
0328: throw new WebServiceException(e);
0329: }
0330: }
0331:
0332: private static void writeW3CMetaData(
0333: StreamWriterBufferCreator writer, QName service,
0334: QName port, QName portType, List<Element> metadata,
0335: String wsdlAddress) throws XMLStreamException {
0336:
0337: writer.writeStartElement(AddressingVersion.W3C.getPrefix(),
0338: W3CAddressingConstants.WSA_METADATA_NAME,
0339: AddressingVersion.W3C.nsUri);
0340: writer.writeNamespace(AddressingVersion.W3C.getWsdlPrefix(),
0341: AddressingVersion.W3C.wsdlNsUri);
0342:
0343: //Write Interface info
0344: if (portType != null) {
0345: writer.writeStartElement(AddressingVersion.W3C
0346: .getWsdlPrefix(),
0347: W3CAddressingConstants.WSAW_INTERFACENAME_NAME,
0348: AddressingVersion.W3C.wsdlNsUri);
0349: String portTypePrefix = portType.getPrefix();
0350: if (portTypePrefix == null || portTypePrefix.equals("")) {
0351: //TODO check prefix again
0352: portTypePrefix = "wsns";
0353: }
0354: writer.writeNamespace(portTypePrefix, portType
0355: .getNamespaceURI());
0356: writer.writeCharacters(portTypePrefix + ":"
0357: + portType.getLocalPart());
0358: writer.writeEndElement();
0359: }
0360: if (service != null) {
0361: //Write service and Port info
0362: if (!(service.getNamespaceURI().equals("") || service
0363: .getLocalPart().equals(""))) {
0364: writer.writeStartElement(AddressingVersion.W3C
0365: .getWsdlPrefix(),
0366: W3CAddressingConstants.WSAW_SERVICENAME_NAME,
0367: AddressingVersion.W3C.wsdlNsUri);
0368: String servicePrefix = service.getPrefix();
0369: if (servicePrefix == null || servicePrefix.equals("")) {
0370: //TODO check prefix again
0371: servicePrefix = "wsns";
0372: }
0373: writer.writeNamespace(servicePrefix, service
0374: .getNamespaceURI());
0375: if (port != null) {
0376: writer
0377: .writeAttribute(
0378: W3CAddressingConstants.WSAW_ENDPOINTNAME_NAME,
0379: port.getLocalPart());
0380: }
0381: writer.writeCharacters(servicePrefix + ":"
0382: + service.getLocalPart());
0383: writer.writeEndElement();
0384: }
0385: }
0386: //Inline the wsdl
0387: if (wsdlAddress != null) {
0388: writeWsdl(writer, service, wsdlAddress);
0389: }
0390: //Add the extra metadata Elements
0391: if (metadata != null)
0392: for (Element e : metadata) {
0393: DOMUtil.serializeNode(e, writer);
0394: }
0395: writer.writeEndElement();
0396:
0397: }
0398:
0399: private static void writeMSMetaData(
0400: StreamWriterBufferCreator writer, QName service,
0401: QName port, QName portType, List<Element> metadata)
0402: throws XMLStreamException {
0403: // TODO: write ReferenceProperties
0404: //TODO: write ReferenceParameters
0405: if (portType != null) {
0406: //Write Interface info
0407: writer
0408: .writeStartElement(
0409: AddressingVersion.MEMBER.getPrefix(),
0410: MemberSubmissionAddressingConstants.WSA_PORTTYPE_NAME,
0411: AddressingVersion.MEMBER.nsUri);
0412:
0413: String portTypePrefix = portType.getPrefix();
0414: if (portTypePrefix == null || portTypePrefix.equals("")) {
0415: //TODO check prefix again
0416: portTypePrefix = "wsns";
0417: }
0418: writer.writeNamespace(portTypePrefix, portType
0419: .getNamespaceURI());
0420: writer.writeCharacters(portTypePrefix + ":"
0421: + portType.getLocalPart());
0422: writer.writeEndElement();
0423: }
0424: //Write service and Port info
0425: if (service != null) {
0426: if (!(service.getNamespaceURI().equals("") || service
0427: .getLocalPart().equals(""))) {
0428: writer
0429: .writeStartElement(
0430: AddressingVersion.MEMBER.getPrefix(),
0431: MemberSubmissionAddressingConstants.WSA_SERVICENAME_NAME,
0432: AddressingVersion.MEMBER.nsUri);
0433: String servicePrefix = service.getPrefix();
0434: if (servicePrefix == null || servicePrefix.equals("")) {
0435: //TODO check prefix again
0436: servicePrefix = "wsns";
0437: }
0438: writer.writeNamespace(servicePrefix, service
0439: .getNamespaceURI());
0440: if (port != null) {
0441: writer
0442: .writeAttribute(
0443: MemberSubmissionAddressingConstants.WSA_PORTNAME_NAME,
0444: port.getLocalPart());
0445: }
0446: writer.writeCharacters(servicePrefix + ":"
0447: + service.getLocalPart());
0448: writer.writeEndElement();
0449: }
0450: }
0451: }
0452:
0453: private static void writeWsdl(StreamWriterBufferCreator writer,
0454: QName service, String wsdlAddress)
0455: throws XMLStreamException {
0456: // Inline-wsdl
0457: writer.writeStartElement(WSDLConstants.PREFIX_NS_WSDL,
0458: WSDLConstants.QNAME_DEFINITIONS.getLocalPart(),
0459: WSDLConstants.NS_WSDL);
0460: writer.writeNamespace(WSDLConstants.PREFIX_NS_WSDL,
0461: WSDLConstants.NS_WSDL);
0462: writer.writeStartElement(WSDLConstants.PREFIX_NS_WSDL,
0463: WSDLConstants.QNAME_IMPORT.getLocalPart(),
0464: WSDLConstants.NS_WSDL);
0465: writer.writeAttribute("namespace", service.getNamespaceURI());
0466: writer.writeAttribute("location", wsdlAddress);
0467: writer.writeEndElement();
0468: writer.writeEndElement();
0469: }
0470:
0471: /**
0472: * Converts from {@link EndpointReference}.
0473: *
0474: * This handles null {@link EndpointReference} correctly.
0475: * Call {@link #WSEndpointReference(EndpointReference)} directly
0476: * if you know it's not null.
0477: */
0478: public static @Nullable
0479: WSEndpointReference create(@Nullable
0480: EndpointReference epr) {
0481: if (epr != null)
0482: return new WSEndpointReference(epr);
0483: else
0484: return null;
0485: }
0486:
0487: /**
0488: * @see #createWithAddress(String)
0489: */
0490: public @NotNull
0491: WSEndpointReference createWithAddress(@NotNull
0492: URI newAddress) {
0493: return createWithAddress(newAddress.toString());
0494: }
0495:
0496: /**
0497: * @see #createWithAddress(String)
0498: */
0499: public @NotNull
0500: WSEndpointReference createWithAddress(@NotNull
0501: URL newAddress) {
0502: return createWithAddress(newAddress.toString());
0503: }
0504:
0505: /**
0506: * Creates a new {@link WSEndpointReference} by replacing the address of this EPR
0507: * to the new one.
0508: *
0509: * <p>
0510: * The following example shows how you can use this to force an HTTPS EPR,
0511: * when the endpoint can serve both HTTP and HTTPS requests.
0512: * <pre>
0513: * if(epr.getAddress().startsWith("http:"))
0514: * epr = epr.createWithAddress("https:"+epr.getAddress().substring(5));
0515: * </pre>
0516: *
0517: * @param newAddress
0518: * This is a complete URL to be written inside <Adress> element of the EPR,
0519: * such as "http://foo.bar/abc/def"
0520: */
0521: public @NotNull
0522: WSEndpointReference createWithAddress(@NotNull
0523: final String newAddress) {
0524: MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer();
0525: XMLFilterImpl filter = new XMLFilterImpl() {
0526: private boolean inAddress = false;
0527:
0528: public void startElement(String uri, String localName,
0529: String qName, Attributes atts) throws SAXException {
0530: if (localName.equals("Address")
0531: && uri.equals(version.nsUri))
0532: inAddress = true;
0533: super .startElement(uri, localName, qName, atts);
0534: }
0535:
0536: public void characters(char ch[], int start, int length)
0537: throws SAXException {
0538: if (!inAddress)
0539: super .characters(ch, start, length);
0540: }
0541:
0542: public void endElement(String uri, String localName,
0543: String qName) throws SAXException {
0544: if (inAddress)
0545: super .characters(newAddress.toCharArray(), 0,
0546: newAddress.length());
0547: inAddress = false;
0548: super .endElement(uri, localName, qName);
0549: }
0550: };
0551: filter.setContentHandler(xsb.createFromSAXBufferCreator());
0552: try {
0553: infoset.writeTo(filter, false);
0554: } catch (SAXException e) {
0555: throw new AssertionError(e); // impossible since we are writing from XSB to XSB.
0556: }
0557:
0558: return new WSEndpointReference(xsb, version);
0559: }
0560:
0561: /**
0562: * Convert the EPR to the spec version. The actual type of
0563: * {@link EndpointReference} to be returned depends on which version
0564: * of the addressing spec this EPR conforms to.
0565: *
0566: * @throws WebServiceException
0567: * if the conversion fails, which can happen if the EPR contains
0568: * invalid infoset (wrong namespace URI, etc.)
0569: */
0570: public @NotNull
0571: EndpointReference toSpec() {
0572: return ProviderImpl.INSTANCE
0573: .readEndpointReference(asSource("EndpointReference"));
0574: }
0575:
0576: /**
0577: * Converts the EPR to the specified spec version.
0578: *
0579: * If the {@link #getVersion() the addressing version in use} and
0580: * the given class is different, then this may involve version conversion.
0581: */
0582: public @NotNull
0583: <T extends EndpointReference> T toSpec(Class<T> clazz) {
0584: return EndpointReferenceUtil.transform(clazz, toSpec());
0585: }
0586:
0587: /**
0588: * Creates a proxy that can be used to talk to this EPR.
0589: *
0590: * <p>
0591: * All the normal WS-Addressing processing happens automatically,
0592: * such as setting the endpoint address to {@link #getAddress() the address},
0593: * and sending the reference parameters associated with this EPR as
0594: * headers, etc.
0595: */
0596: public @NotNull
0597: <T> T getPort(@NotNull
0598: Service jaxwsService, @NotNull
0599: Class<T> serviceEndpointInterface, WebServiceFeature... features) {
0600: // TODO: implement it in a better way
0601: return jaxwsService.getPort(toSpec(), serviceEndpointInterface,
0602: features);
0603: }
0604:
0605: /**
0606: * Creates a {@link Dispatch} that can be used to talk to this EPR.
0607: *
0608: * <p>
0609: * All the normal WS-Addressing processing happens automatically,
0610: * such as setting the endpoint address to {@link #getAddress() the address},
0611: * and sending the reference parameters associated with this EPR as
0612: * headers, etc.
0613: */
0614: public @NotNull
0615: <T> Dispatch<T> createDispatch(@NotNull
0616: Service jaxwsService, @NotNull
0617: Class<T> type, @NotNull
0618: Service.Mode mode, WebServiceFeature... features) {
0619:
0620: // TODO: implement it in a better way
0621: return jaxwsService.createDispatch(toSpec(), type, mode,
0622: features);
0623: }
0624:
0625: /**
0626: * Creates a {@link Dispatch} that can be used to talk to this EPR.
0627: *
0628: * <p>
0629: * All the normal WS-Addressing processing happens automatically,
0630: * such as setting the endpoint address to {@link #getAddress() the address},
0631: * and sending the reference parameters associated with this EPR as
0632: * headers, etc.
0633: */
0634: public @NotNull
0635: Dispatch<Object> createDispatch(@NotNull
0636: Service jaxwsService, @NotNull
0637: JAXBContext context, @NotNull
0638: Service.Mode mode, WebServiceFeature... features) {
0639:
0640: // TODO: implement it in a better way
0641: return jaxwsService.createDispatch(toSpec(), context, mode,
0642: features);
0643: }
0644:
0645: /**
0646: * Gets the addressing version of this EPR.
0647: */
0648: public @NotNull
0649: AddressingVersion getVersion() {
0650: return version;
0651: }
0652:
0653: /**
0654: * The value of the <wsa:address> header.
0655: */
0656: public @NotNull
0657: String getAddress() {
0658: return address;
0659: }
0660:
0661: /**
0662: * Returns true if this has anonymous URI as the {@link #getAddress() address}.
0663: */
0664: public boolean isAnonymous() {
0665: return address.equals(version.anonymousUri);
0666: }
0667:
0668: /**
0669: * Returns true if this has {@link AddressingVersion#noneUri none URI}
0670: * as the {@link #getAddress() address}.
0671: */
0672: public boolean isNone() {
0673: return address.equals(version.noneUri);
0674: }
0675:
0676: /**
0677: * Parses inside EPR and mark all reference parameters.
0678: */
0679: private void parse() throws XMLStreamException {
0680: // TODO: validate the EPR structure.
0681: // check for non-existent Address, that sort of things.
0682:
0683: StreamReaderBufferProcessor xsr = infoset
0684: .readAsXMLStreamReader();
0685:
0686: // parser should be either at the start element or the start document
0687: if (xsr.getEventType() == XMLStreamReader.START_DOCUMENT)
0688: xsr.nextTag();
0689: assert xsr.getEventType() == XMLStreamReader.START_ELEMENT;
0690:
0691: String rootLocalName = xsr.getLocalName();
0692: if (!xsr.getNamespaceURI().equals(version.nsUri))
0693: throw new WebServiceException(AddressingMessages
0694: .WRONG_ADDRESSING_VERSION(version.nsUri, xsr
0695: .getNamespaceURI()));
0696:
0697: // since often EPR doesn't have a reference parameter, create array lazily
0698: List<Header> marks = null;
0699:
0700: while (xsr.nextTag() == XMLStreamReader.START_ELEMENT) {
0701: String localName = xsr.getLocalName();
0702: if (version.isReferenceParameter(localName)) {
0703: XMLStreamBuffer mark;
0704: while ((mark = xsr.nextTagAndMark()) != null) {
0705: if (marks == null)
0706: marks = new ArrayList<Header>();
0707:
0708: // TODO: need a different header for member submission version
0709: marks.add(version.createReferenceParameterHeader(
0710: mark, xsr.getNamespaceURI(), xsr
0711: .getLocalName()));
0712: XMLStreamReaderUtil.skipElement(xsr);
0713: }
0714: } else if (localName.equals("Address")) {
0715: if (address != null) // double <Address>. That's an error.
0716: throw new InvalidMapException(
0717: new QName(version.nsUri, rootLocalName),
0718: AddressingVersion.fault_duplicateAddressInEpr);
0719: address = xsr.getElementText().trim();
0720: } else {
0721: XMLStreamReaderUtil.skipElement(xsr);
0722: }
0723: }
0724:
0725: // hit to </EndpointReference> by now
0726:
0727: if (marks == null) {
0728: this .referenceParameters = EMPTY_ARRAY;
0729: } else {
0730: this .referenceParameters = marks.toArray(new Header[marks
0731: .size()]);
0732: }
0733:
0734: if (address == null)
0735: throw new InvalidMapException(new QName(version.nsUri,
0736: rootLocalName), version.fault_missingAddressInEpr);
0737: }
0738:
0739: /**
0740: * Reads this EPR as {@link XMLStreamReader}.
0741: *
0742: * @param localName
0743: * EPR uses a different root tag name depending on the context.
0744: * The returned {@link XMLStreamReader} will use the given local name
0745: * for the root element name.
0746: */
0747: public XMLStreamReader read(final @NotNull
0748: String localName) throws XMLStreamException {
0749: return new StreamReaderBufferProcessor(infoset) {
0750: protected void processElement(String prefix, String uri,
0751: String _localName) {
0752: if (_depth == 0)
0753: _localName = localName;
0754: super .processElement(prefix, uri, _localName);
0755: }
0756: };
0757: }
0758:
0759: /**
0760: * Returns a {@link Source} that represents this EPR.
0761: *
0762: * @param localName
0763: * EPR uses a different root tag name depending on the context.
0764: * The returned {@link Source} will use the given local name
0765: * for the root element name.
0766: */
0767: public Source asSource(@NotNull
0768: String localName) {
0769: return new SAXSource(new SAXBufferProcessorImpl(localName),
0770: new InputSource());
0771: }
0772:
0773: /**
0774: * Writes this EPR to the given {@link ContentHandler}.
0775: *
0776: * @param localName
0777: * EPR uses a different root tag name depending on the context.
0778: * The returned {@link Source} will use the given local name
0779: * for the root element name.
0780: * @param fragment
0781: * If true, generate a fragment SAX events without start/endDocument callbacks.
0782: * If false, generate a full XML document event.
0783: */
0784: public void writeTo(@NotNull
0785: String localName, ContentHandler contentHandler,
0786: ErrorHandler errorHandler, boolean fragment)
0787: throws SAXException {
0788: SAXBufferProcessorImpl p = new SAXBufferProcessorImpl(localName);
0789: p.setContentHandler(contentHandler);
0790: p.setErrorHandler(errorHandler);
0791: p.process(infoset, fragment);
0792: }
0793:
0794: /**
0795: * Writes this EPR into the given writer.
0796: *
0797: * @param localName
0798: * EPR uses a different root tag name depending on the context.
0799: * The returned {@link Source} will use the given local name
0800: */
0801: public void writeTo(final @NotNull
0802: String localName, @NotNull
0803: XMLStreamWriter w) throws XMLStreamException {
0804: infoset.writeToXMLStreamWriter(new XMLStreamWriterFilter(w) {
0805: private boolean root = true;
0806:
0807: @Override
0808: public void writeStartDocument() throws XMLStreamException {
0809: }
0810:
0811: @Override
0812: public void writeStartDocument(String encoding,
0813: String version) throws XMLStreamException {
0814: }
0815:
0816: @Override
0817: public void writeStartDocument(String version)
0818: throws XMLStreamException {
0819: }
0820:
0821: @Override
0822: public void writeEndDocument() throws XMLStreamException {
0823: }
0824:
0825: private String override(String ln) {
0826: if (root) {
0827: root = false;
0828: return localName;
0829: }
0830: return ln;
0831: }
0832:
0833: public void writeStartElement(String localName)
0834: throws XMLStreamException {
0835: super .writeStartElement(override(localName));
0836: }
0837:
0838: public void writeStartElement(String namespaceURI,
0839: String localName) throws XMLStreamException {
0840: super .writeStartElement(namespaceURI,
0841: override(localName));
0842: }
0843:
0844: public void writeStartElement(String prefix,
0845: String localName, String namespaceURI)
0846: throws XMLStreamException {
0847: super .writeStartElement(prefix, override(localName),
0848: namespaceURI);
0849: }
0850: }, true/*write as fragment*/);
0851: }
0852:
0853: /**
0854: * Returns a {@link Header} that wraps this {@link WSEndpointReference}.
0855: *
0856: * <p>
0857: * The returned header is immutable too, and can be reused with
0858: * many {@link Message}s.
0859: *
0860: * @param rootTagName
0861: * The header tag name to be used, such as <ReplyTo> or <FaultTo>.
0862: * (It's bit ugly that this method takes {@link QName} and not just local name,
0863: * unlike other methods. If it's making the caller's life miserable, then
0864: * we can talk.)
0865: */
0866: public Header createHeader(QName rootTagName) {
0867: return new EPRHeader(rootTagName, this );
0868: }
0869:
0870: /**
0871: * Copies all the reference parameters in this EPR as headers
0872: * to the given {@link HeaderList}.
0873: */
0874: public void addReferenceParameters(HeaderList outbound) {
0875: for (Header header : referenceParameters) {
0876: outbound.add(header);
0877: }
0878: }
0879:
0880: /**
0881: * Dumps the EPR infoset in a human-readable string.
0882: */
0883: @Override
0884: public String toString() {
0885: try {
0886: // debug convenience
0887: StringWriter sw = new StringWriter();
0888: XmlUtil.newTransformer()
0889: .transform(asSource("EndpointReference"),
0890: new StreamResult(sw));
0891: return sw.toString();
0892: } catch (TransformerException e) {
0893: return e.toString();
0894: }
0895: }
0896:
0897: /**
0898: * Filtering {@link SAXBufferProcessor} that replaces the root tag name.
0899: */
0900: class SAXBufferProcessorImpl extends SAXBufferProcessor {
0901: private final String rootLocalName;
0902: private boolean root = true;
0903:
0904: public SAXBufferProcessorImpl(String rootLocalName) {
0905: super (infoset, false);
0906: this .rootLocalName = rootLocalName;
0907: }
0908:
0909: protected void processElement(String uri, String localName,
0910: String qName) throws SAXException {
0911: if (root) {
0912: root = false;
0913:
0914: if (qName.equals(localName)) {
0915: qName = localName = rootLocalName;
0916: } else {
0917: localName = rootLocalName;
0918: int idx = qName.indexOf(':');
0919: qName = qName.substring(0, idx + 1) + rootLocalName;
0920: }
0921: }
0922: super .processElement(uri, localName, qName);
0923: }
0924: }
0925:
0926: private static final OutboundReferenceParameterHeader[] EMPTY_ARRAY = new OutboundReferenceParameterHeader[0];
0927:
0928: /**
0929: * Parses the metadata inside this EPR and obtains it in a easy-to-process form.
0930: *
0931: * <p>
0932: * See {@link Metadata} class for what's avaliable as "metadata".
0933: */
0934: public @NotNull
0935: Metadata getMetaData() {
0936: return new Metadata();
0937: }
0938:
0939: /**
0940: * Parses the Metadata in an EPR and provides convenience methods to access
0941: * the metadata.
0942: *
0943: */
0944: public class Metadata {
0945: private @Nullable
0946: QName serviceName;
0947: private @Nullable
0948: QName portName;
0949: private @Nullable
0950: QName portTypeName; //interfaceName
0951: private @Nullable
0952: Source wsdlSource;
0953: private @Nullable
0954: String wsdliLocation;
0955:
0956: public @Nullable
0957: QName getServiceName() {
0958: return serviceName;
0959: }
0960:
0961: public @Nullable
0962: QName getPortName() {
0963: return portName;
0964: }
0965:
0966: public @Nullable
0967: QName getPortTypeName() {
0968: return portTypeName;
0969: }
0970:
0971: public @Nullable
0972: Source getWsdlSource() {
0973: return wsdlSource;
0974: }
0975:
0976: public @Nullable
0977: String getWsdliLocation() {
0978: return wsdliLocation;
0979: }
0980:
0981: private Metadata() {
0982: try {
0983: parseMetaData();
0984: } catch (XMLStreamException e) {
0985: throw new WebServiceException(e);
0986: }
0987: }
0988:
0989: /**
0990: * Parses the Metadata section of the EPR.
0991: */
0992: private void parseMetaData() throws XMLStreamException {
0993: StreamReaderBufferProcessor xsr = infoset
0994: .readAsXMLStreamReader();
0995:
0996: // parser should be either at the start element or the start document
0997: if (xsr.getEventType() == XMLStreamReader.START_DOCUMENT)
0998: xsr.nextTag();
0999: assert xsr.getEventType() == XMLStreamReader.START_ELEMENT;
1000: String rootElement = xsr.getLocalName();
1001: if (!xsr.getNamespaceURI().equals(version.nsUri))
1002: throw new WebServiceException(AddressingMessages
1003: .WRONG_ADDRESSING_VERSION(version.nsUri, xsr
1004: .getNamespaceURI()));
1005: String localName;
1006: String ns;
1007: if (version == AddressingVersion.W3C) {
1008: do {
1009: //If the current element is metadata enclosure, look inside
1010: if (xsr.getLocalName()
1011: .equals(
1012: version.eprType.wsdlMetadata
1013: .getLocalPart())) {
1014: String wsdlLoc = xsr.getAttributeValue(
1015: "http://www.w3.org/ns/wsdl-instance",
1016: "wsdlLocation");
1017: if (wsdlLoc != null)
1018: wsdliLocation = wsdlLoc.trim();
1019: XMLStreamBuffer mark;
1020: while ((mark = xsr.nextTagAndMark()) != null) {
1021: localName = xsr.getLocalName();
1022: ns = xsr.getNamespaceURI();
1023: if (localName
1024: .equals(version.eprType.serviceName)) {
1025: String portStr = xsr.getAttributeValue(
1026: null, version.eprType.portName);
1027: if (serviceName != null)
1028: throw new RuntimeException(
1029: "More than one "
1030: + version.eprType.serviceName
1031: + " element in EPR Metadata");
1032: serviceName = getElementTextAsQName(xsr);
1033: if (serviceName != null
1034: && portStr != null)
1035: portName = new QName(serviceName
1036: .getNamespaceURI(), portStr);
1037: } else if (localName
1038: .equals(version.eprType.portTypeName)) {
1039: if (portTypeName != null)
1040: throw new RuntimeException(
1041: "More than one "
1042: + version.eprType.portTypeName
1043: + " element in EPR Metadata");
1044: portTypeName = getElementTextAsQName(xsr);
1045: } else if (ns.equals(WSDLConstants.NS_WSDL)
1046: && localName
1047: .equals(WSDLConstants.QNAME_DEFINITIONS
1048: .getLocalPart())) {
1049: wsdlSource = new XMLStreamBufferSource(
1050: mark);
1051: } else {
1052: XMLStreamReaderUtil.skipElement(xsr);
1053: }
1054: }
1055: } else {
1056: //Skip is it is not root element
1057: if (!xsr.getLocalName().equals(rootElement))
1058: XMLStreamReaderUtil.skipElement(xsr);
1059: }
1060: } while (XMLStreamReaderUtil.nextElementContent(xsr) == XMLStreamReader.START_ELEMENT);
1061: } else if (version == AddressingVersion.MEMBER) {
1062: do {
1063: localName = xsr.getLocalName();
1064: ns = xsr.getNamespaceURI();
1065: //If the current element is metadata enclosure, look inside
1066: if (localName.equals(version.eprType.wsdlMetadata
1067: .getLocalPart())
1068: && ns.equals(version.eprType.wsdlMetadata
1069: .getNamespaceURI())) {
1070: while (xsr.nextTag() == XMLStreamReader.START_ELEMENT) {
1071: XMLStreamBuffer mark;
1072: while ((mark = xsr.nextTagAndMark()) != null) {
1073: localName = xsr.getLocalName();
1074: ns = xsr.getNamespaceURI();
1075: if (ns.equals(WSDLConstants.NS_WSDL)
1076: && localName
1077: .equals(WSDLConstants.QNAME_DEFINITIONS
1078: .getLocalPart())) {
1079: wsdlSource = new XMLStreamBufferSource(
1080: mark);
1081: } else {
1082: XMLStreamReaderUtil
1083: .skipElement(xsr);
1084: }
1085: }
1086: }
1087: } else if (localName
1088: .equals(version.eprType.serviceName)) {
1089: String portStr = xsr.getAttributeValue(null,
1090: version.eprType.portName);
1091: serviceName = getElementTextAsQName(xsr);
1092: if (serviceName != null && portStr != null)
1093: portName = new QName(serviceName
1094: .getNamespaceURI(), portStr);
1095: } else if (localName
1096: .equals(version.eprType.portTypeName)) {
1097: portTypeName = getElementTextAsQName(xsr);
1098: } else {
1099: //Skip is it is not root element
1100: if (!xsr.getLocalName().equals(rootElement))
1101: XMLStreamReaderUtil.skipElement(xsr);
1102: }
1103: } while (XMLStreamReaderUtil.nextElementContent(xsr) == XMLStreamReader.START_ELEMENT);
1104: }
1105: }
1106:
1107: private QName getElementTextAsQName(
1108: StreamReaderBufferProcessor xsr)
1109: throws XMLStreamException {
1110: String text = xsr.getElementText().trim();
1111: String prefix = XmlUtil.getPrefix(text);
1112: String name = XmlUtil.getLocalPart(text);
1113: if (name != null) {
1114: if (prefix != null) {
1115: String ns = xsr.getNamespaceURI(prefix);
1116: if (ns != null)
1117: return new QName(ns, name, prefix);
1118: } else {
1119: return new QName(null, name);
1120: }
1121: }
1122: return null;
1123: }
1124: }
1125: }
|