You are viewing a plain text version of this content. The canonical link for it is here.
Posted to soap-dev@ws.apache.org by Wouter Cloetens <wc...@raleigh.ibm.com> on 2000/07/30 11:10:53 UTC
Multipart Mime support (85KB patch)
diff -u -P -r xml-soap/java/samples/mime/foo.txt xml-soap-mime/java/samples/mime/foo.txt
--- xml-soap/java/samples/mime/foo.txt Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/samples/mime/foo.txt Tue Jul 25 19:12:16 2000
@@ -0,0 +1 @@
+bar!
diff -u -P -r xml-soap/java/samples/mime/mimesoaptest.cmd xml-soap-mime/java/samples/mime/mimesoaptest.cmd
--- xml-soap/java/samples/mime/mimesoaptest.cmd Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/samples/mime/mimesoaptest.cmd Sun Jul 30 12:14:44 2000
@@ -0,0 +1,19 @@
+@echo off
+
+set URL=http://localhost/servlet/rpcrouter
+rem set URL=http://localhost/apache-soap/rpcrouter
+rem set URL=http://localhost:81/apache-soap/rpcrouter
+rem set URL="queue://dmzqm/esrv.proto2a.q?persistence=1&targetclient=1"
+rem set URL="topic://eat/my/shorts"
+
+rem set ACTION=sendFile
+rem set ACTION=loopFile
+set ACTION=getFileVector
+rem set ACTION=getFileArray
+
+set BASEDIR=/home/projects/xml-soap-mime/java/samples/mime
+rem set FILELIST=%BASEDIR%/foo.txt
+rem set FILELIST=%BASEDIR%/fields.gif
+set FILELIST=%BASEDIR%/fields.gif %BASEDIR%/foo.txt
+
+java -nojit mimesoaptest %URL% %ACTION% %FILELIST% 2>err | tee -a out
diff -u -P -r xml-soap/java/samples/mime/mimesoaptest.java xml-soap-mime/java/samples/mime/mimesoaptest.java
--- xml-soap/java/samples/mime/mimesoaptest.java Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/samples/mime/mimesoaptest.java Sun Jul 30 12:25:34 2000
@@ -0,0 +1,149 @@
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import org.w3c.dom.*;
+import org.apache.soap.util.xml.*;
+import org.apache.soap.util.mime.*;
+import org.apache.soap.*;
+import org.apache.soap.transport.*;
+import org.apache.soap.encoding.*;
+import org.apache.soap.encoding.soapenc.*;
+import org.apache.soap.rpc.*;
+import com.ibm.eservice.transport.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.activation.*;
+
+public class mimesoaptest
+{
+ public static void main(String[] args) throws Exception
+ {
+ String encodingStyleURI = Constants.NS_URI_SOAP_ENC;
+ URL url = new URL(args[0]);
+ SOAPMappingRegistry smr = new SOAPMappingRegistry();
+ BeanSerializer beanSer = new BeanSerializer();
+
+ try
+ {
+ // Build the call.
+ Call call = new Call();
+
+ call.setSOAPMappingRegistry(smr);
+ call.setTargetObjectURI("urn:mimetest");
+ call.setMethodName(args[1]);
+ call.setEncodingStyleURI(encodingStyleURI);
+
+ if(url.getProtocol().equals("queue") || url.getProtocol().equals("topic"))
+ {
+ SOAPJMSConnection qs = new SOAPMQJMSConnection();
+ call.setSOAPTransport(qs);
+ }
+
+ Vector params = new Vector();
+ if(args[1].equals("sendFile") || args[1].equals("loopFile"))
+ for(int i = 2; i < args.length; i++)
+ {
+ DataSource ds = new ByteArrayDataSource(new File(args[i]), null);
+ DataHandler dh = new DataHandler(ds);
+ params.addElement(new Parameter("addedfile", javax.activation.DataHandler.class, dh, null));
+ }
+ else
+ {
+ String s[] = new String[args.length - 2];
+ for(int i = 2; i < args.length; i++)
+ {
+ s[i - 2] = args[i];
+ }
+ params.addElement(new Parameter("filenames", String[].class, s, null));
+ }
+ call.setParams(params);
+
+ // System.out.println("Call: " + call);
+ // System.out.println("Context: " + RPCContext.getRPCContext());
+
+ // Invoke the call.
+ Response resp;
+
+ try
+ {
+ resp = call.invoke(url, "");
+ }
+ catch (SOAPException e)
+ {
+ System.err.println("Caught SOAPException (" +
+ e.getFaultCode() + "): " +
+ e.getMessage());
+ e.printStackTrace();
+ return;
+ }
+
+ // Check the response.
+ if (!resp.generatedFault())
+ {
+ Parameter ret = resp.getReturnValue();
+ if(ret == null)
+ System.out.println("No response.");
+ else
+ {
+ // System.out.println("Response: " + resp);
+
+ printObject(ret.getValue());
+ }
+ }
+ else
+ {
+ Fault fault = resp.getFault();
+
+ System.err.println("Generated fault: ");
+ System.err.println (" Fault Code = " + fault.getFaultCode());
+ System.err.println (" Fault String = " + fault.getFaultString());
+ }
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void printObject(Object obj)
+ {
+ if(obj instanceof DataHandler)
+ {
+ DataHandler dh = (DataHandler)obj;
+ Object o;
+ try
+ {
+ o = dh.getContent();
+ }
+ catch(IOException ioe)
+ {
+ o = ioe;
+ }
+ System.out.println("DataHandler, name=" + dh.getName()
+ + ", type=" + dh.getContentType()
+ + ", content: (" + o.getClass().getName()
+ + ")\n" + o);
+ DataSource ds = dh.getDataSource();
+ String fname = "" + System.currentTimeMillis() + ".out";
+ System.out.println(" Writing to " + fname);
+ try
+ {
+ ByteArrayDataSource bds = new ByteArrayDataSource(ds.getInputStream(), dh.getContentType());
+ bds.writeTo(new FileOutputStream(fname));
+ }
+ catch(IOException ioe)
+ {
+ System.out.println(ioe);
+ ioe.printStackTrace(System.err);
+ }
+ }
+ else if(obj instanceof Object[])
+ {
+ Object[] s = (Object[])obj;
+ for(int i = 0; i < s.length; i++)
+ printObject(s[i]);
+ }
+ else
+ System.out.println(obj);
+ }
+}
diff -u -P -r xml-soap/java/samples/mime/mimetest.java xml-soap-mime/java/samples/mime/mimetest.java
--- xml-soap/java/samples/mime/mimetest.java Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/samples/mime/mimetest.java Sun Jul 30 12:26:52 2000
@@ -0,0 +1,53 @@
+/**
+ * NOTE!!! This service is a *huge* security hole and is provided for
+ * demonstration purposes only.
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.activation.*;
+import org.apache.soap.util.mime.*;
+
+public class mimetest
+{
+ public mimetest()
+ {
+ }
+
+ public static String sendFile(DataHandler dh) throws IOException
+ {
+ StringBuffer sb = new StringBuffer("Received attachment:\n");
+ sb.append("Content type: ").append(dh.getContentType());
+ sb.append("\nName: ").append(dh.getName());
+ Object o = dh.getContent();
+ sb.append("\nContent class: ").append(o.getClass().getName());
+ sb.append("\nContent: ").append(o.toString());
+ return sb.toString();
+ }
+
+ public static DataHandler loopFile(DataHandler dh) throws IOException
+ {
+ return dh;
+ }
+
+ public static Vector getFileVector(String[] fname) throws IOException
+ {
+ Vector res = new Vector();
+
+ for(int i = 0; i < fname.length; i++)
+ {
+ DataSource ds = new ByteArrayDataSource(new File(fname[i]), null);
+ res.addElement(new DataHandler(ds));
+ }
+ return res;
+ }
+
+ public static DataHandler[] getFileArray(String[] fname) throws IOException
+ {
+ Vector v = getFileVector(fname);
+ DataHandler[] dhs = new DataHandler[v.size()];
+ for(int i = 0; i < dhs.length; i++)
+ dhs[i] = (DataHandler)v.elementAt(i);
+ return dhs;
+ }
+}
diff -u -P -r xml-soap/java/src/org/apache/soap/encoding/soapenc/MimePartSerializer.java xml-soap-mime/java/src/org/apache/soap/encoding/soapenc/MimePartSerializer.java
--- xml-soap/java/src/org/apache/soap/encoding/soapenc/MimePartSerializer.java Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/src/org/apache/soap/encoding/soapenc/MimePartSerializer.java Sun Jul 30 11:53:42 2000
@@ -0,0 +1,279 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "SOAP" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2000, International
+ * Business Machines, Inc., http://www.apache.org. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.soap.encoding.soapenc;
+
+import java.beans.*;
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.*;
+import org.w3c.dom.*;
+import org.apache.soap.util.*;
+import org.apache.soap.util.xml.*;
+import org.apache.soap.util.mime.*;
+import org.apache.soap.*;
+import org.apache.soap.rpc.*;
+import javax.activation.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+
+/**
+ * A <code>MimePartSerializer</code> can be used to serialize
+ * Java's InputStream, JavaMail's MimeBodyPart and
+ * Java Activation Framework's DataSource and DataHandler objects
+ * from/to multipart Mime attachments to the SOAP message.<p>
+ * Inside the SOAP message body, the reference looks like:<br>
+ * <code><attachment href="cid:foo"></code><br>
+ * where "foo" is the name of the Content-ID of the mime part.<p>
+ * The class always deserializes to a DataHandler, which provides
+ * an InputStream, a DataSource with a Content-Type, the content
+ * as an object, and allows to write the data to an OutputStream.
+ *
+ * @author Wouter Cloetens (wcloeten@raleigh.ibm.com)
+ */
+public class MimePartSerializer implements Serializer, Deserializer
+{
+ private static final QName mimepartQName = new QName(Constants.NS_URI_SOAP_ENC, "attachment");
+
+ public void marshall(String inScopeEncStyle, Class javaType, Object src,
+ Object context, Writer sink, NSStack nsStack,
+ XMLJavaMappingRegistry xjmr)
+ throws IllegalArgumentException, IOException
+ {
+ nsStack.pushScope();
+
+ if ((src != null) &&
+ !(src instanceof InputStream) &&
+ !(src instanceof DataSource) &&
+ !(src instanceof MimeBodyPart) &&
+ !(src instanceof DataHandler))
+ throw new IllegalArgumentException("Tried to pass a '" +
+ src.getClass().toString() + "' to MimePartSerializer");
+
+ if (src == null)
+ {
+ SoapEncUtils.generateNullStructure(inScopeEncStyle, Object.class,
+ "attachment", sink, nsStack, xjmr);
+ }
+ else
+ {
+ // get a MimeBodyPart out of the various possible input types
+ DataSource ds = null;
+ DataHandler dh = null;
+ MimeBodyPart bp = null;
+ if(src instanceof InputStream)
+ ds = new ByteArrayDataSource((InputStream)src, "application/octet-stream");
+ else if(src instanceof DataSource)
+ ds = (DataSource)ds;
+ if(ds != null)
+ dh = new DataHandler(ds);
+ else if(src instanceof DataHandler)
+ dh = (DataHandler)src;
+ if(dh != null)
+ {
+ bp = new MimeBodyPart();
+ try
+ {
+ bp.setDataHandler(dh);
+ }
+ catch(MessagingException me)
+ {
+ throw new IllegalArgumentException("Invalid InputStream/DataSource/DataHandler: " + me);
+ }
+ // set some Mime headers. Assume that a passed MimeBodyPart
+ // already has these set to appropriate values
+ try
+ {
+ MimeType ctype = new MimeType(dh.getContentType());
+ bp.setHeader("Content-Type", ctype.toString());
+ if(dh.getDataSource() instanceof ByteArrayDataSource)
+ bp.setHeader("Content-Length", String.valueOf(((ByteArrayDataSource)dh.getDataSource()).getSize()));
+ if(ctype.match("application/octet-stream") ||
+ ctype.getPrimaryType().equals("image") ||
+ ctype.getPrimaryType().equals("audio") ||
+ ctype.getPrimaryType().equals("video"))
+ bp.setHeader("Content-Transfer-Encoding", "8bit");
+ }
+ catch(MessagingException me)
+ {
+ throw new IllegalArgumentException("Invalid InputStream/DataSource/DataHandler metadata: " + me);
+ }
+ catch(MimeTypeParseException mtpe)
+ {
+ throw new IllegalArgumentException("Invalid Mime type \"" + dh.getContentType() + "\": " + mtpe);
+ }
+ }
+ else if(src instanceof MimeBodyPart)
+ {
+ bp = (MimeBodyPart)src;
+ }
+ // by now we must logically have a valid MimeBodyPart
+
+ // set a unique content-ID
+ String cid = null;
+ try
+ {
+ cid = bp.getContentID();
+ }
+ catch(MessagingException me)
+ {
+ }
+ if(cid == null)
+ {
+ cid = MimeUtils.getUniqueValue();
+ try
+ {
+ bp.setHeader("Content-ID", cid);
+ }
+ catch(MessagingException me)
+ {
+ throw new IllegalArgumentException("Could not set Content-ID: " + me);
+ }
+ }
+
+ // get multipart context
+ RPCContext ctx = RPCContext.getRPCContext();
+
+ // add the part to the context
+ try
+ {
+ ctx.addBodyPart(bp);
+ }
+ catch(MessagingException me)
+ {
+ throw new IllegalArgumentException("Could not add attachment: " + me);
+ }
+
+ // Now write the XML element.
+ sink.write('<' + context.toString());
+
+ // Get prefixes for the needed namespaces.
+ String xsiNSPrefix = nsStack.getPrefixFromURI(Constants.NS_URI_SCHEMA_XSI, sink);
+
+ String elementTypeNSPrefix = nsStack.getPrefixFromURI(mimepartQName.getNamespaceURI(), sink);
+ sink.write(' ' + xsiNSPrefix + ':' + Constants.ATTR_TYPE + "=\"" +
+ elementTypeNSPrefix + ':' +
+ mimepartQName.getLocalPart() + '"');
+
+ if(inScopeEncStyle == null
+ || !inScopeEncStyle.equals(Constants.NS_URI_SOAP_ENC))
+ {
+ // Determine the prefix associated with the NS_URI_SOAP_ENV
+ // namespace URI.
+ String soapEnvNSPrefix = nsStack.getPrefixFromURI(Constants.NS_URI_SOAP_ENV, sink);
+
+ sink.write(' ' + soapEnvNSPrefix + ':' +
+ Constants.ATTR_ENCODING_STYLE + "=\"" +
+ Constants.NS_URI_SOAP_ENC + '"');
+ }
+
+ // Write the reference.
+ sink.write(" href=\"cid:" + cid + '"');
+
+ sink.write("/>");
+ }
+
+ nsStack.popScope();
+ }
+
+ public Bean unmarshall(String inScopeEncStyle, QName elementType, Node src,
+ XMLJavaMappingRegistry xjmr)
+ throws IllegalArgumentException
+ {
+ // get multipart context
+ RPCContext ctx = RPCContext.getRPCContext();
+
+ Element paramEl = (Element)src;
+
+ DataHandler dh = null;
+ if(!SoapEncUtils.isNull(paramEl))
+ {
+ String cid = paramEl.getAttribute("href");
+
+ try
+ {
+ MimeBodyPart bp = null;
+ if(cid != null && cid.startsWith("cid:"))
+ {
+ cid = cid.substring(4);
+ try
+ {
+ bp = (MimeBodyPart)ctx.getBodyPart(cid);
+ }
+ catch(NullPointerException npe)
+ {
+ }
+ catch(ClassCastException cce)
+ {
+ }
+ }
+ if(bp == null)
+ throw new IllegalArgumentException("Attachment tag \"" + paramEl.getTagName()
+ + "\" refers to a Mime attachment with Content-ID \""
+ + cid + "\" which could not be found.");
+ else
+ dh = bp.getDataHandler();
+ }
+ catch(MessagingException me)
+ {
+ throw new IllegalArgumentException("Failed to read attachment for tag \"" + paramEl.getTagName()
+ + "\" with Content-ID \"" + cid + "\": " + me);
+ }
+ }
+ return new Bean(javax.activation.DataHandler.class, dh);
+ }
+}
diff -u -P -r xml-soap/java/src/org/apache/soap/encoding/SOAPMappingRegistry.java xml-soap-mime/java/src/org/apache/soap/encoding/SOAPMappingRegistry.java
--- xml-soap/java/src/org/apache/soap/encoding/SOAPMappingRegistry.java Thu Jul 27 06:13:54 2000
+++ xml-soap-mime/java/src/org/apache/soap/encoding/SOAPMappingRegistry.java Sat Jul 29 20:23:46 2000
@@ -91,10 +91,12 @@
private static final QName shortQName = new QName(schemaURI, "short");
private static final QName byteQName = new QName(schemaURI, "byte");
private static final QName arrayQName = new QName(soapEncURI, "Array");
+ private static final QName mimepartQName = new QName(soapEncURI, "attachment");
private final ParameterSerializer paramSer = new ParameterSerializer();
private final ArraySerializer arraySer = new ArraySerializer();
private final VectorSerializer vectorSer = new VectorSerializer();
+ private final MimePartSerializer partSer = new MimePartSerializer();
private final XMLParameterSerializer xmlParamSer =
new XMLParameterSerializer();
@@ -119,6 +121,18 @@
mapTypes(Constants.NS_URI_LITERAL_XML, RPCConstants.Q_ELEM_PARAMETER,
Parameter.class, xmlParamSer, xmlParamSer);
+ // Register inputstreams, data handlers, data sources as Mime parts.
+ // The order is important! When deserialing an array of these objects,
+ // DataHandler must be the target class.
+ mapTypes(soapEncURI, mimepartQName, javax.mail.internet.MimeBodyPart.class,
+ partSer, partSer);
+ mapTypes(soapEncURI, mimepartQName, java.io.InputStream.class,
+ partSer, partSer);
+ mapTypes(soapEncURI, mimepartQName, javax.activation.DataSource.class,
+ partSer, partSer);
+ mapTypes(soapEncURI, mimepartQName, javax.activation.DataHandler.class,
+ partSer, partSer);
+
try {
Class XMISerializer =
Class.forName("org.apache.soap.util.xml.XMISerializer");
@@ -137,6 +151,7 @@
} catch (IllegalAccessException iae) {
} catch (InstantiationException ie) {
} catch (ClassNotFoundException cnfe) {
+ } catch (NoClassDefFoundError ncdfe) {
// If the class can't be loaded, continue without it...
diff -u -P -r xml-soap/java/src/org/apache/soap/rpc/RPCContext.java xml-soap-mime/java/src/org/apache/soap/rpc/RPCContext.java
--- xml-soap/java/src/org/apache/soap/rpc/RPCContext.java Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/src/org/apache/soap/rpc/RPCContext.java Sat Jul 29 16:29:50 2000
@@ -0,0 +1,318 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "SOAP" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2000, International
+ * Business Machines, Inc., http://www.apache.org. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.soap.rpc;
+
+import java.io.*;
+import java.util.*;
+import org.apache.soap.util.*;
+import org.apache.soap.*;
+import org.apache.soap.encoding.*;
+import org.apache.soap.server.*;
+
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.activation.*;
+
+/**
+ * <code>Call</code> and <code>Response</code> is done here.
+ *
+ * @author Wouter Cloetens (wcloeten@raleigh.ibm.com)
+ */
+public class RPCContext
+{
+ protected MimeMultipart parts;
+ protected static Hashtable contextTable = new Hashtable();
+
+ // TODO: put this in Constants
+ public static final String HEADERVAL_MULTIPART_CONTENT_SUBTYPE = "related";
+
+ private static final String[] ignoreHeaders = {"Message-ID"};
+
+ /**
+ * Get the current RPCMessage context (temp kludge).<p>
+ * The structure of the code currently doesn't expose any context
+ * to the [de]serializers. The Mime parts, currently embedded in
+ * this calss, need to be
+ * accessible to the [de]serializers. Until this situation is
+ * fundamentally resolved, a kludgy mechanism is introduced here,
+ * allowing any class to extract a reference to the current
+ * RPCContext using the current thread.<p>
+ * This mechanism assumes that only one call or response is being
+ * handled at any time, and only within the context of one thread.
+ */
+ public static RPCContext getRPCContext()
+ {
+ Thread me = Thread.currentThread();
+ Object o = contextTable.get(me);
+ if(o != null && o instanceof RPCContext)
+ return (RPCContext)o;
+ else
+ {
+ RPCContext ctx = new RPCContext();
+ ctx.setRPCContext();
+ return ctx;
+ }
+ }
+
+ public void setRPCContext()
+ {
+ Thread me = Thread.currentThread();
+ contextTable.put(me, this);
+ }
+
+ public RPCContext()
+ {
+ parts = null;
+ }
+
+ public void readMultipart(DataSource ds) throws MessagingException
+ {
+ parts = new MimeMultipart(ds);
+ }
+
+ /**
+ * Get the specified Part. Parts are numbered starting at 0.
+ *
+ * @param index the index of the desired Part
+ * @return the Part
+ * @exception IndexOutOfBoundsException if no such Part exists
+ */
+ public BodyPart getBodyPart(int index) throws IndexOutOfBoundsException
+ {
+ /* Actually, this method never throws a MessagingException. In case a
+ * future implementation does, catch it and throw an IndexOutOfBoundsException
+ */
+ if (parts == null)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ try
+ {
+ return parts.getBodyPart(index);
+ }
+ catch (MessagingException me)
+ {
+ me.printStackTrace();
+ throw new IndexOutOfBoundsException(me.getMessage());
+ }
+ }
+
+ /**
+ * Get the Mimepart referred to by the given ContentID (CID).
+ * Returns null if the part is not found.
+ *
+ * @param CID the ContentID of the desired part
+ * @return the Part
+ */
+ public BodyPart getBodyPart(String CID)
+ {
+ if (parts == null)
+ {
+ return null;
+ }
+ try
+ {
+ return parts.getBodyPart(CID);
+ }
+ catch (MessagingException me)
+ {
+ return null;
+ }
+ catch (NullPointerException npe)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Adds a Part. The BodyPart is appended to
+ * the list of existing Parts.
+ *
+ * @param part The Part to be appended
+ * @exception MessagingException
+ * @exception IllegalWriteException if the underlying
+ * implementation does not support modification
+ * of existing values
+ */
+ public void addBodyPart(BodyPart part) throws MessagingException
+ {
+ if (parts == null)
+ parts = new MimeMultipart(HEADERVAL_MULTIPART_CONTENT_SUBTYPE);
+ parts.addBodyPart(part);
+ }
+
+ /**
+ * Adds a BodyPart at position <code>index</code>.
+ * If <code>index</code> is not the last one in the list,
+ * the subsequent parts are shifted up. If <code>index</code>
+ * is larger than the number of parts present, the
+ * BodyPart is appended to the end.
+ *
+ * @param part The BodyPart to be inserted
+ * @param index Location where to insert the part
+ * @exception MessagingException
+ * @exception IllegalWriteException if the underlying
+ * implementation does not support modification
+ * of existing values
+ */
+ public void addBodyPart(BodyPart part, int index) throws MessagingException
+ {
+ if (parts == null)
+ parts = new MimeMultipart(HEADERVAL_MULTIPART_CONTENT_SUBTYPE);
+ parts.addBodyPart(part, index);
+ }
+
+ /**
+ * 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>
+ *
+ * @param subtype Subtype
+ * @exception MessagingException
+ */
+ public void setSubType(String subtype) throws MessagingException
+ {
+ if (parts == null)
+ parts = new MimeMultipart(subtype);
+ else
+ parts.setSubType(subtype);
+ }
+
+ /**
+ * Return the number of enclosed BodyPart objects.
+ *
+ * @return number of parts
+ */
+ public int getCount() throws MessagingException
+ {
+ if (parts == null)
+ return 0;
+ else
+ return parts.getCount();
+ }
+
+ /**
+ * Return the content-type
+ *
+ * @return content type of the Mime multipart
+ */
+ public String getContentType()
+ {
+ if (parts == null)
+ return null;
+ else
+ return parts.getContentType();
+ }
+
+ /**
+ * Encode the whole multipart and write to an OutputStream
+ *
+ * @param os stream to write to
+ * @exception IOException
+ * @exception MessagingException
+ */
+ public void writeTo(OutputStream os) throws IOException, MessagingException
+ {
+ Session session = Session.getDefaultInstance(new Properties(), null);
+ MimeMessage msg = new MimeMessage(session);
+ msg.setContent(parts);
+ msg.saveChanges();
+ msg.writeTo(os, ignoreHeaders);
+ }
+
+ public String toString()
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+
+ pw.print("[Parts={");
+
+ if (parts != null)
+ {
+ try
+ {
+ for (int i = 0; i < getCount(); i++)
+ {
+ if (i > 0)
+ {
+ pw.print(", ");
+ }
+
+ BodyPart bp = getBodyPart(i);
+ if(bp instanceof MimeBodyPart)
+ {
+ MimeBodyPart mbp = (MimeBodyPart)bp;
+ pw.print("[cid:" + mbp.getContentID()
+ + " type: " + mbp.getContentType()
+ + " enc: " + mbp.getEncoding() + "]");
+ }
+ else
+ pw.print("[bodypart]");
+ }
+ }
+ catch(MessagingException me)
+ {
+ me.printStackTrace();
+ }
+ }
+
+ pw.print("}]");
+
+ return sw.toString();
+ }
+}
diff -u -P -r xml-soap/java/src/org/apache/soap/server/ServiceManagerClient.java xml-soap-mime/java/src/org/apache/soap/server/ServiceManagerClient.java
--- xml-soap/java/src/org/apache/soap/server/ServiceManagerClient.java Thu Jul 20 12:24:52 2000
+++ xml-soap-mime/java/src/org/apache/soap/server/ServiceManagerClient.java Sat Jul 29 17:20:16 2000
@@ -154,7 +154,7 @@
ServiceManagerClient.class.getName () +
" url operation arguments");
System.err.println ("where");
- System.err.println ("\turl is the IBM-SOAP router's URL whose services" +
+ System.err.println ("\turl is the Apache-SOAP router's URL whose services" +
" are managed");
System.err.println ("\toperation and arguments are:");
System.err.println ("\t\tdeploy deployment-descriptor-file.xml");
diff -u -P -r xml-soap/java/src/org/apache/soap/transport/http/rpcrouter.java xml-soap-mime/java/src/org/apache/soap/transport/http/rpcrouter.java
--- xml-soap/java/src/org/apache/soap/transport/http/rpcrouter.java Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/src/org/apache/soap/transport/http/rpcrouter.java Sun Jul 30 11:57:14 2000
@@ -0,0 +1,479 @@
+package org.apache.soap.transport.http;
+
+import java.io.*;
+import java.util.*;
+import java.beans.Beans;
+import java.lang.reflect.*;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+import javax.activation.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+
+import org.w3c.dom.*;
+
+import org.apache.soap.util.Bean;
+import org.apache.soap.util.MethodUtils;
+import org.apache.soap.util.IOUtils;
+import org.apache.soap.util.StringUtils;
+import org.apache.soap.util.xml.XMLParserLiaison;
+import org.apache.soap.util.xml.XercesParserLiaison;
+import org.apache.soap.util.mime.*;
+import org.apache.soap.*;
+import org.apache.soap.encoding.*;
+import org.apache.soap.rpc.*;
+import org.apache.soap.server.*;
+import org.apache.soap.server.ServiceManager;
+import org.apache.soap.server.RPCRouter;
+
+public class rpcrouter extends HttpServlet {
+ public void service(HttpServletRequest request,HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ try
+ {
+ OutputStream outStream = response.getOutputStream ();
+ PrintWriter out = new PrintWriter (new OutputStreamWriter (outStream));
+
+ // get servlet init parameters to initialize bean properties
+ Properties p = new java.util.Properties();
+ Enumeration e = request.getParameterNames();
+ while (e.hasMoreElements()) {
+ String name = (String) e.nextElement();
+ p.put(name, request.getParameter(name));
+ }
+
+ // get ServiceManager bean
+ org.apache.soap.server.ServiceManager serviceManager =
+ (ServiceManager)request.getAttribute("serviceManager");
+ if (serviceManager == null) {
+ try {
+ serviceManager =
+ (ServiceManager) Beans.instantiate(this.getClass().getClassLoader(),
+ "org.apache.soap.server.ServiceManager");
+ } catch (Exception ex) {
+ throw new ServletException("Can't create BEAN of class org.apache.soap.server.ServiceManager: "+ ex.getMessage());
+ }
+ //request.setAttribute("serviceManager", serviceManager);
+ ((com.sun.server.http.HttpServiceRequest)request).setAttribute("serviceManager", serviceManager);
+ }
+ // com.ibm.servlet.util.BeansUtil.setProperties(serviceManager, p);
+ com.sun.server.util.BeansUtil.setProperties(serviceManager, p);
+
+ // get RPCRouter bean
+ org.apache.soap.server.RPCRouter rpcRouter= (org.apache.soap.server.RPCRouter)
+ request.getAttribute("rpcRouter");
+ if (rpcRouter == null) {
+ try {
+ rpcRouter = (org.apache.soap.server.RPCRouter) Beans.instantiate(this.getClass().getClassLoader(), "org.apache.soap.server.RPCRouter");
+ } catch (Exception ex) {
+ throw new ServletException("Can't create BEAN of class org.apache.soap.server.RPCRouter: "+ ex.getMessage());
+ }
+ //request.setAttribute("rpcRouter", rpcRouter);
+ ((com.sun.server.http.HttpServiceRequest)request).setAttribute("rpcRouter", rpcRouter);
+ }
+ // com.ibm.servlet.util.BeansUtil.setProperties(rpcRouter, p);
+ com.sun.server.util.BeansUtil.setProperties(rpcRouter, p);
+
+ rpcRouter.setServiceManager (serviceManager);
+
+ Response resp = null;
+ String targetID = null;
+
+ // Query the relevant header fields.
+ String requestMethod = request.getMethod ();
+ String contentType = request.getContentType ();
+ int contentLength = request.getContentLength ();
+
+ Call call = null;
+ RPCContext ctx = new RPCContext();
+ try
+ {
+ if (requestMethod == null ||
+ !requestMethod.equals (Constants.HEADER_POST))
+ {
+ throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
+ "Can only respond to '" +
+ Constants.HEADER_POST + "' requests.");
+ }
+ else if (contentType == null
+ || !(contentType.equals (Constants.HEADERVAL_CONTENT_TYPE)
+ || contentType.startsWith ("multipart/related")))
+ {
+ throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
+ "Content type must be: '" +
+ Constants.HEADERVAL_CONTENT_TYPE + "'.");
+ }
+ else if (contentLength < 0)
+ {
+ throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
+ "Content length must be specified.");
+ }
+ else
+ {
+ System.err.println (">>(" + new Date() +
+ ") Processing SOAP request...");
+
+ Reader payloadReader;
+ if(contentType.startsWith("multipart/related"))
+ {
+ ServletInputStream stream = request.getInputStream();
+ byte[] buf = new byte[contentLength];
+ int totNRead = 0, nRead;
+ do
+ nRead = stream.read(buf, totNRead, buf.length - totNRead);
+ while (nRead >= 0 && (totNRead += nRead) < buf.length);
+ if (totNRead < buf.length)
+ throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
+ "Premature end of stream. Data is truncated. Read "
+ + totNRead + " bytes successfully, expected " + contentLength);
+
+ ByteArrayDataSource ds = new ByteArrayDataSource(buf, contentType);
+
+ ctx.readMultipart(ds);
+ // if (mmp.getCount() < 1 ||
+ BodyPart soapPart = ctx.getBodyPart(0);
+ ContentType ctype = new ContentType(soapPart.getContentType());
+ String charset = ctype.getParameter("charset");
+ if (charset == null || charset.equals(""))
+ charset = "iso-8859-1";
+ if (!(Constants.HEADERVAL_CONTENT_TYPE).equals(ctype.getBaseType()))
+ {
+ throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
+ "Content type of first MIME part must be: '" +
+ Constants.HEADERVAL_CONTENT_TYPE + "'.");
+ }
+ payloadReader = new InputStreamReader((InputStream)(soapPart.getContent()), charset);
+ }
+ else
+ {
+ Reader requestReader = request.getReader ();
+ char[] payload = new char[contentLength];
+ int offset = 0;
+
+ while (offset < contentLength) {
+ offset += requestReader.read (payload, offset, contentLength - offset);
+ }
+ payloadReader = new CharArrayReader (payload);
+ }
+
+ ctx.setRPCContext();
+ // System.out.println("Read request content, context = " + ctx);
+
+ // Parse the incoming request stream.
+ org.apache.soap.util.xml.XMLParserLiaison xpl = new XercesParserLiaison ();
+ Document callDoc = xpl.read("- SOAP HTTP RPC Call Envelope -",
+ payloadReader);
+ Element payloadEl = null;
+
+ if (callDoc == null) {
+ throw new SOAPException(Constants.FAULT_CODE_PROTOCOL,
+ "DOM parsing error.");
+ }
+
+ // get the call out
+ try {
+ payloadEl = callDoc.getDocumentElement ();
+ Envelope callEnv = Envelope.unmarshall (payloadEl);
+ call = rpcRouter.extractCallFromEnvelope (callEnv);
+ targetID = call.getTargetObjectURI ();
+ } catch (IllegalArgumentException iae) {
+ String msg = iae.getMessage ();
+ String faultCode = (msg != null
+ && msg.equals(Constants.ERR_MSG_VERSION_MISMATCH))
+ ? Constants.FAULT_CODE_VERSION_MISMATCH
+ : Constants.FAULT_CODE_CLIENT;
+
+ throw new SOAPException (faultCode, msg, iae);
+ }
+
+ // call on a valid method name?
+ if (!rpcRouter.validCall (call)) {
+ throw new SOAPException (Constants.FAULT_CODE_SERVER,
+ "Method '" + call.getMethodName () +
+ "' is not supported.");
+ }
+
+ // lifecycle stuff of target object: what's the class to instantiate?
+ DeploymentDescriptor dd = serviceManager.query (targetID);
+ int scope = dd.getScope ();
+ byte providerType = dd.getProviderType ();
+ String className;
+ Object targetObject = null;
+ if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
+ className = dd.getProviderClass ();
+ } else {
+ // for scripts, we need a new BSF manager basically
+ className = "com.ibm.bsf.BSFManager";
+ }
+
+ // determine the scope and lock object to use to manage the lifecycle
+ // of the service providing object
+ // NOTE: removed for JSP 0.9 support
+ // int[] iScopes = {PageContext.PAGE_SCOPE, PageContext.REQUEST_SCOPE,
+ // PageContext.SESSION_SCOPE,
+ // PageContext.APPLICATION_SCOPE};
+ // int iScope = iScopes[scope];
+ // Object[] scopeLocks = {pageContext, request, session, application};
+ // Object scopeLock = scopeLocks[scope];
+
+ boolean freshObject = false;
+
+ // find the target object on which the requested method should
+ // be invoked
+ if (targetID.equals (ServerConstants.SERVICE_MANAGER_SERVICE_NAME)) {
+ targetObject = serviceManager;
+ } else {
+ // locate (or create) the target object and invoke the method
+ // synchronized (scopeLock) {
+ // NOTE: only request scope supported
+ synchronized (request) {
+ // targetObject = pageContext.getAttribute (targetID, iScope);
+ targetObject = ((com.sun.server.http.HttpServiceRequest)request).getAttribute (targetID);
+ //targetObject = request.getAttribute (targetID);
+ if (targetObject == null) {
+ try {
+ Class c = Class.forName (className);
+ if (dd.getIsStatic ()) {
+ targetObject = c;
+ } else {
+ targetObject = c.newInstance ();
+ }
+ freshObject = true;
+ } catch (Exception ex) {
+ String msg;
+ if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
+ msg = "Unable to resolve target object: " + ex.getMessage ();
+ } else {
+ msg = "Unable to load BSF: script services not available " +
+ "without BSF: " + ex.getMessage ();
+ }
+ throw new SOAPException (RPCConstants.FAULT_CODE_SERVER_BAD_TARGET_OBJECT_URI,
+ msg, ex);
+ }
+ }
+ // pageContext.setAttribute (targetID, targetObject, iScope);
+ ((com.sun.server.http.HttpServiceRequest)request).setAttribute (targetID, targetObject);
+ //request.setAttribute (targetID, targetObject);
+ }
+ }
+
+ // if script provider type and first time to it, then load and
+ // exec the script
+ if (providerType != DeploymentDescriptor.PROVIDER_JAVA &&
+ freshObject) {
+ // find the class that provides the BSF services (done
+ // this way via reflection to avoid a static dependency on BSF)
+ Class bc = Class.forName ("org.apache.soap.server.InvokeBSF");
+
+ // get the script string to exec
+ String script = dd.getScriptFilenameOrString ();
+ if (providerType == DeploymentDescriptor.PROVIDER_SCRIPT_FILE) {
+ String fileName = getServletContext().getRealPath (script);
+ script = IOUtils.getStringFromReader (new FileReader (fileName));
+ }
+
+ // exec it
+ Class[] sig = {DeploymentDescriptor.class,
+ Object.class,
+ String.class};
+ Method m = MethodUtils.getMethod (bc, "init", sig, true);
+ m.invoke (null, new Object[] {dd, targetObject, script});
+ }
+
+ // build a new context for the response. The call has already been rebuilt
+ // and its parameters hold references to DataHandlers, so we can discard
+ // the MimeMultipart and BodyPart objects
+ ctx = new RPCContext();
+ ctx.setRPCContext();
+
+ // invoke the method on the target object
+ resp = rpcRouter.invoke (call, targetObject);
+ }
+ }
+ catch (SOAPException se)
+ {
+ // Wipe context for fault response, so it's not wrapped as a multipart
+ // containing the source's parts in the response.
+ ctx = new RPCContext();
+ ctx.setRPCContext();
+
+ Fault fault = new Fault ();
+ String faultCode = se.getFaultCode ();
+ String faultString = se.getMessage ();
+ boolean returnSOAPResponse = true;
+
+ if (faultCode == null || faultCode.startsWith (Constants.FAULT_CODE_SERVER))
+ {
+ response.setStatus (ServerConstants.SC_INTERNAL_SERVER_ERROR);
+ }
+ else if (faultCode.startsWith (Constants.FAULT_CODE_CLIENT))
+ {
+ response.setStatus (ServerConstants.SC_BAD_REQUEST);
+ }
+ else if (faultCode.startsWith (Constants.FAULT_CODE_PROTOCOL))
+ {
+ response.setStatus (ServerConstants.SC_BAD_REQUEST);
+ returnSOAPResponse = false;
+ }
+
+ if (returnSOAPResponse)
+ {
+ fault.setFaultCode (faultCode);
+ fault.setFaultString (faultString);
+ fault.setFaultActorURI (request.getRequestURI ());
+
+ resp = new Response (null,
+ null,
+ fault,
+ null,
+ null,
+ null);
+ }
+ else
+ {
+ out.println (faultString);
+ }
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace ();
+ t.printStackTrace (new PrintWriter (out));
+ }
+
+ // Send it out.
+ if (resp != null)
+ {
+ try
+ {
+ try
+ {
+ // Build an envelope containing the response.
+ Envelope respEnvelope = resp.buildEnvelope ();
+ SOAPMappingRegistry smr = (call != null
+ ? call.getSOAPMappingRegistry ()
+ : new SOAPMappingRegistry());
+
+ StringWriter sw = new StringWriter ();
+ respEnvelope.marshall (sw, smr);
+ if (ctx.getCount() == 0)
+ {
+ response.setContentType (Constants.HEADERVAL_CONTENT_TYPE);
+ out.print (sw.toString ());
+ }
+ else
+ {
+ // Add the SOAP response part.
+ ByteArrayDataSource ds = new ByteArrayDataSource (sw.toString (),
+ Constants.HEADERVAL_CONTENT_TYPE);
+ DataHandler dh = new DataHandler(ds);
+ MimeBodyPart bp = new MimeBodyPart();
+ bp.setDataHandler (dh);
+ bp.setHeader ("Content-Length", String.valueOf(ds.getSize()));
+ bp.setHeader("Content-ID", MimeUtils.getUniqueValue());
+ ctx.addBodyPart (bp, 0);
+
+ // Print the whole response to a byte array.
+ ByteArrayOutputStream multipartPayload = new ByteArrayOutputStream();
+ ctx.writeTo (multipartPayload);
+ byte[] content = multipartPayload.toByteArray();
+
+ // Now strip off the headers. (Grmbl).
+ int i;
+ StringBuffer namebuf = new StringBuffer();
+ StringBuffer valuebuf = new StringBuffer();
+ boolean parsingName = true;
+ for (i = 0; i < content.length; i++)
+ {
+ if (content[i] == '\n')
+ {
+ if (namebuf.length() == 0)
+ break;
+ String name = namebuf.toString();
+ if (name.equals("Content-Type"))
+ response.setContentType(valuebuf.toString());
+ else
+ response.setHeader(name, valuebuf.toString());
+ namebuf = new StringBuffer();
+ valuebuf = new StringBuffer();
+ parsingName = true;
+ }
+ else if (content[i] != '\r')
+ {
+ if (parsingName)
+ {
+ if (content[i] == ':')
+ {
+ parsingName = false;
+ i++;
+ }
+ else
+ namebuf.append((char)content[i]);
+ }
+ else
+ valuebuf.append((char)content[i]);
+ }
+ }
+ outStream.write(content, i, content.length - i);
+ outStream.flush();
+ }
+
+ out.println (StringUtils.lineSeparator);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ throw new SOAPException (Constants.FAULT_CODE_SERVER, iae.getMessage(), iae);
+ }
+ catch (IOException ioe)
+ {
+ throw new SOAPException (Constants.FAULT_CODE_SERVER, ioe.getMessage(), ioe);
+ }
+ catch (MessagingException me)
+ {
+ throw new SOAPException (Constants.FAULT_CODE_SERVER, me.getMessage(), me);
+ }
+ }
+ catch (SOAPException se)
+ {
+ // Wipe context for fault response, so it's not wrapped as a multipart
+ // containing the source's parts in the response.
+ ctx = new RPCContext();
+ ctx.setRPCContext();
+
+ Fault fault = new Fault ();
+ String faultCode = se.getFaultCode ();
+ String faultString = se.getMessage ();
+
+ if (faultCode == null || faultCode.startsWith (Constants.FAULT_CODE_SERVER))
+ {
+ response.setStatus (ServerConstants.SC_INTERNAL_SERVER_ERROR);
+ }
+ else if (faultCode.startsWith (Constants.FAULT_CODE_CLIENT))
+ {
+ response.setStatus (ServerConstants.SC_BAD_REQUEST);
+ }
+ else if (faultCode.startsWith (Constants.FAULT_CODE_PROTOCOL))
+ {
+ response.setStatus (ServerConstants.SC_BAD_REQUEST);
+ }
+
+ out.println (faultString);
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace ();
+ t.printStackTrace (new PrintWriter (out));
+ }
+ }
+ out.flush ();
+ }
+ catch(Throwable t)
+ {
+ if (t.getMessage() == null)
+ throw new ServletException("Unhandled exception caught in service method.");
+ else
+ throw new ServletException("Unhandled exception caught in service method: " + t.getMessage());
+ }
+ }
+}
diff -u -P -r xml-soap/java/src/org/apache/soap/transport/http/SOAPHTTPConnection.java xml-soap-mime/java/src/org/apache/soap/transport/http/SOAPHTTPConnection.java
--- xml-soap/java/src/org/apache/soap/transport/http/SOAPHTTPConnection.java Tue May 30 05:24:14 2000
+++ xml-soap-mime/java/src/org/apache/soap/transport/http/SOAPHTTPConnection.java Sun Jul 30 11:56:36 2000
@@ -63,9 +63,14 @@
import org.w3c.dom.*;
import org.apache.soap.util.net.*;
import org.apache.soap.util.xml.*;
+import org.apache.soap.util.mime.*;
import org.apache.soap.*;
import org.apache.soap.encoding.*;
import org.apache.soap.transport.*;
+import org.apache.soap.rpc.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.activation.*;
/**
* <code>SOAPHTTPConnection</code> is an implementation of the
@@ -105,9 +110,42 @@
headers.put (Constants.HEADER_SOAP_ACTION,
(action != null) ? ('\"' + action + '\"') : "");
- HTTPUtils.Response response = HTTPUtils.post (sendTo, headers,
- Constants.HEADERVAL_CONTENT_TYPE,
- payloadSW.toString ());
+ HTTPUtils.Response response;
+ try
+ {
+ RPCContext ctx = RPCContext.getRPCContext();
+ if (ctx.getCount() == 0)
+ {
+ response = HTTPUtils.post (sendTo, headers,
+ Constants.HEADERVAL_CONTENT_TYPE,
+ payloadSW.toString ());
+ }
+ else
+ {
+ // StringWriter multipartPayloadSW = new StringWriter();
+ ByteArrayOutputStream multipartPayloadSW = new ByteArrayOutputStream();
+ ByteArrayDataSource ds = new ByteArrayDataSource (payloadSW.toString(),
+ Constants.HEADERVAL_CONTENT_TYPE);
+ DataHandler dh = new DataHandler(ds);
+ MimeBodyPart bp = new MimeBodyPart();
+ bp.setDataHandler (dh);
+ bp.setHeader ("Content-Length", String.valueOf(ds.getSize()));
+ bp.setHeader("Content-ID", MimeUtils.getUniqueValue());
+ ctx.addBodyPart (bp, 0);
+ ctx.writeTo (multipartPayloadSW);
+ response = HTTPUtils.post (sendTo, headers,
+ null,
+ multipartPayloadSW.toByteArray());
+ }
+ }
+ catch (MessagingException me)
+ {
+ throw new IOException ("Failed to encode mime multipart: " + me);
+ }
+ catch (UnsupportedEncodingException uee)
+ {
+ throw new IOException ("Failed to encode mime multipart: " + uee);
+ }
responseReader = response.content;
responseHeaders = response.headers;
diff -u -P -r xml-soap/java/src/org/apache/soap/util/mime/ByteArrayDataSource.java xml-soap-mime/java/src/org/apache/soap/util/mime/ByteArrayDataSource.java
--- xml-soap/java/src/org/apache/soap/util/mime/ByteArrayDataSource.java Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/src/org/apache/soap/util/mime/ByteArrayDataSource.java Sun Jul 30 11:43:20 2000
@@ -0,0 +1,212 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "SOAP" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2000, International
+ * Business Machines, Inc., http://www.apache.org. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.soap.util.mime;
+
+import java.io.*;
+import javax.activation.*;
+
+/**
+ * This class implements a typed DataSource from
+ * an InputStream,
+ * a byte array,
+ * a String,
+ * a File.
+ *
+ * @author Wouter Cloetens (wcloeten@raleigh.ibm.com)
+ */
+
+public class ByteArrayDataSource implements DataSource
+{
+ private byte[] data; // data
+ private String type; // content-type
+
+ /**
+ * Create a datasource from a File.
+ */
+ public ByteArrayDataSource(File f, String type) throws IOException
+ {
+ this(new FileInputStream(f), type);
+ if(this.type == null)
+ this.type = FileTypeMap.getDefaultFileTypeMap().getContentType(f);
+ }
+
+ /**
+ * Create a datasource from an input stream.
+ */
+ public ByteArrayDataSource(InputStream is, String type) throws IOException
+ {
+ this.type = type;
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ byte buf[] = new byte[4096];
+ int len;
+ while (true)
+ {
+ len = is.read(buf);
+ if (len < 0)
+ break;
+ os.write(buf, 0, len);
+ }
+ /*
+ int ch;
+ while ((ch = is.read()) != -1)
+ // XXX : must be made more efficient by
+ // doing buffered reads, rather than one byte reads
+ os.write(ch);
+ */
+ data = os.toByteArray();
+ }
+
+ /**
+ * Create a datasource from a byte array.
+ */
+ public ByteArrayDataSource(byte[] data, String type)
+ {
+ this.type = type;
+ this.data = data;
+ }
+
+ /**
+ * Create a datasource from a String. This method assumes that the
+ * String only contains ASCII characters. For a different encoding,
+ * encode the String into a byte array and call the byte array
+ * constructor instead.
+ */
+ public ByteArrayDataSource(String data, String type)
+ {
+ this.type = type;
+
+ try
+ {
+ this.data = data.getBytes("iso-8859-1");
+ }
+ catch (UnsupportedEncodingException uex)
+ {
+ }
+ }
+
+ /**
+ * Return an InputStream to read the content.
+ */
+ public InputStream getInputStream() throws IOException
+ {
+ if (data == null)
+ throw new IOException("No data.");
+ return new ByteArrayInputStream(data);
+ }
+
+ /**
+ * This DataSource cannot return an OutputStream.
+ */
+ public OutputStream getOutputStream() throws IOException
+ {
+ throw new IOException("getOutputStream() not supported.");
+ }
+
+ /**
+ * Get the content type.
+ */
+ public String getContentType()
+ {
+ return type;
+ }
+
+ /**
+ * Set the content type.
+ */
+ public void setContentType(String type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * getName() is not supported.
+ */
+ public String getName()
+ {
+ return "";
+ }
+
+ /**
+ * Write the content to an OutputStream.
+ */
+ public void writeTo(OutputStream os) throws IOException
+ {
+ os.write(data);
+ }
+
+ /**
+ * Return the content as a byte array.
+ */
+ public byte[] toByteArray()
+ {
+ return data;
+ }
+
+ /**
+ * Return the size of the byte array.
+ */
+ public int getSize()
+ {
+ if (data == null)
+ return -1;
+ else
+ return data.length;
+ }
+}
diff -u -P -r xml-soap/java/src/org/apache/soap/util/mime/MimeUtils.java xml-soap-mime/java/src/org/apache/soap/util/mime/MimeUtils.java
--- xml-soap/java/src/org/apache/soap/util/mime/MimeUtils.java Sun Feb 7 00:28:16 2106
+++ xml-soap-mime/java/src/org/apache/soap/util/mime/MimeUtils.java Sun Jul 30 11:55:30 2000
@@ -0,0 +1,97 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "SOAP" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2000, International
+ * Business Machines, Inc., http://www.apache.org. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.soap.util.mime;
+
+import javax.mail.internet.InternetAddress;
+
+/**
+ * Mime-related utility functions.
+ *
+ * @author Wouter Cloetens (wcloeten@raleigh.ibm.com)
+ */
+
+public class MimeUtils
+{
+ /**
+ * Get a unique value.
+ *
+ * Similar to javax.mail.internet.UniqueValue, this implementation
+ * generates a unique value by concatenating a newly
+ * created object's <code>hashCode()</code>, the current
+ * time (in milliseconds), and this system's hostname generated by
+ * <code>InternetAddress.getLocalAddress()</code>.
+ */
+ public static String getUniqueValue()
+ {
+ String suffix = null;
+
+ InternetAddress addr = InternetAddress.getLocalAddress(null);
+ if (addr != null)
+ suffix = addr.getAddress();
+ else {
+ suffix = "user@localhost";
+ }
+
+ StringBuffer s = new StringBuffer();
+
+ // Unique string is <hashcode>.<currentTime>.apache-soap.<suffix>
+ s.append(s.hashCode()).append('.').append(System.currentTimeMillis()).
+ append(".apache-soap.").append(suffix);
+ return s.toString();
+ }
+}
diff -u -P -r xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java xml-soap-mime/java/src/org/apache/soap/util/net/HTTPUtils.java
--- xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java Sat Jul 29 14:14:06 2000
+++ xml-soap-mime/java/src/org/apache/soap/util/net/HTTPUtils.java Sun Jul 30 11:20:34 2000
@@ -61,11 +61,20 @@
import java.io.*;
import java.util.*;
+import org.apache.soap.rpc.*;
+import org.apache.soap.util.mime.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.activation.*;
+
/**
* A bunch of utility stuff for doing HTTP things.
+ * <p>
+ * 2000/07/30 W. Cloetens added Multipart Mime support
*
* @author Sanjiva Weerawarana (sanjiva@watson.ibm.com)
* @author Matthew J. Duftler (duftler@us.ibm.com)
+ * @author Wouter Cloetens (wcloeten@raleigh.ibm.com)
*/
public class HTTPUtils {
private static final String HTTP_VERSION = "1.0";
@@ -109,90 +118,234 @@
*/
public static Response post (URL url, Hashtable headers,
String contentType, String content)
- throws IllegalArgumentException {
- PrintWriter out = null;
- BufferedReader in = null;
- try {
- int port = url.getPort ();
-
- if (port < 0) // No port given..use HTTP default which is pry 80 :-)
- port = HTTP_DEFAULT_PORT;
-
- Socket s = new Socket (url.getHost (), port);
-
- out = new PrintWriter (s.getOutputStream ());
- in = new BufferedReader (new InputStreamReader (s.getInputStream ()));
- } catch (Exception e) {
- throw new IllegalArgumentException ("error opening socket: " +
- e.getMessage ());
- }
+ throws IllegalArgumentException, IOException
+ {
+ return post (url, headers, contentType, content.getBytes(), false);
+ }
- /* send it out */
- out.print (HTTP_POST + " " + url.getFile() + " HTTP/" + HTTP_VERSION +
- "\r\n");
- out.print (HEADER_HOST + ": " + url.getHost () + ':' + url.getPort () +
- "\r\n");
- out.print (HEADER_CONTENT_TYPE + ": " + contentType + "\r\n");
- out.print (HEADER_CONTENT_LENGTH + ": " + content.length () + "\r\n");
- for (Enumeration e = headers.keys (); e.hasMoreElements (); ) {
- Object key = e.nextElement ();
- out.print (key + ": " + headers.get (key) + "\r\n");
- }
- out.print ("\r\n");
- out.print (content);
- out.print ("\r\n\r\n");
- out.flush ();
- // out.close ();
-
- /* read the status line */
- int statusCode = 0;
- String statusString = null;
- try {
- StringTokenizer st = new StringTokenizer (in.readLine ());
- st.nextToken (); // ignore version part
- statusCode = Integer.parseInt (st.nextToken ());
- StringBuffer sb = new StringBuffer ();
- while (st.hasMoreTokens ()) {
- sb.append (st.nextToken ());
- if (st.hasMoreTokens ()) {
- sb.append (" ");
- }
- }
- statusString = sb.toString ();
- } catch (Exception e) {
- throw new IllegalArgumentException ("error parsing HTTP status line: " +
- e.getMessage ());
- }
+ public static Response post (URL url, Hashtable headers,
+ String contentType, byte[] content)
+ throws IllegalArgumentException, IOException
+ {
+ return post (url, headers, contentType, content, true);
+ }
- /* get the headers */
- Hashtable respHeaders = new Hashtable ();
- int respContentLength = -1;
- String respContentType = null;
- try {
- String line = null;
- while ((line = in.readLine ()) != null) {
- if (line.length () == 0) {
- break;
- }
- int colonIndex = line.indexOf (':');
- String fieldName = line.substring (0, colonIndex);
- String fieldValue = line.substring (colonIndex + 1).trim ();
- if (fieldName.equals (HEADER_CONTENT_LENGTH)) {
- respContentLength = Integer.parseInt (fieldValue);
- } else if (fieldName.equals (HEADER_CONTENT_TYPE)) {
- respContentType = fieldValue;
- } else {
- respHeaders.put (fieldName, fieldValue);
- }
- }
- } catch (Exception e) {
- throw new IllegalArgumentException ("error reading HTTP headers: " +
- e.getMessage ());
- }
+ /**
+ * POST something to the given URL. The headers are put in as
+ * HTTP headers, the content length is calculated and the content
+ * is sent as content. The content is a byte array to avoid
+ * codepage conversion. The content may include extra headers
+ * and must include an empty line between header and body section
+ * if the hasHeaders argument is true.
+ * The content type must be provided in the header hashtable or
+ * header part of the content if the contentType parameter is
+ * null.
+ *
+ * @param url the url to post to
+ * @param headers additional headers to send as HTTP headers
+ * @param contentType type of the content
+ * @param content the body of the post
+ * @param hasHeaders indicates content contains headers
+ */
+ public static Response post (URL url, Hashtable headers,
+ String contentType, byte[] content,
+ boolean hasHeaders)
+ throws IllegalArgumentException, IOException
+ {
+ PrintWriter out = null;
+ OutputStream outStream = null;
+ InputStream inStream = null;
+ BufferedReader in = null;
+ try
+ {
+ int port = url.getPort ();
+
+ if (port < 0) // No port given..use HTTP default which is pry 80 :-)
+ port = HTTP_DEFAULT_PORT;
+
+ Socket s = new Socket (url.getHost (), port);
+
+ outStream = s.getOutputStream ();
+ out = new PrintWriter (outStream);
+ inStream = s.getInputStream ();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException ("error opening socket: " +
+ e.getMessage ());
+ }
+
+ /* send it */
+ out.print (HTTP_POST + " " + url.getFile() + " HTTP/" + HTTP_VERSION +
+ "\r\n");
+ out.print (HEADER_HOST + ": " + url.getHost () + ':' + url.getPort () +
+ "\r\n");
+ if (contentType != null)
+ out.print (HEADER_CONTENT_TYPE + ": " + contentType + "\r\n");
+
+ /* If the content contains headers, we need to know the content length
+ * without them. Read until the end of the content's header block. */
+ int contentLength;
+ if (!hasHeaders)
+ {
+ contentLength = content.length;
+ }
+ else
+ {
+ if (content.length >= 2
+ && content[0] == '\r'
+ && content[1] == '\n')
+ contentLength = content.length - 2;
+ else
+ {
+ int i;
+ for (i = 3; i < content.length; i++)
+ if (content[i] == '\n'
+ && content[i - 1] == '\r'
+ && content[i - 2] == '\n'
+ && content[i - 3] == '\r')
+ break;
+ contentLength = content.length - i;
+ }
+ }
+
+ out.print (HEADER_CONTENT_LENGTH + ": " + contentLength + "\r\n");
+ for (Enumeration e = headers.keys (); e.hasMoreElements (); )
+ {
+ Object key = e.nextElement ();
+ out.print (key + ": " + headers.get (key) + "\r\n");
+ }
+ if (!hasHeaders)
+ {
+ out.print("\r\n");
+ }
+ out.flush();
+ outStream.write (content);
+ outStream.flush();
+ out.print("\r\n\r\n");
+ out.flush ();
+
+ /* read the status line */
+ int statusCode = 0;
+ String statusString = null;
+ StringBuffer linebuf = new StringBuffer ();
+ int b = 0;
+ while (b != '\n' && b != -1)
+ {
+ b = inStream.read ();
+ if (b != '\n' && b != '\r' && b != -1)
+ linebuf.append ((char)b);
+ }
+ String line = linebuf.toString ();
+ try
+ {
+ StringTokenizer st = new StringTokenizer (line);
+ st.nextToken (); // ignore version part
+ statusCode = Integer.parseInt (st.nextToken ());
+ StringBuffer sb = new StringBuffer ();
+ while (st.hasMoreTokens ())
+ {
+ sb.append (st.nextToken ());
+ if (st.hasMoreTokens ())
+ {
+ sb.append (" ");
+ }
+ }
+ statusString = sb.toString ();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException ("error parsing HTTP status line: " +
+ e.getMessage ());
+ }
+
+ /* read the entire response (following the status line) into a byte array */
+ ByteArrayDataSource ds = new ByteArrayDataSource(inStream, null);
+
+ /* get the headers */
+ in = new BufferedReader (new InputStreamReader (ds.getInputStream()));
+ Hashtable respHeaders = readHeaderBlock(in);
+ int respContentLength = getContentLength(respHeaders);
+ String respContentType = getContentType(respHeaders);
+
+ /* set the DataSource's Content-Type now we have it. */
+ ds.setContentType(respContentType);
+
+ /* if it's multipart, extract context */
+ try
+ {
+ if((new ContentType(respContentType)).getPrimaryType().equals("multipart"))
+ {
+ RPCContext ctx = new RPCContext();
+ ctx.setRPCContext();
+ ctx.readMultipart(ds);
+
+ MimeBodyPart soapPart = (MimeBodyPart)ctx.getBodyPart(0);
+ in = new BufferedReader (new InputStreamReader (soapPart.getDataHandler().getInputStream()));
+
+ /* The SOAP headers are in the HTTP header, not in the SOAP mime part.
+ * We only want the Content-Type and Content-Length. */
+ respContentLength = -1;
+ String len = soapPart.getHeader (HEADER_CONTENT_LENGTH, null);
+ if (len != null)
+ {
+ try
+ {
+ respContentLength = Integer.parseInt (len);
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw new IllegalArgumentException("Non-numeric content length \"" + len + "\" in SOAP response: " + nfe);
+ }
+ }
+ respContentType = soapPart.getContentType();
+ }
+ }
+ catch (MessagingException me)
+ {
+ throw new IllegalArgumentException("Error parsing response: " + me);
+ }
+
+ /* all done here! */
+ return new Response (statusCode, statusString, respHeaders,
+ respContentLength, respContentType, in);
+ }
+
+ private static Hashtable readHeaderBlock(BufferedReader in) throws IllegalArgumentException
+ {
+ Hashtable respHeaders = new Hashtable ();
+ String respContentType = null;
+ try {
+ String line = null;
+ while ((line = in.readLine ()) != null) {
+ if (line.length () == 0) {
+ break;
+ }
+ int colonIndex = line.indexOf (':');
+ String fieldName = line.substring (0, colonIndex);
+ String fieldValue = line.substring (colonIndex + 1).trim ();
+ respHeaders.put (fieldName, fieldValue);
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException ("error reading HTTP headers: " +
+ e.getMessage ());
+ }
+ return respHeaders;
+ }
+
+ private static int getContentLength(Hashtable respHeaders)
+ {
+ String len = (String)respHeaders.get (HEADER_CONTENT_LENGTH);
+ if (len == null)
+ return -1;
+ respHeaders.remove(HEADER_CONTENT_LENGTH);
+ return Integer.parseInt (len);
+ }
-
- /* all done */
- return new Response (statusCode, statusString, respHeaders,
- respContentLength, respContentType, in);
+ private static String getContentType(Hashtable respHeaders)
+ {
+ String type = (String)respHeaders.get (HEADER_CONTENT_TYPE);
+ respHeaders.remove(HEADER_CONTENT_LENGTH);
+ return type;
}
}