Hi Vivek,
I wonder if there is a better way to handle SOAP action more cleanly
rather than exposing SOAP 1.1 HTTP transport binding semantics to the
Encoder and SOAP 1.2 HTTP transport binding semantics to the
implementations?
The same encoders may be used with other transports (JMS, SOAP/TCP,
BEEP, SMTP, XMPP) and new encoders may be used with the same transport
(FI). Some encoders may not encode SOAP messages.
It is tricky though, especially when having to support MTOM!
Putting my heretical hat on i am becoming more and more convinced that
the transport pipe cannot be separated from the binding of the protocol
to the transport e.g. the SOAP 1.1 or SOAP 1.2 transport binding or the
MTOM transport binding.
I think a general problem is that content type is meant to be meta-data
but it is leaking into the encoding layer (a bit like what prefixes do
for qnames in content). In this respect i am not sure that
Encoder/Decoder should actually be using the content type string at all
for the actual encode/decode process. And this goes to the heart of the
argument of using facades up front as well which tend to encourage
transport level binding semantics to be pushed to the encoding/decoding
layer.
At the moment i still think things are too restrictive for pluggable
transports, sorry :-(
Transport pipes can be responsible for instantiating the
encoder/decoders they require from factories obtained from the pipeline
constructor (since the constructor is in best position to know what
implementations to use e.g. SAAJ, stream, JAXB etc). The constructor can
also use the binding to determine what encoders/decoders are allowed
(easy way to switch of FI).
The transport pipe is in the best position to determine how to use the
Encoders/Decoders based on binding and runtime information.
Encoders/Decoders can operate on Message and take parameters and return
parameters (e.g. to support MTOM). Thus Encoder/Decoder is cleanly
separated from the content type leaking and transports. This does create
more work for a transport pipe, but all transport binding stuff is kept
localized and is not spread between the transport pipe and
Encoder/Decoder. Helper classes can be defined to aid the development of
a transport pipe.
I will try and write a clearer proposal on this.
Paul.
--
| ? + ? = To question
----------------\
Paul Sandoz
x38109
+33-4-76188109
attached mail follows:
Tag: rearch-2005
User: vivekp
Date: 2006/02/22 15:40:40
Log:
Changes for SOAPAction support:
- Encoder.encode() returns Content-Type
- String getStaticContentType() changed to ContentType getStaticContentType(Packet)
- HTTPTransportPipe writes out SOAPAction header if ContentType.getSOAPACtion is non-null.
File Changes:
Directory: /jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/api/pipe/
===================================================================
File [changed]: Encoder.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/api/pipe/Encoder.java?r1=1.1.2.4&r2=1.1.2.5
Delta lines: +3 -3
-------------------
--- Encoder.java 7 Feb 2006 19:11:47 -0000 1.1.2.4
+++ Encoder.java 22 Feb 2006 23:40:35 -0000 1.1.2.5
@@ -74,7 +74,7 @@
* null if the content-type may change from a {_at_link Message} to {_at_link Message}.
* Otherwise return the static content type, like "application/xml".
*/
- String getStaticContentType();
+ ContentType getStaticContentType(Packet packaet);
/**
* Encodes an XML infoset portion of the {_at_link Message}
@@ -96,7 +96,7 @@
* @throws IOException
* if a {_at_link OutputStream} throws {_at_link IOException}.
*/
- String encode( Packet packet, OutputStream out ) throws IOException;
+ ContentType encode( Packet packet, OutputStream out ) throws IOException;
/**
* The version of {_at_link #encode(Packet,OutputStream)}
@@ -106,7 +106,7 @@
* TODO: for the convenience of implementation, write
* an adapter that wraps {_at_link WritableByteChannel} to {_at_link OutputStream}.
*/
- String encode( Packet packet, WritableByteChannel buffer );
+ ContentType encode( Packet packet, WritableByteChannel buffer );
/*
* The following methods need to be documented and implemented.
File [added]: ContentType.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/api/pipe/ContentType.java?rev=1.1.2.1&content-type=text/vnd.viewcvs-markup
Added lines: 22
---------------
package com.sun.xml.ws.api.pipe;
/**
* A Content-Type transport header that will be returned by {_at_link Encoder#encode(com.sun.xml.ws.api.message.Packet, java.io.OutputStream)}.
* It will provide the Content-Type header and also take care of SOAP 1.1 SOAPAction header.
*
* @author Vivek Pandey
*/
public interface ContentType {
/**
* Gives non-null Content-Type header value.
*/
public String getContentType();
/**
* Gives SOAPAction transport header value. It will be non-null only for SOAP 1.1 messages. In other cases
* it MUST be null. The SOAPAction transport header should be written out only when its non-null.
*
* @return It can be null, in that case SOAPAction header should be written.
*/
public String getSOAPAction();
}
Directory: /jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/sandbox/impl/
=======================================================================
File [changed]: EncoderFacade.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/sandbox/impl/EncoderFacade.java?r1=1.1.2.2&r2=1.1.2.3
Delta lines: +5 -4
-------------------
--- EncoderFacade.java 15 Feb 2006 00:18:36 -0000 1.1.2.2
+++ EncoderFacade.java 22 Feb 2006 23:40:36 -0000 1.1.2.3
@@ -1,6 +1,7 @@
package com.sun.xml.ws.sandbox.impl;
import com.sun.xml.ws.api.pipe.Encoder;
+import com.sun.xml.ws.api.pipe.ContentType;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.SOAPVersion;
@@ -26,15 +27,15 @@
this.binding = binding;
}
- public String getStaticContentType() {
- return getEncoder().getStaticContentType();
+ public ContentType getStaticContentType(Packet packet) {
+ return getEncoder().getStaticContentType(packet);
}
- public String encode(Packet packet, OutputStream out) throws IOException {
+ public ContentType encode(Packet packet, OutputStream out) throws IOException {
return getEncoder().encode(packet, out);
}
- public String encode(Packet packet, WritableByteChannel buffer) {
+ public ContentType encode(Packet packet, WritableByteChannel buffer) {
return getEncoder().encode(packet, buffer);
}
File [changed]: MimeEncoder.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/sandbox/impl/MimeEncoder.java?r1=1.1.2.9&r2=1.1.2.10
Delta lines: +6 -6
-------------------
--- MimeEncoder.java 2 Feb 2006 01:18:37 -0000 1.1.2.9
+++ MimeEncoder.java 22 Feb 2006 23:40:36 -0000 1.1.2.10
@@ -1,8 +1,8 @@
package com.sun.xml.ws.sandbox.impl;
-import com.sun.xml.messaging.saaj.packaging.mime.internet.ContentType;
import com.sun.xml.messaging.saaj.packaging.mime.util.OutputUtil;
import com.sun.xml.ws.api.pipe.Encoder;
+import com.sun.xml.ws.api.pipe.ContentType;
import com.sun.xml.ws.api.message.Attachment;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Packet;
@@ -25,20 +25,20 @@
/**
* TODO: can we generate a content-id ? otherwise, buffering is required
*/
- public String getStaticContentType() {
+ public ContentType getStaticContentType(Packet packet) {
return null;
}
// TODO: preencode String literals to byte[] so that they don't have to
// go through char[]->byte[] conversion at runtime.
- public String encode(Packet packet, OutputStream out) throws IOException {
+ public ContentType encode(Packet packet, OutputStream out) throws IOException {
Message msg = packet.getMessage();
String primaryCid = null; // TODO
String primaryCt = null; // TODO
- ContentType contentType = new ContentType("multipart", "related", null);
+ com.sun.xml.messaging.saaj.packaging.mime.internet.ContentType contentType = new com.sun.xml.messaging.saaj.packaging.mime.internet.ContentType("multipart", "related", null);
String boundary = UniqueValue.getUniqueBoundaryValue();
contentType.setParameter("type", "text/xml"); // TODO
contentType.setParameter("boundary", boundary);
@@ -72,10 +72,10 @@
OutputUtil.writeAsAscii(startBoundary, out); // write --boundary
OutputUtil.writeAsAscii("--", out);
- return "multipart/related";
+ return new ContentTypeImpl("multipart/related", null);
}
- public String encode(Packet packet, WritableByteChannel buffer) {
+ public ContentType encode(Packet packet, WritableByteChannel buffer) {
//TODO: not yet implemented
throw new UnsupportedOperationException();
}
File [changed]: MtomEncoder.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/sandbox/impl/MtomEncoder.java?r1=1.1.2.6&r2=1.1.2.7
Delta lines: +36 -10
---------------------
--- MtomEncoder.java 18 Feb 2006 02:25:22 -0000 1.1.2.6
+++ MtomEncoder.java 22 Feb 2006 23:40:36 -0000 1.1.2.7
@@ -5,6 +5,7 @@
import com.sun.xml.ws.api.message.AttachmentSet;
import com.sun.xml.ws.api.message.Attachment;
import com.sun.xml.ws.api.pipe.Encoder;
+import com.sun.xml.ws.api.pipe.ContentType;
import com.sun.xml.ws.streaming.XMLStreamWriterFactory;
import com.sun.xml.messaging.saaj.packaging.mime.util.OutputUtil;
@@ -44,12 +45,23 @@
private String messageContentType;
private final String soapContentType;
private XMLStreamWriter writer;
+ private final SOAPVersion version;
//This is the mtom attachment stream, we should write it just after the root part for decoder
private final List<ByteArrayOutputStream> mtomAttachmentStream = new ArrayList<ByteArrayOutputStream>();
- public MtomEncoder(String contentType){
- this.soapContentType = contentType;
+ MtomEncoder(SOAPVersion version){
+ this.version = version;
+ switch(version){
+ case SOAP_11:
+ this.soapContentType = "text/xml";
+ break;
+ case SOAP_12:
+ this.soapContentType = "application/soap+xml";
+ break;
+ default:
+ throw new AssertionError();
+ }
createConteTypeHeader();
this.soapXopContentType = xopContentType+";charset=utf-8;type=\""+soapContentType+"\"";
}
@@ -65,18 +77,32 @@
*
* @return A non-null content type for soap11 or soap 1.2 content type
*/
- public String getStaticContentType() {
- return messageContentType;
+ public ContentType getStaticContentType(Packet packet) {
+ return getContentType(packet);
+ }
+
+ private ContentType getContentType(Packet packet){
+ switch(version){
+ case SOAP_11:
+ return new ContentTypeImpl(messageContentType, (packet.soapAction == null)?"":packet.soapAction);
+ case SOAP_12:
+ if(packet.soapAction != null){
+ messageContentType += ";action=\""+packet.soapAction+"\"";
+ }
+ return new ContentTypeImpl(messageContentType, null);
+ }
+ //never happens
+ return null;
}
private OutputStream writeMtomBinary(String contentType){
throw new UnsupportedOperationException();
}
- public String encode(Packet packet, OutputStream out) throws IOException {
+ public ContentType encode(Packet packet, OutputStream out) throws IOException {
//get the current boundary thaat will be reaturned from this method
mtomAttachmentStream.clear();
- String currBoundary = boundary;
+ ContentType contentType = getContentType(packet);
this.writer = XMLStreamWriterFactory.createXMLStreamWriter(out);
if(packet.getMessage() != null){
try {
@@ -116,7 +142,7 @@
}
//now create the boundary for next encode() call
createConteTypeHeader();
- return currBoundary;
+ return contentType;
}
private static final String XOP_LOCALNAME = "Include";
@@ -172,7 +198,7 @@
}
}
- public String encode(Packet packet, WritableByteChannel buffer) {
+ public ContentType encode(Packet packet, WritableByteChannel buffer) {
throw new UnsupportedOperationException();
}
@@ -211,8 +237,8 @@
return name + cid;
}
- public static final Encoder SOAP11 = new MtomEncoder("text/xml");
- public static final Encoder SOAP12 = new MtomEncoder("application/soap+xml");
+ public static final Encoder SOAP11 = new MtomEncoder(SOAPVersion.SOAP_11);
+ public static final Encoder SOAP12 = new MtomEncoder(SOAPVersion.SOAP_12);
public static Encoder get(SOAPVersion version) {
if(version==null)
File [changed]: TestEncoderImpl.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/sandbox/impl/TestEncoderImpl.java?r1=1.1.2.12&r2=1.1.2.13
Delta lines: +14 -5
--------------------
--- TestEncoderImpl.java 2 Feb 2006 03:27:34 -0000 1.1.2.12
+++ TestEncoderImpl.java 22 Feb 2006 23:40:37 -0000 1.1.2.13
@@ -1,6 +1,7 @@
package com.sun.xml.ws.sandbox.impl;
import com.sun.xml.ws.api.pipe.Encoder;
+import com.sun.xml.ws.api.pipe.ContentType;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.streaming.XMLStreamWriterFactory;
@@ -25,11 +26,11 @@
this.contentType = contentType;
}
- public String getStaticContentType() {
- return contentType;
+ public ContentType getStaticContentType(Packet packet) {
+ return getContentType(packet.soapAction);
}
- public String encode(Packet packet, OutputStream out) {
+ public ContentType encode(Packet packet, OutputStream out) {
if (packet.getMessage() != null) {
XMLStreamWriter writer = XMLStreamWriterFactory.createXMLStreamWriter(out);
try {
@@ -38,10 +39,10 @@
throw new WebServiceException(e);
}
}
- return contentType;
+ return getContentType(packet.soapAction);
}
- public String encode(Packet packet, WritableByteChannel buffer) {
+ public ContentType encode(Packet packet, WritableByteChannel buffer) {
//TODO: not yet implemented
throw new UnsupportedOperationException();
}
@@ -65,5 +66,13 @@
default:
throw new AssertionError();
}
+ }
+
+ private ContentType getContentType(String soapAction){
+ if((soapAction != null) && contentType.equals("application/soap+xml"))
+ return new ContentTypeImpl(contentType + ";action=\""+soapAction+"\"", null);
+
+ String action = (soapAction == null)?"":soapAction;
+ return new ContentTypeImpl(contentType, action);
}
}
File [added]: ContentTypeImpl.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/sandbox/impl/ContentTypeImpl.java?rev=1.1.2.1&content-type=text/vnd.viewcvs-markup
Added lines: 24
---------------
package com.sun.xml.ws.sandbox.impl;
import com.sun.xml.ws.api.pipe.ContentType;
/**
* @author Vivek Pandey
*/
class ContentTypeImpl implements ContentType {
private final String contentType;
private final String soapAction;
public ContentTypeImpl(String contentType, String soapAction) {
this.contentType = contentType;
this.soapAction = soapAction;
}
public String getContentType() {
return contentType;
}
public String getSOAPAction() {
return soapAction;
}
}
Directory: /jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/transport/http/client/
================================================================================
File [changed]: HttpTransportPipe.java
Url:
https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/transport/http/client/HttpTransportPipe.java?r1=1.1.2.33&r2=1.1.2.34
Delta lines: +18 -5
--------------------
--- HttpTransportPipe.java 22 Feb 2006 20:33:22 -0000 1.1.2.33
+++ HttpTransportPipe.java 22 Feb 2006 23:40:37 -0000 1.1.2.34
@@ -24,6 +24,7 @@
import com.sun.xml.ws.api.pipe.Encoder;
import com.sun.xml.ws.api.pipe.Pipe;
import com.sun.xml.ws.api.pipe.PipeCloner;
+import com.sun.xml.ws.api.pipe.ContentType;
import com.sun.xml.ws.api.WSBinding;
import com.sun.xml.ws.spi.runtime.WSConnection;
import com.sun.xml.ws.util.ByteArrayBuffer;
@@ -71,19 +72,22 @@
HttpClientTransport con = new HttpClientTransport(request,reqHeaders);
- String ct = encoder.getStaticContentType();
+ ContentType ct = encoder.getStaticContentType(request);
if (ct == null) {
ByteArrayBuffer buf = new ByteArrayBuffer();
ct = encoder.encode(request, buf);
// data size is available, set it as Content-Length
reqHeaders.put("Content-Length", Arrays.asList(""+buf.size()));
- reqHeaders.put("Content-Type", Arrays.asList(ct));
+ reqHeaders.put("Content-Type", Arrays.asList(ct.getContentType()));
+ writeSOAPAction(reqHeaders, ct.getSOAPAction());
buf.writeTo(con.getOutput());
} else {
// Set static Content-Type
- reqHeaders.put("Content-Type", Arrays.asList(ct));
+ reqHeaders.put("Content-Type", Arrays.asList(ct.getContentType()));
+ writeSOAPAction(reqHeaders, ct.getSOAPAction());
encoder.encode(request, con.getOutput());
}
+
con.closeOutput();
Map<String, List<String>> respHeaders = con.getHeaders();
@@ -92,14 +96,23 @@
|| con.statusCode==WSConnection.ONEWAY) {
return new Packet(null); // one way. no response given.
}
- ct = getContentType(respHeaders);
+ String contentType = getContentType(respHeaders);
Packet reply = request.createResponse(null);
- decoder.decode(con.getInput(), ct, reply);
+ decoder.decode(con.getInput(), contentType, reply);
return reply;
} catch(WebServiceException wex) {
throw wex;
} catch(Exception ex) {
throw new WebServiceException(ex);
+ }
+ }
+
+ /**
+ * write SOAPAction header if the soapAction parameter is non-null
+ */
+ private void writeSOAPAction(Map<String, List<String>> reqHeaders, String soapAction) {
+ if(soapAction != null){
+ reqHeaders.put("SOAPAction", Arrays.asList(soapAction));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe_at_jax-ws-sources.dev.java.net
For additional commands, e-mail: cvs-help_at_jax-ws-sources.dev.java.net