Scott,

sorry, what is correct algorithm for working with CVS?  I made some changes,
collect patch, send it to cvs. Than I run cvs checkout again, but my files
not updates. Only known solution I know is to move old src tree, get
completely new on, compare changes, put updated files, send collect patch
again. Most probably I'm doing something wrong...

Please find also old patch for using pooled DocumentBuilder.

Thanks,
Pavel


> -----Original Message-----
> From: Scott Nichol [mailto:[EMAIL PROTECTED]]
> Sent: Wednesday, November 20, 2002 4:23 PM
> To: [EMAIL PROTECTED]
> Subject: Re: Using mime parts - huge drawbacks
> 
> 
> Pavel,
> 
> I could not use patch on these patches, apparently because 
> they are done
> against older CVS versions.  I need the diffs against the current CVS
> sources.  Also, please send diffs for all 5 files (SOAPContext, Call,
> TransportMessage, RPCJavaProvider, RPCRouterServlet).
> 
> Thanks.
> 
> Scott Nichol
> 
> ----- Original Message -----
> From: "Pavel Ausianik" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>
> Sent: Wednesday, November 20, 2002 6:09 AM
> Subject: RE: Using mime parts - huge drawbacks
> 
> 
> > Scott,
> >
> > It seems like two bugs fixed.
> >
> > One is related to missed fillRootPart() in SOAPContext.writeTo()
> > Second is relates on how content type identified in case  
> envelope is
> set
> > Attaching a patch against current cvs
> >
> > During mime test execution I had one error related to SOAP registry
> >
> > Generated fault: [Attributes={}] [faultCode=SOAP-ENV:Server]
> > [faultString=java.l
> > ang.IllegalArgumentException: No mapping found for 
> 'java.lang.Object'
> using
> > enco
> > ding style 'http://schemas.xmlsoap.org/soap/encoding/'.]
> > [faultActorURI=/soap/se
> > rvlet/rpcrouter] [DetailEntries=] [FaultEntries=]
> >
> > This should not be related to Mime Part, and I'll look at 
> this Friday
> (sorry
> > busy today-tomorrow)
> >
> > Best regards,
> > Pavel
> >
> >
> >
> > > -----Original Message-----
> > > From: Scott Nichol [mailto:[EMAIL PROTECTED]]
> > > Sent: Wednesday, November 20, 2002 8:26 AM
> > > To: [EMAIL PROTECTED]
> > > Subject: Re: Using mime parts - huge drawbacks
> > >
> > >
> > > Pavel,
> > >
> > > I applied these patches, but the mime sample does not work.
> > > Please get
> > > this sample working and submit a new patch.
> > >
> > > Thanks.
> > >
> > > Scott Nichol
> > >
> > > ----- Original Message -----
> > > From: "Pavel Ausianik" <[EMAIL PROTECTED]>
> > > To: <[EMAIL PROTECTED]>
> > > Sent: Friday, November 15, 2002 9:59 AM
> > > Subject: RE: Using mime parts - huge drawbacks
> > >
> > >
> > > >
> > > >
> > > > 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:[EMAIL PROTECTED]]
> > > > > 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:[EMAIL PROTECTED]]
> > > > > > > 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:[EMAIL PROTECTED]>
> > > > > > > For additional commands, e-mail:
> > > > > <mailto:[EMAIL PROTECTED]>
> > > > > > >
> > > > > > >
> > > > > >
> > > > > >
> > > > > > --
> > > > > > To unsubscribe, e-mail:
> > > > > <mailto:[EMAIL PROTECTED]>
> > > > > > For additional commands, e-mail:
> > > > > <mailto:[EMAIL PROTECTED]>
> > > > > >
> > > > > >
> > > > >
> > > > >
> > > > > --------------------------------------------------------------
> > > > > ----------
> > > > > --------
> > > > >
> > > > >
> > > > > > --
> > > > > > To unsubscribe, e-mail:
> > > > > <mailto:[EMAIL PROTECTED]>
> > > > > > For additional commands, e-mail:
> > > > > <mailto:[EMAIL PROTECTED]>
> > > > >
> > > > >
> > > > > --
> > > > > To unsubscribe, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > > > > For additional commands, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > > > >
> > > >
> > > >
> > >
> > >
> > > --------------------------------------------------------------
> > > ----------
> > > --------
> > >
> > >
> > > > --
> > > > To unsubscribe, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > > > For additional commands, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > >
> > >
> > > --
> > > To unsubscribe, e-mail:
> <mailto:[EMAIL PROTECTED]>
> > > For additional commands, e-mail:
> <mailto:[EMAIL PROTECTED]>
> > >
> >
> >
> 
> 
> --------------------------------------------------------------
> ----------
> --------
> 
> 
> > --
> > To unsubscribe, e-mail:   
> <mailto:[EMAIL PROTECTED]>
> > For additional commands, e-mail: 
> <mailto:[EMAIL PROTECTED]>
> 
> 
> --
> To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
> 

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        20 Nov 2002 16:28:56 -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: Call.java
===================================================================
RCS file: /home/cvspublic/xml-soap/java/src/org/apache/soap/rpc/Call.java,v
retrieving revision 1.22
diff -u -r1.22 Call.java
--- Call.java   19 Nov 2002 02:47:38 -0000      1.22
+++ Call.java   20 Nov 2002 16:31:07 -0000
@@ -90,7 +90,6 @@
  */
 public class Call extends RPCMessage
 {
-  private DocumentBuilder     xdb;
   private SOAPMappingRegistry smr = null;
   private SOAPTransport       st  = null;;
   private int                 to  = 0;
@@ -187,7 +186,7 @@
   {
     this.st = st;
   }
-   
+
   public SOAPTransport getSOAPTransport()
   {
     return st;
@@ -195,16 +194,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 +225,7 @@
   public void setUseDocumentBuilder(boolean useDocumentBuilder) {
     this.useDocumentBuilder = useDocumentBuilder;
   }
-    
+
   /**
    * Add a MIME BodyPart.
    *
@@ -271,15 +270,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
@@ -337,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.
@@ -454,8 +451,15 @@
     }
 
     // if the DOM parser hasn't been created yet, do it now
-    if (xdb == null)
-      xdb = XMLParserUtils.getXMLDocBuilder();
-    return xdb.parse(input);
+    DocumentBuilder  xdb = XMLParserUtils.getXMLDocBuilderFromPool();
+    Document doc = null;
+    // if the DOM parser hasn't been created yet, do it now
+    try {
+        doc = xdb.parse(input);
+    }
+    finally {
+        XMLParserUtils.returnDocumentBuilderToPool(xdb);
+    }
+    return doc;
   }
 }
Index: SOAPContext.java
===================================================================
RCS file: /home/cvspublic/xml-soap/java/src/org/apache/soap/rpc/SOAPContext.java,v
retrieving revision 1.15
diff -u -r1.15 SOAPContext.java
--- SOAPContext.java    19 Nov 2002 02:47:38 -0000      1.15
+++ SOAPContext.java    20 Nov 2002 16:32:33 -0000
@@ -83,12 +83,16 @@
     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 = "";
     protected boolean       oneWay = false;
 
     // Constants for checking type for base64 encoding
@@ -160,6 +164,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
@@ -189,6 +194,7 @@
      * @return          the Part, or null if no such part exists.
      */
     public MimeBodyPart getBodyPart(String CID) {
+        fillRootPart();
         if (parts == null) {
             return null;
         }
@@ -222,6 +228,7 @@
      * @return          the Part or null if not found
      */
     public MimeBodyPart findBodyPart(String uri) {
+        fillRootPart();
         if (parts == null || uri == null) {
             return null;
         }
@@ -420,10 +427,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;
     }
@@ -438,7 +447,10 @@
      */
     public void setRootPart(String s, String contentType)
         throws MessagingException, IOException {
-        setRootPart(s.getBytes("UTF8"), contentType);
+        isRootPartEnvelope = true;
+        rootPartContentType = contentType;
+        rootPartString = s;
+        rootPartSet = true;
     }
 
     /**
@@ -458,7 +470,6 @@
         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");
@@ -467,6 +478,60 @@
     }
 
     /**
+     * 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");
+                bp.setHeader(Constants.HEADERVAL_CONTENT_TYPE, rootPartContentType);
+                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.
@@ -475,9 +540,10 @@
      * @exception       MessagingException
      */
     public MimeBodyPart getRootPart() throws MessagingException {
+        fillRootPart();
         MimeBodyPart rootPart = null;
         if (getCount() > 1) {
-            String startCid = MimeUtils.getContentType(
+            String startCid = new ContentType(
                 parts.getContentType()).getParameter("start");
             if (startCid != null)
                 rootPart = getBodyPart(MimeUtils.decode(startCid));
@@ -488,6 +554,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>
@@ -515,10 +597,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;
     }
 
     /**
@@ -530,7 +613,7 @@
      */
     public String getContentType() throws MessagingException {
         if (parts == null)
-            return null;
+            return isRootPartEnvelope ? rootPartContentType : null;
         else
             if (parts.getCount() == 1)
                 return getRootPart().getContentType();
@@ -554,6 +637,8 @@
             getRootPart().writeTo(os);
         }
         else {
+            // fill Root part first
+            fillRootPart();
             Session session = Session.getDefaultInstance(new Properties(), null);
             MimeMessage msg = new MimeMessage(session);
             msg.setContent(parts);
@@ -691,14 +776,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;
     }
 
@@ -709,7 +796,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;
     }
 
     /**
@@ -719,7 +806,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;
     }
 
     /**
@@ -728,7 +815,7 @@
      * @return The number of multiRefs.
      */
     public int getMultiRefCount() {
-        return multiRef.size();
+        return  multiRef != null ? multiRef.size() : 0;
     }
 
     /**
@@ -738,6 +825,8 @@
      * @param o The deserialized object.
      */
     public void addDeserializedMultiRef(String id, Object o) {
+        if (deserializedMultiRef == null)
+            deserializedMultiRef = new HashMap();
         deserializedMultiRef.put(id, o);
     }
 
@@ -748,7 +837,7 @@
      * @return The multiRef for the id.
      */
     public Object getDeserializedMultiRef(String id) {
-        return deserializedMultiRef.get(id);
+        return deserializedMultiRef == null ? null :deserializedMultiRef.get(id);
     }
 
     /**
@@ -794,7 +883,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: 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       20 Nov 2002 16:33:54 -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,
@@ -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: ServerUtils.java
===================================================================
RCS file: /home/cvspublic/xml-soap/java/src/org/apache/soap/server/ServerUtils.java,v
retrieving revision 1.10
diff -u -r1.10 ServerUtils.java
--- ServerUtils.java    5 Sep 2002 16:50:52 -0000       1.10
+++ ServerUtils.java    20 Nov 2002 16:35:17 -0000
@@ -147,11 +147,13 @@
         reqMsg.read();
         // Check Content-Type of root part of request to see if it's
         // consistent with a SOAP envelope (text/xml).
-        MimeBodyPart rootPart = ctx.getRootPart();
-        if (!rootPart.isMimeType(Constants.HEADERVAL_CONTENT_TYPE))
+        String ctype = ctx.getRootPartContentType();
+        ContentType type = null;
+        type = MimeUtils.getContentType(ctype);
+        if (type == null || !Constants.CTYPE_TEXT_XML.match(type))
             throw new SOAPException(Constants.FAULT_CODE_PROTOCOL,
                 "Unsupported content type \"" +
-                rootPart.getContentType() + "\", must be: \"" +
+                ctype + "\", must be: \"" +
                 Constants.HEADERVAL_CONTENT_TYPE + "\".");
         // Apply Transport-Hook-Extension
         reqMsg.editIncoming(editor);
Index: TransportMessage.java
===================================================================
RCS file: 
/home/cvspublic/xml-soap/java/src/org/apache/soap/transport/TransportMessage.java,v
retrieving revision 1.22
diff -u -r1.22 TransportMessage.java
--- TransportMessage.java       20 Nov 2002 07:29:32 -0000      1.22
+++ TransportMessage.java       20 Nov 2002 16:36:23 -0000
@@ -330,13 +330,22 @@
         } 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.
@@ -394,20 +403,14 @@
          * 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);
-        }
-        if (rootContentType == null)
-            rootContentType = Constants.HEADERVAL_CONTENT_TYPE_UTF8;
         if (getEnvelope() != null && !rootPartIsEnvelope) {
-            ctx.setRootPart(envelope, rootContentType);
+            rootContentType = Constants.HEADERVAL_CONTENT_TYPE_UTF8;
+            ctx.setRootPart(envelope, Constants.HEADERVAL_CONTENT_TYPE_UTF8);
             rootPartIsEnvelope = true;
+        } else {
+            rootContentType = ctx.getRootPartContentType();
+            if (rootContentType == null)
+                rootContentType = Constants.HEADERVAL_CONTENT_TYPE_UTF8;
         }
 
         // If we only have one part, it is the envelope, so handle
@@ -511,21 +514,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 = MimeUtils.getContentType(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;
     }
Index: XMLParserUtils.java
===================================================================
RCS file: 
/home/cvspublic/xml-soap/java/src/org/apache/soap/util/xml/XMLParserUtils.java,v
retrieving revision 1.7
diff -u -r1.7 XMLParserUtils.java
--- XMLParserUtils.java 30 Oct 2002 02:43:04 -0000      1.7
+++ XMLParserUtils.java 20 Nov 2002 16:38:40 -0000
@@ -57,7 +57,8 @@
 
 package org.apache.soap.util.xml;
 
-import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
 import javax.xml.parsers.*;
 import org.xml.sax.*;
 import org.xml.sax.helpers.*;
@@ -73,7 +74,7 @@
  */
 public class XMLParserUtils {
   private static DocumentBuilderFactory dbf = null;
-  private static HashMap docBuilderTable = new HashMap ();
+  private static List allocatedBuildersList = new ArrayList(10);
 
   static {
     // Create a default instance.
@@ -91,7 +92,7 @@
    * @param factoryClassName the fully-qualified name of a class
    * that implemements DocumentBuilderFactory. If this argument
    * is null, the default (platform-specific) implementation is
-   * used. Basically, if this argument is not null, the 
+   * used. Basically, if this argument is not null, the
    * javax.xml.parsers.DocumentBuilderFactory system property
    * is set (with the specified value) before the
    * DocumentBuilderFactory.newInstance() method is invoked.
@@ -121,7 +122,7 @@
    * @param factoryClassName the fully-qualified name of a class
    * that implemements DocumentBuilderFactory. If this argument
    * is null, the default (platform-specific) implementation is
-   * used. Basically, if this argument is not null, the 
+   * used. Basically, if this argument is not null, the
    * javax.xml.parsers.DocumentBuilderFactory system property
    * is set (with the specified value) before the
    * DocumentBuilderFactory.newInstance() method is invoked.
@@ -167,20 +168,45 @@
    */
   synchronized public static DocumentBuilder getXMLDocBuilder()
     throws IllegalArgumentException {
-    // if a document builder has already been created for this thread 
-    // then just reuse that. otherwise create a new one and remember it.
-    Thread t = Thread.currentThread ();
-    DocumentBuilder db = (DocumentBuilder) docBuilderTable.get (t);
-    if (db != null) {
-      return db;
-    } else {
       try {
-        db = dbf.newDocumentBuilder();
-        docBuilderTable.put (t, db);
-        return db;
+        return dbf.newDocumentBuilder();
       } catch (ParserConfigurationException pce) {
         throw new IllegalArgumentException(pce.toString());
       }
     }
+
+
+  /**
+   * Use this method to get a JAXP document builder.
+   * This method either returns a previosly allocated DocumentBuilder
+   * or creates a namespace aware, nonvalidating
+   * instance of the XML parser.
+   *
+   * @return DocumentBuilder an instance of a document builder,
+   * or null if a ParserConfigurationException was thrown.
+   */
+  synchronized public static DocumentBuilder getXMLDocBuilderFromPool() {
+      // First check if we have DocBuider available
+      DocumentBuilder  builder = null;
+      int size = allocatedBuildersList.size();
+      if ( size > 0) {
+          builder = (DocumentBuilder)allocatedBuildersList.get(size-1);
+          allocatedBuildersList.remove(size-1);
+      } else
+          // Not available - create a new DocumentBuilder
+          builder = XMLParserUtils.getXMLDocBuilder();
+
+      return builder;
+  }
+
+  /**
+   * Return a JAXP document builder, previosly allocated by method
+   * getXMLDocBuilderFromPool() for further reuse
+   *
+   * @param builder a DocumentBuilder to release
+   */
+  synchronized public static void returnDocumentBuilderToPool(DocumentBuilder 
+builder) {
+      if (builder != null)
+          allocatedBuildersList.add(builder);
   }
 }

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to