blob: 140b545a86838809324f8c780226b37389fe7a4d [file] [log] [blame]
/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis2.saaj;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axis2.transport.http.HTTPConstants;
import javax.xml.soap.AttachmentPart;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
public class SOAPMessageImpl extends SOAPMessage {
private SOAPPart soapPart;
private Collection attachmentParts = new ArrayList();
private MimeHeadersEx mimeHeaders;
private Map props = new Hashtable();
private boolean saveRequired;
public SOAPMessageImpl(SOAPEnvelopeImpl soapEnvelope) {
String contentType = null;
if (mimeHeaders != null) {
String contentTypes[] = mimeHeaders.getHeader("Content-Type");
contentType = (contentTypes != null) ? contentTypes[0] : null;
}
setCharsetEncoding(contentType);
soapPart = new SOAPPartImpl(this, soapEnvelope);
this.mimeHeaders = new MimeHeadersEx();
}
public SOAPMessageImpl(InputStream inputstream,
javax.xml.soap.MimeHeaders mimeHeaders) throws SOAPException {
String contentType = null;
if (mimeHeaders != null) {
String contentTypes[] = mimeHeaders.getHeader("Content-Type");
contentType = (contentTypes != null) ? contentTypes[0] : null;
}
setCharsetEncoding(contentType);
if (contentType != null && contentType.indexOf("multipart/related;") == 0) {
// soapPart = new SOAPPartImpl(this, inputstream, mimeHeaders);
} else {
soapPart = new SOAPPartImpl(this, inputstream);
}
this.mimeHeaders = (mimeHeaders == null) ?
new MimeHeadersEx() :
new MimeHeadersEx(mimeHeaders);
}
/**
* Retrieves a description of this <CODE>SOAPMessage</CODE>
* object's content.
*
* @return a <CODE>String</CODE> describing the content of this
* message or <CODE>null</CODE> if no description has been
* set
* @see #setContentDescription(java.lang.String) setContentDescription(java.lang.String)
*/
public String getContentDescription() {
String values[] = mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_DESCRIPTION);
if (values != null && values.length > 0) {
return values[0];
}
return null;
}
/**
* Sets the description of this <CODE>SOAPMessage</CODE>
* object's content with the given description.
*
* @param description a <CODE>String</CODE>
* describing the content of this message
* @see #getContentDescription() getContentDescription()
*/
public void setContentDescription(String description) {
mimeHeaders.setHeader(HTTPConstants.HEADER_CONTENT_DESCRIPTION, description);
}
/**
* Gets the SOAP part of this <CODE>SOAPMessage</CODE> object.
* <p/>
* <p/>
* <P>If a <CODE>SOAPMessage</CODE> object contains one or
* more attachments, the SOAP Part must be the first MIME body
* part in the message.</P>
*
* @return the <CODE>SOAPPart</CODE> object for this <CODE>
* SOAPMessage</CODE> object
*/
public SOAPPart getSOAPPart() {
return soapPart;
}
/**
* Removes all <CODE>AttachmentPart</CODE> objects that have
* been added to this <CODE>SOAPMessage</CODE> object.
* <p/>
* <P>This method does not touch the SOAP part.</P>
*/
public void removeAllAttachments() {
attachmentParts.clear();
}
/**
* Gets a count of the number of attachments in this
* message. This count does not include the SOAP part.
*
* @return the number of <CODE>AttachmentPart</CODE> objects
* that are part of this <CODE>SOAPMessage</CODE>
* object
*/
public int countAttachments() {
return attachmentParts.size();
}
/**
* Retrieves all the <CODE>AttachmentPart</CODE> objects
* that are part of this <CODE>SOAPMessage</CODE> object.
*
* @return an iterator over all the attachments in this
* message
*/
public Iterator getAttachments() {
return attachmentParts.iterator();
}
/**
* Retrieves all the AttachmentPart objects that have header entries that match the specified
* headers.
* Note that a returned attachment could have headers in addition to those specified.
*
* @param headers a {@link javax.xml.soap.MimeHeaders}
* object containing the MIME headers for which to search
* @return an iterator over all attachments({@link javax.xml.soap.AttachmentPart})
* that have a header that matches one of the given headers
*/
public Iterator getAttachments(javax.xml.soap.MimeHeaders headers) {
Collection matchingAttachmentParts = new ArrayList();
Iterator iterator = getAttachments();
{
AttachmentPartImpl part;
while (iterator.hasNext()) {
part = (AttachmentPartImpl) iterator.next();
if (part.matches(headers)) {
matchingAttachmentParts.add(part);
}
}
}
return matchingAttachmentParts.iterator();
}
/**
* Adds the given <CODE>AttachmentPart</CODE> object to this
* <CODE>SOAPMessage</CODE> object. An <CODE>
* AttachmentPart</CODE> object must be created before it can be
* added to a message.
*
* @param attachmentPart an <CODE>
* AttachmentPart</CODE> object that is to become part of
* this <CODE>SOAPMessage</CODE> object
* @throws java.lang.IllegalArgumentException
*
*/
public void addAttachmentPart(AttachmentPart attachmentPart) {
if (attachmentPart != null) {
attachmentParts.add(attachmentPart);
mimeHeaders.setHeader("Content-Type", "multipart/related");
}
}
/**
* Creates a new empty <CODE>AttachmentPart</CODE> object.
* Note that the method <CODE>addAttachmentPart</CODE> must be
* called with this new <CODE>AttachmentPart</CODE> object as
* the parameter in order for it to become an attachment to this
* <CODE>SOAPMessage</CODE> object.
*
* @return a new <CODE>AttachmentPart</CODE> object that can be
* populated and added to this <CODE>SOAPMessage</CODE>
* object
*/
public AttachmentPart createAttachmentPart() {
return new AttachmentPartImpl();
}
/**
* Returns all the transport-specific MIME headers for this
* <CODE>SOAPMessage</CODE> object in a transport-independent
* fashion.
*
* @return a <CODE>MimeHeaders</CODE> object containing the
* <CODE>MimeHeader</CODE> objects
*/
public javax.xml.soap.MimeHeaders getMimeHeaders() {
return mimeHeaders;
}
/**
* Updates this <CODE>SOAPMessage</CODE> object with all the
* changes that have been made to it. This method is called
* automatically when a message is sent or written to by the
* methods <CODE>ProviderConnection.send</CODE>, <CODE>
* SOAPConnection.call</CODE>, or <CODE>
* SOAPMessage.writeTo</CODE>. However, if changes are made to
* a message that was received or to one that has already been
* sent, the method <CODE>saveChanges</CODE> needs to be
* called explicitly in order to save the changes. The method
* <CODE>saveChanges</CODE> also generates any changes that
* can be read back (for example, a MessageId in profiles that
* support a message id). All MIME headers in a message that
* is created for sending purposes are guaranteed to have
* valid values only after <CODE>saveChanges</CODE> has been
* called.
* <p/>
* <P>In addition, this method marks the point at which the
* data from all constituent <CODE>AttachmentPart</CODE>
* objects are pulled into the message.</P>
*
* @throws SOAPException if there was a problem saving changes to this message.
*/
public void saveChanges() throws SOAPException {
saveRequired = false;
// TODO not sure of the implementation
}
public void setSaveRequired() {
this.saveRequired = true;
}
/**
* Indicates whether this <CODE>SOAPMessage</CODE> object
* has had the method {@link #saveChanges()} called on
* it.
*
* @return <CODE>true</CODE> if <CODE>saveChanges</CODE> has
* been called on this message at least once; <CODE>
* false</CODE> otherwise.
*/
public boolean saveRequired() {
return saveRequired;
}
/**
* Writes this <CODE>SOAPMessage</CODE> object to the given
* output stream. The externalization format is as defined by
* the SOAP 1.1 with Attachments specification.
* <p/>
* <P>If there are no attachments, just an XML stream is
* written out. For those messages that have attachments,
* <CODE>writeTo</CODE> writes a MIME-encoded byte stream.</P>
*
* @param out the <CODE>OutputStream</CODE>
* object to which this <CODE>SOAPMessage</CODE> object will
* be written
* @throws SOAPException if there was a problem in externalizing this SOAP message
* @throws IOException if an I/O error occurs
*/
public void writeTo(OutputStream out) throws SOAPException, IOException {
try {
OMOutputFormat format = new OMOutputFormat();
format.setCharSetEncoding((String) getProperty(CHARACTER_SET_ENCODING));
String writeXmlDecl = (String) getProperty(WRITE_XML_DECLARATION);
if (writeXmlDecl == null || writeXmlDecl.equals("false")) {
//SAAJ default case doesn't send XML decl
format.setIgnoreXMLDeclaration(true);
}
//the writeTo method forces the elements to be built!!!
((SOAPEnvelopeImpl) soapPart.getEnvelope()).getOMEnvelope().serialize(out, format);
saveChanges();
} catch (Exception e) {
throw new SOAPException(e);
}
}
/**
* Associates the specified value with the specified property. If there was
* already a value associated with this property, the old value is replaced.
* <p/>
* The valid property names include <code>WRITE_XML_DECLARATION</code> and
* <code>CHARACTER_SET_ENCODING</code>. All of these standard SAAJ
* properties are prefixed by "javax.xml.soap". Vendors may also add
* implementation specific properties. These properties must be prefixed
* with package names that are unique to the vendor.
* <p/>
* Setting the property <code>WRITE_XML_DECLARATION</code> to
* <code>"true"</code> will cause an XML Declaration to be written out at
* the start of the SOAP message. The default value of "false" suppresses
* this declaration.
* <p/>
* The property <code>CHARACTER_SET_ENCODING</code> defaults to the value
* <code>"utf-8"</code> which causes the SOAP message to be encoded using
* UTF-8. Setting <code>CHARACTER_SET_ENCODING</code> to
* <code>"utf-16"</code> causes the SOAP message to be encoded using UTF-16.
* <p/>
* Some implementations may allow encodings in addition to UTF-8 and UTF-16.
* Refer to your vendor's documentation for details.
*
* @param property the property with which the specified value is to be
* associated
* @param value the value
* to be associated with the specified property
*/
public void setProperty(String property, Object value) {
props.put(property, value);
}
/**
* Retrieves value of the specified property.
*
* @param property the name of the property to retrieve
* @return the value of the property or <code>null</code> if no such
* property exists
* @throws SOAPException if the property name is not recognized
*/
public Object getProperty(String property) throws SOAPException {
return props.get(property);
}
/**
* Gets the SOAP Header contained in this <code>SOAPMessage</code> object.
*
* @return the <code>SOAPHeader</code> object contained by this
* <code>SOAPMessage</code> object
* @throws javax.xml.soap.SOAPException if the SOAP Header does not exist or cannot be
* retrieved
*/
public SOAPHeader getSOAPHeader() throws SOAPException {
return this.soapPart.getEnvelope().getHeader();
}
/**
* Gets the SOAP Body contained in this <code>SOAPMessage</code> object.
*
* @return the <code>SOAPBody</code> object contained by this
* <code>SOAPMessage</code> object
* @throws javax.xml.soap.SOAPException if the SOAP Body does not exist or cannot be
* retrieved
*/
public SOAPBody getSOAPBody() throws SOAPException {
return this.soapPart.getEnvelope().getBody();
}
/**
* Set the character encoding based on the <code>contentType</code> parameter
*
* @param contentType
*/
private void setCharsetEncoding(final String contentType) {
if (contentType != null) {
int delimiterIndex = contentType.lastIndexOf("charset");
if (delimiterIndex > 0) {
String charsetPart = contentType.substring(delimiterIndex);
int charsetIndex = charsetPart.indexOf('=');
String charset = charsetPart.substring(charsetIndex + 1).trim();
if ((charset.startsWith("\"") || charset.startsWith("\'"))) {
charset = charset.substring(1, charset.length());
}
if ((charset.endsWith("\"") || charset.endsWith("\'"))) {
charset = charset.substring(0, charset.length() - 1);
}
setProperty(SOAPMessage.CHARACTER_SET_ENCODING, charset);
}
}
}
}