snichol 2002/11/20 13:34:43 Modified: java/src/org/apache/soap/providers RPCJavaProvider.java java/src/org/apache/soap/rpc Call.java SOAPContext.java java/src/org/apache/soap/server ServerUtils.java java/src/org/apache/soap/server/http RPCRouterServlet.java java/src/org/apache/soap/transport TransportMessage.java Log: Submitted by: Pavel Ausianik <[EMAIL PROTECTED]> 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... 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! I think I managed make it compatible to existing code and yet still much faster (8-10 sec of 60 I had in the morning ). The Mime part will be created as soon as it requested, otherwise plain Envelope used Also I set up initial buffer in couple of classes... Revision Changes Path 1.6 +1 -1 xml-soap/java/src/org/apache/soap/providers/RPCJavaProvider.java Index: RPCJavaProvider.java =================================================================== RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/providers/RPCJavaProvider.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- RPCJavaProvider.java 17 May 2001 17:45:46 -0000 1.5 +++ RPCJavaProvider.java 20 Nov 2002 21:34:42 -0000 1.6 @@ -129,7 +129,7 @@ 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); } 1.23 +2 -4 xml-soap/java/src/org/apache/soap/rpc/Call.java Index: Call.java =================================================================== RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/rpc/Call.java,v retrieving revision 1.22 retrieving revision 1.23 diff -u -r1.22 -r1.23 --- Call.java 19 Nov 2002 02:47:38 -0000 1.22 +++ Call.java 20 Nov 2002 21:34:42 -0000 1.23 @@ -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 1.16 +109 -17 xml-soap/java/src/org/apache/soap/rpc/SOAPContext.java Index: SOAPContext.java =================================================================== RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/rpc/SOAPContext.java,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- SOAPContext.java 19 Nov 2002 02:47:38 -0000 1.15 +++ SOAPContext.java 20 Nov 2002 21:34:42 -0000 1.16 @@ -78,17 +78,22 @@ * * @author Wouter Cloetens ([EMAIL PROTECTED]) * @author Scott Nichol ([EMAIL PROTECTED]) + * @author Pavel Ausianik ([EMAIL PROTECTED]) */ public class SOAPContext { 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 +165,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 +195,7 @@ * @return the Part, or null if no such part exists. */ public MimeBodyPart getBodyPart(String CID) { + fillRootPart(); if (parts == null) { return null; } @@ -222,6 +229,7 @@ * @return the Part or null if not found */ public MimeBodyPart findBodyPart(String uri) { + fillRootPart(); if (parts == null || uri == null) { return null; } @@ -420,10 +428,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 +448,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 +471,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 +479,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 +541,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 +555,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 +598,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 +614,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 +638,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 +777,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 +797,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 +807,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 +816,7 @@ * @return The number of multiRefs. */ public int getMultiRefCount() { - return multiRef.size(); + return multiRef != null ? multiRef.size() : 0; } /** @@ -738,6 +826,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 +838,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 +884,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(); } 1.11 +5 -3 xml-soap/java/src/org/apache/soap/server/ServerUtils.java Index: ServerUtils.java =================================================================== RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/server/ServerUtils.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- ServerUtils.java 5 Sep 2002 16:50:52 -0000 1.10 +++ ServerUtils.java 20 Nov 2002 21:34:42 -0000 1.11 @@ -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); 1.43 +1 -1 xml-soap/java/src/org/apache/soap/server/http/RPCRouterServlet.java Index: RPCRouterServlet.java =================================================================== RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/server/http/RPCRouterServlet.java,v retrieving revision 1.42 retrieving revision 1.43 diff -u -r1.42 -r1.43 --- RPCRouterServlet.java 10 Sep 2002 07:27:25 -0000 1.42 +++ RPCRouterServlet.java 20 Nov 2002 21:34:42 -0000 1.43 @@ -409,7 +409,7 @@ (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); 1.23 +24 -34 xml-soap/java/src/org/apache/soap/transport/TransportMessage.java Index: TransportMessage.java =================================================================== RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/transport/TransportMessage.java,v retrieving revision 1.22 retrieving revision 1.23 diff -u -r1.22 -r1.23 --- TransportMessage.java 20 Nov 2002 07:29:32 -0000 1.22 +++ TransportMessage.java 20 Nov 2002 21:34:42 -0000 1.23 @@ -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; }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>