Hi,
I think I managed make it compatible to existing code and yet still mush faster (8-10 sec of 60 I had in the morning ). The Mime part will be creates as soon as it requested, otherwise plain Envelope used Also I set up initial buffer in couple of classes... Please take a look Also, if comparing to yesterday's picture timeload, we have 4 big time consumers, which I suppose quite logical 1. DocumentBulder.parse 2. RPCMessage.extractFromEnvelope 3. EnvelopeMaprshall 4. InputStream.read Pavel > -----Original Message----- > From: Scott Nichol [mailto:snicholnews@;scottnichol.com] > Sent: Thursday, November 14, 2002 6:54 PM > To: [EMAIL PROTECTED] > Subject: Re: Using mime parts - huge drawbacks > > > Thanks for yet another valuable contribution! I've committed this > patch. Your others will have to wait a little while since I have to > earn some money today (instead of working on Apache SOAP). > > I have some questions. > > 1. What do you use to do this profile? I have very little experience > with profilers, mainly with JInsight, but that was over a year ago. > > 2. What is "ComplexRequest"? > > 3. Do you know what version of JavaMail you are using? > > Something very interesting that I had not noticed before is that > provider.invoke gets on the request and response contexts, so > that even > "plain" RPCs have their SOAP envelope put into SOAPContext and > subsequently extracted. I am thinking that the SOAPContext > should gain > the ability to hold a SOAP envelope other than simply as the root part > to avoid the expense of extracting it. In fact, SOAPContext should be > able to keep track of whether there are any attachments versus just an > evelope to optimize the situation where there is only an envelope. We > would use lazy evaluation to stuff it into the root part if the root > part is requested, but otherwise provide shortcuts to just access the > envelope. > > Scott Nichol > > ----- Original Message ----- > From: "Pavel Ausianik" <[EMAIL PROTECTED]> > To: <[EMAIL PROTECTED]> > Sent: Thursday, November 14, 2002 9:04 AM > Subject: RE: Using mime parts - huge drawbacks > > > > Scott, > > > > Here is server time picture taken on the Tomcat server , processing > > ComplexRequest. > > The red ellipses show that MimePart initialization takes 10-15% of > CPU > > load. > > The blue ellipses show that ContentType is also quite expensive for > benefits > > it provide. I prepared patch for caching ContentType... > > > > Pavel > > > > > -----Original Message----- > > > From: Scott Nichol [mailto:snicholnews@;scottnichol.com] > > > Sent: Wednesday, November 13, 2002 5:48 PM > > > To: [EMAIL PROTECTED] > > > Subject: Re: Using mime parts - huge drawbacks > > > > > > > > > Pavel, > > > > > > Yes, this is a good observation. In the case where there are no > > > attachments, the process could be streamlined by serializing > directly. > > > I am still actively working on this part of the code > > > (TransportMessage, > > > SOAPContext, Call) and will look at sidestepping some of the > activity > > > where there are no attachments, just a SOAP envelope, which > > > as you point > > > out is the typical scenario. > > > > > > Scott Nichol > > > > > > ----- Original Message ----- > > > From: "Pavel Ausianik" <[EMAIL PROTECTED]> > > > To: <[EMAIL PROTECTED]> > > > Sent: Wednesday, November 13, 2002 9:04 AM > > > Subject: Using mime parts - huge drawbacks > > > > > > > > > > Hello, > > > > > > > > thinking more on the current code I have found interesting > > > thing. Most > > > > requests we have a simple, straight SOAP envelopes, without any > > > attachments. > > > > Looking how it is processed I have found following (traced from > > > > httpconnection): > > > > > > > > In SOAPHTTPConnection.send() we call TransportMessage.save(). > > > > Let's look into it (see my comment how I understand it: > > > > > > > > String rootContentType = null; > > > > > > > > // Root Part is Not set for Simple Envelope ! > > > > > > > > if (ctx.isRootPartSet()) { > > > > //... Not in use for simple case > > > > } > > > > > > > > if (rootContentType == null) > > > > rootContentType = > Constants.HEADERVAL_CONTENT_TYPE_UTF8; > > > > if (getEnvelope() != null) { > > > > > > > > // Now really create root part - how important it is if we > > > now how to > > > write > > > > this Envelope without involving Mime !!! > > > > > > > > ctx.setRootPart(envelope, rootContentType); > > > > } else { > > > > //... Not in use for simple case > > > > } > > > > > > > > // Print the whole response to a byte array. > > > > // Tracing into this code we'll found that all it will do it add > > > > unnecessary header to envelope > > > > // The headers include Content-Type - we know which is, > > > > // Content-id - do we need it? Even if yes we can create any id > > > > // Content-Transfer-Encoding - not for HTTp, anyway we > force it to > 8 > > > bit > > > > // Content-Lenght - easy to calculate > > > > > > > > ByteArrayOutputStream payload = > > > > new ByteArrayOutputStream(1024); > > > > ctx.writeTo(payload); > > > > bytes = payload.toByteArray(); > > > > > > > > // Now strip off the headers. (Grmbl, get rid > of JavaMail > > > > // for MIME support). Just intercept the Content-Type > > > > // Remove headers which created right now.... > > > > > > > > .... > > > > > > > > // TODO: should not send for HTTP response > > > > headers.put("Accept-Encoding", "x-gzip"); > > > > if (Boolean.TRUE.equals(ctx.getGzip())) { > > > > // Deflate > > > > ByteArrayOutputStream baos = > > > > new > > > ByteArrayOutputStream(bytes.length > > > * 2); > > > > GZIPOutputStream gzos = new GZIPOutputStream(baos); > > > > gzos.write(bytes, offset, bytes.length - offset); > > > > gzos.close(); > > > > baos.close(); > > > > bytes = baos.toByteArray(); > > > > offset = 0; > > > > > > > > headers.put("Content-Encoding", "x-gzip"); > > > > } > > > > > > > > Seems like we are doing wonderful job of running a lot > unnecessary > > > > operations, involving a lot of memory allocations... It > > > could be most > > > > advanced improvement we ever done! > > > > > > > > Best regards, > > > > Pavel > > > > > > > > > > > > > > > > -- > > > > To unsubscribe, e-mail: > > <mailto:soap-dev-unsubscribe@;xml.apache.org> > > > For additional commands, e-mail: > <mailto:soap-dev-help@;xml.apache.org> > > > > > > > > > > > > -- > > To unsubscribe, e-mail: > <mailto:soap-dev-unsubscribe@;xml.apache.org> > > For additional commands, e-mail: > <mailto:soap-dev-help@;xml.apache.org> > > > > > > > -------------------------------------------------------------- > ---------- > -------- > > > > -- > > To unsubscribe, e-mail: > <mailto:soap-dev-unsubscribe@;xml.apache.org> > > For additional commands, e-mail: > <mailto:soap-dev-help@;xml.apache.org> > > > -- > To unsubscribe, e-mail: <mailto:soap-dev-unsubscribe@;xml.apache.org> > For additional commands, e-mail: <mailto:soap-dev-help@;xml.apache.org> >
Index: SOAPContext.java
===================================================================
RCS file: /home/cvspublic/xml-soap/java/src/org/apache/soap/rpc/SOAPContext.java,v
retrieving revision 1.13
diff -u -r1.13 SOAPContext.java
--- SOAPContext.java 6 Nov 2002 18:08:04 -0000 1.13
+++ SOAPContext.java 15 Nov 2002 13:36:17 -0000
@@ -83,13 +83,17 @@
protected MimeMultipart parts;
protected Hashtable bag = new Hashtable();
protected ClassLoader loader = null ;
- protected Vector multiRef = new Vector();
- protected Hashtable deserializedMultiRef = new Hashtable();
+ protected List multiRef = null;
+ protected Map deserializedMultiRef = null;
protected String currentId = null;
protected boolean docLitSerialization = false;
protected Boolean gzip = null;
protected Boolean acceptGzip = null;
+ protected boolean isRootPartEnvelope = false;
+ protected String rootPartString = null;
+ protected String rootPartContentType = "";
+
// Constants for checking type for base64 encoding
private static MimeType MIME_STREAM;
private static MimeType MIME_IMAGE;
@@ -159,6 +163,7 @@
* @return the Part, or null if no such part exists.
*/
public MimeBodyPart getBodyPart(int index) {
+ fillRootPart();
/* Actually, this method never throws a MessagingException. In case a
* future implementation does, catch it and throw an
* IndexOutOfBoundsException
@@ -188,6 +193,7 @@
* @return the Part, or null if no such part exists.
*/
public MimeBodyPart getBodyPart(String CID) {
+ fillRootPart();
if (parts == null) {
return null;
}
@@ -221,6 +227,7 @@
* @return the Part or null if not found
*/
public MimeBodyPart findBodyPart(String uri) {
+ fillRootPart();
if (parts == null || uri == null) {
return null;
}
@@ -419,10 +426,12 @@
* @exception MessagingException
*/
public void setRootPart(MimeBodyPart part) throws MessagingException {
+ if (rootPartSet && !isRootPartEnvelope)
+ parts.removeBodyPart(getRootPart());
+ isRootPartEnvelope = false;
+
String rootCid = '<' + MimeUtils.getUniqueValue() + '>';
part.setHeader(Constants.HEADER_CONTENT_ID, rootCid);
- if (rootPartSet)
- parts.removeBodyPart(getRootPart());
addBodyPart(part, 0);
rootPartSet = true;
}
@@ -437,7 +446,10 @@
*/
public void setRootPart(String s, String contentType)
throws MessagingException, IOException {
- setRootPart(s.getBytes("UTF8"), contentType);
+ isRootPartEnvelope = true;
+ rootPartContentType = contentType;
+ rootPartString = s;
+ rootPartSet = true;
}
/**
@@ -466,6 +478,59 @@
}
/**
+ * In case MimePart is requested converts Envelope to MimePart
+ */
+ private void fillRootPart() {
+ if (isRootPartEnvelope) {
+ try {
+ byte[] rootPartBytes = rootPartString.getBytes(
+ MimeUtils.getEncoding(rootPartContentType, "UTF8"));
+
+ ByteArrayDataSource ds =
+ new ByteArrayDataSource(rootPartBytes, rootPartContentType);
+ DataHandler dh = new DataHandler(ds);
+ MimeBodyPart bp = new MimeBodyPart();
+ bp.setDataHandler(dh);
+ bp.setHeader(Constants.HEADER_CONTENT_LENGTH,
+ String.valueOf(ds.getSize()));
+
+ // Avoid letting JavaMail determine a transfer-encoding of
+ // quoted-printable or base64... Force 8-bit encoding.
+ bp.setHeader("Content-Transfer-Encoding", "8bit");
+ setRootPart(bp);
+ }
+ catch (MessagingException e) {} // Should never happen
+ catch (UnsupportedEncodingException e) {} // Should never happen
+ }
+ }
+
+ /**
+ * Return Envelope String set up as setRootPart(String)
+ * or converted from MimeBodyPart
+ *
+ * @return Envelope String
+ */
+ public String getEnvelope() {
+ if (isRootPartEnvelope) {
+ return rootPartString;
+ }
+ // Envelope was set up as MimeBodyPart - let's get a text from it
+ try {
+ MimeBodyPart rootPart = getRootPart();
+ if (rootPart != null) {
+ String ctype = rootPart.getContentType();
+ ContentType type = MimeUtils.getContentType(ctype);
+ if (type != null && Constants.CTYPE_TEXT_ALL.match(type)) {
+ ByteArrayDataSource ds = new ByteArrayDataSource(
+ rootPart.getInputStream(), ctype);
+ return ds.getText();
+ }
+ }
+ } catch (Exception e) {}
+ return null;
+ }
+
+ /**
* Find the root part. For multipart, search for a "start" Content-Type
* header modifier, if not present or invalid, assume the first part is
* the root.
@@ -474,9 +539,10 @@
* @exception MessagingException
*/
public MimeBodyPart getRootPart() throws MessagingException {
+ fillRootPart();
MimeBodyPart rootPart = null;
if (getCount() > 1) {
- String startCid = new ContentType(
+ String startCid = MimeUtils.getContentType(
parts.getContentType()).getParameter("start");
if (startCid != null)
rootPart = getBodyPart(MimeUtils.decode(startCid));
@@ -487,6 +553,22 @@
}
/**
+ * Returns root part ContentType.
+ *
+ * @return root BodyPart ContentType
+ * @exception MessagingException
+ */
+ public String getRootPartContentType() throws MessagingException {
+ if (isRootPartEnvelope)
+ return rootPartContentType;
+ else {
+ MimeBodyPart rootPart = getRootPart();
+ return rootPart == null ? null : rootPart.getContentType();
+ }
+ }
+
+
+ /**
* Set the MultiPart Mime subtype. This method should be invoked only on
* a new MimeMultipart object created by the client. The default subtype
* of such a multipart object is "related".<p>
@@ -514,10 +596,11 @@
* @return number of parts
*/
public int getCount() throws MessagingException {
+ int countRoot = isRootPartEnvelope ? 1 : 0;
if (parts == null)
- return 0;
+ return countRoot;
else
- return parts.getCount();
+ return parts.getCount() + countRoot;
}
/**
@@ -529,7 +612,7 @@
*/
public String getContentType() throws MessagingException {
if (parts == null)
- return null;
+ return isRootPartEnvelope ? rootPartContentType : null;
else
if (parts.getCount() == 1)
return getRootPart().getContentType();
@@ -690,14 +773,16 @@
* @return The id of the element.
*/
public int addMultiRef(Object obj, Serializer ser) {
+ if (multiRef == null)
+ multiRef = new ArrayList();
// While a Hashtable might seem a better choice than a vector here,
// a Vector is easier to work with during serialization, since
// multiRefs may be added during the serialization of other multiRefs.
for (int i = 0; i < multiRef.size(); i++) {
- if (((MultiRefInfo) multiRef.elementAt(i)).obj == obj)
+ if (((MultiRefInfo) multiRef.get(i)).obj == obj)
return i;
}
- multiRef.addElement(new MultiRefInfo(obj, ser));
+ multiRef.add(new MultiRefInfo(obj, ser));
return multiRef.size() - 1;
}
@@ -708,7 +793,7 @@
* @return The multiRef object for the id.
*/
public Object getMultiRefObject(int id) {
- return ((MultiRefInfo) multiRef.elementAt(id)).obj;
+ return multiRef != null ? ((MultiRefInfo) multiRef.get(id)).obj : null;
}
/**
@@ -718,7 +803,7 @@
* @return The multiRef serializer for the id.
*/
public Serializer getMultiRefSerializer(int id) {
- return ((MultiRefInfo) multiRef.elementAt(id)).ser;
+ return multiRef != null ? ((MultiRefInfo) multiRef.get(id)).ser : null;
}
/**
@@ -727,7 +812,7 @@
* @return The number of multiRefs.
*/
public int getMultiRefCount() {
- return multiRef.size();
+ return multiRef != null ? multiRef.size() : 0;
}
/**
@@ -737,6 +822,8 @@
* @param o The deserialized object.
*/
public void addDeserializedMultiRef(String id, Object o) {
+ if (deserializedMultiRef == null)
+ deserializedMultiRef = new HashMap();
deserializedMultiRef.put(id, o);
}
@@ -747,7 +834,7 @@
* @return The multiRef for the id.
*/
public Object getDeserializedMultiRef(String id) {
- return deserializedMultiRef.get(id);
+ return deserializedMultiRef == null ? null :deserializedMultiRef.get(id);
}
/**
@@ -779,7 +866,9 @@
pw.print("}]");
- pw.print(" multiRefs: " + multiRef.size() + " deserializedMultiRefs: " +
deserializedMultiRef.size());
+ pw.print(" multiRefs: " + (multiRef != null ? multiRef.size() : '0') +
+ " deserializedMultiRefs: " +
+ (deserializedMultiRef != null ? deserializedMultiRef.size() : '0'));
return sw.toString();
}
Index: Call.java
===================================================================
RCS file: /home/cvspublic/xml-soap/java/src/org/apache/soap/rpc/Call.java,v
retrieving revision 1.21
diff -u -r1.21 Call.java
--- Call.java 14 Nov 2002 16:22:08 -0000 1.21
+++ Call.java 15 Nov 2002 13:50:21 -0000
@@ -187,7 +187,7 @@
{
this.st = st;
}
-
+
public SOAPTransport getSOAPTransport()
{
return st;
@@ -195,16 +195,16 @@
/**
* Set timeout in our MessageContext.
- *
+ *
* @param value the maximum amount of time, in milliseconds
*/
public void setTimeout (int value) {
to = value;
}
-
+
/**
* Get timeout from our MessageContext.
- *
+ *
* @return value the maximum amount of time, in milliseconds
*/
public int getTimeout () {
@@ -226,7 +226,7 @@
public void setUseDocumentBuilder(boolean useDocumentBuilder) {
this.useDocumentBuilder = useDocumentBuilder;
}
-
+
/**
* Add a MIME BodyPart.
*
@@ -271,15 +271,13 @@
BufferedReader in = null;
String payloadStr = null;
- MimeBodyPart rootPart = respCtx.getRootPart();
- String ctype = rootPart.getContentType();
+ String ctype = respCtx.getRootPartContentType();
ContentType type = null;
type = MimeUtils.getContentType(ctype);
if (type != null && Constants.CTYPE_TEXT_ALL.match(type)) {
// Get the input stream to read the response envelope from.
- in = st.receive();
- payloadStr = IOUtils.getStringFromReader(in);
+ payloadStr = respCtx.getEnvelope();
}
// Check Content-Type of root part of response to see if it's
@@ -336,7 +334,7 @@
st = new SOAPHTTPConnection();
// set the timeout
- if (to != 0 && st instanceof SOAPHTTPConnection)
+ if (to != 0 && st instanceof SOAPHTTPConnection)
((SOAPHTTPConnection)st).setTimeout(to);
// Post the call envelope.
Index: RPCJavaProvider.java
===================================================================
RCS file:
/home/cvspublic/xml-soap/java/src/org/apache/soap/providers/RPCJavaProvider.java,v
retrieving revision 1.5
diff -u -r1.5 RPCJavaProvider.java
--- RPCJavaProvider.java 17 May 2001 17:45:46 -0000 1.5
+++ RPCJavaProvider.java 15 Nov 2002 13:51:26 -0000
@@ -84,7 +84,7 @@
String targetObjectURI,
SOAPContext reqContext )
throws SOAPException {
-
+
HttpServlet servlet = (HttpServlet) reqContext.getProperty(
Constants.BAG_HTTPSERVLET );
HttpSession session = (HttpSession) reqContext.getProperty(
Constants.BAG_HTTPSESSION );
@@ -126,10 +126,10 @@
throws SOAPException {
// invoke the method on the target object
try {
- Response resp = RPCRouter.invoke( dd, call, targetObject,
+ Response resp = RPCRouter.invoke( dd, call, targetObject,
reqContext, resContext );
Envelope env = resp.buildEnvelope();
- StringWriter sw = new StringWriter();
+ StringWriter sw = new StringWriter(1024);
env.marshall( sw, call.getSOAPMappingRegistry(), resContext );
resContext.setRootPart( sw.toString(), Constants.HEADERVAL_CONTENT_TYPE_UTF8);
}
Index: RPCRouterServlet.java
===================================================================
RCS file:
/home/cvspublic/xml-soap/java/src/org/apache/soap/server/http/RPCRouterServlet.java,v
retrieving revision 1.42
diff -u -r1.42 RPCRouterServlet.java
--- RPCRouterServlet.java 10 Sep 2002 07:27:25 -0000 1.42
+++ RPCRouterServlet.java 15 Nov 2002 13:52:27 -0000
@@ -96,18 +96,18 @@
For example, you may add the following
description to web.xml when using Tomcat:
- <context-param>
+ <context-param>
<param-name>EnvelopeEditorFactory</param-name>
<param-value>MyEnvelopeEditorFactory</param-value>
- </context-param>
- <context-param>
+ </context-param>
+ <context-param>
<param-name>XMLParser</param-name>
<param-value>SampleXMLDocumentBuilderFactory</param-value>
- </context-param>
- <context-param>
+ </context-param>
+ <context-param>
<param-name>ConfigFile</param-name>
<param-value>myconfig.xml</param-value>
- </context-param>
+ </context-param>
<servlet>
<servlet-name>RPCRouterServlet</servlet-name>
<servlet-class>org.apache.soap.server.http.RPCRouterServlet</servlet-class>
@@ -134,7 +134,7 @@
public void init() throws ServletException {
ClassLoader servletClassLoader =
Thread.currentThread().getContextClassLoader();
-
+
try
{
/*Make sure that we got a useful classloader; if we can not
@@ -146,7 +146,7 @@
{
servletClassLoader = getClass().getClassLoader();
}
-
+
if (servletClassLoader == null)
{
/*This is needed because some containers use hashtable to store
@@ -178,10 +178,10 @@
try {
Properties props = new Properties();
/*First we put in the servletContext parameters, and then
- overwrite them with the servletConfig parameters if
+ overwrite them with the servletConfig parameters if
they are present.*/
Enumeration enum = servletContext.getInitParameterNames();
-
+
while (enum.hasMoreElements()) {
String name = (String)enum.nextElement();
@@ -299,16 +299,17 @@
reqCtx.setProperty( Constants.BAG_HTTPSERVLET, this );
reqCtx.setProperty( Constants.BAG_HTTPSERVLETREQUEST, req );
reqCtx.setProperty( Constants.BAG_HTTPSERVLETRESPONSE, res );
-
+
// Carry the request context from the read to the creation of
// the Call object.
-
+
// Generate Envelope after the incoming message is translated by
// EnvelopeEditor
// Note: XMLParser that is specified by init-param isused in
// this process.
- DocumentBuilder xdb = XMLParserUtils.getXMLDocBuilder();
+ DocumentBuilder xdb = XMLParserUtils.getXMLDocBuilderFromPool();
+ try {
callEnv =
ServerHTTPUtils.readEnvelopeFromRequest(xdb,
req.getContentType(),
@@ -318,6 +319,10 @@
res,
reqCtx,
ServerHTTPUtils.getHeaders(req));
+ }
+ finally {
+ XMLParserUtils.returnDocumentBuilderToPool(xdb);
+ }
if (callEnv == null)
return;
call = RPCRouter.extractCallFromEnvelope(serviceManager, callEnv,
@@ -332,7 +337,7 @@
: Constants.FAULT_CODE_CLIENT;
throw new SOAPException (faultCode, msg, e);
}
-
+
// get the deployment descriptor for this service (will except if
// not known)
dd = serviceManager.query (targetID);
@@ -369,8 +374,8 @@
// Handle scripts
provider = new org.apache.soap.providers.RPCJavaProvider();
}
-
- provider.locate( dd, callEnv, call, call.getMethodName(), fullTargetID,
+
+ provider.locate( dd, callEnv, call, call.getMethodName(), fullTargetID,
reqCtx );
ServerUtils.setResponseGzip(dd, reqCtx, resCtx);
provider.invoke( reqCtx, resCtx );
@@ -395,21 +400,21 @@
// the status code for faults should always be the internal
// server error status code (per soap spec)
status = res.SC_INTERNAL_SERVER_ERROR;
-
+
String respEncStyle = null;
if(call != null)
respEncStyle = call.getEncodingStyleURI();
if(respEncStyle == null)
respEncStyle = Constants.NS_URI_SOAP_ENC;
-
+
resCtx = new SOAPContext(); // get rid of old one
- resp = new Response (null, null, fault, null, null, respEncStyle,
+ resp = new Response (null, null, fault, null, null, respEncStyle,
resCtx);
- SOAPMappingRegistry smr =
+ SOAPMappingRegistry smr =
(call != null) ? call.getSOAPMappingRegistry ()
: ServerHTTPUtils.getSMRFromContext (context);
Envelope env = resp.buildEnvelope();
- StringWriter sw = new StringWriter();
+ StringWriter sw = new StringWriter(1024);
env.marshall(sw, smr, resp.getSOAPContext());
resp.getSOAPContext().setRootPart( sw.toString(),
Constants.HEADERVAL_CONTENT_TYPE_UTF8);
Index: TransportMessage.java
===================================================================
RCS file:
/home/cvspublic/xml-soap/java/src/org/apache/soap/transport/TransportMessage.java,v
retrieving revision 1.19
diff -u -r1.19 TransportMessage.java
--- TransportMessage.java 14 Nov 2002 05:00:42 -0000 1.19
+++ TransportMessage.java 15 Nov 2002 14:00:47 -0000
@@ -169,7 +169,7 @@
if (contentLength != 0) {
int offset = 0;
int bytesRead = 0;
-
+
// We're done reading when we get all the content OR when the stream
// returns a -1.
while ((contentLength < 0 || offset < contentLength) && (bytesRead >= 0))
{
@@ -258,15 +258,12 @@
// Parse and validate content type.
ContentType cType = null;
if (contentType != null) {
- try {
- // Hack since WebSphere puts ;; instead of just ;
- int pos = contentType.indexOf( ";;" );
- if ( pos != -1 )
- contentType = contentType.substring(0,pos) +
- contentType.substring(pos+1) ;
- cType = new ContentType(contentType);
- } catch(ParseException pe) {
- }
+ // Hack since WebSphere puts ;; instead of just ;
+ int pos = contentType.indexOf( ";;" );
+ if ( pos != -1 )
+ contentType = contentType.substring(0,pos) +
+ contentType.substring(pos+1) ;
+ cType = MimeUtils.getContentType(contentType);
}
if (cType == null)
throw new SOAPException(Constants.FAULT_CODE_PROTOCOL,
@@ -321,20 +318,29 @@
// Find root part.
rootPart = ctx.getRootPart();
- rootContentType = new ContentType(rootPart.getContentType());
+ rootContentType = MimeUtils.getContentType(rootPart.getContentType());
ByteArrayDataSource bads = new ByteArrayDataSource(
rootPart.getInputStream(), null);
rootBytes = bads.toByteArray();
} else {
rootBytes = bytes;
rootContentType = cType;
- // Set the single part as the root part of SOAPContext.
- ByteArrayDataSource ds = new ByteArrayDataSource(bytes,
- contentType);
- DataHandler dh = new DataHandler(ds);
- rootPart = new MimeBodyPart();
- rootPart.setDataHandler(dh);
- ctx.addBodyPart(rootPart);
+
+ // If the root part is text, extract it as a String.
+ // Note that we could use JAF's help to do this (see save())
+ // but implementing it ourselves is safer and faster.
+ if (Constants.CTYPE_TEXT_ALL.match(rootContentType)) {
+ String charset = rootContentType.getParameter("charset");
+ // Hmm, risky, the default charset is transport-specific...
+ if (charset == null || charset.equals(""))
+ charset = Constants.HEADERVAL_DEFAULT_CHARSET;
+ envelope = new String(rootBytes, MimeUtility.javaCharset(charset));
+ // Set the envelope as a String.
+ ctx.setRootPart(envelope, contentType);
+ } else
+ // Set the single part as the root part of SOAPContext.
+ ctx.setRootPart(bytes, contentType);
+ return envelope;
}
// If the root part is text, extract it as a String.
@@ -391,16 +397,7 @@
* Otherwise, assume that the SOAPContext already has a root part,
* and try to use it as the envelope.
*/
- String rootContentType = null;
- if (ctx.isRootPartSet()) {
- MimeBodyPart rootPart = ctx.getRootPart();
- if (rootPart != null)
- // Note: don't call MimeBodyPart.getContent() because it will
- // default to "text/plain" if the Content-Type header isn't
- // set.
- rootContentType = rootPart.getHeader(
- Constants.HEADER_CONTENT_TYPE, null);
- }
+ String rootContentType = ctx.getRootPartContentType();
if (rootContentType == null)
rootContentType = Constants.HEADERVAL_CONTENT_TYPE_UTF8;
if (getEnvelope() != null && !rootPartIsEnvelope) {
@@ -420,7 +417,7 @@
new ByteArrayOutputStream(65536);
ctx.writeTo(payload);
bytes = payload.toByteArray();
-
+
// Now strip off the headers. (Grmbl, get rid of JavaMail
// for MIME support). Just intercept the Content-Type
// header. We don't want any of the MIME headers, and we know the
@@ -509,21 +506,8 @@
*/
public String getEnvelope() {
if (envelope == null) {
- // Assign the root part, if any, to the envelope.
- try {
- MimeBodyPart rootPart = ctx.getRootPart();
- if (rootPart != null) {
- String ctype = rootPart.getContentType();
- ContentType type = new ContentType(ctype);
- if (type != null && Constants.CTYPE_TEXT_ALL.match(type)) {
- ByteArrayDataSource ds = new ByteArrayDataSource(
- rootPart.getInputStream(), ctype);
- envelope = ds.getText();
- }
- rootPartIsEnvelope = true;
- }
- } catch (Exception e) {
- }
+ // get an enveope from SOAPContext
+ envelope = ctx.getEnvelope();
}
return envelope;
}
<<attachment: untitled.GIF>>
-- To unsubscribe, e-mail: <mailto:soap-dev-unsubscribe@;xml.apache.org> For additional commands, e-mail: <mailto:soap-dev-help@;xml.apache.org>
