feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,342 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.soap.SOAPBinding;
import com.sun.istack.internal.NotNull;
import com.sun.xml.internal.ws.addressing.WsaTubeHelper;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.addressing.AddressingPropertySet;
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
import com.sun.xml.internal.ws.api.addressing.OneWayFeature;
import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.internal.ws.message.RelatesToHeader;
import com.sun.xml.internal.ws.message.StringHeader;
import com.sun.xml.internal.ws.resources.AddressingMessages;
import com.sun.xml.internal.ws.resources.ClientMessages;
public class AddressingUtils {
//TODO is MessageHeaders to be implicitly assumed? Or moved to utility class and taken out from interface?
public static void fillRequestAddressingHeaders(MessageHeaders headers, Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action) {
fillRequestAddressingHeaders(headers, packet, av, sv, oneway, action, false);
}
public static void fillRequestAddressingHeaders(MessageHeaders headers, Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action, boolean mustUnderstand) {
fillCommonAddressingHeaders(headers, packet, av, sv, action, mustUnderstand);
// wsa:ReplyTo
// null or "true" is equivalent to request/response MEP
if (!oneway) {
WSEndpointReference epr = av.anonymousEpr;
if (headers.get(av.replyToTag, false) == null) {
headers.add(epr.createHeader(av.replyToTag));
}
// wsa:FaultTo
if (headers.get(av.faultToTag, false) == null) {
headers.add(epr.createHeader(av.faultToTag));
}
// wsa:MessageID
if (packet.getMessage().getHeaders().get(av.messageIDTag, false) == null) {
if (headers.get(av.messageIDTag, false) == null) {
Header h = new StringHeader(av.messageIDTag, Message.generateMessageID());
headers.add(h);
}
}
}
}
// private void fillRequestAddressingHeaders(Packet packet, AddressingVersion av, SOAPVersion sv, OneWayFeature oneWayFeature, boolean oneway, String action);
public static void fillRequestAddressingHeaders(MessageHeaders headers, WSDLPort wsdlPort, WSBinding binding, Packet packet) {
if (binding == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_BINDING());
}
if (binding.isFeatureEnabled(SuppressAutomaticWSARequestHeadersFeature.class)) {
return;
}
//See if WSA headers are already set by the user.
MessageHeaders hl = packet.getMessage().getHeaders();
String action = AddressingUtils.getAction(hl, binding.getAddressingVersion(), binding.getSOAPVersion());
if (action != null) {
//assume that all the WSA headers are set by the user
return;
}
AddressingVersion addressingVersion = binding.getAddressingVersion();
//seiModel is passed as null as it is not needed.
WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, null, binding);
// wsa:Action
String effectiveInputAction = wsaHelper.getEffectiveInputAction(packet);
if (effectiveInputAction == null || effectiveInputAction.equals("") && binding.getSOAPVersion() == SOAPVersion.SOAP_11) {
throw new WebServiceException(ClientMessages.INVALID_SOAP_ACTION());
}
boolean oneway = !packet.expectReply;
if (wsdlPort != null) {
// if WSDL has <wsaw:Anonymous>prohibited</wsaw:Anonymous>, then throw an error
// as anonymous ReplyTo MUST NOT be added in that case. BindingProvider need to
// disable AddressingFeature and MemberSubmissionAddressingFeature and hand-craft
// the SOAP message with non-anonymous ReplyTo/FaultTo.
if (!oneway && packet.getMessage() != null && packet.getWSDLOperation() != null) {
WSDLBoundOperation wbo = wsdlPort.getBinding().get(packet.getWSDLOperation());
if (wbo != null && wbo.getAnonymous() == WSDLBoundOperation.ANONYMOUS.prohibited) {
throw new WebServiceException(AddressingMessages.WSAW_ANONYMOUS_PROHIBITED());
}
}
}
OneWayFeature oneWayFeature = binding.getFeature(OneWayFeature.class);
final AddressingPropertySet addressingPropertySet = packet.getSatellite(AddressingPropertySet.class);
oneWayFeature = addressingPropertySet == null ? oneWayFeature : new OneWayFeature(addressingPropertySet, addressingVersion);
if (oneWayFeature == null || !oneWayFeature.isEnabled()) {
// standard oneway
fillRequestAddressingHeaders(headers, packet, addressingVersion, binding.getSOAPVersion(), oneway, effectiveInputAction, AddressingVersion.isRequired(binding));
} else {
// custom oneway
fillRequestAddressingHeaders(headers, packet, addressingVersion, binding.getSOAPVersion(), oneWayFeature, oneway, effectiveInputAction);
}
}
public static String getAction(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
if (av == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
}
String action = null;
Header h = getFirstHeader(headers, av.actionTag, true, sv);
if (h != null) {
action = h.getStringContent();
}
return action;
}
public static WSEndpointReference getFaultTo(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
if (av == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
}
Header h = getFirstHeader(headers, av.faultToTag, true, sv);
WSEndpointReference faultTo = null;
if (h != null) {
try {
faultTo = h.readAsEPR(av);
} catch (XMLStreamException e) {
throw new WebServiceException(AddressingMessages.FAULT_TO_CANNOT_PARSE(), e);
}
}
return faultTo;
}
public static String getMessageID(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
if (av == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
}
Header h = getFirstHeader(headers, av.messageIDTag, true, sv);
String messageId = null;
if (h != null) {
messageId = h.getStringContent();
}
return messageId;
}
public static String getRelatesTo(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
if (av == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
}
Header h = getFirstHeader(headers, av.relatesToTag, true, sv);
String relatesTo = null;
if (h != null) {
relatesTo = h.getStringContent();
}
return relatesTo;
}
public static WSEndpointReference getReplyTo(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
if (av == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
}
Header h = getFirstHeader(headers, av.replyToTag, true, sv);
WSEndpointReference replyTo;
if (h != null) {
try {
replyTo = h.readAsEPR(av);
} catch (XMLStreamException e) {
throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e);
}
} else {
replyTo = av.anonymousEpr;
}
return replyTo;
}
public static String getTo(MessageHeaders headers, AddressingVersion av, SOAPVersion sv) {
if (av == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
}
Header h = getFirstHeader(headers, av.toTag, true, sv);
String to;
if (h != null) {
to = h.getStringContent();
} else {
to = av.anonymousUri;
}
return to;
}
public static Header getFirstHeader(MessageHeaders headers, QName name, boolean markUnderstood, SOAPVersion sv) {
if (sv == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_SOAP_VERSION());
}
Iterator<Header> iter = headers.getHeaders(name.getNamespaceURI(), name.getLocalPart(), markUnderstood);
while (iter.hasNext()) {
Header h = iter.next();
if (h.getRole(sv).equals(sv.implicitRole)) {
return h;
}
}
return null;
}
private static void fillRequestAddressingHeaders(@NotNull MessageHeaders headers, @NotNull Packet packet, @NotNull AddressingVersion av, @NotNull SOAPVersion sv, @NotNull OneWayFeature oneWayFeature, boolean oneway, @NotNull String action) {
if (!oneway&&!oneWayFeature.isUseAsyncWithSyncInvoke() && Boolean.TRUE.equals(packet.isSynchronousMEP)) {
fillRequestAddressingHeaders(headers, packet, av, sv, oneway, action);
} else {
fillCommonAddressingHeaders(headers, packet, av, sv, action, false);
boolean isMessageIdAdded = false;
// wsa:ReplyTo
// add if it doesn't already exist and OneWayFeature requests a specific ReplyTo
if (headers.get(av.replyToTag, false) == null) {
WSEndpointReference replyToEpr = oneWayFeature.getReplyTo();
if (replyToEpr != null) {
headers.add(replyToEpr.createHeader(av.replyToTag));
// add wsa:MessageID only for non-null ReplyTo
if (packet.getMessage().getHeaders().get(av.messageIDTag, false) == null) {
// if header doesn't exist, method getID creates a new random id
String newID = oneWayFeature.getMessageId() == null ? Message.generateMessageID() : oneWayFeature.getMessageId();
headers.add(new StringHeader(av.messageIDTag, newID));
isMessageIdAdded = true;
}
}
}
// If the user sets a messageId, use it.
final String messageId = oneWayFeature.getMessageId();
if (!isMessageIdAdded && messageId != null) {
headers.add(new StringHeader(av.messageIDTag, messageId));
}
// wsa:FaultTo
// add if it doesn't already exist and OneWayFeature requests a specific FaultTo
if (headers.get(av.faultToTag, false) == null) {
WSEndpointReference faultToEpr = oneWayFeature.getFaultTo();
if (faultToEpr != null) {
headers.add(faultToEpr.createHeader(av.faultToTag));
// add wsa:MessageID only for non-null FaultTo
if (headers.get(av.messageIDTag, false) == null) {
headers.add(new StringHeader(av.messageIDTag, Message.generateMessageID()));
}
}
}
// wsa:From
if (oneWayFeature.getFrom() != null) {
headers.addOrReplace(oneWayFeature.getFrom().createHeader(av.fromTag));
}
// wsa:RelatesTo
if (oneWayFeature.getRelatesToID() != null) {
headers.addOrReplace(new RelatesToHeader(av.relatesToTag, oneWayFeature.getRelatesToID()));
}
}
}
/**
* Creates wsa:To, wsa:Action and wsa:MessageID header on the client
*
* @param packet request packet
* @param av WS-Addressing version
* @param sv SOAP version
* @param action Action Message Addressing Property value
* @throws IllegalArgumentException if any of the parameters is null.
*/
private static void fillCommonAddressingHeaders(MessageHeaders headers, Packet packet, @NotNull AddressingVersion av, @NotNull SOAPVersion sv, @NotNull String action, boolean mustUnderstand) {
if (packet == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_PACKET());
}
if (av == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
}
if (sv == null) {
throw new IllegalArgumentException(AddressingMessages.NULL_SOAP_VERSION());
}
if (action == null && !sv.httpBindingId.equals(SOAPBinding.SOAP12HTTP_BINDING)) {
throw new IllegalArgumentException(AddressingMessages.NULL_ACTION());
}
// wsa:To
if (headers.get(av.toTag, false) == null) {
StringHeader h = new StringHeader(av.toTag, packet.endpointAddress.toString());
headers.add(h);
}
// wsa:Action
if (action != null) {
packet.soapAction = action;
if (headers.get(av.actionTag, false) == null) {
//As per WS-I BP 1.2/2.0, if one of the WSA headers is MU, then all WSA headers should be treated as MU.,
// so just set MU on action header
StringHeader h = new StringHeader(av.actionTag, action, sv, mustUnderstand);
headers.add(h);
}
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.NotNull;
import javax.activation.DataHandler;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPException;
import javax.xml.transform.Source;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Attachment.
*/
public interface Attachment {
/**
* Content ID of the attachment. Uniquely identifies an attachment.
*
* http://www.ietf.org/rfc/rfc2392.txt (which is referred by the ws-i attachment profile
* http://www.ws-i.org/Profiles/AttachmentsProfile-1.0.html)
*
* content-id = url-addr-spec
* url-addr-spec = addr-spec ; URL encoding of RFC 822 addr-spec
* cid-url = "cid" ":" content-id
*
* A "cid" URL is converted to the corresponding Content-ID message header [MIME] by
* removing the "cid:" prefix, converting the % encoded character to their equivalent
* US-ASCII characters, and enclosing the remaining parts with an angle bracket pair,
* "<" and ">". For example, "cid:foo4%25foo1@bar.net" corresponds to
* Content-ID: <foo4%25foo1@bar.net>
*
* @return
* The content ID like "foo-bar-zot@abc.com", without
* surrounding '&lt;' and '>' used as the transfer syntax.
*/
@NotNull String getContentId();
/**
* Gets the MIME content-type of this attachment.
*/
String getContentType();
/**
* Gets the attachment as an exact-length byte array.
*/
byte[] asByteArray();
/**
* Gets the attachment as a {@link DataHandler}.
*/
DataHandler asDataHandler();
/**
* Gets the attachment as a {@link Source}.
* Note that there's no guarantee that the attachment is actually an XML.
*/
Source asSource();
/**
* Obtains this attachment as an {@link InputStream}.
*/
InputStream asInputStream();
/**
* Writes the contents of the attachment into the given stream.
*/
void writeTo(OutputStream os) throws IOException;
/**
* Writes this attachment to the given {@link SOAPMessage}.
*/
void writeTo(SOAPMessage saaj) throws SOAPException;
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.NotNull;
import java.util.Iterator;
/**
* Attachment extended interface exposing custom MIME headers.
* @since 2.2.6
*/
public interface AttachmentEx extends Attachment {
/**
* MIME header
*/
public interface MimeHeader {
/**
* MIME header name
* @return name
*/
public String getName();
/**
* MIME header value
* @return value
*/
public String getValue();
}
/**
* Iterator of custom MIME headers associated with this attachment
* @return MIME header iterator
*/
public @NotNull Iterator<MimeHeader> getMimeHeaders();
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.Nullable;
/**
* A set of {@link Attachment} on a {@link Message}.
*
* <p>
* A particular attention is made to ensure that attachments
* can be read and parsed lazily as requested.
*
* @see Message#getAttachments()
*/
public interface AttachmentSet extends Iterable<Attachment> {
/**
* Gets the attachment by the content ID.
*
* @param contentId
* The content ID like "foo-bar-zot@abc.com", without
* surrounding '&lt;' and '>' used as the transfer syntax.
*
* @return null
* if no such attachment exist.
*/
@Nullable
Attachment get(String contentId);
/**
* Returns true if there's no attachment.
*/
boolean isEmpty();
/**
* Adds an attachment to this set.
*
* <p>
* Note that it's OK for an {@link Attachment} to belong to
* more than one {@link AttachmentSet} (which is in fact
* necessary when you wrap a {@link Message} into another.
*
* @param att
* must not be null.
*/
public void add(Attachment att);
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.xml.internal.ws.util.exception.JAXWSExceptionBase;
import com.sun.xml.internal.ws.protocol.soap.VersionMismatchException;
/**
* This class represents an Exception that needs to be marshalled
* with a specific protocol wire format. For example, the SOAP's
* VersionMismatchFault needs to be written with a correct fault code.
* In that case, decoder could throw {@link VersionMismatchException},
* and the corresponding fault {@link Message} from {@link ExceptionHasMessage#getFaultMessage()}
* is sent on the wire.
*
* @author Jitendra Kotamraju
*/
public abstract class ExceptionHasMessage extends JAXWSExceptionBase {
public ExceptionHasMessage(String key, Object... args) {
super(key, args);
}
/**
* Returns the exception into a fault Message
*
* @return Message for this exception
*/
public abstract Message getFaultMessage();
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.bind.api.Bridge;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.internal.ws.spi.db.XMLBridge;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
/**
* A <code>FilterMessageImpl</code> contains some other Message, which it uses
* as its basic source of message data, possibly transforming the data along
* the way or providing additional functionality.
*
* <p>
* The class <code>FilterMessageImpl</code> itself simply overrides
* all the methods of <code>Message</code> and invokes them on
* contained Message delegate. Subclasses of <code>FilterMessageImpl</code>
* may further override some of these methods and may also provide
* additional methods and fields.
*
* @author Jitendra Kotamraju
*/
public class FilterMessageImpl extends Message {
private final Message delegate;
protected FilterMessageImpl(Message delegate) {
this.delegate = delegate;
}
public boolean hasHeaders() {
return delegate.hasHeaders();
}
public @NotNull MessageHeaders getHeaders() {
return delegate.getHeaders();
}
public @NotNull AttachmentSet getAttachments() {
return delegate.getAttachments();
}
protected boolean hasAttachments() {
return delegate.hasAttachments();
}
public boolean isOneWay(@NotNull WSDLPort port) {
return delegate.isOneWay(port);
}
public @Nullable String getPayloadLocalPart() {
return delegate.getPayloadLocalPart();
}
public String getPayloadNamespaceURI() {
return delegate.getPayloadNamespaceURI();
}
public boolean hasPayload() {
return delegate.hasPayload();
}
public boolean isFault() {
return delegate.isFault();
}
public @Nullable QName getFirstDetailEntryName() {
return delegate.getFirstDetailEntryName();
}
public Source readEnvelopeAsSource() {
return delegate.readEnvelopeAsSource();
}
public Source readPayloadAsSource() {
return delegate.readPayloadAsSource();
}
public SOAPMessage readAsSOAPMessage() throws SOAPException {
return delegate.readAsSOAPMessage();
}
public SOAPMessage readAsSOAPMessage(Packet packet, boolean inbound) throws SOAPException {
return delegate.readAsSOAPMessage(packet, inbound);
}
public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException {
return (T)delegate.readPayloadAsJAXB(unmarshaller);
}
/** @deprecated */
public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException {
return delegate.readPayloadAsJAXB(bridge);
}
public <T> T readPayloadAsJAXB(XMLBridge<T> bridge) throws JAXBException {
return delegate.readPayloadAsJAXB(bridge);
}
public XMLStreamReader readPayload() throws XMLStreamException {
return delegate.readPayload();
}
public void consume() {
delegate.consume();
}
public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
delegate.writePayloadTo(sw);
}
public void writeTo(XMLStreamWriter sw) throws XMLStreamException {
delegate.writeTo(sw);
}
public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException {
delegate.writeTo(contentHandler, errorHandler);
}
public Message copy() {
return delegate.copy();
}
public @NotNull String getID(@NotNull WSBinding binding) {
return delegate.getID(binding);
}
public @NotNull String getID(AddressingVersion av, SOAPVersion sv) {
return delegate.getID(av, sv);
}
public SOAPVersion getSOAPVersion() {
return delegate.getSOAPVersion();
}
}

View File

@@ -0,0 +1,334 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.bind.api.Bridge;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
import com.sun.xml.internal.ws.spi.db.XMLBridge;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.ws.WebServiceException;
import java.util.Set;
/**
* A SOAP header.
*
* <p>
* A header is immutable, but unlike body it can be read
* multiple times.
* The {@link Header} abstraction hides how the header
* data is represented in memory; instead, it commits to
* the ability to write itself to XML infoset.
*
* <p>
* When a message is received from the transport and
* being processed, the processor needs to "peek"
* some information of a header, such as the tag name,
* the mustUnderstand attribute, and so on. Therefore,
* the {@link Header} interface exposes those information
* as properties, so that they can be checked without
* replaying the infoset, which is efficiently but still
* costly.
*
* <p>
* A {@link Header} may belong to more than one {@link HeaderList}
* due to wrapping of {@link Message}.
*
* @see HeaderList
* @see Headers
*/
public interface Header {
// TODO: Vivek pointed out that the only time we are looking at
// mustUnderstand and role are when we do the mustUnderstand error check
// (that is, to find out if there's any header with @mustUnderstand that
// has appropriate role for us.)
// if that's the case, it might be better if we define this whole operation
// as one method, instead of exposing two properties.
/**
* Checks if this header is ignorable for us (IOW, make sure
* that this header has a problematic "mustUnderstand" header value
* that we have to reject.)
*
* <p>
* This method is used as a part of the
* <a href="HeaderList.html#MU">mustUnderstanx processing</a>.
* At the end of the processing, the JAX-WS identifies a list of {@link Header}s
* that were not understood. This method is invoked on those {@link Header}s,
* to verify that we don't need to report an error for it.
*
* <p>
* specifically, this method has to perform the following tasks:
*
* <ul>
* <li>If this header does not have <tt>mustUnderstand</tt> as "1" nor "true",
* then this method must return true.
* <li>Otherwise, check the role attribute (for SOAP 1.2) or the actor attribute (for SOAP 1.1).
* When those attributes are absent, the default values have to be assumed.
* See {@link #getRole(SOAPVersion)} for how the values are defaulted.
* Now, see if the {@code roles} set contains the value.
* If so, this method must return false (indicating that an error is in order.)
* <li>Otherwise return true (since we don't play the role this header is intended for.)
* </ul>
*
* @param soapVersion
* The caller specifies the SOAP version that the pipeline is working against.
* Often each {@link Header} implementation already knows the SOAP version
* anyway, but this allows some {@link Header}s to avoid keeping it.
* That's why this redundant parameter is passed in.
* @param roles
* The set of role values that the current JAX-WS pipeline is assuming.
* Note that SOAP 1.1 and SOAP 1.2 use different strings for the same role,
* and the caller is responsible for supplying a proper value depending on the
* active SOAP version in use.
*
* @return
* true if no error needs to be reported. False if an error needs to be raised.
* See the method javadoc for more discussion.
*/
public boolean isIgnorable(@NotNull SOAPVersion soapVersion, @NotNull Set<String> roles);
/**
* Gets the value of the soap:role attribute (or soap:actor for SOAP 1.1).
*
* <p>
* If the attribute is omitted, the value defaults to {@link SOAPVersion#implicitRole}.
*
* @param soapVersion
* The caller specifies the SOAP version that the pipeline is working against.
* Often each {@link Header} implementation already knows the SOAP version
* anyway, but this allows some {@link Header}s to avoid keeping it.
* That's why this redundant parameter is passed in.
* @return
* never null. This string need not be interned.
*/
public @NotNull String getRole(@NotNull SOAPVersion soapVersion);
/**
* True if this header is to be relayed if not processed.
* For SOAP 1.1 messages, this method always return false.
*
* <p>
* IOW, this method returns true if there's @soap:relay='true'
* is present.
*
* <h3>Implementation Note</h3>
* <p>
* The implementation needs to check for both "true" and "1",
* but because attribute values are normalized, it doesn't have
* to consider " true", " 1 ", and so on.
*
* @return
* false.
*/
public boolean isRelay();
/**
* Gets the namespace URI of this header element.
*
* @return
* this string must be interned.
*/
public @NotNull String getNamespaceURI();
/**
* Gets the local name of this header element.
*
* @return
* this string must be interned.
*/
public @NotNull String getLocalPart();
/**
* Gets the attribute value on the header element.
*
* @param nsUri
* The namespace URI of the attribute. Can be empty.
* @param localName
* The local name of the attribute.
*
* @return
* if the attribute is found, return the whitespace normalized value.
* (meaning no leading/trailing space, no consequtive whitespaces in-between.)
* Otherwise null. Note that the XML parsers are responsible for
* whitespace-normalizing attributes, so {@link Header} implementation
* doesn't have to do anything.
*/
@Nullable String getAttribute(@NotNull String nsUri, @NotNull String localName);
/**
* Gets the attribute value on the header element.
*
* <p>
* This is a convenience method that calls into {@link #getAttribute(String, String)}
*
* @param name
* Never null.
*
* @see #getAttribute(String, String)
*/
@Nullable String getAttribute(@NotNull QName name);
/**
* Reads the header as a {@link XMLStreamReader}.
*
* <p>
* The returned parser points at the start element of this header.
* (IOW, {@link XMLStreamReader#getEventType()} would return
* {@link XMLStreamReader#START_ELEMENT}.
*
* <h3>Performance Expectation</h3>
* <p>
* For some {@link Header} implementations, this operation
* is a non-trivial operation. Therefore, use of this method
* is discouraged unless the caller is interested in reading
* the whole header.
*
* <p>
* Similarly, if the caller wants to use this method only to do
* the API conversion (such as simply firing SAX events from
* {@link XMLStreamReader}), then the JAX-WS team requests
* that you talk to us.
*
* <p>
* {@link Message}s that come from tranport usually provides
* a reasonably efficient implementation of this method.
*
* @return
* must not null.
*/
public XMLStreamReader readHeader() throws XMLStreamException;
/**
* Reads the header as a JAXB object by using the given unmarshaller.
*/
public <T> T readAsJAXB(Unmarshaller unmarshaller) throws JAXBException;
/**
* Reads the header as a JAXB object by using the given unmarshaller.
* @deprecated
*/
public <T> T readAsJAXB(Bridge<T> bridge) throws JAXBException;
/**
* Reads the header as a data-bond object
*/
public <T> T readAsJAXB(XMLBridge<T> bridge) throws JAXBException;
/**
* Reads this header as an {@link WSEndpointReference}.
*
* @param expected
* The version of the addressing used to parse the EPR.
* If the actual infoset and this doesn't agree, then
* you'll get an {@link WebServiceException} stating that fact.
*
* @return
* On a successful return, this method never returns null.
*/
public @NotNull WSEndpointReference readAsEPR(AddressingVersion expected) throws XMLStreamException;
/**
* Writes out the header as a fragment.
*
* @throws XMLStreamException
* if the operation fails for some reason. This leaves the
* writer to an undefined state.
*/
public void writeTo(XMLStreamWriter w) throws XMLStreamException;
/**
* Writes out the header to the given SOAPMessage.
*
* <p>
* Sometimes a {@link Message} needs to produce itself
* as {@link SOAPMessage}, in which case each header needs
* to turn itself into a header.
*
* @throws SOAPException
* if the operation fails for some reason. This leaves the
* writer to an undefined state.
*/
public void writeTo(SOAPMessage saaj) throws SOAPException;
/**
* Writes out the header as SAX events.
*
* <p>
* Sometimes a {@link Message} needs to produce SAX events,
* and this method is necessary for headers to participate to it.
*
* <p>
* A header is responsible for producing the SAX events for its part,
* including <tt>startPrefixMapping</tt> and <tt>endPrefixMapping</tt>,
* but not startDocument/endDocument.
*
* <p>
* Note that SAX contract requires that any error that does NOT originate
* from {@link ContentHandler} (meaning any parsing error and etc) must
* be first reported to {@link ErrorHandler}. If the SAX event production
* cannot be continued and the processing needs to abort, the code may
* then throw the same {@link SAXParseException} reported to {@link ErrorHandler}.
*
* @param contentHandler
* The {@link ContentHandler} that receives SAX events.
*
* @param errorHandler
* The {@link ErrorHandler} that receives parsing errors.
*/
public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException;
/**
* Used to obtain value XYZ from a header that looks like
* "&lt;header&gt;XYZ&lt;/header&gt;". The primary use of this header
* for now is to access certain Addressing headers quickly.
*
* @throws WebServiceException
* If the structure of the header is more complicated than
* a simple string header.
*
* @return
* Can be empty but always non-null.
*/
public @NotNull String getStringContent();
}

View File

@@ -0,0 +1,976 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceException;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.internal.ws.api.pipe.Codec;
import com.sun.xml.internal.ws.api.pipe.Pipe;
import com.sun.xml.internal.ws.binding.SOAPBindingImpl;
import com.sun.xml.internal.ws.protocol.soap.ClientMUTube;
import com.sun.xml.internal.ws.protocol.soap.ServerMUTube;
import java.util.Arrays;
/**
* A list of {@link Header}s on a {@link Message}.
*
* <p>
* This list can be modified to add headers
* from outside a {@link Message}, this is necessary
* since intermediate processing layers often need to
* put additional headers.
*
* <p>
* Following the SOAP convention, the order among headers
* are not significant. However, {@link Codec}s are
* expected to preserve the order of headers in the input
* message as much as possible.
*
*
* <a name="MU"></a>
* <h3>MustUnderstand Processing</h3>
* <p>
* To perform SOAP mustUnderstang processing correctly, we need to keep
* track of headers that are understood and headers that are not.
* This is a collaborative process among {@link Pipe}s, thus it's something
* a {@link Pipe} author needs to keep in mind.
*
* <p>
* Specifically, when a {@link Pipe} sees a header and processes it
* (that is, if it did enough computing with the header to claim that
* the header is understood), then it should mark the corresponding
* header as "understood". For example, when a pipe that handles JAX-WSA
* examins the &lt;wsa:To> header, it can claim that it understood the header.
* But for example, if a pipe that does the signature verification checks
* &lt;wsa:To> for a signature, that would not be considered as "understood".
*
* <p>
* There are two ways to mark a header as understood:
*
* <ol>
* <li>Use one of the <tt>getXXX</tt> methods that take a
* boolean <tt>markAsUnderstood</tt> parameter.
* Most often, a {@link Pipe} knows it's going to understand a header
* as long as it's present, so this is the easiest and thus the preferred way.
*
* For example, if JAX-WSA looks for &lt;wsa:To>, then it can set
* <tt>markAsUnderstand</tt> to true, to do the obtaining of a header
* and marking at the same time.
*
* <li>Call {@link #understood(int)}.
* If under a rare circumstance, a pipe cannot determine whether
* it can understand it or not when you are fetching a header, then
* you can use this method afterward to mark it as understood.
* </ol>
*
* <p>
* Intuitively speaking, at the end of the day, if a header is not
* understood but {@link Header#isIgnorable(SOAPVersion, java.util.Set)} is false, a bad thing
* will happen. The actual implementation of the checking is more complicated,
* for that see {@link ClientMUTube}/{@link ServerMUTube}.
*
* @see Message#getHeaders()
*/
public class HeaderList extends ArrayList<Header> implements MessageHeaders {
private static final long serialVersionUID = -6358045781349627237L;
/**
* Bit set to keep track of which headers are understood.
* <p>
* The first 32 headers use this field, and the rest will use
* {@link #moreUnderstoodBits}. The expectation is that
* most of the time a SOAP message will only have up to 32 headers,
* so we can avoid allocating separate objects for {@link BitSet}.
*/
private int understoodBits;
/**
* If there are more than 32 headers, we use this {@link BitSet}
* to keep track of whether those headers are understood.
* Lazily allocated.
*/
private BitSet moreUnderstoodBits = null;
private SOAPVersion soapVersion;
/**
* This method is deprecated - instead use this one:
* public HeaderList(SOAPVersion)
* Creates an empty {@link HeaderList}.
*/
@Deprecated
public HeaderList() {
}
/**
* Creates an empty {@link HeaderList} with the given soap version
* @param soapVersion
*/
public HeaderList(SOAPVersion soapVersion) {
this.soapVersion = soapVersion;
}
/**
* Copy constructor.
*/
public HeaderList(HeaderList that) {
super(that);
this.understoodBits = that.understoodBits;
if (that.moreUnderstoodBits != null) {
this.moreUnderstoodBits = (BitSet) that.moreUnderstoodBits.clone();
}
}
public HeaderList(MessageHeaders that) {
super(that.asList());
if (that instanceof HeaderList) {
HeaderList hThat = (HeaderList) that;
this.understoodBits = hThat.understoodBits;
if (hThat.moreUnderstoodBits != null) {
this.moreUnderstoodBits = (BitSet) hThat.moreUnderstoodBits.clone();
}
} else {
Set<QName> understood = that.getUnderstoodHeaders();
if (understood != null) {
for (QName qname : understood) {
understood(qname);
}
}
}
}
/**
* The total number of headers.
*/
@Override
public int size() {
return super.size();
}
@Override
public boolean hasHeaders() {
return !isEmpty();
}
/**
* Adds all the headers.
* @deprecated throws UnsupportedOperationException from some HeaderList implementations - better iterate over items one by one
*/
@Deprecated
public void addAll(Header... headers) {
addAll(Arrays.asList(headers));
}
/**
* Gets the {@link Header} at the specified index.
*
* <p>
* This method does not mark the returned {@link Header} as understood.
*
* @see #understood(int)
*/
@Override
public Header get(int index) {
return super.get(index);
}
/**
* Marks the {@link Header} at the specified index as
* <a href="#MU">"understood"</a>.
*/
public void understood(int index) {
// check that index is in range
if (index >= size()) {
throw new ArrayIndexOutOfBoundsException(index);
}
if (index < 32) {
understoodBits |= 1 << index;
} else {
if (moreUnderstoodBits == null) {
moreUnderstoodBits = new BitSet();
}
moreUnderstoodBits.set(index - 32);
}
}
/**
* Returns true if a {@link Header} at the given index
* was <a href="#MU">"understood"</a>.
*/
public boolean isUnderstood(int index) {
// check that index is in range
if (index >= size()) {
throw new ArrayIndexOutOfBoundsException(index);
}
if (index < 32) {
return understoodBits == (understoodBits | (1 << index));
} else {
if (moreUnderstoodBits == null) {
return false;
}
return moreUnderstoodBits.get(index - 32);
}
}
/**
* Marks the specified {@link Header} as <a href="#MU">"understood"</a>.
*
* @deprecated
* By the definition of {@link ArrayList}, this operation requires
* O(n) search of the array, and thus inherently inefficient.
*
* Because of this, if you are developing a {@link Pipe} for
* a performance sensitive environment, do not use this method.
*
* @throws IllegalArgumentException
* if the given header is not {@link #contains(Object) contained}
* in this header.
*/
@Override
public void understood(@NotNull Header header) {
int sz = size();
for (int i = 0; i < sz; i++) {
if (get(i) == header) {
understood(i);
return;
}
}
throw new IllegalArgumentException();
}
/**
* Gets the first {@link Header} of the specified name.
*
* @param markAsUnderstood
* If this parameter is true, the returned header will
* be marked as <a href="#MU">"understood"</a>.
* @return null if not found.
*/
@Override
public @Nullable Header get(@NotNull String nsUri, @NotNull String localName, boolean markAsUnderstood) {
int len = size();
for (int i = 0; i < len; i++) {
Header h = get(i);
if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
if (markAsUnderstood) {
understood(i);
}
return h;
}
}
return null;
}
/**
* @deprecated
* Use {@link #get(String, String, boolean)}
*/
public Header get(String nsUri, String localName) {
return get(nsUri, localName, true);
}
/**
* Gets the first {@link Header} of the specified name.
*
* @param markAsUnderstood
* If this parameter is true, the returned header will
* be marked as <a href="#MU">"understood"</a>.
* @return null
* if not found.
*/
@Override
public @Nullable Header get(@NotNull QName name, boolean markAsUnderstood) {
return get(name.getNamespaceURI(), name.getLocalPart(), markAsUnderstood);
}
/**
* @deprecated
* Use {@link #get(QName)}
*/
public
@Nullable
Header get(@NotNull QName name) {
return get(name, true);
}
/**
* @deprecated
* Use {@link #getHeaders(String, String, boolean)}
*/
public Iterator<Header> getHeaders(final String nsUri, final String localName) {
return getHeaders(nsUri, localName, true);
}
/**
* Gets all the {@link Header}s of the specified name,
* including duplicates (if any.)
*
* @param markAsUnderstood
* If this parameter is true, the returned headers will
* be marked as <a href="#MU">"understood"</a> when they are returned
* from {@link Iterator#next()}.
* @return empty iterator if not found.
*/
public
@NotNull
@Override
Iterator<Header> getHeaders(@NotNull final String nsUri, @NotNull final String localName, final boolean markAsUnderstood) {
return new Iterator<Header>() {
int idx = 0;
Header next;
@Override
public boolean hasNext() {
if (next == null) {
fetch();
}
return next != null;
}
@Override
public Header next() {
if (next == null) {
fetch();
if (next == null) {
throw new NoSuchElementException();
}
}
if (markAsUnderstood) {
assert get(idx - 1) == next;
understood(idx - 1);
}
Header r = next;
next = null;
return r;
}
private void fetch() {
while (idx < size()) {
Header h = get(idx++);
if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
next = h;
break;
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* @see #getHeaders(String, String, boolean)
*/
public
@NotNull
@Override
Iterator<Header> getHeaders(@NotNull QName headerName, final boolean markAsUnderstood) {
return getHeaders(headerName.getNamespaceURI(), headerName.getLocalPart(), markAsUnderstood);
}
/**
* @deprecated
* use {@link #getHeaders(String, boolean)}.
*/
public
@NotNull
Iterator<Header> getHeaders(@NotNull final String nsUri) {
return getHeaders(nsUri, true);
}
/**
* Gets an iteration of headers {@link Header} in the specified namespace,
* including duplicates (if any.)
*
* @param markAsUnderstood
* If this parameter is true, the returned headers will
* be marked as <a href="#MU">"understood"</a> when they are returned
* from {@link Iterator#next()}.
* @return
* empty iterator if not found.
*/
public
@NotNull
@Override
Iterator<Header> getHeaders(@NotNull final String nsUri, final boolean markAsUnderstood) {
return new Iterator<Header>() {
int idx = 0;
Header next;
@Override
public boolean hasNext() {
if (next == null) {
fetch();
}
return next != null;
}
@Override
public Header next() {
if (next == null) {
fetch();
if (next == null) {
throw new NoSuchElementException();
}
}
if (markAsUnderstood) {
assert get(idx - 1) == next;
understood(idx - 1);
}
Header r = next;
next = null;
return r;
}
private void fetch() {
while (idx < size()) {
Header h = get(idx++);
if (h.getNamespaceURI().equals(nsUri)) {
next = h;
break;
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Returns the value of WS-Addressing <code>To</code> header. The <code>version</code>
* identifies the WS-Addressing version and the header returned is targeted at
* the current implicit role. Caches the value for subsequent invocation.
* Duplicate <code>To</code> headers are detected earlier.
*
* @param av WS-Addressing version
* @param sv SOAP version
* @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
* @return Value of WS-Addressing To header, anonymous URI if no header is present
*/
public String getTo(AddressingVersion av, SOAPVersion sv) {
return AddressingUtils.getTo(this, av, sv);
}
/**
* Returns the value of WS-Addressing <code>Action</code> header. The <code>version</code>
* identifies the WS-Addressing version and the header returned is targeted at
* the current implicit role. Caches the value for subsequent invocation.
* Duplicate <code>Action</code> headers are detected earlier.
*
* @param av WS-Addressing version
* @param sv SOAP version
* @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
* @return Value of WS-Addressing Action header, null if no header is present
*/
public String getAction(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
return AddressingUtils.getAction(this, av, sv);
}
/**
* Returns the value of WS-Addressing <code>ReplyTo</code> header. The <code>version</code>
* identifies the WS-Addressing version and the header returned is targeted at
* the current implicit role. Caches the value for subsequent invocation.
* Duplicate <code>ReplyTo</code> headers are detected earlier.
*
* @param av WS-Addressing version
* @param sv SOAP version
* @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
* @return Value of WS-Addressing ReplyTo header, null if no header is present
*/
public WSEndpointReference getReplyTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
return AddressingUtils.getReplyTo(this, av, sv);
}
/**
* Returns the value of WS-Addressing <code>FaultTo</code> header. The <code>version</code>
* identifies the WS-Addressing version and the header returned is targeted at
* the current implicit role. Caches the value for subsequent invocation.
* Duplicate <code>FaultTo</code> headers are detected earlier.
*
* @param av WS-Addressing version
* @param sv SOAP version
* @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
* @return Value of WS-Addressing FaultTo header, null if no header is present
*/
public WSEndpointReference getFaultTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
return AddressingUtils.getFaultTo(this, av, sv);
}
/**
* Returns the value of WS-Addressing <code>MessageID</code> header. The <code>version</code>
* identifies the WS-Addressing version and the header returned is targeted at
* the current implicit role. Caches the value for subsequent invocation.
* Duplicate <code>MessageID</code> headers are detected earlier.
*
* @param av WS-Addressing version
* @param sv SOAP version
* @throws WebServiceException if either <code>av</code> or <code>sv</code> is null.
* @return Value of WS-Addressing MessageID header, null if no header is present
*/
public String getMessageID(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
return AddressingUtils.getMessageID(this, av, sv);
}
/**
* Returns the value of WS-Addressing <code>RelatesTo</code> header. The <code>version</code>
* identifies the WS-Addressing version and the header returned is targeted at
* the current implicit role. Caches the value for subsequent invocation.
* Duplicate <code>RelatesTo</code> headers are detected earlier.
*
* @param av WS-Addressing version
* @param sv SOAP version
* @throws WebServiceException if either <code>av</code> or <code>sv</code> is null.
* @return Value of WS-Addressing RelatesTo header, null if no header is present
*/
public String getRelatesTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
return AddressingUtils.getRelatesTo(this, av, sv);
}
/**
* Creates a set of outbound WS-Addressing headers on the client with the
* specified Action Message Addressing Property value.
* <p><p>
* This method needs to be invoked right after such a Message is
* created which is error prone but so far only MEX, RM and JAX-WS
* creates a request so this ugliness is acceptable. This method is also used
* to create protocol messages that are not associated with any {@link WSBinding}
* and {@link WSDLPort}.
*
* @param packet request packet
* @param av WS-Addressing version
* @param sv SOAP version
* @param oneway Indicates if the message exchange pattern is oneway
* @param action Action Message Addressing Property value
* @param mustUnderstand to indicate if the addressing headers are set with mustUnderstand attribute
*/
public void fillRequestAddressingHeaders(Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action, boolean mustUnderstand) {
AddressingUtils.fillRequestAddressingHeaders(this, packet, av, sv, oneway, action, mustUnderstand);
}
public void fillRequestAddressingHeaders(Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action) {
AddressingUtils.fillRequestAddressingHeaders(this, packet, av, sv, oneway, action);
}
/**
* Creates a set of outbound WS-Addressing headers on the client with the
* default Action Message Addressing Property value.
* <p><p>
* This method needs to be invoked right after such a Message is
* created which is error prone but so far only MEX, RM and JAX-WS
* creates a request so this ugliness is acceptable. If more components
* are identified using this, then we may revisit this.
* <p><p>
* This method is used if default Action Message Addressing Property is to
* be used. See
* {@link #fillRequestAddressingHeaders(Packet, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, boolean, String)}
* if non-default Action is to be used, for example when creating a protocol message not
* associated with {@link WSBinding} and {@link WSDLPort}.
* This method uses SOAPAction as the Action unless set expplicitly in the wsdl.
* @param wsdlPort request WSDL port
* @param binding request WSBinding
* @param packet request packet
*/
public void fillRequestAddressingHeaders(WSDLPort wsdlPort, @NotNull WSBinding binding, Packet packet) {
AddressingUtils.fillRequestAddressingHeaders(this, wsdlPort, binding, packet);
}
/**
* Adds a new {@link Header}.
*
* <p>
* Order doesn't matter in headers, so this method
* does not make any guarantee as to where the new header
* is inserted.
*
* @return
* always true. Don't use the return value.
*/
@Override
public boolean add(Header header) {
return super.add(header);
}
/**
* Removes the first {@link Header} of the specified name.
* @param nsUri namespace URI of the header to remove
* @param localName local part of the FQN of the header to remove
*
* @return null if not found.
*/
public
@Nullable
@Override
Header remove(@NotNull String nsUri, @NotNull String localName) {
int len = size();
for (int i = 0; i < len; i++) {
Header h = get(i);
if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
return remove(i);
}
}
return null;
}
/**
* Replaces an existing {@link Header} or adds a new {@link Header}.
*
* <p>
* Order doesn't matter in headers, so this method
* does not make any guarantee as to where the new header
* is inserted.
*
* @return
* always true. Don't use the return value.
*/
@Override
public boolean addOrReplace(Header header) {
for (int i=0; i < size(); i++) {
Header hdr = get(i);
if (hdr.getNamespaceURI().equals(header.getNamespaceURI()) &&
hdr.getLocalPart().equals(header.getLocalPart())) {
// Put the new header in the old position. Call super versions
// internally to avoid UnsupportedOperationException
removeInternal(i);
addInternal(i, header);
return true;
}
}
return add(header);
}
@Override
public void replace(Header old, Header header) {
for (int i=0; i < size(); i++) {
Header hdr = get(i);
if (hdr.getNamespaceURI().equals(header.getNamespaceURI()) &&
hdr.getLocalPart().equals(header.getLocalPart())) {
// Put the new header in the old position. Call super versions
// internally to avoid UnsupportedOperationException
removeInternal(i);
addInternal(i, header);
return;
}
}
throw new IllegalArgumentException();
}
protected void addInternal(int index, Header header) {
super.add(index, header);
}
protected Header removeInternal(int index) {
return super.remove(index);
}
/**
* Removes the first {@link Header} of the specified name.
*
* @param name fully qualified name of the header to remove
*
* @return null if not found.
*/
public
@Nullable
@Override
Header remove(@NotNull QName name) {
return remove(name.getNamespaceURI(), name.getLocalPart());
}
/**
* Removes the first {@link Header} of the specified name.
*
* @param index index of the header to remove
*
* @return removed header
*/
@Override
public Header remove(int index) {
removeUnderstoodBit(index);
return super.remove(index);
}
/**
* Removes the "understood" bit for header on the position specified by {@code index} parameter
* from the set of understood header bits.
*
* @param index position of the bit to remove
*/
private void removeUnderstoodBit(int index) {
assert index < size();
if (index < 32) {
/**
* Let
* R be the bit to be removed
* M be a more significant "upper" bit than bit R
* L be a less significant "lower" bit than bit R
*
* Then following 3 lines of code produce these results:
*
* old understoodBits = MMMMMMMMMMMMRLLLLLLLLLLLLLLLLLLL
*
* shiftedUpperBits = 0MMMMMMMMMMMM0000000000000000000
*
* lowerBits = 0000000000000LLLLLLLLLLLLLLLLLLL
*
* new understoodBits = 0MMMMMMMMMMMMLLLLLLLLLLLLLLLLLLL
*
* The R bit is removed and all the upper bits are shifted right (unsigned)
*/
int shiftedUpperBits = understoodBits >>> -31 + index << index;
int lowerBits = understoodBits << -index >>> 31 - index >>> 1;
understoodBits = shiftedUpperBits | lowerBits;
if (moreUnderstoodBits != null && moreUnderstoodBits.cardinality() > 0) {
if (moreUnderstoodBits.get(0)) {
understoodBits |= 0x80000000;
}
moreUnderstoodBits.clear(0);
for (int i = moreUnderstoodBits.nextSetBit(1); i > 0; i = moreUnderstoodBits.nextSetBit(i + 1)) {
moreUnderstoodBits.set(i - 1);
moreUnderstoodBits.clear(i);
}
}
} else if (moreUnderstoodBits != null && moreUnderstoodBits.cardinality() > 0) {
index -= 32;
moreUnderstoodBits.clear(index);
for (int i = moreUnderstoodBits.nextSetBit(index); i >= 1; i = moreUnderstoodBits.nextSetBit(i + 1)) {
moreUnderstoodBits.set(i - 1);
moreUnderstoodBits.clear(i);
}
}
// remove bit set if the new size will be < 33 => we fit all bits into int
if (size() - 1 <= 33 && moreUnderstoodBits != null) {
moreUnderstoodBits = null;
}
}
/**
* Removes a single instance of the specified element from this
* header list, if it is present. More formally,
* removes a header <tt>h</tt> such that <tt>(o==null ? h==null :
* o.equals(h))</tt>, if the header list contains one or more such
* headers. Returns <tt>true</tt> if the list contained the
* specified element (or equivalently, if the list changed as a
* result of the call).<p>
*
* @param o element to be removed from this list, if present.
* @return <tt>true</tt> if the list contained the specified element.
* @see #remove(javax.xml.namespace.QName)
*/
@Override
public boolean remove(Object o) {
if (o != null) {
for (int index = 0; index < this.size(); index++) {
if (o.equals(this.get(index))) {
remove(index);
return true;
}
}
}
return false;
}
public Header remove(Header h) {
if (remove((Object) h)) {
return h;
} else {
return null;
}
}
/**
* Creates a copy.
*
* This handles null {@link HeaderList} correctly.
*
* @param original
* Can be null, in which case null will be returned.
*/
public static HeaderList copy(MessageHeaders original) {
if (original == null) {
return null;
} else {
return new HeaderList(original);
}
}
/**
* Creates a copy.
*
* This handles null {@link HeaderList} correctly.
*
* @param original
* Can be null, in which case null will be returned.
*/
public static HeaderList copy(HeaderList original) {
return copy((MessageHeaders) original);
}
public void readResponseAddressingHeaders(WSDLPort wsdlPort, WSBinding binding) {
// read Action
// String wsaAction = getAction(binding.getAddressingVersion(), binding.getSOAPVersion());
// TODO: validate client-inbound Action
}
@Override
public void understood(QName name) {
get(name, true);
}
@Override
public void understood(String nsUri, String localName) {
get(nsUri, localName, true);
}
@Override
public Set<QName> getUnderstoodHeaders() {
Set<QName> understoodHdrs = new HashSet<QName>();
for (int i = 0; i < size(); i++) {
if (isUnderstood(i)) {
Header header = get(i);
understoodHdrs.add(new QName(header.getNamespaceURI(), header.getLocalPart()));
}
}
return understoodHdrs;
// throw new UnsupportedOperationException("getUnderstoodHeaders() is not implemented by HeaderList");
}
@Override
public boolean isUnderstood(Header header) {
return isUnderstood(header.getNamespaceURI(), header.getLocalPart());
}
@Override
public boolean isUnderstood(String nsUri, String localName) {
for (int i = 0; i < size(); i++) {
Header h = get(i);
if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
return isUnderstood(i);
}
}
return false;
}
@Override
public boolean isUnderstood(QName name) {
return isUnderstood(name.getNamespaceURI(), name.getLocalPart());
}
@Override
public Set<QName> getNotUnderstoodHeaders(Set<String> roles, Set<QName> knownHeaders, WSBinding binding) {
Set<QName> notUnderstoodHeaders = null;
if (roles == null) {
roles = new HashSet<String>();
}
SOAPVersion effectiveSoapVersion = getEffectiveSOAPVersion(binding);
roles.add(effectiveSoapVersion.implicitRole);
for (int i = 0; i < size(); i++) {
if (!isUnderstood(i)) {
Header header = get(i);
if (!header.isIgnorable(effectiveSoapVersion, roles)) {
QName qName = new QName(header.getNamespaceURI(), header.getLocalPart());
if (binding == null) {
//if binding is null, no further checks needed...we already
//know this header is not understood from the isUnderstood
//check above
if (notUnderstoodHeaders == null) {
notUnderstoodHeaders = new HashSet<QName>();
}
notUnderstoodHeaders.add(qName);
} else {
// if the binding is not null, see if the binding can understand it
if (binding instanceof SOAPBindingImpl && !((SOAPBindingImpl) binding).understandsHeader(qName)) {
if (!knownHeaders.contains(qName)) {
//logger.info("Element not understood=" + qName);
if (notUnderstoodHeaders == null) {
notUnderstoodHeaders = new HashSet<QName>();
}
notUnderstoodHeaders.add(qName);
}
}
}
}
}
}
return notUnderstoodHeaders;
}
private SOAPVersion getEffectiveSOAPVersion(WSBinding binding) {
SOAPVersion mySOAPVersion = (soapVersion != null) ? soapVersion : binding.getSOAPVersion();
if (mySOAPVersion == null) {
mySOAPVersion = SOAPVersion.SOAP_11;
}
return mySOAPVersion;
}
public void setSoapVersion(SOAPVersion soapVersion) {
this.soapVersion = soapVersion;
}
@Override
public Iterator<Header> getHeaders() {
return iterator();
}
@Override
public List<Header> asList() {
return this;
}
}

View File

@@ -0,0 +1,185 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.NotNull;
import com.sun.xml.internal.bind.api.Bridge;
import com.sun.xml.internal.bind.api.JAXBRIContext;
import com.sun.xml.internal.bind.v2.runtime.MarshallerImpl;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.pipe.Pipe;
import com.sun.xml.internal.ws.message.DOMHeader;
import com.sun.xml.internal.ws.message.StringHeader;
import com.sun.xml.internal.ws.message.jaxb.JAXBHeader;
import com.sun.xml.internal.ws.message.saaj.SAAJHeader;
import com.sun.xml.internal.ws.message.stream.StreamHeader11;
import com.sun.xml.internal.ws.message.stream.StreamHeader12;
import com.sun.xml.internal.ws.spi.db.BindingContext;
import com.sun.xml.internal.ws.spi.db.BindingContextFactory;
import com.sun.xml.internal.ws.spi.db.XMLBridge;
import org.w3c.dom.Element;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
/**
* Factory methods for various {@link Header} implementations.
*
* <p>
* This class provides various methods to create different
* flavors of {@link Header} classes that store data
* in different formats.
*
* <p>
* This is a part of the JAX-WS RI internal API so that
* {@link Pipe} implementations can reuse the implementations
* done inside the JAX-WS without having a strong dependency
* to the actual class.
*
* <p>
* If you find some of the useful convenience methods missing
* from this class, please talk to us.
*
*
* @author Kohsuke Kawaguchi
*/
public abstract class Headers {
private Headers() {}
/**
* @deprecated
* Use {@link #create(BindingContext, Object)} instead.
*/
public static Header create(SOAPVersion soapVersion, Marshaller m, Object o) {
return new JAXBHeader(BindingContextFactory.getBindingContext(m),o);
}
/**
* Creates a {@link Header} backed a by a JAXB bean.
*/
public static Header create(JAXBContext context, Object o) {
return new JAXBHeader(BindingContextFactory.create(context),o);
}
public static Header create(BindingContext context, Object o) {
return new JAXBHeader(context,o);
}
/**
* Creates a {@link Header} backed a by a JAXB bean, with the given tag name.
*
* See {@link #create(SOAPVersion, Marshaller, Object)} for the meaning
* of other parameters.
*
* @param tagName
* The name of the newly created header. Must not be null.
* @param o
* The JAXB bean that represents the contents of the header. Must not be null.
*/
public static Header create(SOAPVersion soapVersion, Marshaller m, QName tagName, Object o) {
return create(soapVersion,m,new JAXBElement(tagName,o.getClass(),o));
}
/**
* Creates a {@link Header} backed a by a JAXB bean.
* @deprecated
*/
public static Header create(Bridge bridge, Object jaxbObject) {
return new JAXBHeader(new com.sun.xml.internal.ws.db.glassfish.BridgeWrapper(null,bridge), jaxbObject);
}
public static Header create(XMLBridge bridge, Object jaxbObject) {
return new JAXBHeader(bridge, jaxbObject);
}
/**
* Creates a new {@link Header} backed by a SAAJ object.
*/
public static Header create(SOAPHeaderElement header) {
return new SAAJHeader(header);
}
/**
* Creates a new {@link Header} backed by an {@link Element}.
*/
public static Header create( Element node ) {
return new DOMHeader<Element>(node);
}
/**
* @deprecated
* Use {@link #create(Element)}
*/
public static Header create( SOAPVersion soapVersion, Element node ) {
return create(node);
}
/**
* Creates a new {@link Header} that reads from {@link XMLStreamReader}.
*
* <p>
* Note that the header implementation will read the entire data
* into memory anyway, so this might not be as efficient as you might hope.
*/
public static Header create( SOAPVersion soapVersion, XMLStreamReader reader ) throws XMLStreamException {
switch(soapVersion) {
case SOAP_11:
return new StreamHeader11(reader);
case SOAP_12:
return new StreamHeader12(reader);
default:
throw new AssertionError();
}
}
/**
* Creates a new {@link Header} that that has a single text value in it
* (IOW, of the form &lt;foo>text&lt;/foo>.)
*
* @param name QName of the header element
* @param value text value of the header
*/
public static Header create(QName name, String value) {
return new StringHeader(name, value);
}
/**
* Creates a new {@link Header} that that has a single text value in it
* (IOW, of the form &lt;foo>text&lt;/foo>.)
*
* @param name QName of the header element
* @param value text value of the header
*/
public static Header createMustUnderstand(@NotNull SOAPVersion soapVersion, @NotNull QName name,@NotNull String value) {
return new StringHeader(name, value,soapVersion,true);
}
}

View File

@@ -0,0 +1,789 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.bind.api.Bridge;
import com.sun.xml.internal.ws.api.BindingID;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
import com.sun.xml.internal.ws.api.model.JavaMethod;
import com.sun.xml.internal.ws.api.model.SEIModel;
import com.sun.xml.internal.ws.api.model.WSDLOperationMapping;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundPortType;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.internal.ws.api.pipe.Codec;
import com.sun.xml.internal.ws.api.pipe.Pipe;
import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
import com.sun.xml.internal.ws.client.dispatch.DispatchImpl;
import com.sun.xml.internal.ws.message.AttachmentSetImpl;
import com.sun.xml.internal.ws.message.StringHeader;
import com.sun.xml.internal.ws.message.jaxb.JAXBMessage;
import com.sun.xml.internal.ws.spi.db.XMLBridge;
import com.sun.xml.internal.ws.fault.SOAPFaultBuilder;
import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
import javax.xml.ws.Dispatch;
import javax.xml.ws.WebServiceException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Represents a SOAP message.
*
*
* <h2>What is a message?</h2>
* <p>
* A {@link Message} consists of the following:
*
* <ol>
* <li>
* Random-accessible list of headers.
* a header is a representation of an element inside
* &lt;soap:Header>.
* It can be read multiple times,
* can be added or removed, but it is not modifiable.
* See {@link HeaderList} for more about headers.
*
* <li>
* The payload of the message, which is a representation
* of an element inside &lt;soap:Body>.
* the payload is streamed, and therefore it can be
* only read once (or can be only written to something once.)
* once a payload is used, a message is said to be <b>consumed</b>.
* A message {@link #hasPayload() may not have any payload.}
*
* <li>
* Attachments.
* TODO: can attachments be streamed? I suspect so.
* does anyone need to read attachment twice?
*
* </ol>
*
*
* <h2>How does this abstraction work?</h2>
* <p>
* The basic idea behind the {@link Message} is to hide the actual
* data representation. For example, a {@link Message} might be
* constructed on top of an {@link InputStream} from the accepted HTTP connection,
* or it might be constructed on top of a JAXB object as a result
* of the method invocation through {@link Proxy}. There will be
* a {@link Message} implementation for each of those cases.
*
* <p>
* This interface provides a lot of methods that access the payload
* in many different forms, and implementations can implement those
* methods in the best possible way.
*
* <p>
* A particular attention is paid to make sure that a {@link Message}
* object can be constructed on a stream that is not fully read yet.
* We believe this improves the turn-around time on the server side.
*
* <p>
* It is often useful to wrap a {@link Message} into another {@link Message},
* for example to encrypt the body, or to verify the signature as the body
* is read.
*
* <p>
* This representation is also used for a REST-ful XML message.
* In such case we'll construct a {@link Message} with empty
* attachments and headers, and when serializing all headers
* and attachments will be ignored.
*
*
*
* <h2>Message and XOP</h2>
* <p>
* XOP is considered as an {@link Codec}, and therefore when you are looking at
* {@link Message}, you'll never see &lt;xop:Include> or any such elements
* (instead you'll see the base64 data inlined.) If a consumer of infoset isn't
* interested in handling XOP by himself, this allows him to work with XOP
* correctly even without noticing it.
*
* <p>
* For producers and consumers that are interested in accessing the binary data
* more efficiently, they can use {@link XMLStreamReaderEx} and
* {@link XMLStreamWriterEx}.
*
*
*
* <h2>Message lifespan</h2>
* <p>
* Often {@link Packet} include information local to a particular
* invocaion (such as {@code HttpServletRequest}, from this angle, it makes sense
* to tie a lifespan of a message to one pipeline invocation.
* <p>
* On the other hand, if you think about WS-RM, it often needs to hold on to
* a message longer than a pipeline invocation (you might get an HTTP request,
* get a message X, get a second HTTP request, get another message Y, and
* only then you might want to process X.)
* <p>
* TODO: what do we do about this?
*
*
* <pre>
* TODO: can body element have foreign attributes? maybe ID for security?
* Yes, when the SOAP body is signed there will be an ID attribute present
* But in this case any security based impl may need access
* to the concrete representation.
* TODO: HTTP headers?
* Yes. Abstracted as transport-based properties.
* TODO: who handles SOAP 1.1 and SOAP 1.2 difference?
* As separate channel implementations responsible for the creation of the
* message?
* TODO: session?
* TODO: Do we need to expose SOAPMessage explicitly?
* SOAPMessage could be the concrete representation but is it necessary to
* transform between different concrete representations?
* Perhaps this comes down to how use channels for creation and processing.
* TODO: Do we need to distinguish better between creation and processing?
* Do we really need the requirement that a created message can be resused
* for processing. Shall we bifurcate?
*
* TODO: SOAP version issue
* SOAP version is determined by the context, so message itself doesn't carry it around (?)
*
* TODO: wrapping message needs easier. in particular properties and attachments.
* </pre>
*
* @author Kohsuke Kawaguchi
*/
public abstract class Message {
/**
* Returns true if headers are present in the message.
*
* @return
* true if headers are present.
*/
public abstract boolean hasHeaders();
/**
* Gets all the headers of this message.
*
* <h3>Implementation Note</h3>
* <p>
* {@link Message} implementation is allowed to defer
* the construction of {@link MessageHeaders} object. So
* if you only want to check for the existence of any header
* element, use {@link #hasHeaders()}.
*
* @return
* always return the same non-null object.
*/
public abstract @NotNull MessageHeaders getHeaders();
/**
* Gets the attachments of this message
* (attachments live outside a message.)
*/
public @NotNull AttachmentSet getAttachments() {
if (attachmentSet == null) {
attachmentSet = new AttachmentSetImpl();
}
return attachmentSet;
}
/**
* Optimization hint for the derived class to check
* if we may have some attachments.
*/
protected boolean hasAttachments() {
return attachmentSet!=null;
}
protected AttachmentSet attachmentSet;
private WSDLBoundOperation operation = null;
private WSDLOperationMapping wsdlOperationMapping = null;
private MessageMetadata messageMetadata = null;
public void setMessageMedadata(MessageMetadata metadata) {
messageMetadata = metadata;
}
/**
* Returns the operation of which this message is an instance of.
*
* <p>
* This method relies on {@link WSDLBoundPortType#getOperation(String, String)} but
* it does so in an efficient way.
*
* @deprecated It is not always possible to uniquely identify the WSDL Operation from just the
* information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()}
* to get it correctly.
*
* <p>
* This method works only for a request. A pipe can determine an operation for a request,
* and then keep it in a local variable to use it with a response, so there should be
* no need to find out operation from a response (besides, there might not be any response!).
*
* @param boundPortType
* This represents the port for which this message is used.
* Most {@link Pipe}s should get this information when they are created,
* since a pippeline always work against a particular type of {@link WSDLPort}.
*
* @return
* Null if the operation was not found. This is possible, for example when a protocol
* message is sent through a pipeline, or when we receive an invalid request on the server,
* or when we are on the client and the user appliation sends a random DOM through
* {@link Dispatch}, so this error needs to be handled gracefully.
*/
@Deprecated
public final @Nullable WSDLBoundOperation getOperation(@NotNull WSDLBoundPortType boundPortType) {
if (operation == null && messageMetadata != null) {
if (wsdlOperationMapping == null) wsdlOperationMapping = messageMetadata.getWSDLOperationMapping();
if (wsdlOperationMapping != null) operation = wsdlOperationMapping.getWSDLBoundOperation();
}
if(operation==null)
operation = boundPortType.getOperation(getPayloadNamespaceURI(),getPayloadLocalPart());
return operation;
}
/**
* The same as {@link #getOperation(WSDLBoundPortType)} but
* takes {@link WSDLPort} for convenience.
*
* @deprecated It is not always possible to uniquely identify the WSDL Operation from just the
* information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()}
* to get it correctly.
*/
@Deprecated
public final @Nullable WSDLBoundOperation getOperation(@NotNull WSDLPort port) {
return getOperation(port.getBinding());
}
/**
* Returns the java Method of which this message is an instance of.
*
* It is not always possible to uniquely identify the WSDL Operation from just the
* information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()}
* to get the QName of the associated wsdl operation correctly.
*
* <p>
* This method works only for a request. A pipe can determine a {@link Method}
* for a request, and then keep it in a local variable to use it with a response,
* so there should be no need to find out operation from a response (besides,
* there might not be any response!).
*
* @param seiModel
* This represents the java model for the endpoint
* Some server {@link Pipe}s would get this information when they are created.
*
* @return
* Null if there is no corresponding Method for this message. This is
* possible, for example when a protocol message is sent through a
* pipeline, or when we receive an invalid request on the server,
* or when we are on the client and the user appliation sends a random
* DOM through {@link Dispatch}, so this error needs to be handled
* gracefully.
*/
@Deprecated
public final @Nullable JavaMethod getMethod(@NotNull SEIModel seiModel) {
if (wsdlOperationMapping == null && messageMetadata != null) {
wsdlOperationMapping = messageMetadata.getWSDLOperationMapping();
}
if (wsdlOperationMapping != null) {
return wsdlOperationMapping.getJavaMethod();
}
//fall back to the original logic which could be incorrect ...
String localPart = getPayloadLocalPart();
String nsUri;
if (localPart == null) {
localPart = "";
nsUri = "";
} else {
nsUri = getPayloadNamespaceURI();
}
QName name = new QName(nsUri, localPart);
return seiModel.getJavaMethod(name);
}
private Boolean isOneWay;
/**
* Returns true if this message is a request message for a
* one way operation according to the given WSDL. False otherwise.
*
* <p>
* This method is functionally equivalent as doing
* {@code getOperation(port).getOperation().isOneWay()}
* (with proper null check and all.) But this method
* can sometimes work faster than that (for example,
* on the client side when used with SEI.)
*
* @param port
* {@link Message}s are always created under the context of
* one {@link WSDLPort} and they never go outside that context.
* Pass in that "governing" {@link WSDLPort} object here.
* We chose to receive this as a parameter instead of
* keeping {@link WSDLPort} in a message, just to save the storage.
*
* <p>
* The implementation of this method involves caching the return
* value, so the behavior is undefined if multiple callers provide
* different {@link WSDLPort} objects, which is a bug of the caller.
*/
public boolean isOneWay(@NotNull WSDLPort port) {
if(isOneWay==null) {
// we don't know, so compute.
WSDLBoundOperation op = getOperation(port);
if(op!=null)
isOneWay = op.getOperation().isOneWay();
else
// the contract is to return true only when it's known to be one way.
isOneWay = false;
}
return isOneWay;
}
/**
* Makes an assertion that this {@link Message} is
* a request message for an one-way operation according
* to the context WSDL.
*
* <p>
* This method is really only intended to be invoked from within
* the JAX-WS runtime, and not by any code building on top of it.
*
* <p>
* This method can be invoked only when the caller "knows" what
* WSDL says. Also, there's no point in invoking this method if the caller
* is doing {@code getOperation(port).getOperation().isOneWay()},
* or sniffing the payload tag name.
* In particular, this includes {@link DispatchImpl}.
*
* <p>
* Once called, this allows {@link #isOneWay(WSDLPort)} method
* to return a value quickly.
*
* @see #isOneWay(WSDLPort)
*/
public final void assertOneWay(boolean value) {
// if two callers make different assertions, that's a bug.
// this is an assertion, not a runtime check because
// nobody outside JAX-WS should be using this.
assert isOneWay==null || isOneWay==value;
isOneWay = value;
}
/**
* Gets the local name of the payload element.
*
* @return
* null if a {@link Message} doesn't have any payload.
*/
public abstract @Nullable String getPayloadLocalPart();
/**
* Gets the namespace URI of the payload element.
*
* @return
* null if a {@link Message} doesn't have any payload.
*/
public abstract String getPayloadNamespaceURI();
// I'm not putting @Nullable on it because doing null check on getPayloadLocalPart() should be suffice
/**
* Returns true if a {@link Message} has a payload.
*
* <p>
* A message without a payload is a SOAP message that looks like:
* <pre><xmp>
* <S:Envelope>
* <S:Header>
* ...
* </S:Header>
* <S:Body />
* </S:Envelope>
* </xmp></pre>
*/
public abstract boolean hasPayload();
/**
* Returns true if this message is a fault.
*
* <p>
* Just a convenience method built on {@link #getPayloadNamespaceURI()}
* and {@link #getPayloadLocalPart()}.
*/
public boolean isFault() {
// TODO: is SOAP version a property of a Message?
// or is it defined by external factors?
// how do I compare?
String localPart = getPayloadLocalPart();
if(localPart==null || !localPart.equals("Fault"))
return false;
String nsUri = getPayloadNamespaceURI();
return nsUri.equals(SOAPVersion.SOAP_11.nsUri) || nsUri.equals(SOAPVersion.SOAP_12.nsUri);
}
/**
* It gives S:Envelope/S:Body/S:Fault/detail 's first child's name. Should
* be called for messages that have SOAP Fault.
*
* <p> This implementation is expensive so concrete implementations are
* expected to override this one.
*
* @return first detail entry's name, if there is one
* else null
*/
public @Nullable QName getFirstDetailEntryName() {
assert isFault();
Message msg = copy();
try {
SOAPFaultBuilder fault = SOAPFaultBuilder.create(msg);
return fault.getFirstDetailEntryName();
} catch (JAXBException e) {
throw new WebServiceException(e);
}
}
/**
* Consumes this message including the envelope.
* returns it as a {@link Source} object.
*/
public abstract Source readEnvelopeAsSource();
/**
* Returns the payload as a {@link Source} object.
*
* This consumes the message.
*
* @return
* if there's no payload, this method returns null.
*/
public abstract Source readPayloadAsSource();
/**
* Creates the equivalent {@link SOAPMessage} from this message.
*
* This consumes the message.
*
* @throws SOAPException
* if there's any error while creating a {@link SOAPMessage}.
*/
public abstract SOAPMessage readAsSOAPMessage() throws SOAPException;
/**
* Creates the equivalent {@link SOAPMessage} from this message. It also uses
* transport specific headers from Packet during the SOAPMessage construction
* so that {@link SOAPMessage#getMimeHeaders()} gives meaningful transport
* headers.
*
* This consumes the message.
*
* @throws SOAPException
* if there's any error while creating a {@link SOAPMessage}.
*/
public SOAPMessage readAsSOAPMessage(Packet packet, boolean inbound) throws SOAPException {
return readAsSOAPMessage();
}
public static Map<String, List<String>> getTransportHeaders(Packet packet) {
return getTransportHeaders(packet, packet.getState().isInbound());
}
public static Map<String, List<String>> getTransportHeaders(Packet packet, boolean inbound) {
Map<String, List<String>> headers = null;
String key = inbound ? Packet.INBOUND_TRANSPORT_HEADERS : Packet.OUTBOUND_TRANSPORT_HEADERS;
if (packet.supports(key)) {
headers = (Map<String, List<String>>)packet.get(key);
}
return headers;
}
public static void addSOAPMimeHeaders(MimeHeaders mh, Map<String, List<String>> headers) {
for(Map.Entry<String, List<String>> e : headers.entrySet()) {
if (!e.getKey().equalsIgnoreCase("Content-Type")) {
for(String value : e.getValue()) {
mh.addHeader(e.getKey(), value);
}
}
}
}
/**
* Reads the payload as a JAXB object by using the given unmarshaller.
*
* This consumes the message.
*
* @throws JAXBException
* If JAXB reports an error during the processing.
*/
public abstract <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException;
/**
* Reads the payload as a JAXB object according to the given {@link Bridge}.
*
* This consumes the message.
*
* @deprecated
* @return null
* if there's no payload.
* @throws JAXBException
* If JAXB reports an error during the processing.
*/
public abstract <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException;
/**
* Reads the payload as a Data-Bond object
*
* This consumes the message.
*
* @return null
* if there's no payload.
* @throws JAXBException
* If JAXB reports an error during the processing.
*/
public abstract <T> T readPayloadAsJAXB(XMLBridge<T> bridge) throws JAXBException;
/**
* Reads the payload as a {@link XMLStreamReader}
*
* This consumes the message. The caller is encouraged to call
* {@link XMLStreamReaderFactory#recycle(XMLStreamReader)} when finished using
* the instance.
*
* @return
* If there's no payload, this method returns null.
* Otherwise always non-null valid {@link XMLStreamReader} that points to
* the payload tag name.
*/
public abstract XMLStreamReader readPayload() throws XMLStreamException;
/**
* Marks the message as consumed, without actually reading the contents.
*
* <p>
* This method provides an opportunity for implementations to reuse
* any reusable resources needed for representing the payload.
*
* <p>
* This method may not be called more than once since it may have
* released the reusable resources.
*/
public void consume() {}
/**
* Writes the payload to StAX.
*
* This method writes just the payload of the message to the writer.
* This consumes the message.
* The implementation will not write
* {@link XMLStreamWriter#writeStartDocument()}
* nor
* {@link XMLStreamWriter#writeEndDocument()}
*
* <p>
* If there's no payload, this method is no-op.
*
* @throws XMLStreamException
* If the {@link XMLStreamWriter} reports an error,
* or some other errors happen during the processing.
*/
public abstract void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException;
/**
* Writes the whole SOAP message (but not attachments)
* to the given writer.
*
* This consumes the message.
*
* @throws XMLStreamException
* If the {@link XMLStreamWriter} reports an error,
* or some other errors happen during the processing.
*/
public abstract void writeTo(XMLStreamWriter sw) throws XMLStreamException;
/**
* Writes the whole SOAP envelope as SAX events.
*
* <p>
* This consumes the message.
*
* @param contentHandler
* must not be nulll.
* @param errorHandler
* must not be null.
* any error encountered during the SAX event production must be
* first reported to this error handler. Fatal errors can be then
* thrown as {@link SAXParseException}. {@link SAXException}s thrown
* from {@link ErrorHandler} should propagate directly through this method.
*/
public abstract void writeTo( ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException;
// TODO: do we need a method that reads payload as a fault?
// do we want a separte streaming representation of fault?
// or would SOAPFault in SAAJ do?
/**
* Creates a copy of a {@link Message}.
*
* <p>
* This method creates a new {@link Message} whose header/payload/attachments/properties
* are identical to this {@link Message}. Once created, the created {@link Message}
* and the original {@link Message} behaves independently --- adding header/
* attachment to one {@link Message} doesn't affect another {@link Message}
* at all.
*
* <p>
* This method does <b>NOT</b> consume a message.
*
* <p>
* To enable efficient copy operations, there's a few restrictions on
* how copied message can be used.
*
* <ol>
* <li>The original and the copy may not be
* used concurrently by two threads (this allows two {@link Message}s
* to share some internal resources, such as JAXB marshallers.)
* Note that it's OK for the original and the copy to be processed
* by two threads, as long as they are not concurrent.
*
* <li>The copy has the same 'life scope'
* as the original (this allows shallower copy, such as
* JAXB beans wrapped in {@link JAXBMessage}.)
* </ol>
*
* <p>
* A 'life scope' of a message created during a message processing
* in a pipeline is until a pipeline processes the next message.
* A message cannot be kept beyond its life scope.
*
* (This experimental design is to allow message objects to be reused
* --- feedback appreciated.)
*
*
*
* <h3>Design Rationale</h3>
* <p>
* Since a {@link Message} body is read-once, sometimes
* (such as when you do fail-over, or WS-RM) you need to
* create an idential copy of a {@link Message}.
*
* <p>
* The actual copy operation depends on the layout
* of the data in memory, hence it's best to be done by
* the {@link Message} implementation itself.
*
* <p>
* The restrictions placed on the use of copied {@link Message} can be
* relaxed if necessary, but it will make the copy method more expensive.
*/
// TODO: update the class javadoc with 'lifescope'
// and move the discussion about life scope there.
public abstract Message copy();
/**
* Retuns a unique id for the message. The id can be used for various things,
* like debug assistance, logging, and MIME encoding(say for boundary).
*
* <p>
* This method will check the existence of the addressing <MessageID> header,
* and if present uses that value. Otherwise it generates one from UUID.random(),
* and return it without adding a new header. But it doesn't add a <MessageID>
* to the header list since we expect them to be added before calling this
* method.
*
* <p>
* Addressing tube will go do a separate verification on inbound
* headers to make sure that <MessageID> header is present when it's
* supposed to be.
*
* @param binding object created by {@link BindingID#createBinding()}
*
* @return unique id for the message
* @deprecated
*/
public @NotNull String getID(@NotNull WSBinding binding) {
return getID(binding.getAddressingVersion(), binding.getSOAPVersion());
}
/**
* Retuns a unique id for the message.
* <p><p>
* @see {@link #getID(com.sun.xml.internal.ws.api.WSBinding)} for detailed description.
* @param av WS-Addressing version
* @param sv SOAP version
* @return unique id for the message
* @deprecated
*/
public @NotNull String getID(AddressingVersion av, SOAPVersion sv) {
String uuid = null;
if (av != null) {
uuid = AddressingUtils.getMessageID(getHeaders(), av, sv);
}
if (uuid == null) {
uuid = generateMessageID();
getHeaders().add(new StringHeader(av.messageIDTag, uuid));
}
return uuid;
}
/**
* Generates a UUID suitable for use as a MessageID value
* @return generated UUID
*/
public static String generateMessageID() {
return "uuid:" + UUID.randomUUID().toString();
}
public SOAPVersion getSOAPVersion() {
return null;
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.soap.MTOMFeature;
import com.oracle.webservices.internal.api.EnvelopeStyle;
import com.oracle.webservices.internal.api.EnvelopeStyleFeature;
import com.oracle.webservices.internal.api.message.MessageContext;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSFeatureList;
import com.sun.xml.internal.ws.api.pipe.Codec;
import com.sun.xml.internal.ws.api.pipe.Codecs;
import static com.sun.xml.internal.ws.transport.http.HttpAdapter.fixQuotesAroundSoapAction;
/**
* The MessageContextFactory implements com.oracle.webservices.internal.api.message.MessageContextFactory as
* a factory of Packet and public facade of Codec(s).
*
* @author shih-chang.chen@oracle.com
*/
public class MessageContextFactory extends com.oracle.webservices.internal.api.message.MessageContextFactory {
private WSFeatureList features;
private Codec soapCodec;
private Codec xmlCodec;
private EnvelopeStyleFeature envelopeStyle;
private EnvelopeStyle.Style singleSoapStyle;
public MessageContextFactory(WebServiceFeature[] wsf) {
this(new com.sun.xml.internal.ws.binding.WebServiceFeatureList(wsf));
}
public MessageContextFactory(WSFeatureList wsf) {
features = wsf;
envelopeStyle = features.get(EnvelopeStyleFeature.class);
if (envelopeStyle == null) {//Default to SOAP11
envelopeStyle = new EnvelopeStyleFeature(new EnvelopeStyle.Style[]{EnvelopeStyle.Style.SOAP11});
features.mergeFeatures(new WebServiceFeature[]{envelopeStyle}, false);
}
for (EnvelopeStyle.Style s : envelopeStyle.getStyles()) {
if (s.isXML()) {
if (xmlCodec == null) xmlCodec = Codecs.createXMLCodec(features);
} else {
if (soapCodec == null) soapCodec = Codecs.createSOAPBindingCodec(features);
singleSoapStyle = s;
}
}
}
protected com.oracle.webservices.internal.api.message.MessageContextFactory newFactory(WebServiceFeature... f) {
return new com.sun.xml.internal.ws.api.message.MessageContextFactory(f);
}
public com.oracle.webservices.internal.api.message.MessageContext createContext() {
return packet(null);
}
public com.oracle.webservices.internal.api.message.MessageContext createContext(SOAPMessage soap) {
throwIfIllegalMessageArgument(soap);
return packet(Messages.create(soap));
}
public MessageContext createContext(Source m, com.oracle.webservices.internal.api.EnvelopeStyle.Style envelopeStyle) {
throwIfIllegalMessageArgument(m);
return packet(Messages.create(m, SOAPVersion.from(envelopeStyle)));
}
public com.oracle.webservices.internal.api.message.MessageContext createContext(Source m) {
throwIfIllegalMessageArgument(m);
return packet(Messages.create(m, SOAPVersion.from(singleSoapStyle)));
}
public com.oracle.webservices.internal.api.message.MessageContext createContext(InputStream in, String contentType) throws IOException {
throwIfIllegalMessageArgument(in);
//TODO when do we use xmlCodec?
Packet p = packet(null);
soapCodec.decode(in, contentType, p);
return p;
}
/**
* @deprecated http://java.net/jira/browse/JAX_WS-1077
*/
@Deprecated
public com.oracle.webservices.internal.api.message.MessageContext createContext(InputStream in, MimeHeaders headers) throws IOException {
String contentType = getHeader(headers, "Content-Type");
Packet packet = (Packet) createContext(in, contentType);
packet.acceptableMimeTypes = getHeader(headers, "Accept");
packet.soapAction = fixQuotesAroundSoapAction(getHeader(headers, "SOAPAction"));
// packet.put(Packet.INBOUND_TRANSPORT_HEADERS, toMap(headers));
return packet;
}
static String getHeader(MimeHeaders headers, String name) {
String[] values = headers.getHeader(name);
return (values != null && values.length > 0) ? values[0] : null;
}
static Map<String, List<String>> toMap(MimeHeaders headers) {
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
for (Iterator<MimeHeader> i = headers.getAllHeaders(); i.hasNext();) {
MimeHeader mh = i.next();
List<String> values = map.get(mh.getName());
if (values == null) {
values = new ArrayList<String>();
map.put(mh.getName(), values);
}
values.add(mh.getValue());
}
return map;
}
public MessageContext createContext(Message m) {
throwIfIllegalMessageArgument(m);
return packet(m);
}
private Packet packet(Message m) {
final Packet p = new Packet();
//TODO when do we use xmlCodec?
p.codec = soapCodec;
if (m != null) p.setMessage(m);
MTOMFeature mf = features.get(MTOMFeature.class);
if (mf != null) {
p.setMtomFeature(mf);
}
return p;
}
private void throwIfIllegalMessageArgument(Object message)
throws IllegalArgumentException
{
if (message == null) {
throw new IllegalArgumentException("null messages are not allowed. Consider using MessageContextFactory.createContext()");
}
}
@Deprecated
public com.oracle.webservices.internal.api.message.MessageContext doCreate() {
return packet(null);
}
@Deprecated
public com.oracle.webservices.internal.api.message.MessageContext doCreate(SOAPMessage m) {
return createContext(m);
}
@Deprecated
public com.oracle.webservices.internal.api.message.MessageContext doCreate(Source x, SOAPVersion soapVersion) {
return packet(Messages.create(x, soapVersion));
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import java.util.List;
import java.util.Iterator;
import java.util.Set;
import javax.xml.namespace.QName;
import com.sun.xml.internal.ws.api.WSBinding;
/**
* Interface representing all the headers of a {@link Message}
*/
public interface MessageHeaders {
public void understood(Header header);
public void understood(QName name);
public void understood(String nsUri, String localName);
public Header get(String nsUri, String localName, boolean markAsUnderstood);
public Header get(QName name, boolean markAsUnderstood);
public Iterator<Header> getHeaders(String nsUri, String localName, final boolean markAsUnderstood);
/**
* Get all headers in specified namespace
* @param nsUri
* @param markAsUnderstood
* @return
*/
public Iterator<Header> getHeaders(String nsUri, final boolean markAsUnderstood);
public Iterator<Header> getHeaders(QName headerName, final boolean markAsUnderstood);
public Iterator<Header> getHeaders();
public boolean hasHeaders();
public boolean add(Header header);
public Header remove(QName name);
public Header remove(String nsUri, String localName);
//DONT public Header remove(Header header);
public void replace(Header old, Header header);
/**
* Replaces an existing {@link Header} or adds a new {@link Header}.
*
* <p>
* Order doesn't matter in headers, so this method
* does not make any guarantee as to where the new header
* is inserted.
*
* @return
* always true. Don't use the return value.
*/
public boolean addOrReplace(Header header);
/**
* Return a Set of QNames of headers that have been explicitly marked as understood.
* If none have been marked, this method could return null
*/
public Set<QName> getUnderstoodHeaders();
/**
* Returns a Set of QNames of headers that satisfy ALL the following conditions:
* (a) Have mustUnderstand = true
* (b) have NOT been explicitly marked as understood
* (c) If roles argument is non-null, the header has isIgnorable = false
* for the roles argument and SOAP version
* (d) If non-null binding is passed in, are NOT understood by the binding
* (e) If (d) is met, the header is NOT in the knownHeaders list passed in
*
* @param roles
* @param knownHeaders
* @param binding
* @return
*/
public Set<QName> getNotUnderstoodHeaders(Set<String> roles, Set<QName> knownHeaders, WSBinding binding);
/**
* True if the header has been explicitly marked understood, false otherwise
* @param header
* @return
*/
public boolean isUnderstood(Header header);
/**
* True if the header has been explicitly marked understood, false otherwise
* @param header
* @return
*/
public boolean isUnderstood(QName header);
/**
* True if the header has been explicitly marked understood, false otherwise
* @param header
* @return
*/
public boolean isUnderstood(String nsUri, String header);
/**
* Returns <code>Header</code> instances in a <code>List</code>.
* @return <code>List</code> containing <code>Header</code> instances
*/
public List<Header> asList();
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.xml.internal.ws.api.model.WSDLOperationMapping;
/**
* In order for the Message to get properties from the Packet ...
*
* @author shih-chang.chen@oracle.com
*/
public interface MessageMetadata {
public WSDLOperationMapping getWSDLOperationMapping();
}

View File

@@ -0,0 +1,245 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import com.sun.istack.internal.NotNull;
import com.sun.xml.internal.bind.api.Bridge;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.internal.ws.message.saaj.SAAJMessage;
import com.sun.xml.internal.ws.message.stream.StreamMessage;
import com.sun.xml.internal.ws.spi.db.XMLBridge;
/**
* A <code>MessageWrapper</code> wraps the Message for the access through Packet.
*
* @author shih-chang.chen@oracle.com
*/
class MessageWrapper extends StreamMessage {
Packet packet;
Message delegate;
StreamMessage streamDelegate;
@Override
public void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
streamDelegate.writePayloadTo(contentHandler, errorHandler, fragment);
}
@Override
public String getBodyPrologue() {
return streamDelegate.getBodyPrologue();
}
@Override
public String getBodyEpilogue() {
return streamDelegate.getBodyEpilogue();
}
MessageWrapper(Packet p, Message m) {
super(m.getSOAPVersion());
packet = p;
delegate = m;
streamDelegate = (m instanceof StreamMessage) ? (StreamMessage) m : null;
setMessageMedadata(p);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public boolean hasHeaders() {
return delegate.hasHeaders();
}
@Override
public AttachmentSet getAttachments() {
return delegate.getAttachments();
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public boolean isOneWay(WSDLPort port) {
return delegate.isOneWay(port);
}
@Override
public String getPayloadLocalPart() {
return delegate.getPayloadLocalPart();
}
@Override
public String getPayloadNamespaceURI() {
return delegate.getPayloadNamespaceURI();
}
@Override
public boolean hasPayload() {
return delegate.hasPayload();
}
@Override
public boolean isFault() {
return delegate.isFault();
}
@Override
public QName getFirstDetailEntryName() {
return delegate.getFirstDetailEntryName();
}
@Override
public Source readEnvelopeAsSource() {
//TODO if (delegate instanceof SAAJMessage)
return delegate.readEnvelopeAsSource();
}
@Override
public Source readPayloadAsSource() {
//TODO if (delegate instanceof SAAJMessage)
return delegate.readPayloadAsSource();
}
@Override
public SOAPMessage readAsSOAPMessage() throws SOAPException {
if (!(delegate instanceof SAAJMessage)) {
delegate = toSAAJ(packet, null);
}
return delegate.readAsSOAPMessage();
}
@Override
public SOAPMessage readAsSOAPMessage(Packet p, boolean inbound) throws SOAPException {
if (!(delegate instanceof SAAJMessage)) {
delegate = toSAAJ(p, inbound);
}
return delegate.readAsSOAPMessage();
}
@Override
public Object readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException {
return delegate.readPayloadAsJAXB(unmarshaller);
}
@Override
public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException {
return delegate.readPayloadAsJAXB(bridge);
}
@Override
public <T> T readPayloadAsJAXB(XMLBridge<T> bridge) throws JAXBException {
return delegate.readPayloadAsJAXB(bridge);
}
@Override
public XMLStreamReader readPayload() {
try {
return delegate.readPayload();
} catch (XMLStreamException e) {
e.printStackTrace();
}
return null;
}
@Override
public void consume() {
delegate.consume();
}
@Override
public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
delegate.writePayloadTo(sw);
}
@Override
public void writeTo(XMLStreamWriter sw) throws XMLStreamException {
delegate.writeTo(sw);
}
@Override
public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler)
throws SAXException {
delegate.writeTo(contentHandler, errorHandler);
}
@Override
public Message copy() {
return delegate.copy();
}
@Override
public String getID(WSBinding binding) {
return delegate.getID(binding);
}
@Override
public String getID(AddressingVersion av, SOAPVersion sv) {
return delegate.getID(av, sv);
}
@Override
public SOAPVersion getSOAPVersion() {
return delegate.getSOAPVersion();
}
@Override
public @NotNull MessageHeaders getHeaders() {
return delegate.getHeaders();
}
@Override
public void setMessageMedadata(MessageMetadata metadata) {
super.setMessageMedadata(metadata);
delegate.setMessageMedadata(metadata);
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import java.io.IOException;
import java.io.OutputStream;
import javax.xml.ws.soap.MTOMFeature;
import com.oracle.webservices.internal.api.message.ContentType;
/**
* A Message implementation may implement this interface as an alternative way to write the
* message into the OutputStream.
*
* @author shih-chang.chen@oracle.com
*/
public interface MessageWritable {
/**
* Gets the Content-type of this message.
*
* @return The MIME content type of this message
*/
ContentType getContentType();
/**
* Writes the XML infoset portion of this MessageContext
* (from &lt;soap:Envelope> to &lt;/soap:Envelope>).
*
* @param out
* Must not be null. The caller is responsible for closing the stream,
* not the callee.
*
* @return
* The MIME content type of this message (such as "application/xml").
* This information is often ncessary by transport.
*
* @throws IOException
* if a {@link OutputStream} throws {@link IOException}.
*/
ContentType writeTo( OutputStream out ) throws IOException;
/**
* Passes configuration information to this message to ensure the proper
* wire format is created. (from &lt;soap:Envelope> to &lt;/soap:Envelope>).
*
* @param mtomFeature
* The standard <code>WebServicesFeature</code> for specifying
* the MTOM enablement and possibly threshold for the endpoint.
* This value may be <code>null</code>.
*/
void setMTOMConfiguration(final MTOMFeature mtomFeature);
}

View File

@@ -0,0 +1,420 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory;
import com.sun.xml.internal.ws.api.pipe.Tube;
import com.sun.xml.internal.ws.api.pipe.Codecs;
import com.sun.xml.internal.ws.fault.SOAPFaultBuilder;
import com.sun.xml.internal.ws.message.AttachmentSetImpl;
import com.sun.xml.internal.ws.message.DOMMessage;
import com.sun.xml.internal.ws.message.EmptyMessageImpl;
import com.sun.xml.internal.ws.message.ProblemActionHeader;
import com.sun.xml.internal.ws.message.stream.PayloadStreamReaderMessage;
import com.sun.xml.internal.ws.message.jaxb.JAXBMessage;
import com.sun.xml.internal.ws.message.source.PayloadSourceMessage;
import com.sun.xml.internal.ws.message.source.ProtocolSourceMessage;
import com.sun.xml.internal.ws.spi.db.BindingContextFactory;
import com.sun.xml.internal.ws.streaming.XMLStreamReaderException;
import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
import com.sun.xml.internal.ws.util.DOMUtil;
import com.sun.xml.internal.ws.addressing.WsaTubeHelper;
import com.sun.xml.internal.ws.addressing.model.MissingAddressingHeaderException;
import com.sun.xml.internal.ws.resources.AddressingMessages;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.dom.DOMSource;
import javax.xml.ws.ProtocolException;
import javax.xml.ws.WebServiceException;
/**
* Factory methods for various {@link Message} implementations.
*
* <p>
* This class provides various methods to create different
* flavors of {@link Message} classes that store data
* in different formats.
*
* <p>
* This is a part of the JAX-WS RI internal API so that
* {@link Tube} implementations can reuse the implementations
* done inside the JAX-WS.
*
* <p>
* If you find some of the useful convenience methods missing
* from this class, please talk to us.
*
*
* @author Kohsuke Kawaguchi
*/
public abstract class Messages {
private Messages() {}
/**
* Creates a {@link Message} backed by a JAXB bean.
* @deprecated
* @param context
* The context to be used to produce infoset from the object. Must not be null.
* @param jaxbObject
* The JAXB object that represents the payload. must not be null. This object
* must be bound to an element (which means it either is a {@link JAXBElement} or
* an instanceof a class with {@link XmlRootElement}).
* @param soapVersion
* The SOAP version of the message. Must not be null.
*/
public static Message create(JAXBContext context, Object jaxbObject, SOAPVersion soapVersion) {
return JAXBMessage.create(context,jaxbObject,soapVersion);
}
/**
* @deprecated
* For use when creating a Dispatch object with an unknown JAXB implementation
* for he JAXBContext parameter.
*
*/
public static Message createRaw(JAXBContext context, Object jaxbObject, SOAPVersion soapVersion) {
return JAXBMessage.createRaw(context,jaxbObject,soapVersion);
}
/**
* @deprecated
* Use {@link #create(JAXBRIContext, Object, SOAPVersion)}
*/
public static Message create(Marshaller marshaller, Object jaxbObject, SOAPVersion soapVersion) {
return create(BindingContextFactory.getBindingContext(marshaller).getJAXBContext(),jaxbObject,soapVersion);
}
/**
* Creates a {@link Message} backed by a SAAJ {@link SOAPMessage} object.
*
* <p>
* If the {@link SOAPMessage} contains headers and attachments, this method
* does the right thing.
*
* @param saaj
* The SOAP message to be represented as a {@link Message}.
* Must not be null. Once this method is invoked, the created
* {@link Message} will own the {@link SOAPMessage}, so it shall
* never be touched directly.
*/
public static Message create(SOAPMessage saaj) {
return SAAJFactory.create(saaj);
}
/**
* Creates a {@link Message} using {@link Source} as payload.
*
* @param payload
* Source payload is {@link Message}'s payload
* Must not be null. Once this method is invoked, the created
* {@link Message} will own the {@link Source}, so it shall
* never be touched directly.
*
* @param ver
* The SOAP version of the message. Must not be null.
*/
public static Message createUsingPayload(Source payload, SOAPVersion ver) {
if (payload instanceof DOMSource) {
if (((DOMSource)payload).getNode() == null) {
return new EmptyMessageImpl(ver);
}
} else if (payload instanceof StreamSource) {
StreamSource ss = (StreamSource)payload;
if (ss.getInputStream() == null && ss.getReader() == null && ss.getSystemId() == null) {
return new EmptyMessageImpl(ver);
}
} else if (payload instanceof SAXSource) {
SAXSource ss = (SAXSource)payload;
if (ss.getInputSource() == null && ss.getXMLReader() == null) {
return new EmptyMessageImpl(ver);
}
}
return new PayloadSourceMessage(payload, ver);
}
/**
* Creates a {@link Message} using {@link XMLStreamReader} as payload.
*
* @param payload
* XMLStreamReader payload is {@link Message}'s payload
* Must not be null. Once this method is invoked, the created
* {@link Message} will own the {@link XMLStreamReader}, so it shall
* never be touched directly.
*
* @param ver
* The SOAP version of the message. Must not be null.
*/
public static Message createUsingPayload(XMLStreamReader payload, SOAPVersion ver) {
return new PayloadStreamReaderMessage(payload, ver);
}
/**
* Creates a {@link Message} from an {@link Element} that represents
* a payload.
*
* @param payload
* The element that becomes the child element of the SOAP body.
* Must not be null.
*
* @param ver
* The SOAP version of the message. Must not be null.
*/
public static Message createUsingPayload(Element payload, SOAPVersion ver) {
return new DOMMessage(ver,payload);
}
/**
* Creates a {@link Message} from an {@link Element} that represents
* the whole SOAP message.
*
* @param soapEnvelope
* The SOAP envelope element.
*/
public static Message create(Element soapEnvelope) {
SOAPVersion ver = SOAPVersion.fromNsUri(soapEnvelope.getNamespaceURI());
// find the headers
Element header = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Header");
HeaderList headers = null;
if(header!=null) {
for( Node n=header.getFirstChild(); n!=null; n=n.getNextSibling() ) {
if(n.getNodeType()==Node.ELEMENT_NODE) {
if(headers==null)
headers = new HeaderList(ver);
headers.add(Headers.create((Element)n));
}
}
}
// find the payload
Element body = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Body");
if(body==null)
throw new WebServiceException("Message doesn't have <S:Body> "+soapEnvelope);
Element payload = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Body");
if(payload==null) {
return new EmptyMessageImpl(headers, new AttachmentSetImpl(), ver);
} else {
return new DOMMessage(ver,headers,payload);
}
}
/**
* Creates a {@link Message} using Source as entire envelope.
*
* @param envelope
* Source envelope is used to create {@link Message}
* Must not be null. Once this method is invoked, the created
* {@link Message} will own the {@link Source}, so it shall
* never be touched directly.
*
*/
public static Message create(Source envelope, SOAPVersion soapVersion) {
return new ProtocolSourceMessage(envelope, soapVersion);
}
/**
* Creates a {@link Message} that doesn't have any payload.
*/
public static Message createEmpty(SOAPVersion soapVersion) {
return new EmptyMessageImpl(soapVersion);
}
/**
* Creates a {@link Message} from {@link XMLStreamReader} that points to
* the start of the envelope.
*
* @param reader
* can point to the start document or the start element (of &lt;s:Envelope>)
*/
public static @NotNull Message create(@NotNull XMLStreamReader reader) {
// skip until the root element
if(reader.getEventType()!=XMLStreamConstants.START_ELEMENT)
XMLStreamReaderUtil.nextElementContent(reader);
assert reader.getEventType()== XMLStreamConstants.START_ELEMENT :reader.getEventType();
SOAPVersion ver = SOAPVersion.fromNsUri(reader.getNamespaceURI());
return Codecs.createSOAPEnvelopeXmlCodec(ver).decode(reader);
}
/**
* Creates a {@link Message} from {@link XMLStreamBuffer} that retains the
* whole envelope infoset.
*
* @param xsb
* This buffer must contain the infoset of the whole envelope.
*/
public static @NotNull Message create(@NotNull XMLStreamBuffer xsb) {
// TODO: we should be able to let Messae know that it's working off from a buffer,
// to make some of the operations more efficient.
// meanwhile, adding this as an API so that our users can take advantage of it
// when we get around to such an implementation later.
try {
return create(xsb.readAsXMLStreamReader());
} catch (XMLStreamException e) {
throw new XMLStreamReaderException(e);
}
}
/**
* Creates a {@link Message} that represents an exception as a fault. The
* created message reflects if t or t.getCause() is SOAPFaultException.
*
* creates a fault message with default faultCode env:Server if t or t.getCause()
* is not SOAPFaultException. Otherwise, it use SOAPFaultException's faultCode
*
* @return
* Always non-null. A message that wraps this {@link Throwable}.
*
*/
public static Message create(Throwable t, SOAPVersion soapVersion) {
return SOAPFaultBuilder.createSOAPFaultMessage(soapVersion, null, t);
}
/**
* Creates a fault {@link Message}.
*
* <p>
* This method is not designed for efficiency, and we don't expect
* to be used for the performance critical codepath.
*
* @param fault
* The populated SAAJ data structure that represents a fault
* in detail.
*
* @return
* Always non-null. A message that wraps this {@link SOAPFault}.
*/
public static Message create(SOAPFault fault) {
SOAPVersion ver = SOAPVersion.fromNsUri(fault.getNamespaceURI());
return new DOMMessage(ver,fault);
}
/**
* @deprecated
* Use {@link #createAddressingFaultMessage(WSBinding, Packet, QName)}
*/
public static Message createAddressingFaultMessage(WSBinding binding, QName missingHeader) {
return createAddressingFaultMessage(binding,null,missingHeader);
}
/**
* Creates a fault {@link Message} that captures the code/subcode/subsubcode
* defined by WS-Addressing if one of the expected WS-Addressing headers is
* missing in the message
*
* @param binding WSBinding
* @param p
* {@link Packet} that was missing a WS-Addressing header.
* @param missingHeader The missing WS-Addressing Header
* @return
* A message representing SOAPFault that contains the WS-Addressing code/subcode/subsubcode.
*/
public static Message createAddressingFaultMessage(WSBinding binding, Packet p, QName missingHeader) {
AddressingVersion av = binding.getAddressingVersion();
if(av == null) {
// Addressing is not enabled.
throw new WebServiceException(AddressingMessages.ADDRESSING_SHOULD_BE_ENABLED());
}
WsaTubeHelper helper = av.getWsaHelper(null,null,binding);
return create(helper.newMapRequiredFault(new MissingAddressingHeaderException(missingHeader,p)));
}
/**
* Creates a fault {@link Message} that captures the code/subcode/subsubcode
* defined by WS-Addressing if wsa:Action is not supported.
*
* @param unsupportedAction The unsupported Action. Must not be null.
* @param av The WS-Addressing version of the message. Must not be null.
* @param sv The SOAP Version of the message. Must not be null.
*
* @return
* A message representing SOAPFault that contains the WS-Addressing code/subcode/subsubcode.
*/
public static Message create(@NotNull String unsupportedAction, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
QName subcode = av.actionNotSupportedTag;
String faultstring = String.format(av.actionNotSupportedText, unsupportedAction);
Message faultMessage;
SOAPFault fault;
try {
if (sv == SOAPVersion.SOAP_12) {
fault = SOAPVersion.SOAP_12.getSOAPFactory().createFault();
fault.setFaultCode(SOAPConstants.SOAP_SENDER_FAULT);
fault.appendFaultSubcode(subcode);
Detail detail = fault.addDetail();
SOAPElement se = detail.addChildElement(av.problemActionTag);
se = se.addChildElement(av.actionTag);
se.addTextNode(unsupportedAction);
} else {
fault = SOAPVersion.SOAP_11.getSOAPFactory().createFault();
fault.setFaultCode(subcode);
}
fault.setFaultString(faultstring);
faultMessage = SOAPFaultBuilder.createSOAPFaultMessage(sv, fault);
if (sv == SOAPVersion.SOAP_11) {
faultMessage.getHeaders().add(new ProblemActionHeader(unsupportedAction, av));
}
} catch (SOAPException e) {
throw new WebServiceException(e);
}
return faultMessage;
}
/**
* To be called to convert a {@link ProtocolException} and faultcode for a given {@link SOAPVersion} in to a {@link Message}.
*
* @param soapVersion {@link SOAPVersion#SOAP_11} or {@link SOAPVersion#SOAP_12}
* @param pex a ProtocolException
* @param faultcode soap faultcode. Its ignored if the {@link ProtocolException} instance is {@link javax.xml.ws.soap.SOAPFaultException} and it has a
* faultcode present in the underlying {@link SOAPFault}.
* @return {@link Message} representing SOAP fault
*/
public static @NotNull Message create(@NotNull SOAPVersion soapVersion, @NotNull ProtocolException pex, @Nullable QName faultcode){
return SOAPFaultBuilder.createSOAPFaultMessage(soapVersion, pex, faultcode);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import javax.xml.stream.XMLStreamReader;
public interface StreamingSOAP {
public XMLStreamReader readEnvelope();
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message;
import javax.xml.ws.WebServiceFeature;
/**
* Suppresses automatic generation of WS-Addressing headers in request messages. Use this in cases
* where required headers will be generated by other means.
*
* @since 2.2.6
*/
public class SuppressAutomaticWSARequestHeadersFeature extends
WebServiceFeature {
public SuppressAutomaticWSARequestHeadersFeature() {
enabled = true;
}
@Override
public String getID() {
return SuppressAutomaticWSARequestHeadersFeature.class.toString();
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* {@link com.sun.xml.internal.ws.api.message.Message} and related abstractions that represent a SOAP message.
*/
package com.sun.xml.internal.ws.api.message;

View File

@@ -0,0 +1,339 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message.saaj;
import java.util.Iterator;
import javax.xml.soap.AttachmentPart;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SAAJMetaFactory;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import org.xml.sax.SAXException;
import com.sun.xml.internal.bind.marshaller.SAX2DOMEx;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.message.Attachment;
import com.sun.xml.internal.ws.api.message.AttachmentEx;
import com.sun.xml.internal.ws.api.message.Message;
import com.sun.xml.internal.ws.api.message.Packet;
import com.sun.xml.internal.ws.message.saaj.SAAJMessage;
import com.sun.xml.internal.ws.util.ServiceFinder;
import com.sun.xml.internal.ws.util.xml.XmlUtil;
/**
* Factory SPI for SAAJ implementations
*
* @since 2.2.6
*/
public class SAAJFactory {
private static final SAAJFactory instance = new SAAJFactory();
/**
* Creates a new <code>MessageFactory</code> object that is an instance
* of the specified implementation. May be a dynamic message factory,
* a SOAP 1.1 message factory, or a SOAP 1.2 message factory. A dynamic
* message factory creates messages based on the MIME headers specified
* as arguments to the <code>createMessage</code> method.
*
* This method uses the SAAJMetaFactory to locate the implementation class
* and create the MessageFactory instance.
*
* @return a new instance of a <code>MessageFactory</code>
*
* @param protocol a string constant representing the class of the
* specified message factory implementation. May be
* either <code>DYNAMIC_SOAP_PROTOCOL</code>,
* <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
* as) <code>SOAP_1_1_PROTOCOL</code>, or
* <code>SOAP_1_2_PROTOCOL</code>.
*
* @exception SOAPException if there was an error in creating the
* specified implementation of <code>MessageFactory</code>.
* @see SAAJMetaFactory
*/
public static MessageFactory getMessageFactory(String protocol) throws SOAPException {
for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
MessageFactory mf = s.createMessageFactory(protocol);
if (mf != null)
return mf;
}
return instance.createMessageFactory(protocol);
}
/**
* Creates a new <code>SOAPFactory</code> object that is an instance of
* the specified implementation, this method uses the SAAJMetaFactory to
* locate the implementation class and create the SOAPFactory instance.
*
* @return a new instance of a <code>SOAPFactory</code>
*
* @param protocol a string constant representing the protocol of the
* specified SOAP factory implementation. May be
* either <code>DYNAMIC_SOAP_PROTOCOL</code>,
* <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
* as) <code>SOAP_1_1_PROTOCOL</code>, or
* <code>SOAP_1_2_PROTOCOL</code>.
*
* @exception SOAPException if there was an error creating the
* specified <code>SOAPFactory</code>
* @see SAAJMetaFactory
*/
public static SOAPFactory getSOAPFactory(String protocol) throws SOAPException {
for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
SOAPFactory sf = s.createSOAPFactory(protocol);
if (sf != null)
return sf;
}
return instance.createSOAPFactory(protocol);
}
/**
* Creates Message from SOAPMessage
* @param saaj SOAPMessage
* @return created Message
*/
public static Message create(SOAPMessage saaj) {
for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
Message m = s.createMessage(saaj);
if (m != null)
return m;
}
return instance.createMessage(saaj);
}
/**
* Reads Message as SOAPMessage. After this call message is consumed.
* @param soapVersion SOAP version
* @param message Message
* @return Created SOAPMessage
* @throws SOAPException if SAAJ processing fails
*/
public static SOAPMessage read(SOAPVersion soapVersion, Message message) throws SOAPException {
for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
SOAPMessage msg = s.readAsSOAPMessage(soapVersion, message);
if (msg != null)
return msg;
}
return instance.readAsSOAPMessage(soapVersion, message);
}
/**
* Reads Message as SOAPMessage. After this call message is consumed.
* @param soapVersion SOAP version
* @param message Message
* @param packet The packet that owns the Message
* @return Created SOAPMessage
* @throws SOAPException if SAAJ processing fails
*/
public static SOAPMessage read(SOAPVersion soapVersion, Message message, Packet packet) throws SOAPException {
for (SAAJFactory s : ServiceFinder.find(SAAJFactory.class)) {
SOAPMessage msg = s.readAsSOAPMessage(soapVersion, message, packet);
if (msg != null)
return msg;
}
return instance.readAsSOAPMessage(soapVersion, message, packet);
}
/**
* Reads the message within the Packet to a SAAJMessage. After this call message is consumed.
* @param packet Packet
* @return Created SAAJPMessage
* @throws SOAPException if SAAJ processing fails
*/
public static SAAJMessage read(Packet packet) throws SOAPException {
// Use the Component from the Packet if it exists. Note the logic
// in the ServiceFinder is such that find(Class) is not equivalent
// to find (Class, null), so the ternary operator is needed.
ServiceFinder<SAAJFactory> factories = (packet.component != null ?
ServiceFinder.find(SAAJFactory.class, packet.component) :
ServiceFinder.find(SAAJFactory.class));
for (SAAJFactory s : factories) {
SAAJMessage msg = s.readAsSAAJ(packet);
if (msg != null) return msg;
}
return instance.readAsSAAJ(packet);
}
/**
* Reads the message within the Packet to a SAAJMessage. After this call message is consumed.
* @param packet Packet
* @return Created SAAJPMessage
* @throws SOAPException if SAAJ processing fails
*/
public SAAJMessage readAsSAAJ(Packet packet) throws SOAPException {
SOAPVersion v = packet.getMessage().getSOAPVersion();
SOAPMessage msg = readAsSOAPMessage(v, packet.getMessage());
return new SAAJMessage(msg);
}
/**
* Creates a new <code>MessageFactory</code> object that is an instance
* of the specified implementation. May be a dynamic message factory,
* a SOAP 1.1 message factory, or a SOAP 1.2 message factory. A dynamic
* message factory creates messages based on the MIME headers specified
* as arguments to the <code>createMessage</code> method.
*
* This method uses the SAAJMetaFactory to locate the implementation class
* and create the MessageFactory instance.
*
* @return a new instance of a <code>MessageFactory</code>
*
* @param protocol a string constant representing the class of the
* specified message factory implementation. May be
* either <code>DYNAMIC_SOAP_PROTOCOL</code>,
* <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
* as) <code>SOAP_1_1_PROTOCOL</code>, or
* <code>SOAP_1_2_PROTOCOL</code>.
*
* @exception SOAPException if there was an error in creating the
* specified implementation of <code>MessageFactory</code>.
* @see SAAJMetaFactory
*/
public MessageFactory createMessageFactory(String protocol) throws SOAPException {
return MessageFactory.newInstance(protocol);
}
/**
* Creates a new <code>SOAPFactory</code> object that is an instance of
* the specified implementation, this method uses the SAAJMetaFactory to
* locate the implementation class and create the SOAPFactory instance.
*
* @return a new instance of a <code>SOAPFactory</code>
*
* @param protocol a string constant representing the protocol of the
* specified SOAP factory implementation. May be
* either <code>DYNAMIC_SOAP_PROTOCOL</code>,
* <code>DEFAULT_SOAP_PROTOCOL</code> (which is the same
* as) <code>SOAP_1_1_PROTOCOL</code>, or
* <code>SOAP_1_2_PROTOCOL</code>.
*
* @exception SOAPException if there was an error creating the
* specified <code>SOAPFactory</code>
* @see SAAJMetaFactory
*/
public SOAPFactory createSOAPFactory(String protocol) throws SOAPException {
return SOAPFactory.newInstance(protocol);
}
/**
* Creates Message from SOAPMessage
* @param saaj SOAPMessage
* @return created Message
*/
public Message createMessage(SOAPMessage saaj) {
return new SAAJMessage(saaj);
}
/**
* Reads Message as SOAPMessage. After this call message is consumed.
* @param soapVersion SOAP version
* @param message Message
* @return Created SOAPMessage
* @throws SOAPException if SAAJ processing fails
*/
public SOAPMessage readAsSOAPMessage(final SOAPVersion soapVersion, final Message message) throws SOAPException {
SOAPMessage msg = soapVersion.getMessageFactory().createMessage();
SaajStaxWriter writer = new SaajStaxWriter(msg);
try {
message.writeTo(writer);
} catch (XMLStreamException e) {
throw (e.getCause() instanceof SOAPException) ? (SOAPException) e.getCause() : new SOAPException(e);
}
msg = writer.getSOAPMessage();
addAttachmentsToSOAPMessage(msg, message);
if (msg.saveRequired())
msg.saveChanges();
return msg;
}
public SOAPMessage readAsSOAPMessageSax2Dom(final SOAPVersion soapVersion, final Message message) throws SOAPException {
SOAPMessage msg = soapVersion.getMessageFactory().createMessage();
SAX2DOMEx s2d = new SAX2DOMEx(msg.getSOAPPart());
try {
message.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER);
} catch (SAXException e) {
throw new SOAPException(e);
}
addAttachmentsToSOAPMessage(msg, message);
if (msg.saveRequired())
msg.saveChanges();
return msg;
}
static protected void addAttachmentsToSOAPMessage(SOAPMessage msg, Message message) {
for(Attachment att : message.getAttachments()) {
AttachmentPart part = msg.createAttachmentPart();
part.setDataHandler(att.asDataHandler());
// Be safe and avoid double angle-brackets.
String cid = att.getContentId();
if (cid != null) {
if (cid.startsWith("<") && cid.endsWith(">"))
part.setContentId(cid);
else
part.setContentId('<' + cid + '>');
}
// Add any MIME headers beside Content-ID, which is already
// accounted for above, and Content-Type, which is provided
// by the DataHandler above.
if (att instanceof AttachmentEx) {
AttachmentEx ax = (AttachmentEx) att;
Iterator<AttachmentEx.MimeHeader> imh = ax.getMimeHeaders();
while (imh.hasNext()) {
AttachmentEx.MimeHeader ame = imh.next();
if ((!"Content-ID".equals(ame.getName()))
&& (!"Content-Type".equals(ame.getName())))
part.addMimeHeader(ame.getName(), ame.getValue());
}
}
msg.addAttachmentPart(part);
}
}
/**
* Reads Message as SOAPMessage. After this call message is consumed.
* The implementation in this class simply calls readAsSOAPMessage(SOAPVersion, Message),
* and ignores the other parameters
* Subclasses can override and choose to base SOAPMessage creation on Packet properties if needed
* @param soapVersion SOAP version
* @param message Message
* @return Created SOAPMessage
* @throws SOAPException if SAAJ processing fails
*/
public SOAPMessage readAsSOAPMessage(SOAPVersion soapVersion, Message message, Packet packet) throws SOAPException {
return readAsSOAPMessage(soapVersion, message);
}
}

View File

@@ -0,0 +1,498 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message.saaj;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.message.Header;
import com.sun.xml.internal.ws.api.message.MessageHeaders;
import com.sun.xml.internal.ws.binding.SOAPBindingImpl;
import com.sun.xml.internal.ws.message.saaj.SAAJHeader;
public class SAAJMessageHeaders implements MessageHeaders {
SOAPMessage sm;
Map<SOAPHeaderElement, Header> nonSAAJHeaders;
Map<QName, Integer> notUnderstoodCount;
SOAPVersion soapVersion;
private Set<QName> understoodHeaders;
public SAAJMessageHeaders(SOAPMessage sm, SOAPVersion version) {
this.sm = sm;
this.soapVersion = version;
initHeaderUnderstanding();
}
/** Set the initial understood/not understood state of the headers in this
* object
*/
private void initHeaderUnderstanding() {
SOAPHeader soapHeader = ensureSOAPHeader();
if (soapHeader == null) {
return;
}
Iterator allHeaders = soapHeader.examineAllHeaderElements();
while(allHeaders.hasNext()) {
SOAPHeaderElement nextHdrElem = (SOAPHeaderElement) allHeaders.next();
if (nextHdrElem == null) {
continue;
}
if (nextHdrElem.getMustUnderstand()) {
notUnderstood(nextHdrElem.getElementQName());
}
//only headers explicitly marked as understood should be
//in the understoodHeaders set, so don't add anything to
//that set at the beginning
}
}
@Override
public void understood(Header header) {
understood(header.getNamespaceURI(), header.getLocalPart());
}
@Override
public void understood(String nsUri, String localName) {
understood(new QName(nsUri, localName));
}
@Override
public void understood(QName qName) {
if (notUnderstoodCount == null) {
notUnderstoodCount = new HashMap<QName, Integer>();
}
Integer count = notUnderstoodCount.get(qName);
if (count != null && count.intValue() > 0) {
//found the header in notUnderstood headers - decrement count
count = count.intValue() - 1;
if (count <= 0) {
//if the value is zero or negative, remove that header name
//since all headers by that name are understood now
notUnderstoodCount.remove(qName);
} else {
notUnderstoodCount.put(qName, count);
}
}
if (understoodHeaders == null) {
understoodHeaders = new HashSet<QName>();
}
//also add it to the understood headers list (optimization for getUnderstoodHeaders)
understoodHeaders.add(qName);
}
@Override
public boolean isUnderstood(Header header) {
return isUnderstood(header.getNamespaceURI(), header.getLocalPart());
}
@Override
public boolean isUnderstood(String nsUri, String localName) {
return isUnderstood(new QName(nsUri, localName));
}
@Override
public boolean isUnderstood(QName name) {
if (understoodHeaders == null) {
return false;
}
return understoodHeaders.contains(name);
}
public boolean isUnderstood(int index) {
// TODO Auto-generated method stub
return false;
}
@Override
public Header get(String nsUri, String localName, boolean markAsUnderstood) {
SOAPHeaderElement h = find(nsUri, localName);
if (h != null) {
if (markAsUnderstood) {
understood(nsUri, localName);
}
return new SAAJHeader(h);
}
return null;
}
@Override
public Header get(QName name, boolean markAsUnderstood) {
return get(name.getNamespaceURI(), name.getLocalPart(), markAsUnderstood);
}
@Override
public Iterator<Header> getHeaders(QName headerName,
boolean markAsUnderstood) {
return getHeaders(headerName.getNamespaceURI(), headerName.getLocalPart(), markAsUnderstood);
}
@Override
public Iterator<Header> getHeaders(final String nsUri, final String localName,
final boolean markAsUnderstood) {
SOAPHeader soapHeader = ensureSOAPHeader();
if (soapHeader == null) {
return null;
}
Iterator allHeaders = soapHeader.examineAllHeaderElements();
if (markAsUnderstood) {
//mark all the matchingheaders as understood up front
//make an iterator while we're doing that
List<Header> headers = new ArrayList<Header>();
while (allHeaders.hasNext()) {
SOAPHeaderElement nextHdr = (SOAPHeaderElement) allHeaders.next();
if (nextHdr != null &&
nextHdr.getNamespaceURI().equals(nsUri)) {
if (localName == null ||
nextHdr.getLocalName().equals(localName)) {
understood(nextHdr.getNamespaceURI(), nextHdr.getLocalName());
headers.add(new SAAJHeader(nextHdr));
}
}
}
return headers.iterator();
}
//if we got here markAsUnderstood is false - return a lazy iterator rather
//than traverse the entire list of headers now
return new HeaderReadIterator(allHeaders, nsUri, localName);
}
@Override
public Iterator<Header> getHeaders(String nsUri, boolean markAsUnderstood) {
return getHeaders(nsUri, null, markAsUnderstood);
}
@Override
public boolean add(Header header) {
try {
header.writeTo(sm);
} catch (SOAPException e) {
//TODO log exception
return false;
}
//the newly added header is not understood by default
notUnderstood(new QName(header.getNamespaceURI(), header.getLocalPart()));
//track non saaj headers so that they can be retrieved later
if (isNonSAAJHeader(header)) {
//TODO assumes only one header with that name?
addNonSAAJHeader(find(header.getNamespaceURI(), header.getLocalPart()),
header);
}
return true;
}
@Override
public Header remove(QName name) {
return remove(name.getNamespaceURI(), name.getLocalPart());
}
@Override
public Header remove(String nsUri, String localName) {
SOAPHeader soapHeader = ensureSOAPHeader();
if (soapHeader == null) {
return null;
}
SOAPHeaderElement headerElem = find(nsUri, localName);
if (headerElem == null) {
return null;
}
headerElem = (SOAPHeaderElement) soapHeader.removeChild(headerElem);
//it might have been a nonSAAJHeader - remove from that map
removeNonSAAJHeader(headerElem);
//remove it from understoodHeaders and notUnderstoodHeaders if present
QName hdrName = (nsUri == null) ? new QName(localName) : new QName(nsUri, localName);
if (understoodHeaders != null) {
understoodHeaders.remove(hdrName);
}
removeNotUnderstood(hdrName);
return new SAAJHeader(headerElem);
}
private void removeNotUnderstood(QName hdrName) {
if (notUnderstoodCount == null) {
return;
}
Integer notUnderstood = notUnderstoodCount.get(hdrName);
if (notUnderstood != null) {
int intNotUnderstood = notUnderstood;
intNotUnderstood--;
if (intNotUnderstood <= 0) {
notUnderstoodCount.remove(hdrName);
}
}
}
private SOAPHeaderElement find(QName qName) {
return find(qName.getNamespaceURI(), qName.getLocalPart());
}
private SOAPHeaderElement find(String nsUri, String localName) {
SOAPHeader soapHeader = ensureSOAPHeader();
if (soapHeader == null) {
return null;
}
Iterator allHeaders = soapHeader.examineAllHeaderElements();
while(allHeaders.hasNext()) {
SOAPHeaderElement nextHdrElem = (SOAPHeaderElement) allHeaders.next();
if (nextHdrElem.getNamespaceURI().equals(nsUri) &&
nextHdrElem.getLocalName().equals(localName)) {
return nextHdrElem;
}
}
return null;
}
private void notUnderstood(QName qName) {
if (notUnderstoodCount == null) {
notUnderstoodCount = new HashMap<QName, Integer>();
}
Integer count = notUnderstoodCount.get(qName);
if (count == null) {
notUnderstoodCount.put(qName, 1);
} else {
notUnderstoodCount.put(qName, count + 1);
}
//if for some strange reason it was previously understood and now is not,
//remove it from understoodHeaders if it exists there
if (understoodHeaders != null) {
understoodHeaders.remove(qName);
}
}
/**
* Utility method to get the SOAPHeader from a SOAPMessage, adding one if
* one is not present in the original message.
*/
private SOAPHeader ensureSOAPHeader() {
SOAPHeader header;
try {
header = sm.getSOAPPart().getEnvelope().getHeader();
if (header != null) {
return header;
} else {
return sm.getSOAPPart().getEnvelope().addHeader();
}
} catch (Exception e) {
return null;
}
}
private boolean isNonSAAJHeader(Header header) {
return !(header instanceof SAAJHeader);
}
private void addNonSAAJHeader(SOAPHeaderElement headerElem, Header header) {
if (nonSAAJHeaders == null) {
nonSAAJHeaders = new HashMap<SOAPHeaderElement, Header>();
}
nonSAAJHeaders.put(headerElem, header);
}
private void removeNonSAAJHeader(SOAPHeaderElement headerElem) {
if (nonSAAJHeaders != null) {
nonSAAJHeaders.remove(headerElem);
}
}
@Override
public boolean addOrReplace(Header header) {
remove(header.getNamespaceURI(), header.getLocalPart());
return add(header);
}
@Override
public void replace(Header old, Header header) {
if (remove(old.getNamespaceURI(), old.getLocalPart()) == null)
throw new IllegalArgumentException();
add(header);
}
@Override
public Set<QName> getUnderstoodHeaders() {
return understoodHeaders;
}
@Override
public Set<QName> getNotUnderstoodHeaders(Set<String> roles,
Set<QName> knownHeaders, WSBinding binding) {
Set<QName> notUnderstoodHeaderNames = new HashSet<QName>();
if (notUnderstoodCount == null) {
return notUnderstoodHeaderNames;
}
for (QName headerName : notUnderstoodCount.keySet()) {
int count = notUnderstoodCount.get(headerName);
if (count <= 0) {
continue;
}
SOAPHeaderElement hdrElem = find(headerName);
if (!hdrElem.getMustUnderstand()) {
continue;
}
SAAJHeader hdr = new SAAJHeader(hdrElem);
//mustUnderstand attribute is true - but there may be
//additional criteria
boolean understood = false;
if (roles != null) {
understood = !roles.contains(hdr.getRole(soapVersion));
}
if (understood) {
continue;
}
//if it must be understood see if it is understood by the binding
//or is in knownheaders
if (binding != null && binding instanceof SOAPBindingImpl) {
understood = ((SOAPBindingImpl) binding).understandsHeader(headerName);
if (!understood) {
if (knownHeaders != null && knownHeaders.contains(headerName)) {
understood = true;
}
}
}
if (!understood) {
notUnderstoodHeaderNames.add(headerName);
}
}
return notUnderstoodHeaderNames;
}
@Override
public Iterator<Header> getHeaders() {
SOAPHeader soapHeader = ensureSOAPHeader();
if (soapHeader == null) {
return null;
}
Iterator allHeaders = soapHeader.examineAllHeaderElements();
return new HeaderReadIterator(allHeaders, null, null);
}
private static class HeaderReadIterator implements Iterator<Header> {
SOAPHeaderElement current;
Iterator soapHeaders;
String myNsUri;
String myLocalName;
public HeaderReadIterator(Iterator allHeaders, String nsUri,
String localName) {
this.soapHeaders = allHeaders;
this.myNsUri = nsUri;
this.myLocalName = localName;
}
@Override
public boolean hasNext() {
if (current == null) {
advance();
}
return (current != null);
}
@Override
public Header next() {
if (!hasNext()) {
return null;
}
if (current == null) {
return null;
}
SAAJHeader ret = new SAAJHeader(current);
current = null;
return ret;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private void advance() {
while (soapHeaders.hasNext()) {
SOAPHeaderElement nextHdr = (SOAPHeaderElement) soapHeaders.next();
if (nextHdr != null &&
(myNsUri == null || nextHdr.getNamespaceURI().equals(myNsUri)) &&
(myLocalName == null || nextHdr.getLocalName().equals(myLocalName))) {
current = nextHdr;
//found it
return;
}
}
//if we got here we didn't find a match
current = null;
}
}
@Override
public boolean hasHeaders() {
SOAPHeader soapHeader = ensureSOAPHeader();
if (soapHeader == null) {
return false;
}
Iterator allHeaders = soapHeader.examineAllHeaderElements();
return allHeaders.hasNext();
}
@Override
public List<Header> asList() {
SOAPHeader soapHeader = ensureSOAPHeader();
if (soapHeader == null) {
return Collections.emptyList();
}
Iterator allHeaders = soapHeader.examineAllHeaderElements();
List<Header> headers = new ArrayList<Header>();
while (allHeaders.hasNext()) {
SOAPHeaderElement nextHdr = (SOAPHeaderElement) allHeaders.next();
headers.add(new SAAJHeader(nextHdr));
}
return headers;
}
}

View File

@@ -0,0 +1,559 @@
/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message.saaj;
import java.util.Iterator;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedList;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.w3c.dom.Comment;
import org.w3c.dom.Node;
/**
* SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface.
*
* <p>
* Defers creation of SOAPElement until all the aspects of the name of the element are known.
* In some cases, the namespace uri is indicated only by the {@link #writeNamespace(String, String)} call.
* After opening an element ({@code writeStartElement}, {@code writeEmptyElement} methods), all attributes
* and namespace assignments are retained within {@link DeferredElement} object ({@code deferredElement} field).
* As soon as any other method than {@code writeAttribute}, {@code writeNamespace}, {@code writeDefaultNamespace}
* or {@code setNamespace} is called, the contents of {@code deferredElement} is transformed into new SOAPElement
* (which is appropriately inserted into the SOAPMessage under construction).
* This mechanism is necessary to fix JDK-8159058 issue.
* </p>
*
* @author shih-chang.chen@oracle.com
*/
public class SaajStaxWriter implements XMLStreamWriter {
protected SOAPMessage soap;
protected String envURI;
protected SOAPElement currentElement;
protected DeferredElement deferredElement;
static final protected String Envelope = "Envelope";
static final protected String Header = "Header";
static final protected String Body = "Body";
static final protected String xmlns = "xmlns";
public SaajStaxWriter(final SOAPMessage msg) throws SOAPException {
soap = msg;
currentElement = soap.getSOAPPart().getEnvelope();
envURI = currentElement.getNamespaceURI();
this.deferredElement = new DeferredElement();
}
public SOAPMessage getSOAPMessage() {
return soap;
}
@Override
public void writeStartElement(final String localName) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
deferredElement.setLocalName(localName);
}
@Override
public void writeStartElement(final String ns, final String ln) throws XMLStreamException {
writeStartElement(null, ln, ns);
}
@Override
public void writeStartElement(final String prefix, final String ln, final String ns) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
if (envURI.equals(ns)) {
try {
if (Envelope.equals(ln)) {
currentElement = soap.getSOAPPart().getEnvelope();
fixPrefix(prefix);
return;
} else if (Header.equals(ln)) {
currentElement = soap.getSOAPHeader();
fixPrefix(prefix);
return;
} else if (Body.equals(ln)) {
currentElement = soap.getSOAPBody();
fixPrefix(prefix);
return;
}
} catch (SOAPException e) {
throw new XMLStreamException(e);
}
}
deferredElement.setLocalName(ln);
deferredElement.setNamespaceUri(ns);
deferredElement.setPrefix(prefix);
}
private void fixPrefix(final String prfx) throws XMLStreamException {
String oldPrfx = currentElement.getPrefix();
if (prfx != null && !prfx.equals(oldPrfx)) {
currentElement.setPrefix(prfx);
}
}
@Override
public void writeEmptyElement(final String uri, final String ln) throws XMLStreamException {
writeStartElement(null, ln, uri);
}
@Override
public void writeEmptyElement(final String prefix, final String ln, final String uri) throws XMLStreamException {
writeStartElement(prefix, ln, uri);
}
@Override
public void writeEmptyElement(final String ln) throws XMLStreamException {
writeStartElement(null, ln, null);
}
@Override
public void writeEndElement() throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
if (currentElement != null) currentElement = currentElement.getParentElement();
}
@Override
public void writeEndDocument() throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
}
@Override
public void close() throws XMLStreamException {
}
@Override
public void flush() throws XMLStreamException {
}
@Override
public void writeAttribute(final String ln, final String val) throws XMLStreamException {
writeAttribute(null, null, ln, val);
}
@Override
public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException {
if (ns == null && prefix == null && xmlns.equals(ln)) {
writeNamespace("", value);
} else {
if (deferredElement.isInitialized()) {
deferredElement.addAttribute(prefix, ns, ln, value);
} else {
addAttibuteToElement(currentElement, prefix, ns, ln, value);
}
}
}
@Override
public void writeAttribute(final String ns, final String ln, final String val) throws XMLStreamException {
writeAttribute(null, ns, ln, val);
}
@Override
public void writeNamespace(String prefix, final String uri) throws XMLStreamException {
// make prefix default if null or "xmlns" (according to javadoc)
String thePrefix = prefix == null || "xmlns".equals(prefix) ? "" : prefix;
if (deferredElement.isInitialized()) {
deferredElement.addNamespaceDeclaration(thePrefix, uri);
} else {
try {
currentElement.addNamespaceDeclaration(thePrefix, uri);
} catch (SOAPException e) {
throw new XMLStreamException(e);
}
}
}
@Override
public void writeDefaultNamespace(final String uri) throws XMLStreamException {
writeNamespace("", uri);
}
@Override
public void writeComment(final String data) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
Comment c = soap.getSOAPPart().createComment(data);
currentElement.appendChild(c);
}
@Override
public void writeProcessingInstruction(final String target) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createProcessingInstruction(target, "");
currentElement.appendChild(n);
}
@Override
public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createProcessingInstruction(target, data);
currentElement.appendChild(n);
}
@Override
public void writeCData(final String data) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createCDATASection(data);
currentElement.appendChild(n);
}
@Override
public void writeDTD(final String dtd) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
}
@Override
public void writeEntityRef(final String name) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createEntityReference(name);
currentElement.appendChild(n);
}
@Override
public void writeStartDocument() throws XMLStreamException {
}
@Override
public void writeStartDocument(final String version) throws XMLStreamException {
if (version != null) soap.getSOAPPart().setXmlVersion(version);
}
@Override
public void writeStartDocument(final String encoding, final String version) throws XMLStreamException {
if (version != null) soap.getSOAPPart().setXmlVersion(version);
if (encoding != null) {
try {
soap.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding);
} catch (SOAPException e) {
throw new XMLStreamException(e);
}
}
}
@Override
public void writeCharacters(final String text) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
try {
currentElement.addTextNode(text);
} catch (SOAPException e) {
throw new XMLStreamException(e);
}
}
@Override
public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException {
currentElement = deferredElement.flushTo(currentElement);
char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len);
try {
currentElement.addTextNode(new String(chr));
} catch (SOAPException e) {
throw new XMLStreamException(e);
}
}
@Override
public String getPrefix(final String uri) throws XMLStreamException {
return currentElement.lookupPrefix(uri);
}
@Override
public void setPrefix(final String prefix, final String uri) throws XMLStreamException {
// TODO: this in fact is not what would be expected from XMLStreamWriter
// (e.g. XMLStreamWriter for writing to output stream does not write anything as result of
// this method, it just rememebers that given prefix is associated with the given uri
// for the scope; to actually declare the prefix assignment in the resulting XML, one
// needs to call writeNamespace(...) method
// Kept for backwards compatibility reasons - this might be worth of further investigation.
if (deferredElement.isInitialized()) {
deferredElement.addNamespaceDeclaration(prefix, uri);
} else {
throw new XMLStreamException("Namespace not associated with any element");
}
}
@Override
public void setDefaultNamespace(final String uri) throws XMLStreamException {
setPrefix("", uri);
}
@Override
public void setNamespaceContext(final NamespaceContext context)throws XMLStreamException {
throw new UnsupportedOperationException();
}
@Override
public Object getProperty(final String name) throws IllegalArgumentException {
//TODO the following line is to make eclipselink happy ... they are aware of this problem -
if (javax.xml.stream.XMLOutputFactory.IS_REPAIRING_NAMESPACES.equals(name)) return Boolean.FALSE;
return null;
}
@Override
public NamespaceContext getNamespaceContext() {
return new NamespaceContext() {
public String getNamespaceURI(final String prefix) {
return currentElement.getNamespaceURI(prefix);
}
public String getPrefix(final String namespaceURI) {
return currentElement.lookupPrefix(namespaceURI);
}
public Iterator getPrefixes(final String namespaceURI) {
return new Iterator<String>() {
String prefix = getPrefix(namespaceURI);
public boolean hasNext() {
return (prefix != null);
}
public String next() {
if (!hasNext()) throw new java.util.NoSuchElementException();
String next = prefix;
prefix = null;
return next;
}
public void remove() {}
};
}
};
}
static void addAttibuteToElement(SOAPElement element, String prefix, String ns, String ln, String value)
throws XMLStreamException {
try {
if (ns == null) {
element.setAttributeNS("", ln, value);
} else {
QName name = prefix == null ? new QName(ns, ln) : new QName(ns, ln, prefix);
element.addAttribute(name, value);
}
} catch (SOAPException e) {
throw new XMLStreamException(e);
}
}
/**
* Holds details of element that needs to be deferred in order to manage namespace assignments correctly.
*
* <p>
* An instance of can be set with all the aspects of the element name (local name, prefix, namespace uri).
* Attributes and namespace declarations (special case of attribute) can be added.
* Namespace declarations are handled so that the element namespace is updated if it is implied by the namespace
* declaration and the namespace was not set to non-{@code null} value previously.
* </p>
*
* <p>
* The state of this object can be {@link #flushTo(SOAPElement) flushed} to SOAPElement - new SOAPElement will
* be added a child element; the new element will have exactly the shape as represented by the state of this
* object. Note that the {@link #flushTo(SOAPElement)} method does nothing
* (and returns the argument immediately) if the state of this object is not initialized
* (i.e. local name is null).
* </p>
*
* @author ondrej.cerny@oracle.com
*/
static class DeferredElement {
private String prefix;
private String localName;
private String namespaceUri;
private final List<NamespaceDeclaration> namespaceDeclarations;
private final List<AttributeDeclaration> attributeDeclarations;
DeferredElement() {
this.namespaceDeclarations = new LinkedList<NamespaceDeclaration>();
this.attributeDeclarations = new LinkedList<AttributeDeclaration>();
reset();
}
/**
* Set prefix of the element.
* @param prefix namespace prefix
*/
public void setPrefix(final String prefix) {
this.prefix = prefix;
}
/**
* Set local name of the element.
*
* <p>
* This method initializes the element.
* </p>
*
* @param localName local name {@code not null}
*/
public void setLocalName(final String localName) {
if (localName == null) {
throw new IllegalArgumentException("localName can not be null");
}
this.localName = localName;
}
/**
* Set namespace uri.
*
* @param namespaceUri namespace uri
*/
public void setNamespaceUri(final String namespaceUri) {
this.namespaceUri = namespaceUri;
}
/**
* Adds namespace prefix assignment to the element.
*
* @param prefix prefix (not {@code null})
* @param namespaceUri namespace uri
*/
public void addNamespaceDeclaration(final String prefix, final String namespaceUri) {
if (null == this.namespaceUri && null != namespaceUri && prefix.equals(emptyIfNull(this.prefix))) {
this.namespaceUri = namespaceUri;
}
this.namespaceDeclarations.add(new NamespaceDeclaration(prefix, namespaceUri));
}
/**
* Adds attribute to the element.
* @param prefix prefix
* @param ns namespace
* @param ln local name
* @param value value
*/
public void addAttribute(final String prefix, final String ns, final String ln, final String value) {
if (ns == null && prefix == null && xmlns.equals(ln)) {
this.addNamespaceDeclaration(prefix, value);
} else {
this.attributeDeclarations.add(new AttributeDeclaration(prefix, ns, ln, value));
}
}
/**
* Flushes state of this element to the {@code target} element.
*
* <p>
* If this element is initialized then it is added with all the namespace declarations and attributes
* to the {@code target} element as a child. The state of this element is reset to uninitialized.
* The newly added element object is returned.
* </p>
* <p>
* If this element is not initialized then the {@code target} is returned immediately, nothing else is done.
* </p>
*
* @param target target element
* @return {@code target} or new element
* @throws XMLStreamException on error
*/
public SOAPElement flushTo(final SOAPElement target) throws XMLStreamException {
try {
if (this.localName != null) {
// add the element appropriately (based on namespace declaration)
final SOAPElement newElement;
if (this.namespaceUri == null) {
// add element with inherited scope
newElement = target.addChildElement(this.localName);
} else if (prefix == null) {
newElement = target.addChildElement(new QName(this.namespaceUri, this.localName));
} else {
newElement = target.addChildElement(this.localName, this.prefix, this.namespaceUri);
}
// add namespace declarations
for (NamespaceDeclaration namespace : this.namespaceDeclarations) {
newElement.addNamespaceDeclaration(namespace.prefix, namespace.namespaceUri);
}
// add attribute declarations
for (AttributeDeclaration attribute : this.attributeDeclarations) {
addAttibuteToElement(newElement,
attribute.prefix, attribute.namespaceUri, attribute.localName, attribute.value);
}
// reset state
this.reset();
return newElement;
} else {
return target;
}
// else after reset state -> not initialized
} catch (SOAPException e) {
throw new XMLStreamException(e);
}
}
/**
* Is the element initialized?
* @return boolean indicating whether it was initialized after last flush
*/
public boolean isInitialized() {
return this.localName != null;
}
private void reset() {
this.localName = null;
this.prefix = null;
this.namespaceUri = null;
this.namespaceDeclarations.clear();
this.attributeDeclarations.clear();
}
private static String emptyIfNull(String s) {
return s == null ? "" : s;
}
}
static class NamespaceDeclaration {
final String prefix;
final String namespaceUri;
NamespaceDeclaration(String prefix, String namespaceUri) {
this.prefix = prefix;
this.namespaceUri = namespaceUri;
}
}
static class AttributeDeclaration {
final String prefix;
final String namespaceUri;
final String localName;
final String value;
AttributeDeclaration(String prefix, String namespaceUri, String localName, String value) {
this.prefix = prefix;
this.namespaceUri = namespaceUri;
this.localName = localName;
this.value = value;
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message.stream;
import com.sun.xml.internal.ws.api.message.AttachmentSet;
import com.sun.xml.internal.ws.api.message.Packet;
import java.io.InputStream;
/**
* Low level representation of an XML or SOAP message as an {@link InputStream}.
*
*/
public class InputStreamMessage extends StreamBasedMessage {
/**
* The MIME content-type of the encoding.
*/
public final String contentType;
/**
* The message represented as an {@link InputStream}.
*/
public final InputStream msg;
/**
* Create a new message.
*
* @param properties
* the properties of the message.
*
* @param contentType
* the MIME content-type of the encoding.
*
* @param msg
* always a non-null unconsumed {@link InputStream} that
* represents a request.
*/
public InputStreamMessage(Packet properties, String contentType, InputStream msg) {
super(properties);
this.contentType = contentType;
this.msg = msg;
}
/**
* Create a new message.
*
* @param properties
* the properties of the message.
*
* @param attachments
* the attachments of the message.
*
* @param contentType
* the MIME content-type of the encoding.
*
* @param msg
* always a non-null unconsumed {@link InputStream} that
* represents a request.
*/
public InputStreamMessage(Packet properties, AttachmentSet attachments,
String contentType, InputStream msg) {
super(properties, attachments);
this.contentType = contentType;
this.msg = msg;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message.stream;
import com.sun.xml.internal.ws.api.message.AttachmentSet;
import com.sun.xml.internal.ws.api.message.Packet;
import com.sun.xml.internal.ws.message.AttachmentSetImpl;
/**
* Base representation an XML or SOAP message as stream.
*
*/
abstract class StreamBasedMessage {
/**
* The properties of the message.
*/
public final Packet properties;
/**
* The attachments of this message
* (attachments live outside a message.)
*/
public final AttachmentSet attachments;
/**
* Create a new message.
*
* @param properties
* the properties of the message.
*
*/
protected StreamBasedMessage(Packet properties) {
this.properties = properties;
this.attachments = new AttachmentSetImpl();
}
/**
* Create a new message.
*
* @param properties
* the properties of the message.
*
* @param attachments
* the attachments of the message.
*/
protected StreamBasedMessage(Packet properties, AttachmentSet attachments) {
this.properties = properties;
this.attachments = attachments;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.xml.internal.ws.api.message.stream;
import com.sun.xml.internal.ws.api.message.AttachmentSet;
import com.sun.xml.internal.ws.api.message.Packet;
import javax.xml.stream.XMLStreamReader;
/**
* Low level representation of an XML or SOAP message as an {@link XMLStreamReader}.
*
*/
public class XMLStreamReaderMessage extends StreamBasedMessage {
/**
* The message represented as an {@link XMLStreamReader}.
*/
public final XMLStreamReader msg;
/**
* Create a new message.
*
* @param properties
* the properties of the message.
*
* @param msg
* always a non-null unconsumed {@link XMLStreamReader} that
* represents a request.
*/
public XMLStreamReaderMessage(Packet properties, XMLStreamReader msg) {
super(properties);
this.msg = msg;
}
/**
* Create a new message.
*
* @param properties
* the properties of the message.
*
* @param attachments
* the attachments of the message.
*
* @param msg
* always a non-null unconsumed {@link XMLStreamReader} that
* represents a request.
*/
public XMLStreamReaderMessage(Packet properties, AttachmentSet attachments, XMLStreamReader msg) {
super(properties, attachments);
this.msg = msg;
}
}