/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ws.core.soap;
// $Id: MessageFactoryImpl.java 9825 2009-04-14 16:15:17Z darran.lofthouse@jboss.com $
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Iterator;
import javax.mail.internet.ContentType;
import javax.mail.internet.ParseException;
import javax.xml.soap.AttachmentPart;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Service.Mode;
import org.jboss.logging.Logger;
import org.jboss.ws.core.CommonMessageContext;
import org.jboss.ws.core.soap.attachment.MimeConstants;
import org.jboss.ws.core.soap.attachment.MultipartRelatedDecoder;
import org.jboss.wsf.common.IOUtils;
import org.jboss.wsf.spi.util.ServiceLoader;
/**
* MessageFactory implementation
*
* @author Thomas.Diesler@jboss.org
*/
public class MessageFactoryImpl extends MessageFactory
{
private static Logger log = Logger.getLogger(MessageFactoryImpl.class);
// The envelope namespace used by the MessageFactory
private String envNamespace;
// The JAXWS ServiceMode
private Mode serviceMode;
// The style used by this MessageFactory
private Style style;
// Used if the style is dynamic
private boolean dynamic;
private EnvelopeBuilder envelopeBuilder;
public MessageFactoryImpl()
{
envNamespace = SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE;
envelopeBuilder = (EnvelopeBuilder)ServiceLoader.loadService(EnvelopeBuilder.class.getName(), EnvelopeBuilderDOM.class.getName());
}
public MessageFactoryImpl(String protocol) throws SOAPException
{
envelopeBuilder = (EnvelopeBuilder)ServiceLoader.loadService(EnvelopeBuilder.class.getName(), EnvelopeBuilderDOM.class.getName());
if (SOAPConstants.SOAP_1_1_PROTOCOL.equals(protocol) || SOAPConstants.DEFAULT_SOAP_PROTOCOL.equals(protocol))
envNamespace = SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE;
else if (SOAPConstants.SOAP_1_2_PROTOCOL.equals(protocol))
envNamespace = SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE;
else if (SOAPConstants.DYNAMIC_SOAP_PROTOCOL.equals(protocol))
dynamic = true;
else
throw new SOAPException("Unknown protocol: " + protocol);
}
/**
* Get the SOAP envelope URI this factory will use when creating envelopes.
*/
public String getEnvNamespace()
{
return envNamespace;
}
/**
* Set the SOAP envelope URI this factory will use when creating envelopes.
*/
public void setEnvNamespace(String envelopeURI)
{
this.envNamespace = envelopeURI;
}
/**
* Get the Style this message factory will use
*/
public Style getStyle()
{
if (style == null)
{
CommonMessageContext msgContext = MessageContextAssociation.peekMessageContext();
if (msgContext != null && msgContext.getOperationMetaData() != null)
{
style = msgContext.getOperationMetaData().getStyle();
}
log.trace("Using style: " + style);
}
return style;
}
public void setStyle(Style style)
{
this.style = style;
}
public Mode getServiceMode()
{
return serviceMode;
}
public void setServiceMode(Mode serviceMode)
{
this.serviceMode = serviceMode;
}
/**
* Creates a new SOAPMessage object with the default SOAPPart, SOAPEnvelope,
* SOAPBody, and SOAPHeader objects. Profile-specific message factories can
* choose to prepopulate the SOAPMessage object with profile-specific
* headers.
*
* Content can be added to this message's SOAPPart object, and the message
* can be sent "as is" when a message containing only a SOAP part is
* sufficient. Otherwise, the SOAPMessage object needs to create one or more
* AttachmentPart objects and add them to itself. Any content that is not in
* XML format must be in an AttachmentPart object.
*
* @return a new SOAPMessage object
* @throws javax.xml.soap.SOAPException
* if a SOAP error occurs
*/
public SOAPMessage createMessage() throws SOAPException
{
if (dynamic)
throw new UnsupportedOperationException("Cannot create default message when protocol is dynamic");
SOAPMessageImpl soapMessage = new SOAPMessageImpl();
SOAPPartImpl soapPart = (SOAPPartImpl)soapMessage.getSOAPPart();
new SOAPEnvelopeImpl(soapPart, envNamespace, true);
return soapMessage;
}
/**
* Internalizes the contents of the given InputStream object into a new
* SOAPMessage object and returns the SOAPMessage object.
*
* @param mimeHeaders
* the transport-specific headers passed to the message in a
* transport-independent fashion for creation of the message
* @param ins
* the InputStream object that contains the data for a message
* @return a new SOAPMessage object containing the data from the given
* InputStream object
* @throws java.io.IOException
* if there is a problem in reading data from the input stream
* @throws javax.xml.soap.SOAPException
* if the message is invalid
*/
public SOAPMessage createMessage(MimeHeaders mimeHeaders, InputStream ins) throws IOException, SOAPException
{
return createMessage(mimeHeaders, ins, false);
}
public SOAPMessage createMessage(MimeHeaders mimeHeaders, InputStream inputStream, boolean ignoreParseError) throws IOException, SOAPException
{
if (mimeHeaders == null)
{
mimeHeaders = new MimeHeaders();
}
else if (log.isTraceEnabled())
{
Iterator<MimeHeader> itMimeHeaders = mimeHeaders.getAllHeaders();
while (itMimeHeaders.hasNext())
{
MimeHeader mh = itMimeHeaders.next();
log.trace(mh);
}
}
ContentType contentType = getContentType(mimeHeaders);
log.debug("createMessage: [contentType=" + contentType + "]");
SOAPMessageImpl soapMessage = new SOAPMessageImpl();
if (inputStream != null)
{
// Debug the incoming message
if (log.isTraceEnabled())
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
IOUtils.copyStream(baos, inputStream);
byte[] bytes = baos.toByteArray();
log.trace("createMessage\n" + new String(bytes));
inputStream = new ByteArrayInputStream(bytes);
}
Collection<AttachmentPart> attachments = null;
if (isMultipartRelatedContent(contentType))
{
MultipartRelatedDecoder decoder;
try
{
decoder = new MultipartRelatedDecoder(contentType);
decoder.decodeMultipartRelatedMessage(inputStream);
}
catch (RuntimeException rte)
{
throw rte;
}
catch (IOException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new SOAPException("Cannot decode multipart related message", ex);
}
inputStream = decoder.getRootPart().getDataHandler().getInputStream();
attachments = decoder.getRelatedParts();
if (isXOPContent(contentType))
{
soapMessage.setXOPMessage(true);
}
}
else if (isSoapContent(contentType) == false)
{
throw new SOAPException("Unsupported content type: " + contentType);
}
if (mimeHeaders != null)
soapMessage.setMimeHeaders(mimeHeaders);
if (attachments != null)
soapMessage.setAttachments(attachments);
// Get the SOAPEnvelope builder
envelopeBuilder.setStyle(getStyle());
// Build the payload
envelopeBuilder.build(soapMessage, inputStream, ignoreParseError);
}
return soapMessage;
}
private static ContentType getContentType(MimeHeaders headers) throws SOAPException
{
ContentType contentType = null;
try
{
String[] type = headers.getHeader(MimeConstants.CONTENT_TYPE);
if (type != null)
{
contentType = new ContentType(type[0]);
}
else
{
contentType = new ContentType(MimeConstants.TYPE_SOAP11);
}
return contentType;
}
catch (ParseException e)
{
throw new SOAPException("Could not parse content type:" + e);
}
}
private boolean isSoapContent(ContentType type)
{
String baseType = type.getBaseType();
return MimeConstants.TYPE_SOAP11.equalsIgnoreCase(baseType) || MimeConstants.TYPE_SOAP12.equalsIgnoreCase(baseType);
}
private boolean isMultipartRelatedContent(ContentType type)
{
String baseType = type.getBaseType();
return MimeConstants.TYPE_MULTIPART_RELATED.equalsIgnoreCase(baseType);
}
private boolean isXOPContent(ContentType type)
{
String paramType = type.getParameter("type");
return MimeConstants.TYPE_APPLICATION_XOP_XML.endsWith(paramType);
}
}