ohair@286: /* alanb@368: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.xml.internal.messaging.saaj.soap; ohair@286: ohair@286: import java.io.*; ohair@286: import java.util.*; ohair@286: import java.util.logging.Level; ohair@286: import java.util.logging.Logger; ohair@286: ohair@286: import javax.activation.DataHandler; ohair@286: import javax.activation.DataSource; ohair@286: import javax.xml.soap.*; ohair@286: import javax.xml.transform.Source; ohair@286: import javax.xml.transform.stream.StreamSource; ohair@286: ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.Header; ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.*; ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*; ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.MessagingException; ohair@286: ohair@286: import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; ohair@286: import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl; ohair@286: import com.sun.xml.internal.messaging.saaj.util.*; ohair@286: import com.sun.xml.internal.org.jvnet.mimepull.MIMEPart; ohair@286: ohair@286: /** ohair@286: * The message implementation for SOAP messages with ohair@286: * attachments. Messages for specific profiles will likely extend this ohair@286: * MessageImpl class and add more value for that particular profile. ohair@286: * ohair@286: * @author Anil Vijendran (akv@eng.sun.com) ohair@286: * @author Rajiv Mordani (rajiv.mordani@sun.com) ohair@286: * @author Manveen Kaur (manveen.kaur@sun.com) ohair@286: */ ohair@286: ohair@286: public abstract class MessageImpl ohair@286: extends SOAPMessage ohair@286: implements SOAPConstants { ohair@286: ohair@286: ohair@286: public static final String CONTENT_ID = "Content-ID"; ohair@286: public static final String CONTENT_LOCATION = "Content-Location"; ohair@286: ohair@286: protected static final Logger log = ohair@286: Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, ohair@286: "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); ohair@286: ohair@286: protected static final int PLAIN_XML_FLAG = 1; // 00001 ohair@286: protected static final int MIME_MULTIPART_FLAG = 2; // 00010 ohair@286: protected static final int SOAP1_1_FLAG = 4; // 00100 ohair@286: protected static final int SOAP1_2_FLAG = 8; // 01000 ohair@286: //protected static final int MIME_MULTIPART_XOP_FLAG = 14; // 01110 ohair@286: protected static final int MIME_MULTIPART_XOP_SOAP1_1_FLAG = 6; // 00110 ohair@286: protected static final int MIME_MULTIPART_XOP_SOAP1_2_FLAG = 10; // 01010 ohair@286: protected static final int XOP_FLAG = 13; // 01101 ohair@286: protected static final int FI_ENCODED_FLAG = 16; // 10000 ohair@286: ohair@286: protected MimeHeaders headers; ohair@286: protected ContentType contentType; ohair@286: protected SOAPPartImpl soapPartImpl; ohair@286: protected FinalArrayList attachments; ohair@286: protected boolean saved = false; ohair@286: protected byte[] messageBytes; ohair@286: protected int messageByteCount; ohair@286: protected HashMap properties = new HashMap(); ohair@286: ohair@286: // used for lazy attachment initialization ohair@286: protected MimeMultipart multiPart = null; ohair@286: protected boolean attachmentsInitialized = false; ohair@286: ohair@286: /** ohair@286: * True if this part is encoded using Fast Infoset. ohair@286: * MIME -> application/fastinfoset ohair@286: */ ohair@286: protected boolean isFastInfoset = false; ohair@286: ohair@286: /** ohair@286: * True if the Accept header of this message includes ohair@286: * application/fastinfoset ohair@286: */ ohair@286: protected boolean acceptFastInfoset = false; ohair@286: ohair@286: protected MimeMultipart mmp = null; ohair@286: ohair@286: // if attachments are present, don't read the entire message in byte stream in saveTo() ohair@286: private boolean optimizeAttachmentProcessing = true; ohair@286: ohair@286: private InputStream inputStreamAfterSaveChanges = null; ohair@286: ohair@286: // switch back to old MimeMultipart incase of problem ohair@286: private static boolean switchOffBM = false; ohair@286: private static boolean switchOffLazyAttachment = false; ohair@286: private static boolean useMimePull = false; ohair@286: ohair@286: static { ohair@286: String s = SAAJUtil.getSystemProperty("saaj.mime.optimization"); ohair@286: if ((s != null) && s.equals("false")) { ohair@286: switchOffBM = true; ohair@286: } ohair@286: s = SAAJUtil.getSystemProperty("saaj.lazy.mime.optimization"); ohair@286: if ((s != null) && s.equals("false")) { ohair@286: switchOffLazyAttachment = true; ohair@286: } ohair@286: useMimePull = SAAJUtil.getSystemBoolean("saaj.use.mimepull"); ohair@286: ohair@286: } ohair@286: ohair@286: //property to indicate optimized serialization for lazy attachments ohair@286: private boolean lazyAttachments = false; ohair@286: ohair@286: // most of the times, Content-Types are already all lower cased. ohair@286: // String.toLowerCase() works faster in this case, so even if you ohair@286: // are only doing one comparison, it pays off to use String.toLowerCase() ohair@286: // than String.equalsIgnoreCase(). When you do more than one comparison, ohair@286: // the benefits of String.toLowerCase() dominates. ohair@286: // ohair@286: // ohair@286: // for FI, ohair@286: // use application/fastinfoset for SOAP 1.1 ohair@286: // use application/soap+fastinfoset for SOAP 1.2 ohair@286: // to speed up comparisons, test methods always use lower cases. ohair@286: ohair@286: /** ohair@286: * @param primary ohair@286: * must be all lower case ohair@286: * @param sub ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isSoap1_1Type(String primary, String sub) { ohair@286: return primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml") ohair@286: || primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml-soap") ohair@286: || primary.equals("application") ohair@286: && sub.equals("fastinfoset"); ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param type ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isEqualToSoap1_1Type(String type) { ohair@286: return type.startsWith("text/xml") || ohair@286: type.startsWith("application/fastinfoset"); ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param primary ohair@286: * must be all lower case ohair@286: * @param sub ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isSoap1_2Type(String primary, String sub) { ohair@286: return primary.equals("application") ohair@286: && (sub.equals("soap+xml") ohair@286: || sub.equals("soap+fastinfoset")); ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param type ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isEqualToSoap1_2Type(String type) { ohair@286: return type.startsWith("application/soap+xml") || ohair@286: type.startsWith("application/soap+fastinfoset"); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a new message. This will be invoked before message ohair@286: * sends. ohair@286: */ ohair@286: protected MessageImpl() { ohair@286: this(false, false); ohair@286: attachmentsInitialized = true; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a new message. This will be invoked before message ohair@286: * sends. ohair@286: */ ohair@286: protected MessageImpl(boolean isFastInfoset, boolean acceptFastInfoset) { ohair@286: this.isFastInfoset = isFastInfoset; ohair@286: this.acceptFastInfoset = acceptFastInfoset; ohair@286: ohair@286: headers = new MimeHeaders(); ohair@286: headers.setHeader("Accept", getExpectedAcceptHeader()); ohair@286: contentType = new ContentType(); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Shallow copy. ohair@286: */ ohair@286: protected MessageImpl(SOAPMessage msg) { ohair@286: if (!(msg instanceof MessageImpl)) { ohair@286: // don't know how to handle this. ohair@286: } ohair@286: MessageImpl src = (MessageImpl) msg; ohair@286: this.headers = src.headers; ohair@286: this.soapPartImpl = src.soapPartImpl; ohair@286: this.attachments = src.attachments; ohair@286: this.saved = src.saved; ohair@286: this.messageBytes = src.messageBytes; ohair@286: this.messageByteCount = src.messageByteCount; ohair@286: this.properties = src.properties; ohair@286: this.contentType = src.contentType; ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param stat ohair@286: * the mask value obtained from {@link #identifyContentType(ContentType)} ohair@286: */ ohair@286: protected static boolean isSoap1_1Content(int stat) { ohair@286: return (stat & SOAP1_1_FLAG) != 0; ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param stat ohair@286: * the mask value obtained from {@link #identifyContentType(ContentType)} ohair@286: */ ohair@286: protected static boolean isSoap1_2Content(int stat) { ohair@286: return (stat & SOAP1_2_FLAG) != 0; ohair@286: } ohair@286: ohair@286: private static boolean isMimeMultipartXOPSoap1_2Package(ContentType contentType) { ohair@286: String type = contentType.getParameter("type"); ohair@286: if (type == null) { ohair@286: return false; ohair@286: } ohair@286: type = type.toLowerCase(); ohair@286: if (!type.startsWith("application/xop+xml")) { ohair@286: return false; ohair@286: } ohair@286: String startinfo = contentType.getParameter("start-info"); ohair@286: if (startinfo == null) { ohair@286: return false; ohair@286: } ohair@286: startinfo = startinfo.toLowerCase(); ohair@286: return isEqualToSoap1_2Type(startinfo); ohair@286: } ohair@286: ohair@286: ohair@286: //private static boolean isMimeMultipartXOPPackage(ContentType contentType) { ohair@286: private static boolean isMimeMultipartXOPSoap1_1Package(ContentType contentType) { ohair@286: String type = contentType.getParameter("type"); ohair@286: if(type==null) ohair@286: return false; ohair@286: ohair@286: type = type.toLowerCase(); ohair@286: if(!type.startsWith("application/xop+xml")) ohair@286: return false; ohair@286: ohair@286: String startinfo = contentType.getParameter("start-info"); ohair@286: if(startinfo == null) ohair@286: return false; ohair@286: startinfo = startinfo.toLowerCase(); ohair@286: return isEqualToSoap1_1Type(startinfo); ohair@286: } ohair@286: ohair@286: private static boolean isSOAPBodyXOPPackage(ContentType contentType){ ohair@286: String primary = contentType.getPrimaryType(); ohair@286: String sub = contentType.getSubType(); ohair@286: ohair@286: if (primary.equalsIgnoreCase("application")) { ohair@286: if (sub.equalsIgnoreCase("xop+xml")) { ohair@286: String type = getTypeParameter(contentType); ohair@286: return isEqualToSoap1_2Type(type) || isEqualToSoap1_1Type(type); ohair@286: } ohair@286: } ohair@286: return false; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a message from an input stream. When messages are ohair@286: * received, there's two parts -- the transport headers and the ohair@286: * message content in a transport specific stream. ohair@286: */ ohair@286: protected MessageImpl(MimeHeaders headers, final InputStream in) ohair@286: throws SOAPExceptionImpl { ohair@286: contentType = parseContentType(headers); ohair@286: init(headers,identifyContentType(contentType),contentType,in); ohair@286: } ohair@286: ohair@286: private static ContentType parseContentType(MimeHeaders headers) throws SOAPExceptionImpl { ohair@286: final String ct; ohair@286: if (headers != null) ohair@286: ct = getContentType(headers); ohair@286: else { ohair@286: log.severe("SAAJ0550.soap.null.headers"); ohair@286: throw new SOAPExceptionImpl("Cannot create message: " + ohair@286: "Headers can't be null"); ohair@286: } ohair@286: ohair@286: if (ct == null) { ohair@286: log.severe("SAAJ0532.soap.no.Content-Type"); ohair@286: throw new SOAPExceptionImpl("Absent Content-Type"); ohair@286: } ohair@286: try { ohair@286: return new ContentType(ct); ohair@286: } catch (Throwable ex) { ohair@286: log.severe("SAAJ0535.soap.cannot.internalize.message"); ohair@286: throw new SOAPExceptionImpl("Unable to internalize message", ex); ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a message from an input stream. When messages are ohair@286: * received, there's two parts -- the transport headers and the ohair@286: * message content in a transport specific stream. ohair@286: * ohair@286: * @param contentType ohair@286: * The parsed content type header from the headers variable. ohair@286: * This is redundant parameter, but it avoids reparsing this header again. ohair@286: * @param stat ohair@286: * The result of {@link #identifyContentType(ContentType)} over ohair@286: * the contentType parameter. This redundant parameter, but it avoids ohair@286: * recomputing this information again. ohair@286: */ ohair@286: protected MessageImpl(MimeHeaders headers, final ContentType contentType, int stat, final InputStream in) throws SOAPExceptionImpl { ohair@286: init(headers, stat, contentType, in); ohair@286: ohair@286: } ohair@286: ohair@286: private void init(MimeHeaders headers, int stat, final ContentType contentType, final InputStream in) throws SOAPExceptionImpl { ohair@286: this.headers = headers; ohair@286: ohair@286: try { ohair@286: ohair@286: // Set isFastInfoset/acceptFastInfoset flag based on MIME type ohair@286: if ((stat & FI_ENCODED_FLAG) > 0) { ohair@286: isFastInfoset = acceptFastInfoset = true; ohair@286: } ohair@286: ohair@286: // If necessary, inspect Accept header to set acceptFastInfoset ohair@286: if (!isFastInfoset) { ohair@286: String[] values = headers.getHeader("Accept"); ohair@286: if (values != null) { ohair@286: for (int i = 0; i < values.length; i++) { ohair@286: StringTokenizer st = new StringTokenizer(values[i], ","); ohair@286: while (st.hasMoreTokens()) { ohair@286: final String token = st.nextToken().trim(); ohair@286: if (token.equalsIgnoreCase("application/fastinfoset") || ohair@286: token.equalsIgnoreCase("application/soap+fastinfoset")) { ohair@286: acceptFastInfoset = true; ohair@286: break; ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: if (!isCorrectSoapVersion(stat)) { ohair@286: log.log( ohair@286: Level.SEVERE, ohair@286: "SAAJ0533.soap.incorrect.Content-Type", ohair@286: new String[] { ohair@286: contentType.toString(), ohair@286: getExpectedContentType()}); ohair@286: throw new SOAPVersionMismatchException( ohair@286: "Cannot create message: incorrect content-type for SOAP version. Got: " ohair@286: + contentType ohair@286: + " Expected: " ohair@286: + getExpectedContentType()); ohair@286: } ohair@286: ohair@286: if ((stat & PLAIN_XML_FLAG) != 0) { ohair@286: if (isFastInfoset) { ohair@286: getSOAPPart().setContent( ohair@286: FastInfosetReflection.FastInfosetSource_new(in)); ohair@286: } else { ohair@286: initCharsetProperty(contentType); ohair@286: getSOAPPart().setContent(new StreamSource(in)); ohair@286: } ohair@286: } ohair@286: else if ((stat & MIME_MULTIPART_FLAG) != 0) { ohair@286: DataSource ds = new DataSource() { ohair@286: public InputStream getInputStream() { ohair@286: return in; ohair@286: } ohair@286: ohair@286: public OutputStream getOutputStream() { ohair@286: return null; ohair@286: } ohair@286: ohair@286: public String getContentType() { ohair@286: return contentType.toString(); ohair@286: } ohair@286: ohair@286: public String getName() { ohair@286: return ""; ohair@286: } ohair@286: }; ohair@286: ohair@286: multiPart = null; ohair@286: if (useMimePull) { ohair@286: multiPart = new MimePullMultipart(ds,contentType); ohair@286: } else if (switchOffBM) { ohair@286: multiPart = new MimeMultipart(ds,contentType); ohair@286: } else { ohair@286: multiPart = new BMMimeMultipart(ds,contentType); ohair@286: } ohair@286: ohair@286: String startParam = contentType.getParameter("start"); ohair@286: MimeBodyPart soapMessagePart = null; ohair@286: InputStream soapPartInputStream = null; ohair@286: String contentID = null; ohair@286: String contentIDNoAngle = null; ohair@286: if (switchOffBM || switchOffLazyAttachment) { ohair@286: if(startParam == null) { ohair@286: soapMessagePart = multiPart.getBodyPart(0); ohair@286: for (int i = 1; i < multiPart.getCount(); i++) { ohair@286: initializeAttachment(multiPart, i); ohair@286: } ohair@286: } else { ohair@286: soapMessagePart = multiPart.getBodyPart(startParam); ohair@286: for (int i = 0; i < multiPart.getCount(); i++) { ohair@286: contentID = multiPart.getBodyPart(i).getContentID(); ohair@286: // Old versions of AXIS2 put angle brackets around the content ohair@286: // id but not the start param ohair@286: contentIDNoAngle = (contentID != null) ? ohair@286: contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null; ohair@286: if(!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle)) ohair@286: initializeAttachment(multiPart, i); ohair@286: } ohair@286: } ohair@286: } else { ohair@286: if (useMimePull) { ohair@286: MimePullMultipart mpMultipart = (MimePullMultipart)multiPart; ohair@286: MIMEPart sp = mpMultipart.readAndReturnSOAPPart(); ohair@286: soapMessagePart = new MimeBodyPart(sp); ohair@286: soapPartInputStream = sp.readOnce(); ohair@286: } else { ohair@286: BMMimeMultipart bmMultipart = ohair@286: (BMMimeMultipart) multiPart; ohair@286: InputStream stream = bmMultipart.initStream(); ohair@286: ohair@286: SharedInputStream sin = null; ohair@286: if (stream instanceof SharedInputStream) { ohair@286: sin = (SharedInputStream) stream; ohair@286: } ohair@286: ohair@286: String boundary = "--" + ohair@286: contentType.getParameter("boundary"); ohair@286: byte[] bndbytes = ASCIIUtility.getBytes(boundary); ohair@286: if (startParam == null) { ohair@286: soapMessagePart = ohair@286: bmMultipart.getNextPart(stream, bndbytes, sin); ohair@286: bmMultipart.removeBodyPart(soapMessagePart); ohair@286: } else { ohair@286: MimeBodyPart bp = null; ohair@286: try { ohair@286: while (!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle)) { ohair@286: bp = bmMultipart.getNextPart( ohair@286: stream, bndbytes, sin); ohair@286: contentID = bp.getContentID(); ohair@286: // Old versions of AXIS2 put angle brackets around the content ohair@286: // id but not the start param ohair@286: contentIDNoAngle = (contentID != null) ? ohair@286: contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null; ohair@286: } ohair@286: soapMessagePart = bp; ohair@286: bmMultipart.removeBodyPart(bp); ohair@286: } catch (Exception e) { ohair@286: throw new SOAPExceptionImpl(e); ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: if (soapPartInputStream == null && soapMessagePart != null) { ohair@286: soapPartInputStream = soapMessagePart.getInputStream(); ohair@286: } ohair@286: ohair@286: ContentType soapPartCType = new ContentType( ohair@286: soapMessagePart.getContentType()); ohair@286: initCharsetProperty(soapPartCType); ohair@286: String baseType = soapPartCType.getBaseType().toLowerCase(); ohair@286: if(!(isEqualToSoap1_1Type(baseType) ohair@286: || isEqualToSoap1_2Type(baseType) ohair@286: || isSOAPBodyXOPPackage(soapPartCType))) { ohair@286: log.log(Level.SEVERE, ohair@286: "SAAJ0549.soap.part.invalid.Content-Type", ohair@286: new Object[] {baseType}); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Bad Content-Type for SOAP Part : " + ohair@286: baseType); ohair@286: } ohair@286: ohair@286: SOAPPart soapPart = getSOAPPart(); ohair@286: setMimeHeaders(soapPart, soapMessagePart); ohair@286: soapPart.setContent(isFastInfoset ? ohair@286: (Source) FastInfosetReflection.FastInfosetSource_new( ohair@286: soapPartInputStream) : ohair@286: (Source) new StreamSource(soapPartInputStream)); ohair@286: } else { ohair@286: log.severe("SAAJ0534.soap.unknown.Content-Type"); ohair@286: throw new SOAPExceptionImpl("Unrecognized Content-Type"); ohair@286: } ohair@286: } catch (Throwable ex) { ohair@286: log.severe("SAAJ0535.soap.cannot.internalize.message"); ohair@286: throw new SOAPExceptionImpl("Unable to internalize message", ex); ohair@286: } ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: public boolean isFastInfoset() { ohair@286: return isFastInfoset; ohair@286: } ohair@286: ohair@286: public boolean acceptFastInfoset() { ohair@286: return acceptFastInfoset; ohair@286: } ohair@286: ohair@286: public void setIsFastInfoset(boolean value) { ohair@286: if (value != isFastInfoset) { ohair@286: isFastInfoset = value; ohair@286: if (isFastInfoset) { ohair@286: acceptFastInfoset = true; ohair@286: } ohair@286: saved = false; // ensure transcoding if necessary ohair@286: } ohair@286: } ohair@286: ohair@286: public Object getProperty(String property) { ohair@286: return (String) properties.get(property); ohair@286: } ohair@286: ohair@286: public void setProperty(String property, Object value) { ohair@286: verify(property, value); ohair@286: properties.put(property, value); ohair@286: } ohair@286: ohair@286: private void verify(String property, Object value) { ohair@286: if (property.equalsIgnoreCase(SOAPMessage.WRITE_XML_DECLARATION)) { ohair@286: if (!("true".equals(value) || "false".equals(value))) ohair@286: throw new RuntimeException( ohair@286: property + " must have value false or true"); ohair@286: ohair@286: try { ohair@286: EnvelopeImpl env = (EnvelopeImpl) getSOAPPart().getEnvelope(); ohair@286: if ("true".equalsIgnoreCase((String)value)) { ohair@286: env.setOmitXmlDecl("no"); ohair@286: } else if ("false".equalsIgnoreCase((String)value)) { ohair@286: env.setOmitXmlDecl("yes"); ohair@286: } ohair@286: } catch (Exception e) { ohair@286: log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property", ohair@286: new Object[] {e.getMessage(), "javax.xml.soap.write-xml-declaration"}); ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: return; ohair@286: } ohair@286: ohair@286: if (property.equalsIgnoreCase(SOAPMessage.CHARACTER_SET_ENCODING)) { ohair@286: try { ohair@286: ((EnvelopeImpl) getSOAPPart().getEnvelope()).setCharsetEncoding((String)value); ohair@286: } catch (Exception e) { ohair@286: log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property", ohair@286: new Object[] {e.getMessage(), "javax.xml.soap.character-set-encoding"}); ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: protected abstract boolean isCorrectSoapVersion(int contentTypeId); ohair@286: ohair@286: protected abstract String getExpectedContentType(); ohair@286: protected abstract String getExpectedAcceptHeader(); ohair@286: ohair@286: /** ohair@286: * Sniffs the Content-Type header so that we can determine how to process. ohair@286: * ohair@286: *
ohair@286: * In the absence of type attribute we assume it to be text/xml.
ohair@286: * That would mean we're easy on accepting the message and
ohair@286: * generate the correct thing (as the SWA spec also specifies
ohair@286: * that the type parameter should always be text/xml)
ohair@286: *
ohair@286: * @return
ohair@286: * combination of flags, such as PLAIN_XML_CODE and MIME_MULTIPART_CODE.
ohair@286: */
ohair@286: // SOAP1.2 allow SOAP1.2 content type
ohair@286: static int identifyContentType(ContentType ct)
ohair@286: throws SOAPExceptionImpl {
ohair@286: // TBD
ohair@286: // Is there anything else we need to verify here?
ohair@286:
ohair@286: String primary = ct.getPrimaryType().toLowerCase();
ohair@286: String sub = ct.getSubType().toLowerCase();
ohair@286:
ohair@286: if (primary.equals("multipart")) {
ohair@286: if (sub.equals("related")) {
ohair@286: String type = getTypeParameter(ct);
ohair@286: if (isEqualToSoap1_1Type(type)) {
ohair@286: return (type.equals("application/fastinfoset") ?
ohair@286: FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_1_FLAG;
ohair@286: }
ohair@286: else if (isEqualToSoap1_2Type(type)) {
ohair@286: return (type.equals("application/soap+fastinfoset") ?
ohair@286: FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_2_FLAG;
ohair@286: /*} else if (isMimeMultipartXOPPackage(ct)) {
ohair@286: return MIME_MULTIPART_XOP_FLAG;*/
ohair@286: } else if (isMimeMultipartXOPSoap1_1Package(ct)) {
ohair@286: return MIME_MULTIPART_XOP_SOAP1_1_FLAG;
ohair@286: } else if (isMimeMultipartXOPSoap1_2Package(ct)) {
ohair@286: return MIME_MULTIPART_XOP_SOAP1_2_FLAG;
ohair@286: } else {
ohair@286: log.severe("SAAJ0536.soap.content-type.mustbe.multipart");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Content-Type needs to be Multipart/Related "
ohair@286: + "and with \"type=text/xml\" "
ohair@286: + "or \"type=application/soap+xml\"");
ohair@286: }
ohair@286: } else {
ohair@286: log.severe("SAAJ0537.soap.invalid.content-type");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Invalid Content-Type: " + primary + '/' + sub);
ohair@286: }
ohair@286: }
ohair@286: else if (isSoap1_1Type(primary, sub)) {
ohair@286: return (primary.equalsIgnoreCase("application")
ohair@286: && sub.equalsIgnoreCase("fastinfoset") ?
ohair@286: FI_ENCODED_FLAG : 0)
ohair@286: | PLAIN_XML_FLAG | SOAP1_1_FLAG;
ohair@286: }
ohair@286: else if (isSoap1_2Type(primary, sub)) {
ohair@286: return (primary.equalsIgnoreCase("application")
ohair@286: && sub.equalsIgnoreCase("soap+fastinfoset") ?
ohair@286: FI_ENCODED_FLAG : 0)
ohair@286: | PLAIN_XML_FLAG | SOAP1_2_FLAG;
ohair@286: } else if(isSOAPBodyXOPPackage(ct)){
ohair@286: return XOP_FLAG;
ohair@286: } else {
ohair@286: log.severe("SAAJ0537.soap.invalid.content-type");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Invalid Content-Type:"
ohair@286: + primary
ohair@286: + '/'
ohair@286: + sub
ohair@286: + ". Is this an error message instead of a SOAP response?");
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: /**
ohair@286: * Obtains the type parameter of the Content-Type header. Defaults to "text/xml".
ohair@286: */
ohair@286: private static String getTypeParameter(ContentType contentType) {
ohair@286: String p = contentType.getParameter("type");
ohair@286: if(p!=null)
ohair@286: return p.toLowerCase();
ohair@286: else
ohair@286: return "text/xml";
ohair@286: }
ohair@286:
ohair@286: public MimeHeaders getMimeHeaders() {
ohair@286: return this.headers;
ohair@286: }
ohair@286:
ohair@286: final static String getContentType(MimeHeaders headers) {
ohair@286: String[] values = headers.getHeader("Content-Type");
ohair@286: if (values == null)
ohair@286: return null;
ohair@286: else
ohair@286: return values[0];
ohair@286: }
ohair@286:
ohair@286: /*
ohair@286: * Get the complete ContentType value along with optional parameters.
ohair@286: */
ohair@286: public String getContentType() {
ohair@286: return getContentType(this.headers);
ohair@286: }
ohair@286:
ohair@286: public void setContentType(String type) {
ohair@286: headers.setHeader("Content-Type", type);
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: private ContentType contentType() {
ohair@286: ContentType ct = null;
ohair@286: try {
ohair@286: String currentContent = getContentType();
ohair@286: if (currentContent == null) {
ohair@286: return this.contentType;
ohair@286: }
ohair@286: ct = new ContentType(currentContent);
ohair@286: } catch (Exception e) {
ohair@286: // what to do here?
ohair@286: }
ohair@286: return ct;
ohair@286: }
ohair@286:
ohair@286: /*
ohair@286: * Return the MIME type string, without the parameters.
ohair@286: */
ohair@286: public String getBaseType() {
ohair@286: return contentType().getBaseType();
ohair@286: }
ohair@286:
ohair@286: public void setBaseType(String type) {
ohair@286: ContentType ct = contentType();
ohair@286: ct.setParameter("type", type);
ohair@286: headers.setHeader("Content-Type", ct.toString());
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: public String getAction() {
ohair@286: return contentType().getParameter("action");
ohair@286: }
ohair@286:
ohair@286: public void setAction(String action) {
ohair@286: ContentType ct = contentType();
ohair@286: ct.setParameter("action", action);
ohair@286: headers.setHeader("Content-Type", ct.toString());
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: public String getCharset() {
ohair@286: return contentType().getParameter("charset");
ohair@286: }
ohair@286:
ohair@286: public void setCharset(String charset) {
ohair@286: ContentType ct = contentType();
ohair@286: ct.setParameter("charset", charset);
ohair@286: headers.setHeader("Content-Type", ct.toString());
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: /**
ohair@286: * All write methods (i.e setters) should call this method in
ohair@286: * order to make sure that a save is necessary since the state
ohair@286: * has been modified.
ohair@286: */
ohair@286: private final void needsSave() {
ohair@286: saved = false;
ohair@286: }
ohair@286:
ohair@286: public boolean saveRequired() {
ohair@286: return saved != true;
ohair@286: }
ohair@286:
ohair@286: public String getContentDescription() {
ohair@286: String[] values = headers.getHeader("Content-Description");
ohair@286: if (values != null && values.length > 0)
ohair@286: return values[0];
ohair@286: return null;
ohair@286: }
ohair@286:
ohair@286: public void setContentDescription(String description) {
ohair@286: headers.setHeader("Content-Description", description);
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: public abstract SOAPPart getSOAPPart();
ohair@286:
ohair@286: public void removeAllAttachments() {
ohair@286: try {
ohair@286: initializeAllAttachments();
ohair@286: } catch (Exception e) {
ohair@286: throw new RuntimeException(e);
ohair@286: }
ohair@286:
ohair@286: if (attachments != null) {
ohair@286: attachments.clear();
ohair@286: needsSave();
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: public int countAttachments() {
ohair@286: try {
ohair@286: initializeAllAttachments();
ohair@286: } catch (Exception e) {
ohair@286: throw new RuntimeException(e);
ohair@286: }
ohair@286: if (attachments != null)
ohair@286: return attachments.size();
ohair@286: return 0;
ohair@286: }
ohair@286:
ohair@286: public void addAttachmentPart(AttachmentPart attachment) {
ohair@286: try {
ohair@286: initializeAllAttachments();
ohair@286: this.optimizeAttachmentProcessing = true;
ohair@286: } catch (Exception e) {
ohair@286: throw new RuntimeException(e);
ohair@286: }
ohair@286: if (attachments == null)
ohair@286: attachments = new FinalArrayList();
ohair@286:
ohair@286: attachments.add(attachment);
ohair@286:
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: static private final Iterator nullIter = Collections.EMPTY_LIST.iterator();
ohair@286:
ohair@286: public Iterator getAttachments() {
ohair@286: try {
ohair@286: initializeAllAttachments();
ohair@286: } catch (Exception e) {
ohair@286: throw new RuntimeException(e);
ohair@286: }
ohair@286: if (attachments == null)
ohair@286: return nullIter;
ohair@286: return attachments.iterator();
ohair@286: }
ohair@286:
ohair@286: private void setFinalContentType(String charset) {
ohair@286: ContentType ct = contentType();
ohair@286: if (ct == null) {
ohair@286: ct = new ContentType();
ohair@286: }
ohair@286: String[] split = getExpectedContentType().split("/");
ohair@286: ct.setPrimaryType(split[0]);
ohair@286: ct.setSubType(split[1]);
ohair@286: ct.setParameter("charset", charset);
ohair@286: headers.setHeader("Content-Type", ct.toString());
ohair@286: }
ohair@286:
ohair@286: private class MimeMatchingIterator implements Iterator {
ohair@286: public MimeMatchingIterator(MimeHeaders headers) {
ohair@286: this.headers = headers;
ohair@286: this.iter = attachments.iterator();
ohair@286: }
ohair@286:
ohair@286: private Iterator iter;
ohair@286: private MimeHeaders headers;
ohair@286: private Object nextAttachment;
ohair@286:
ohair@286: public boolean hasNext() {
ohair@286: if (nextAttachment == null)
ohair@286: nextAttachment = nextMatch();
ohair@286: return nextAttachment != null;
ohair@286: }
ohair@286:
ohair@286: public Object next() {
ohair@286: if (nextAttachment != null) {
ohair@286: Object ret = nextAttachment;
ohair@286: nextAttachment = null;
ohair@286: return ret;
ohair@286: }
ohair@286:
ohair@286: if (hasNext())
ohair@286: return nextAttachment;
ohair@286:
ohair@286: return null;
ohair@286: }
ohair@286:
ohair@286: Object nextMatch() {
ohair@286: while (iter.hasNext()) {
ohair@286: AttachmentPartImpl ap = (AttachmentPartImpl) iter.next();
ohair@286: if (ap.hasAllHeaders(headers))
ohair@286: return ap;
ohair@286: }
ohair@286: return null;
ohair@286: }
ohair@286:
ohair@286: public void remove() {
ohair@286: iter.remove();
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: public Iterator getAttachments(MimeHeaders headers) {
ohair@286: try {
ohair@286: initializeAllAttachments();
ohair@286: } catch (Exception e) {
ohair@286: throw new RuntimeException(e);
ohair@286: }
ohair@286: if (attachments == null)
ohair@286: return nullIter;
ohair@286:
ohair@286: return new MimeMatchingIterator(headers);
ohair@286: }
ohair@286:
ohair@286: public void removeAttachments(MimeHeaders headers) {
ohair@286: try {
ohair@286: initializeAllAttachments();
ohair@286: } catch (Exception e) {
ohair@286: throw new RuntimeException(e);
ohair@286: }
ohair@286: if (attachments == null)
ohair@286: return ;
ohair@286:
ohair@286: Iterator it = new MimeMatchingIterator(headers);
ohair@286: while (it.hasNext()) {
ohair@286: int index = attachments.indexOf(it.next());
ohair@286: attachments.set(index, null);
ohair@286: }
ohair@286: FinalArrayList f = new FinalArrayList();
ohair@286: for (int i = 0; i < attachments.size(); i++) {
ohair@286: if (attachments.get(i) != null) {
ohair@286: f.add(attachments.get(i));
ohair@286: }
ohair@286: }
ohair@286: attachments = f;
ohair@286: // needsSave();
ohair@286: }
ohair@286:
ohair@286: public AttachmentPart createAttachmentPart() {
ohair@286: return new AttachmentPartImpl();
ohair@286: }
ohair@286:
ohair@286: public AttachmentPart getAttachment(SOAPElement element)
ohair@286: throws SOAPException {
ohair@286: try {
ohair@286: initializeAllAttachments();
ohair@286: } catch (Exception e) {
ohair@286: throw new RuntimeException(e);
ohair@286: }
ohair@286: String uri;
ohair@286: String hrefAttr = element.getAttribute("href");
ohair@286: if ("".equals(hrefAttr)) {
ohair@286: Node node = getValueNodeStrict(element);
ohair@286: String swaRef = null;
ohair@286: if (node != null) {
ohair@286: swaRef = node.getValue();
ohair@286: }
ohair@286: if (swaRef == null || "".equals(swaRef)) {
ohair@286: return null;
ohair@286: } else {
ohair@286: uri = swaRef;
ohair@286: }
ohair@286: } else {
ohair@286: uri = hrefAttr;
ohair@286: }
ohair@286: return getAttachmentPart(uri);
ohair@286: }
ohair@286:
ohair@286: private Node getValueNodeStrict(SOAPElement element) {
ohair@286: Node node = (Node)element.getFirstChild();
ohair@286: if (node != null) {
ohair@286: if (node.getNextSibling() == null
ohair@286: && node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
ohair@286: return node;
ohair@286: } else {
ohair@286: return null;
ohair@286: }
ohair@286: }
ohair@286: return null;
ohair@286: }
ohair@286:
ohair@286:
ohair@286: private AttachmentPart getAttachmentPart(String uri) throws SOAPException {
ohair@286: AttachmentPart _part;
ohair@286: try {
ohair@286: if (uri.startsWith("cid:")) {
ohair@286: // rfc2392
ohair@286: uri = '<'+uri.substring("cid:".length())+'>';
ohair@286:
ohair@286: MimeHeaders headersToMatch = new MimeHeaders();
ohair@286: headersToMatch.addHeader(CONTENT_ID, uri);
ohair@286:
ohair@286: Iterator i = this.getAttachments(headersToMatch);
ohair@286: _part = (i == null) ? null : (AttachmentPart)i.next();
ohair@286: } else {
ohair@286: // try content-location
ohair@286: MimeHeaders headersToMatch = new MimeHeaders();
ohair@286: headersToMatch.addHeader(CONTENT_LOCATION, uri);
ohair@286:
ohair@286: Iterator i = this.getAttachments(headersToMatch);
ohair@286: _part = (i == null) ? null : (AttachmentPart)i.next();
ohair@286: }
ohair@286:
ohair@286: // try auto-generated JAXRPC CID
ohair@286: if (_part == null) {
ohair@286: Iterator j = this.getAttachments();
ohair@286:
ohair@286: while (j.hasNext()) {
ohair@286: AttachmentPart p = (AttachmentPart)j.next();
ohair@286: String cl = p.getContentId();
ohair@286: if (cl != null) {
ohair@286: // obtain the partname
ohair@286: int eqIndex = cl.indexOf("=");
ohair@286: if (eqIndex > -1) {
ohair@286: cl = cl.substring(1, eqIndex);
ohair@286: if (cl.equalsIgnoreCase(uri)) {
ohair@286: _part = p;
ohair@286: break;
ohair@286: }
ohair@286: }
ohair@286: }
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: } catch (Exception se) {
ohair@286: log.log(Level.SEVERE, "SAAJ0590.soap.unable.to.locate.attachment", new Object[] {uri});
ohair@286: throw new SOAPExceptionImpl(se);
ohair@286: }
ohair@286: return _part;
ohair@286: }
ohair@286:
ohair@286: private final InputStream getHeaderBytes()
ohair@286: throws IOException {
ohair@286: SOAPPartImpl sp = (SOAPPartImpl) getSOAPPart();
ohair@286: return sp.getContentAsStream();
ohair@286: }
ohair@286:
ohair@286: private String convertToSingleLine(String contentType) {
ohair@286: StringBuffer buffer = new StringBuffer();
ohair@286: for (int i = 0; i < contentType.length(); i ++) {
ohair@286: char c = contentType.charAt(i);
ohair@286: if (c != '\r' && c != '\n' && c != '\t')
ohair@286: buffer.append(c);
ohair@286: }
ohair@286: return buffer.toString();
ohair@286: }
ohair@286:
ohair@286: private MimeMultipart getMimeMessage() throws SOAPException {
ohair@286: try {
ohair@286: SOAPPartImpl soapPart = (SOAPPartImpl) getSOAPPart();
ohair@286: MimeBodyPart mimeSoapPart = soapPart.getMimePart();
ohair@286:
ohair@286: /*
ohair@286: * Get content type from this message instead of soapPart
ohair@286: * to ensure agreement if soapPart is transcoded (XML <-> FI)
ohair@286: */
ohair@286: ContentType soapPartCtype = new ContentType(getExpectedContentType());
ohair@286:
ohair@286: if (!isFastInfoset) {
ohair@286: soapPartCtype.setParameter("charset", initCharset());
ohair@286: }
ohair@286: mimeSoapPart.setHeader("Content-Type", soapPartCtype.toString());
ohair@286:
ohair@286: MimeMultipart headerAndBody = null;
ohair@286:
ohair@286: if (!switchOffBM && !switchOffLazyAttachment &&
ohair@286: (multiPart != null) && !attachmentsInitialized) {
ohair@286: headerAndBody = new BMMimeMultipart();
ohair@286: headerAndBody.addBodyPart(mimeSoapPart);
ohair@286: if (attachments != null) {
ohair@286: for (Iterator eachAttachment = attachments.iterator();
ohair@286: eachAttachment.hasNext();) {
ohair@286: headerAndBody.addBodyPart(
ohair@286: ((AttachmentPartImpl) eachAttachment.next())
ohair@286: .getMimePart());
ohair@286: }
ohair@286: }
ohair@286: InputStream in = ((BMMimeMultipart)multiPart).getInputStream();
ohair@286: if (!((BMMimeMultipart)multiPart).lastBodyPartFound() &&
ohair@286: !((BMMimeMultipart)multiPart).isEndOfStream()) {
ohair@286: ((BMMimeMultipart)headerAndBody).setInputStream(in);
ohair@286: ((BMMimeMultipart)headerAndBody).setBoundary(
ohair@286: ((BMMimeMultipart)multiPart).getBoundary());
ohair@286: ((BMMimeMultipart)headerAndBody).
ohair@286: setLazyAttachments(lazyAttachments);
ohair@286: }
ohair@286:
ohair@286: } else {
ohair@286: headerAndBody = new MimeMultipart();
ohair@286: headerAndBody.addBodyPart(mimeSoapPart);
ohair@286:
ohair@286: for (Iterator eachAttachement = getAttachments();
ohair@286: eachAttachement.hasNext();
ohair@286: ) {
ohair@286: headerAndBody.addBodyPart(
ohair@286: ((AttachmentPartImpl) eachAttachement.next())
ohair@286: .getMimePart());
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: ContentType contentType = headerAndBody.getContentType();
ohair@286:
ohair@286: ParameterList l = contentType.getParameterList();
ohair@286:
ohair@286: // set content type depending on SOAP version
ohair@286: l.set("type", getExpectedContentType());
ohair@286: l.set("boundary", contentType.getParameter("boundary"));
ohair@286: ContentType nct = new ContentType("multipart", "related", l);
ohair@286:
ohair@286: headers.setHeader(
ohair@286: "Content-Type",
ohair@286: convertToSingleLine(nct.toString()));
ohair@286: // TBD
ohair@286: // Set content length MIME header here.
ohair@286:
ohair@286: return headerAndBody;
ohair@286: } catch (SOAPException ex) {
ohair@286: throw ex;
ohair@286: } catch (Throwable ex) {
ohair@286: log.severe("SAAJ0538.soap.cannot.convert.msg.to.multipart.obj");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Unable to convert SOAP message into "
ohair@286: + "a MimeMultipart object",
ohair@286: ex);
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: private String initCharset() {
ohair@286:
ohair@286: String charset = null;
ohair@286:
ohair@286: String[] cts = getMimeHeaders().getHeader("Content-Type");
ohair@286: if ((cts != null) && (cts[0] != null)) {
ohair@286: charset = getCharsetString(cts[0]);
ohair@286: }
ohair@286:
ohair@286: if (charset == null) {
ohair@286: charset = (String) getProperty(CHARACTER_SET_ENCODING);
ohair@286: }
ohair@286:
ohair@286: if (charset != null) {
ohair@286: return charset;
ohair@286: }
ohair@286:
ohair@286: return "utf-8";
ohair@286: }
ohair@286:
ohair@286: private String getCharsetString(String s) {
ohair@286: try {
ohair@286: int index = s.indexOf(";");
ohair@286: if(index < 0)
ohair@286: return null;
ohair@286: ParameterList pl = new ParameterList(s.substring(index));
ohair@286: return pl.get("charset");
ohair@286: } catch(Exception e) {
ohair@286: return null;
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: public void saveChanges() throws SOAPException {
ohair@286:
ohair@286: // suck in all the data from the attachments and have it
ohair@286: // ready for writing/sending etc.
ohair@286:
ohair@286: String charset = initCharset();
ohair@286:
ohair@286: /*if (countAttachments() == 0) {*/
ohair@286: int attachmentCount = (attachments == null) ? 0 : attachments.size();
ohair@286: if (attachmentCount == 0) {
ohair@286: if (!switchOffBM && !switchOffLazyAttachment &&
ohair@286: !attachmentsInitialized && (multiPart != null)) {
ohair@286: // so there might be attachments
ohair@286: attachmentCount = 1;
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: try {
ohair@286: if ((attachmentCount == 0) && !hasXOPContent()) {
ohair@286: InputStream in;
ohair@286: try{
ohair@286: /*
ohair@286: * Not sure why this is called getHeaderBytes(), but it actually
ohair@286: * returns the whole message as a byte stream. This stream could
ohair@286: * be either XML of Fast depending on the mode.
ohair@286: */
ohair@286: in = getHeaderBytes();
ohair@286: // no attachments, hence this property can be false
ohair@286: this.optimizeAttachmentProcessing = false;
ohair@286: if (SOAPPartImpl.lazyContentLength) {
ohair@286: inputStreamAfterSaveChanges = in;
ohair@286: }
ohair@286: } catch (IOException ex) {
ohair@286: log.severe("SAAJ0539.soap.cannot.get.header.stream");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Unable to get header stream in saveChanges: ",
ohair@286: ex);
ohair@286: }
ohair@286:
ohair@286: if (in instanceof ByteInputStream) {
ohair@286: ByteInputStream bIn = (ByteInputStream)in;
ohair@286: messageBytes = bIn.getBytes();
ohair@286: messageByteCount = bIn.getCount();
ohair@286: }
ohair@286:
ohair@286: setFinalContentType(charset);
ohair@286: /*
ohair@286: headers.setHeader(
ohair@286: "Content-Type",
ohair@286: getExpectedContentType() +
ohair@286: (isFastInfoset ? "" : "; charset=" + charset));*/
ohair@286: if (messageByteCount > 0) {
ohair@286: headers.setHeader(
ohair@286: "Content-Length",
ohair@286: Integer.toString(messageByteCount));
ohair@286: }
ohair@286: } else {
ohair@286: if(hasXOPContent())
ohair@286: mmp = getXOPMessage();
ohair@286: else
ohair@286: mmp = getMimeMessage();
ohair@286: }
ohair@286: } catch (Throwable ex) {
ohair@286: log.severe("SAAJ0540.soap.err.saving.multipart.msg");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Error during saving a multipart message",
ohair@286: ex);
ohair@286: }
ohair@286:
ohair@286: // FIX ME -- SOAP Action replaced by Content-Type optional parameter action
ohair@286: /*
ohair@286: if(isCorrectSoapVersion(SOAP1_1_FLAG)) {
ohair@286:
ohair@286: String[] soapAction = headers.getHeader("SOAPAction");
ohair@286:
ohair@286: if (soapAction == null || soapAction.length == 0)
ohair@286: headers.setHeader("SOAPAction", "\"\"");
ohair@286:
ohair@286: }
ohair@286: */
ohair@286:
ohair@286: saved = true;
ohair@286: }
ohair@286:
ohair@286: private MimeMultipart getXOPMessage() throws SOAPException {
ohair@286: try {
ohair@286: MimeMultipart headerAndBody = new MimeMultipart();
ohair@286: SOAPPartImpl soapPart = (SOAPPartImpl)getSOAPPart();
ohair@286: MimeBodyPart mimeSoapPart = soapPart.getMimePart();
ohair@286: ContentType soapPartCtype =
ohair@286: new ContentType("application/xop+xml");
ohair@286: soapPartCtype.setParameter("type", getExpectedContentType());
ohair@286: String charset = initCharset();
ohair@286: soapPartCtype.setParameter("charset", charset);
ohair@286: mimeSoapPart.setHeader("Content-Type", soapPartCtype.toString());
ohair@286: headerAndBody.addBodyPart(mimeSoapPart);
ohair@286:
ohair@286: for (Iterator eachAttachement = getAttachments();
ohair@286: eachAttachement.hasNext();
ohair@286: ) {
ohair@286: headerAndBody.addBodyPart(
ohair@286: ((AttachmentPartImpl) eachAttachement.next())
ohair@286: .getMimePart());
ohair@286: }
ohair@286:
ohair@286: ContentType contentType = headerAndBody.getContentType();
ohair@286:
ohair@286: ParameterList l = contentType.getParameterList();
ohair@286:
ohair@286: //lets not write start-info for now till we get servlet fix done
ohair@286: l.set("start-info", getExpectedContentType());//+";charset="+initCharset());
ohair@286:
ohair@286: // set content type depending on SOAP version
ohair@286: l.set("type", "application/xop+xml");
ohair@286:
ohair@286: if (isCorrectSoapVersion(SOAP1_2_FLAG)) {
ohair@286: String action = getAction();
ohair@286: if(action != null)
ohair@286: l.set("action", action);
ohair@286: }
ohair@286:
ohair@286: l.set("boundary", contentType.getParameter("boundary"));
ohair@286: ContentType nct = new ContentType("Multipart", "Related", l);
ohair@286: headers.setHeader(
ohair@286: "Content-Type",
ohair@286: convertToSingleLine(nct.toString()));
ohair@286: // TBD
ohair@286: // Set content length MIME header here.
ohair@286:
ohair@286: return headerAndBody;
ohair@286: } catch (SOAPException ex) {
ohair@286: throw ex;
ohair@286: } catch (Throwable ex) {
ohair@286: log.severe("SAAJ0538.soap.cannot.convert.msg.to.multipart.obj");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Unable to convert SOAP message into "
ohair@286: + "a MimeMultipart object",
ohair@286: ex);
ohair@286: }
ohair@286:
ohair@286: }
ohair@286:
ohair@286: private boolean hasXOPContent() throws ParseException {
ohair@286: String type = getContentType();
ohair@286: if(type == null)
ohair@286: return false;
ohair@286: ContentType ct = new ContentType(type);
ohair@286: //return isMimeMultipartXOPPackage(ct) || isSOAPBodyXOPPackage(ct);
ohair@286: return isMimeMultipartXOPSoap1_1Package(ct) ||
ohair@286: isMimeMultipartXOPSoap1_2Package(ct) || isSOAPBodyXOPPackage(ct);
ohair@286:
ohair@286: }
ohair@286:
ohair@286: public void writeTo(OutputStream out) throws SOAPException, IOException {
ohair@286: if (saveRequired()){
ohair@286: this.optimizeAttachmentProcessing = true;
ohair@286: saveChanges();
ohair@286: }
ohair@286:
ohair@286: if(!optimizeAttachmentProcessing){
ohair@286: if (SOAPPartImpl.lazyContentLength && messageByteCount <= 0) {
ohair@286: byte[] buf = new byte[1024];
ohair@286:
ohair@286: int length = 0;
ohair@286: while( (length = inputStreamAfterSaveChanges.read(buf)) != -1) {
ohair@286: out.write(buf,0, length);
ohair@286: messageByteCount += length;
ohair@286: }
ohair@286: if (messageByteCount > 0) {
ohair@286: headers.setHeader(
ohair@286: "Content-Length",
ohair@286: Integer.toString(messageByteCount));
ohair@286: }
ohair@286: } else {
ohair@286: out.write(messageBytes, 0, messageByteCount);
ohair@286: }
ohair@286: }
ohair@286: else{
ohair@286: try{
ohair@286: if(hasXOPContent()){
ohair@286: mmp.writeTo(out);
ohair@286: }else{
ohair@286: mmp.writeTo(out);
ohair@286: if (!switchOffBM && !switchOffLazyAttachment &&
ohair@286: (multiPart != null) && !attachmentsInitialized) {
ohair@286: ((BMMimeMultipart)multiPart).setInputStream(
ohair@286: ((BMMimeMultipart)mmp).getInputStream());
ohair@286: }
ohair@286: }
ohair@286: } catch(Exception ex){
ohair@286: log.severe("SAAJ0540.soap.err.saving.multipart.msg");
ohair@286: throw new SOAPExceptionImpl(
ohair@286: "Error during saving a multipart message",
ohair@286: ex);
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: if(isCorrectSoapVersion(SOAP1_1_FLAG)) {
ohair@286:
ohair@286: String[] soapAction = headers.getHeader("SOAPAction");
ohair@286:
ohair@286: if (soapAction == null || soapAction.length == 0)
ohair@286: headers.setHeader("SOAPAction", "\"\"");
ohair@286:
ohair@286: }
ohair@286:
ohair@286: messageBytes = null;
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: public SOAPBody getSOAPBody() throws SOAPException {
ohair@286: SOAPBody body = getSOAPPart().getEnvelope().getBody();
ohair@286: /*if (body == null) {
ohair@286: throw new SOAPException("No SOAP Body was found in the SOAP Message");
ohair@286: }*/
ohair@286: return body;
ohair@286: }
ohair@286:
ohair@286: public SOAPHeader getSOAPHeader() throws SOAPException {
ohair@286: SOAPHeader hdr = getSOAPPart().getEnvelope().getHeader();
ohair@286: /*if (hdr == null) {
ohair@286: throw new SOAPException("No SOAP Header was found in the SOAP Message");
ohair@286: }*/
ohair@286: return hdr;
ohair@286: }
ohair@286:
ohair@286: private void initializeAllAttachments ()
ohair@286: throws MessagingException, SOAPException {
ohair@286: if (switchOffBM || switchOffLazyAttachment) {
ohair@286: return;
ohair@286: }
ohair@286:
ohair@286: if (attachmentsInitialized || (multiPart == null)) {
ohair@286: return;
ohair@286: }
ohair@286:
ohair@286: if (attachments == null)
ohair@286: attachments = new FinalArrayList();
ohair@286:
ohair@286: int count = multiPart.getCount();
ohair@286: for (int i=0; i < count; i++ ) {
ohair@286: initializeAttachment(multiPart.getBodyPart(i));
ohair@286: }
ohair@286: attachmentsInitialized = true;
ohair@286: //multiPart = null;
ohair@286: needsSave();
ohair@286: }
ohair@286:
ohair@286: private void initializeAttachment(MimeBodyPart mbp) throws SOAPException {
ohair@286: AttachmentPartImpl attachmentPart = new AttachmentPartImpl();
ohair@286: DataHandler attachmentHandler = mbp.getDataHandler();
ohair@286: attachmentPart.setDataHandler(attachmentHandler);
ohair@286:
ohair@286: AttachmentPartImpl.copyMimeHeaders(mbp, attachmentPart);
ohair@286: attachments.add(attachmentPart);
ohair@286: }
ohair@286:
ohair@286: private void initializeAttachment(MimeMultipart multiPart, int i)
ohair@286: throws Exception {
ohair@286: MimeBodyPart currentBodyPart = multiPart.getBodyPart(i);
ohair@286: AttachmentPartImpl attachmentPart = new AttachmentPartImpl();
ohair@286:
ohair@286: DataHandler attachmentHandler = currentBodyPart.getDataHandler();
ohair@286: attachmentPart.setDataHandler(attachmentHandler);
ohair@286:
ohair@286: AttachmentPartImpl.copyMimeHeaders(currentBodyPart, attachmentPart);
ohair@286: addAttachmentPart(attachmentPart);
ohair@286: }
ohair@286:
ohair@286: private void setMimeHeaders(SOAPPart soapPart,
ohair@286: MimeBodyPart soapMessagePart) throws Exception {
ohair@286:
ohair@286: // first remove the existing content-type
ohair@286: soapPart.removeAllMimeHeaders();
ohair@286: // add everything present in soapMessagePart
ohair@286: List headers = soapMessagePart.getAllHeaders();
ohair@286: int sz = headers.size();
ohair@286: for( int i=0; i