/*
* Copyright(c) 2002 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the Academic Free License Version 1.0
*
* Academic Free License
* Version 1.0
*
* This Academic Free License applies to any software and associated
* documentation (the "Software") whose owner (the "Licensor") has placed the
* statement "Licensed under the Academic Free License Version 1.0" immediately
* after the copyright notice that applies to the Software.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of the Software (1) to use, copy, modify, merge, publish, perform,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, and (2) under patent
* claims owned or controlled by the Licensor that are embodied in the Software
* as furnished by the Licensor, to make, use, sell and offer for sale the
* Software and derivative works thereof, subject to the following conditions:
*
* - Redistributions of the Software in source code form must retain all
* copyright notices in the Software as furnished by the Licensor, this list
* of conditions, and the following disclaimers.
* - Redistributions of the Software in executable form must reproduce all
* copyright notices in the Software as furnished by the Licensor, this list
* of conditions, and the following disclaimers in the documentation and/or
* other materials provided with the distribution.
* - Neither the names of Licensor, nor the names of any contributors to the
* Software, nor any of their trademarks or service marks, may be used to
* endorse or promote products derived from this Software without express
* prior written permission of the Licensor.
*
* DISCLAIMERS: LICENSOR WARRANTS THAT THE COPYRIGHT IN AND TO THE SOFTWARE IS
* OWNED BY THE LICENSOR OR THAT THE SOFTWARE IS DISTRIBUTED BY LICENSOR UNDER
* A VALID CURRENT LICENSE. EXCEPT AS EXPRESSLY STATED IN THE IMMEDIATELY
* PRECEDING SENTENCE, THE SOFTWARE IS PROVIDED BY THE LICENSOR, CONTRIBUTORS
* AND COPYRIGHT OWNERS "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* LICENSOR, CONTRIBUTORS OR COPYRIGHT OWNERS BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE.
*
* This license is Copyright (C) 2002 Lawrence E. Rosen. All rights reserved.
* Permission is hereby granted to copy and distribute this license without
* modification. This license may not be modified without the express written
* permission of its copyright owner.
*/
/*
* =====
*
* $Header: /home/cvsroot/ebxml-pkg/src/hk/hku/cecid/ebms/pkg/EbxmlMessage.java,v 1.1 2005/07/28 09:36:24 dcmsze Exp $
*
* Code authored by:
*
* cyng [2002-03-21]
*
* Code reviewed by:
*
* username [YYYY-MM-DD]
*
* Remarks:
*
* =====
*/
package hk.hku.cecid.ebms.pkg;
import hk.hku.cecid.ebms.pkg.validation.EbxmlValidationException;
import hk.hku.cecid.ebms.pkg.validation.SOAPValidationException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeUtility;
import javax.xml.soap.AttachmentPart;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
/**
* A representation of an ebXML message. An ebXML message conforms to the <a
* href="http://www.w3.org/TR/2000/NOTE-SOAP-attachments-20001211"> SOAP 1.1
* with Attachments Specification </a>. This <code>EbxmlMessage</code>
* encapsulates a <code>javax.xml.soap.SOAPMessage</code>.
*
* @author cyng
* @version $Revision: 1.1 $
*/
public class EbxmlMessage {
/**
* SOAPAction in the SOAP message MIME header
*/
public final static String SOAP_ACTION = "SOAPAction";
/**
* SOAPAction value in the SOAP message MIME header
*/
public final static String SOAP_ACTION_VALUE = "\"ebXML\"";
/**
* Default content id of soap part
*/
public final static String SOAP_PART_CONTENT_ID = "soappart";
/**
* MIME boundary generated
*/
public final static String mimeBoundary = "----=_BOUNDARY_01";
/**
* Description of the Field
*/
public static boolean needPatch = false;
/**
* Default value of writing XML declaration in front of message
*/
public final static boolean WRITE_XML_DECLARATION = true;
/**
* Default value XML character set
*/
public final static String CHARACTER_SET_ENCODING = "UTF-8";
// check if content id need to be patched with current SOAP implementation
static {
String s = "--MIMEBoundary\r\nContent-Type: text/xml\r\n\r\n"
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
+ "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/"
+ "soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body/>"
+ "</SOAP-ENV:Envelope>\r\n--MIMEBoundary\r\n"
+ "Content-Type: text/plain\r\nContent-Id: <ebxmlms>\r\n\r\n"
+ "ebxmlms\r\n--MIMEBoundary--\r\n";
try {
MimeHeaders headers = new MimeHeaders();
headers.setHeader(Constants.CONTENT_TYPE,
Constants.MULTIPART_RELATED_TYPE + "MIMEBoundary");
ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
SOAPMessage message = MessageFactory.newInstance().createMessage(
headers, bais);
String contentId = ((AttachmentPart) message.getAttachments()
.next()).getContentId();
needPatch = (contentId.startsWith("<") ? true : false);
} catch (Exception e) {
}
}
/**
* A SOAP message representing the header of this <code>EbxmlMessage</code>,
* which is composed of the <code>HeaderContainer</code> and the
* <code>PayloadContainer</code>
*/
private SOAPMessage soapMessage;
/**
* SOAP message envelope, which contains an optional header and a mandatory
* body [SOAP 1.1 Section 4].
*/
private SOAPEnvelope soapEnvelope;
/**
* SOAP header [SOAP 1.1 Section 4.2].
*/
private HeaderContainer headerContainer;
/**
* Message Order element [ebMSS 9].
*/
private MessageOrder messageOrder;
/**
* ebXML message payloads as SOAP attachments.
*/
private ArrayList payloadContainers;
private byte[] soapEnvelopeBytes = null;
/**
* Optional file name in which the message is persisted.
*/
private String filename;
/**
* Optional persistence name in which the message is persisted
*/
private String persistenceName;
/**
* Optional persistence handler in which the message is persisted
*/
private Object persistenceHandler;
private DataSource datasource;
private byte[] bytes;
/**
* @return Returns the bytestream.
*/
public byte[] getBytes() {
return bytes;
}
/**
* @param bytes
* The bytestream to set.
*/
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
/**
* @return Returns the datasource.
*/
public DataSource getDatasource() {
return datasource;
}
/**
* @return Returns the headerContainer.
*/
public HeaderContainer getHeaderContainer() {
return headerContainer;
}
/**
* Constructs an <code>EbxmlMessage</code> using the default JAXM
* <code>MessageFactory</code> implementation
*
* @exception SOAPException
* Description of the Exception
*/
public EbxmlMessage() throws SOAPException {
this(MessageFactory.newInstance());
}
/**
* Constructs an <code>EbxmlMessage</code> using the provided
* <code>javax.xml.soap.MessageFactory</code>
*
* @param messageFactory
* <code>MessageFactory</code> for creating message.
* @exception SOAPException
* Description of the Exception
*/
public EbxmlMessage(MessageFactory messageFactory) throws SOAPException {
this(messageFactory.createMessage());
}
/**
* construct an <code>EbxmlMessage</code> from File using the logic in
* MessageServer. The file must not contain any content header like
* Content-Type
*
* @param file
* the file contain the messsage.
* @exception SOAPException
* Description of the Exception
* @exception IOException
* Description of the Exception
*/
public EbxmlMessage(File file) throws SOAPException, IOException {
/*
* EbxmlMessage message = null; message = (EbxmlMessage)
* getMessageFromDataSource( new FileDataSource(file), true);
* init(message);
*/
getMessageFromDataSource(new FileDataSource(file), true, this);
}
/**
* constructs an <code>EbxmlMessage</code> from InputStream using the
* logic in MessageServer. The input stream must not contain any content
* headers like Content-type.
*
* @param inputStream
* Description of the Parameter
* @exception SOAPException
* Description of the Exception
* @exception IOException
* Description of the Exception
*/
public EbxmlMessage(InputStream inputStream) throws SOAPException,
IOException {
/*
* EbxmlMessage message = null; message = (EbxmlMessage)
* getMessageFromDataSource( new AttachmentDataSource(inputStream,
* Constants.SERIALIZABLE_OBJECT), true); init(message);
*/
getMessageFromDataSource(new AttachmentDataSource(inputStream,
Constants.SERIALIZABLE_OBJECT), true, this);
}
/**
* Constructs an <code>EbxmlMessage</code> using the given
* <code>SOAPMessage</code>
*
* @param soapMessage
* @exception SOAPException
* Description of the Exception
*/
public EbxmlMessage(SOAPMessage soapMessage) throws SOAPException {
init(soapMessage);
}
/**
* initialize the object using Ebxml message.
*
* @param message
* Description of the Parameter
* @throws SOAPException
* Description of the Exception
*/
private void init(EbxmlMessage message) throws SOAPException {
init(message.getSOAPMessage());
//MessageServer.getMessageFromInputStream(inputStream, true);
this.soapMessage = message.getSOAPMessage();
this.soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
payloadContainers = message.payloadContainers;
soapEnvelopeBytes = message.getSoapEnvelopeBytes();
}
/**
* initialize the object using SOAP message.
*
* @param soapMessage
* Description of the Parameter
* @throws SOAPException
* Description of the Exception
*/
private void init(SOAPMessage soapMessage) throws SOAPException {
this.soapMessage = soapMessage;
// set default SOAP XML declaration and encoding
this.soapMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION,
Boolean.toString(EbxmlMessage.WRITE_XML_DECLARATION));
this.soapMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
EbxmlMessage.CHARACTER_SET_ENCODING);
this.soapEnvelope = this.soapMessage.getSOAPPart().getEnvelope();
headerContainer = new HeaderContainer(soapMessage.getSOAPPart());
payloadContainers = new ArrayList();
/*
* this.soapMessage = soapMessage; this.soapEnvelope =
* soapMessage.getSOAPPart().getEnvelope(); final SOAPHeader soapHeader =
* soapEnvelope.getHeader(); final SOAPBody soapBody =
* soapEnvelope.getBody(); headerContainer = new
* HeaderContainer(soapMessage.getSOAPPart()); payloadContainers = new
* ArrayList();
*/
Manifest manifest = headerContainer.getManifest();
if (manifest != null) {
Iterator it = manifest.getReferences();
HashMap cidMap = new HashMap();
while (it.hasNext()) {
Reference reference = (Reference) it.next();
String cid = reference.getHref();
if (cid.startsWith(Reference.HREF_PREFIX)) {
cid = cid.substring(Reference.HREF_PREFIX.length());
cidMap.put(cid, reference);
}
}
for (Iterator attachments = soapMessage.getAttachments(); attachments
.hasNext();) {
final AttachmentPart attachment = (AttachmentPart) attachments
.next();
String contentId = attachment.getContentId();
if (contentId.startsWith("<") && needPatch) {
contentId = contentId.substring(1);
if (contentId.endsWith(">")) {
contentId = contentId.substring(0,
contentId.length() - 1);
}
}
contentId = contentId.trim();
if (cidMap.containsKey(contentId)) {
payloadContainers.add(new PayloadContainer(attachment
.getDataHandler(), contentId, (Reference) cidMap
.get(contentId)));
}
}
}
String[] soapAction = this.soapMessage.getMimeHeaders().getHeader(
SOAP_ACTION);
if (headerContainer.getMessageHeader() == null || soapAction == null
|| !soapAction[0].equals(SOAP_ACTION_VALUE)) {
this.soapMessage.getMimeHeaders().setHeader(SOAP_ACTION,
SOAP_ACTION_VALUE);
}
String soapPartContentId = this.soapMessage.getSOAPPart()
.getContentId();
if (soapPartContentId == null || soapPartContentId.equals("")) {
soapPartContentId = (
needPatch ? " <" + SOAP_PART_CONTENT_ID +
">" :
SOAP_PART_CONTENT_ID);
this.soapMessage.getSOAPPart().setContentId(soapPartContentId);
}
/*
* String[] soapAction =
* soapMessage.getMimeHeaders().getHeader(SOAP_ACTION); if
* (headerContainer.getMessageHeader() == null || soapAction == null ||
* !soapAction[0].equals(SOAP_ACTION_VALUE)) {
* soapMessage.getMimeHeaders(). setHeader(SOAP_ACTION,
* SOAP_ACTION_VALUE); } String soapPartContentId =
* soapMessage.getSOAPPart().getContentId(); if (soapPartContentId ==
* null || soapPartContentId.equals("")) { soapPartContentId =
* (needPatch ? " <" + SOAP_PART_CONTENT_ID + ">" :
* SOAP_PART_CONTENT_ID);
* soapMessage.getSOAPPart().setContentId(soapPartContentId); }
*/
filename = null;
messageOrder = null;
}
/**
* Constructs a <code>EbxmlMessage</code> using the given
* <code>InputStream</code> and default JAXM <code>MessageFactory</code>
* implementation
*
* @param headers
* MIME headers to be included in the message.
* @param in
* Message content in form of <code>InputStream</code>.
* @exception IOException
* Description of the Exception
* @exception SOAPException
* Description of the Exception
*/
public EbxmlMessage(MimeHeaders headers, InputStream in)
throws IOException, SOAPException {
this(MessageFactory.newInstance().createMessage(headers, in));
}
/**
* Gets the <code>SOAPMessage</code> encapsulated in this
* <code>EbxmlMessage</code>.
*
* @return <code>SOAPMessage</code> representing this
* <code>EbxmlMessage</code>
*/
public SOAPMessage getSOAPMessage() {
return soapMessage;
}
/**
* Adds a <code>MessageHeader</code> to this <code>EbxmlMessage</code>
* with the given mandatory fields
*
* @param fromPartyId
* Party ID of the sender [ebMSS 3.1.1.1]
* @param toPartyId
* Party ID of the receiver [ebMSS 3.1.1.1]
* @param cpaId
* CPA Id [ebMSS 3.1.2]
* @param conversationId
* ID of the conversation in which this message is involved
* [ebMSS 3.1.3]
* @param service
* Service name [ebMSS 3.1.4]
* @param action
* Action name [ebMSS 3.1.5]
* @param messageId
* Unique identifier of the message [ebMSS 3.1.6.1]
* @param timestamp
* Date/time of the message header creation expressed as UTC
* [ebMSS 3.1.6.2]
* @return the newly added <code>MessageHeader</code>
* @throws SOAPException
* Description of the Exception
*/
public MessageHeader addMessageHeader(String fromPartyId, String toPartyId,
String cpaId, String conversationId, String service, String action,
String messageId, String timestamp) throws SOAPException {
return addMessageHeader(fromPartyId, null, toPartyId, null, cpaId,
conversationId, service, action, messageId, timestamp);
}
/**
* Adds a <code>MessageHeader</code> to this <code>EbxmlMessage</code>
* with the given mandatory fields
*
* @param fromPartyId
* Party ID of the sender [ebMSS 3.1.1.1]
* @param fromPartyIdType
* PartyID type of the sender [ebMSS 3.1.1.1]
* @param toPartyId
* Party ID of the receiver [ebMSS 3.1.1.1]
* @param toPartyIdType
* PartyID type of the receiver [ebMSS 3.1.1.1]
* @param cpaId
* CPA Id [ebMSS 3.1.2]
* @param conversationId
* ID of the conversation in which this message is involved
* [ebMSS 3.1.3]
* @param service
* Service name [ebMSS 3.1.4]
* @param action
* Action name [ebMSS 3.1.5]
* @param messageId
* Unique identifier of the message [ebMSS 3.1.6.1]
* @param timestamp
* Date/time of the message header creation expressed as UTC
* [ebMSS 3.1.6.2]
* @return the newly added <code>MessageHeader</code>
* @throws SOAPException
* Description of the Exception
*/
public MessageHeader addMessageHeader(String fromPartyId,
String fromPartyIdType, String toPartyId, String toPartyIdType,
String cpaId, String conversationId, String service, String action,
String messageId, String timestamp) throws SOAPException {
MessageHeader messageHeader = new MessageHeader(soapEnvelope,
fromPartyId, fromPartyIdType, toPartyId, toPartyIdType, cpaId,
conversationId, service, action, messageId, timestamp);
headerContainer.addExtensionElement(messageHeader);
return messageHeader;
}
/**
* Adds a default <code>MessageHeader</code> to this
* <code>EbxmlMessage</code>.
*
* @return the newly added <code>MessageHeader</code>
* @throws SOAPException
*/
public MessageHeader addMessageHeader() throws SOAPException {
MessageHeader messageHeader = new MessageHeader(soapEnvelope);
headerContainer.addExtensionElement(messageHeader);
return messageHeader;
}
/**
* Get the message header of this ebXML message.
*
* @return <code>MessageHeader</code> of this ebXML message.
*/
public MessageHeader getMessageHeader() {
return headerContainer.getMessageHeader();
}
/**
* Gets the list of from party IDs. There can be multiple party IDs [ebMSS
* 3.1.1].
*
* @return Iterator pointing to a list of party IDs.
*/
public Iterator getFromPartyIds() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return new ArrayList().iterator();
}
return messageHeader.getFromPartyIds();
}
/**
* Gets the list of to party IDs. There can be multiple party IDs [ebMSS
* 3.1.1].
*
* @return Iterator pointing to a list of party IDs.
*/
public Iterator getToPartyIds() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return new ArrayList().iterator();
}
return messageHeader.getToPartyIds();
}
/**
* Gets cpaId
*
* @return CPA ID
*/
public String getCpaId() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getCpaId();
}
/**
* Gets conversationId
*
* @return Conversation ID
*/
public String getConversationId() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getConversationId();
}
/**
* Gets service name
*
* @return Service name.
*/
public String getService() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getService();
}
/**
* Gets service type
*
* @return Service type.
*/
public String getServiceType() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getServiceType();
}
/**
* Gets action name
*
* @return Action name
*/
public String getAction() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getAction();
}
/**
* Gets messageId
*
* @return Unique message identifier
*/
public String getMessageId() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getMessageId();
}
/**
* Gets timestamp
*
* @return Timestamp of the message expressed in UTC format.
*/
public String getTimestamp() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getTimestamp();
}
/**
* Gets TimeToLive of the message
*
* @return TimeToLive expressed in UTC format.
*/
public String getTimeToLive() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return null;
}
return messageHeader.getTimeToLive();
}
/**
* Gets the flag stating if duplicate elimination is enabled or not.
*
* @return true if duplicate elimination is required; false otherwise.
*/
public boolean getDuplicateElimination() {
final MessageHeader messageHeader = headerContainer.getMessageHeader();
if (messageHeader == null) {
return false;
}
return messageHeader.getDuplicateElimination();
}
/**
* Add a SyncReply element to the message.
*
* @throws SOAPException
*/
public void addSyncReply() throws SOAPException {
if (getMessageOrder() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ MessageOrder.MESSAGE_ORDER
+ "> has already been added which must not exist "
+ "togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ SyncReply.SYNC_REPLY + ">!");
}
headerContainer.addExtensionElement(new SyncReply(soapEnvelope));
}
/**
* Gets the flag stating if sync reply is enabled or not.
*
* @return true if sync reply is enabled; false otherwise.
*/
public boolean getSyncReply() {
final SyncReply syncReply = headerContainer.getSyncReply();
return (syncReply != null);
}
/**
* Add acknowledgement request element to the message.
*
* @param signed
* The feature to be added to the AckRequested attribute
* @throws SOAPException
*/
public void addAckRequested(boolean signed) throws SOAPException {
headerContainer.addExtensionElement(new AckRequested(soapEnvelope,
signed));
if (messageOrder != null) {
headerContainer.addExtensionElement(messageOrder);
headerContainer.getMessageHeader().setDuplicateElimination();
}
}
/**
* Get acknowledgement request element.
*
* @return <code>AckRequested</code> object representing the element.
*/
public AckRequested getAckRequested() {
return headerContainer.getAckRequested();
}
/**
* Add acknowledgement element to the message using given timestamp,
* refToMessageId.
*
* @param timestamp
* Timestamp string expressed in UTC format.
* @param refToMessage
* The feature to be added to the Acknowledgment attribute
* @throws SOAPException
* Description of the Exception
*/
public void addAcknowledgment(String timestamp, EbxmlMessage refToMessage)
throws SOAPException {
addAcknowledgment(timestamp, refToMessage, null, null);
}
/**
* Add acknowledgement element to the message using given timestamp,
* refToMessageId and fromPartyId.
*
* @param timestamp
* Timestamp string expressed in UTC format.
* @param fromPartyId
* Sender party ID.
* @param refToMessage
* The feature to be added to the Acknowledgment attribute
* @throws SOAPException
* Description of the Exception
*/
public void addAcknowledgment(String timestamp, EbxmlMessage refToMessage,
String fromPartyId) throws SOAPException {
addAcknowledgment(timestamp, refToMessage, fromPartyId, null);
}
/**
* Add acknowledgement element to the message using given timestamp,
* refToMessageId, fromPartyId and fromPartyIdType.
*
* @param timestamp
* Timestamp string expressed in UTC format.
* @param fromPartyId
* Sender party ID.
* @param fromPartyIdType
* Sender party ID type.
* @param refToMessage
* The feature to be added to the Acknowledgment attribute
* @throws SOAPException
* Description of the Exception
*/
public void addAcknowledgment(String timestamp, EbxmlMessage refToMessage,
String fromPartyId, String fromPartyIdType) throws SOAPException {
final Acknowledgment acknowledgment = new Acknowledgment(soapEnvelope,
timestamp, refToMessage, fromPartyId, fromPartyIdType);
String actor = refToMessage.getAckRequested().getActor();
if (actor != null) {
acknowledgment.setActor(actor);
}
headerContainer.addExtensionElement(acknowledgment);
}
/**
* Get acknowledgement element.
*
* @return <code>Acknowledgement</code> object representing the element.
*/
public Acknowledgment getAcknowledgment() {
return headerContainer.getAcknowledgment();
}
/**
* Add an error list to the message using given error code, severity and
* description.
*
* @param errorCode
* [ebMSS 4.2.3.4]
* @param severity
* Valid values are "Error" and "Warning".
* @param description
* Description of the error.
* @throws SOAPException
* Description of the Exception
*/
public void addErrorList(String errorCode, String severity,
String description) throws SOAPException {
addErrorList(errorCode, severity, description, null);
}
/**
* Add an error list to the message using given error code, severity and
* description.
*
* @param errorCode
* [ebMSS 4.2.3.4]
* @param severity
* Valid values are "Error" and "Warning".
* @param description
* Description of the error.
* @param location
* Location of the message containing the error.
* @throws SOAPException
*/
public void addErrorList(String errorCode, String severity,
String description, String location) throws SOAPException {
if (headerContainer.getStatusRequest() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusRequest.STATUS_REQUEST
+ "> has already been "
+ "added which must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ ErrorList.ERROR_LIST + ">!");
}
final ErrorList errorList = new ErrorList(soapEnvelope, errorCode,
severity, description, ExtensionElement.LANG_TYPE, location);
headerContainer.addExtensionElement(errorList);
}
/**
* Get the error list in the message.
*
* @return <code>ErrorList</code> object containing error list in the
* message. Returns null if it does not exist.
*/
public ErrorList getErrorList() {
return headerContainer.getErrorList();
}
/**
* Add a status request element to the message.
*
* @param refToMessageId
* Identifier of the message it is referring to.
* @throws SOAPException
*/
public void addStatusRequest(String refToMessageId) throws SOAPException {
if (headerContainer.getStatusResponse() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusResponse.STATUS_RESPONSE
+ "> has already been "
+ "added which must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusRequest.STATUS_REQUEST + ">!");
}
if (headerContainer.getManifest() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ Manifest.MANIFEST
+ "> has already been added which "
+ "must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusRequest.STATUS_REQUEST + ">!");
}
if (headerContainer.getErrorList() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ ErrorList.ERROR_LIST
+ "> has already been added which"
+ " must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusRequest.STATUS_REQUEST + ">!");
}
final StatusRequest statusRequest = new StatusRequest(soapEnvelope,
refToMessageId);
headerContainer.addExtensionElement(statusRequest);
}
/**
* Get the status request element in the message.
*
* @return Content of the status request element stored in
* <code>StatusRequest</code> object.
*/
public StatusRequest getStatusRequest() {
return headerContainer.getStatusRequest();
}
/**
* Add a status response element to the message.
*
* @param refToMessageId
* Identifier of the message it is referring to.
* @param messageStatus
* Status string to be added in the response element.
* @throws SOAPException
*/
public void addStatusResponse(String refToMessageId, String messageStatus)
throws SOAPException {
addStatusResponse(refToMessageId, messageStatus, null);
}
/**
* Add a status response element to the message.
*
* @param refToMessageId
* Identifier of the message it is referring to.
* @param messageStatus
* Status string to be added in the response element.
* @param timestamp
* Timestamp of the status response expressed in UTC format.
* @throws SOAPException
*/
public void addStatusResponse(String refToMessageId, String messageStatus,
String timestamp) throws SOAPException {
if (headerContainer.getStatusRequest() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusRequest.STATUS_REQUEST
+ "> has already been "
+ "added which must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusResponse.STATUS_RESPONSE + ">!");
}
if (headerContainer.getManifest() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ Manifest.MANIFEST
+ "> has already been added which "
+ "must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusResponse.STATUS_RESPONSE + ">!");
}
if (headerContainer.getErrorList() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ ErrorList.ERROR_LIST
+ "> has already been added which"
+ " must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusResponse.STATUS_RESPONSE + ">!");
}
final StatusResponse statusResponse = new StatusResponse(soapEnvelope,
refToMessageId, messageStatus, timestamp);
headerContainer.addExtensionElement(statusResponse);
}
/**
* Get the status response element in the message.
*
* @return Content of the status response element stored in
* <code>StatusResponse</code> object.
*/
public StatusResponse getStatusResponse() {
return headerContainer.getStatusResponse();
}
/**
* Add a MessageOrder element to the header.
*
* @param status
* Status of the sequence number. It should have the value of
* either MessageOrder.STATUS_RESET or
* MessageOrder.STATUS_CONTINUE.
* @param sequenceNumber
* Sequence number to be assigned to this message.
* @throws SOAPException
* Description of the Exception
*/
public void addMessageOrder(int status, int sequenceNumber)
throws SOAPException {
if (messageOrder == null) {
messageOrder = new MessageOrder(soapEnvelope, status,
sequenceNumber);
if (headerContainer.getAckRequested() != null) {
headerContainer.addExtensionElement(messageOrder);
headerContainer.getMessageHeader().setDuplicateElimination();
}
} else {
throw new SOAPValidationException(
SOAPValidationException.SOAP_FAULT_CLIENT, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ MessageOrder.MESSAGE_ORDER
+ "> has already been " + "added.");
}
}
/**
* Get the message order element in the message.
*
* @return <code>MessageOrder</code> object if it exists in the ebXML
* message; null otherwise.
*/
public MessageOrder getMessageOrder() {
return headerContainer.getMessageOrder();
}
/**
* Get the digital signatures in the message.
*
* @return Iterator of <code>Signature</code> objects in the message.
*/
public Iterator getSignatures() {
return headerContainer.getSignatures();
}
/**
* Add an ebXML message payload container.
*
* @param dataHandler
* the <code>DataHandler</code> that generates the payload
* content.
* @param contentId
* the contentId of this payload attachment. The contentId must
* be unique among all payload attachment.
* @param description
* the description of this payload.
* @return the <code>PayloadContainer</code> object that is created and
* added.
* @throws SOAPException
*/
public PayloadContainer addPayloadContainer(DataHandler dataHandler,
String contentId, String description) throws SOAPException {
if (headerContainer.getStatusRequest() != null) {
throw new EbxmlValidationException(
EbxmlValidationException.EBXML_ERROR_INCONSISTENT,
EbxmlValidationException.SEVERITY_ERROR, "<"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ StatusRequest.STATUS_REQUEST
+ "> has already been "
+ "added which must not exist togther with <"
+ ExtensionElement.NAMESPACE_PREFIX_EB + ":"
+ Manifest.MANIFEST
+ "> referring to added payloads!");
}
Manifest manifest = headerContainer.getManifest();
if (manifest == null) {
manifest = new Manifest(soapEnvelope);
headerContainer.addExtensionElement(manifest);
}
final Reference reference = manifest.addReference(contentId,
Reference.HREF_PREFIX + contentId);
reference.addDescription(description);
final PayloadContainer payload;
if (needPatch) {
payload = new PayloadContainer(dataHandler, "<" + contentId + ">",
reference);
} else {
payload = new PayloadContainer(dataHandler, contentId, reference);
}
payloadContainers.add(payload);
// we now keep the SOAP message object away from attachment to avoid
// it to load the payload to memory
AttachmentPart attachment = soapMessage.createAttachmentPart();
attachment.setContentId(needPatch ? " <" + contentId +
">" : contentId);
attachment.setDataHandler(dataHandler);
soapMessage.addAttachmentPart(attachment);
return payload;
}
/**
* Gets all <code>PayloadContainer</code>s' attached in this
* <code>EbxmlMessage</code> object.
*
* @return An iterator point to a list of payload containers.
*/
public Iterator getPayloadContainers() {
return payloadContainers.iterator();
}
/**
* Sets the <code>PayloadContainer</code>
*
* @param payloads
* The new payloadContainers value
* @return The old payload container as an array list
*/
public ArrayList setPayloadContainers(ArrayList payloads) {
ArrayList oldPayloads = this.payloadContainers;
this.payloadContainers = payloads;
return oldPayloads;
}
/**
* Gets the payload that is identified by the given content ID.
*
* @param contentId
* Content ID of the payload to be retrieved.
* @return <code>PayloadContainer</code> of the given content ID or
* <code>null</code> if no such <code>PayloadContainer</code>
* exists
*/
public PayloadContainer getPayloadContainer(String contentId) {
for (Iterator i = payloadContainers.iterator(); i.hasNext();) {
final PayloadContainer payload = (PayloadContainer) i.next();
if (payload.getContentId().equals(contentId)) {
return payload;
}
}
return null;
}
/**
* Gets the number of payloads in this ebXML message
*
* @return the number of payloads
*/
public int getPayloadCount() {
return payloadContainers.size();
}
/**
* Gets the Manifest element in this ebXML message
*
* @return Manifest element
*/
public Manifest getManifest() {
return headerContainer.getManifest();
}
/**
* Updates the encapsulated <code>SOAPMessage</code> with all changes that
* have been made to it.
*
* @throws SOAPException
* @see javax.xml.soap.SOAPMessage#saveChanges()
*/
public void saveChanges() throws SOAPException {
// It may cause lose of attachment in JDK1.6.
soapMessage.saveChanges();
}
/**
* Indicates whether the encapsulated <code>SOAPMessage</code> need to be
* updated by calling <code>saveChanges</code> on it.
*
* @return true if it is required to call saveChanges on the message; false
* otherwise.
* @see javax.xml.soap.SOAPMessage#saveRequired()
*/
public boolean saveRequired() {
return soapMessage.saveRequired();
}
/**
* Gets the MIME headers of this ebXML message
*
* @return the MIME headers of this ebXML message
* @throws IOException
* Description of the Exception
* @throws SOAPException
* Description of the Exception
*/
public Map getMimeHeaders() throws IOException, SOAPException {
return getMimeHeaders(Constants.DEFAULT_CONTENT_TRANSFER_ENCODING,
Constants.DEFAULT_CONTENT_TRANSFER_ENCODING);
}
/**
* Gets the MIME headers of this ebXML message
*
* @param soapEncoding
* content transfer encoding to be applied to SOAP part when
* computing length
* @param payloadEncoding
* content transfer encoding to be applied to payload when
* computing length
* @return the MIME headers of this ebXML message
* @throws IOException
* Description of the Exception
* @throws SOAPException
* Description of the Exception
*/
public Map getMimeHeaders(String soapEncoding, String payloadEncoding)
throws IOException, SOAPException {
HashMap headers = new HashMap();
// fill in Content-Type
String contentType;
if (getPayloadCount() > 0) {
if (needPatch) {
contentType = Constants.MULTIPART_RELATED_TYPE + "\""
+ mimeBoundary + "\"; " + Constants.CHARACTER_SET
+ "=\"" + Constants.CHARACTER_ENCODING + "\"; "
+ Constants.START + "=\"<"
+ soapMessage.getSOAPPart().getContentId() + ">\"";
} else {
contentType = Constants.MULTIPART_RELATED_TYPE + "\""
+ mimeBoundary + "\"; " + Constants.CHARACTER_SET
+ "=\"" + Constants.CHARACTER_ENCODING + "\"; "
+ Constants.START + "=\""
+ soapMessage.getSOAPPart().getContentId() + "\"";
}
} else {
contentType = Constants.TEXT_XML_TYPE + "; "
+ Constants.CHARACTER_SET + "=\""
+ Constants.CHARACTER_ENCODING + "\"";
}
headers.put(Constants.CONTENT_TYPE, contentType);
// fill in Content-Length
headers.put(Constants.CONTENT_LENGTH, String.valueOf(serialize(null,
soapEncoding, payloadEncoding, true)));
// fill in SOAPAction
headers.put(SOAP_ACTION, SOAP_ACTION_VALUE);
return headers;
}
/**
* Walks through the serialization process to get the content length. It can
* do the actually serialization also optionally
*
* @param out
* <code>OutputStream</code> to write the message to.
* @param soapEncoding
* content transfer encoding to be applied to SOAPPart
* @param payloadEncoding
* content transfer encoding to be applied to payload
* @param getLengthOnly
* get length only and do no actual serialization
* @return the content length of the serialization
* @throws IOException
* @throws SOAPException
*/
private long serialize(OutputStream out, String soapEncoding,
String payloadEncoding, boolean getLengthOnly) throws IOException,
SOAPException {
/*
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os;
try {
os = MimeUtility.encode(baos, soapEncoding);
} catch (Exception e) {
throw new SOAPException("Content-Transfer-Encoding encode error: "
+ e.getMessage());
}
soapMessage.writeTo(os);
long soapMessageLength = baos.toByteArray().length;
long totalLength = 0;
try {
os = MimeUtility.encode(out, soapEncoding);
} catch (Exception e) {
throw new SOAPException("Content-Transfer-Encoding encode error: "
+ e.getMessage());
}
Iterator i = getPayloadContainers();
// not multipart
if (!i.hasNext()) {
if (!getLengthOnly) {
soapMessage.writeTo(os);
os.flush();
}
return soapMessageLength;
}
String buffer;
byte[] bytes;
// print SOAP part
buffer = Constants.MIME_BOUNDARY_PREFIX + mimeBoundary + Constants.CRLF;
buffer = buffer + Constants.CONTENT_TYPE + ": "
+ Constants.TEXT_XML_TYPE + "; " + Constants.CHARACTER_SET
+ "=\"" + Constants.CHARACTER_ENCODING + "\"" + Constants.CRLF;
if (needPatch) {
buffer = buffer + Constants.CONTENT_ID + ": <"
+ soapMessage.getSOAPPart().getContentId() + ">"
+ Constants.CRLF;
} else {
buffer = buffer + Constants.CONTENT_ID + ": "
+ soapMessage.getSOAPPart().getContentId() + Constants.CRLF;
}
buffer = buffer + Constants.CONTENT_TRANSFER_ENCODING + ": "
+ soapEncoding + Constants.CRLF;
buffer = buffer + Constants.CRLF;
bytes = buffer.getBytes(Constants.CHARACTER_ENCODING);
totalLength += bytes.length;
totalLength += soapMessageLength;
if (!getLengthOnly) {
out.write(bytes);
out.flush();
soapMessage.writeTo(os);
os.flush();
}
bytes = Constants.CRLF.getBytes(Constants.CHARACTER_ENCODING);
totalLength += bytes.length;
if (!getLengthOnly) {
out.write(bytes);
out.flush();
}
// print payloads
while (i.hasNext()) {
PayloadContainer pc = (PayloadContainer) i.next();
buffer = Constants.MIME_BOUNDARY_PREFIX + mimeBoundary
+ Constants.CRLF;
buffer = buffer + Constants.CONTENT_TYPE + ": "
+ pc.getContentType() + Constants.CRLF;
System.out.println("Payload Container Content-id: '"+pc.getContentId());
buffer = buffer
+ Constants.CONTENT_ID
+ ": "
+ (needPatch ? "<" + pc.getContentId() + ">" : pc
.getContentId()) + Constants.CRLF;
System.out.println("Buffer : " + buffer.toString());
buffer = buffer + Constants.CONTENT_TRANSFER_ENCODING + ": "
+ payloadEncoding + Constants.CRLF;
buffer = buffer + Constants.CRLF;
bytes = buffer.getBytes(Constants.CHARACTER_ENCODING);
totalLength += bytes.length;
if (!getLengthOnly) {
System.out.println("can you write those bytes " + out.getClass());
out.write(bytes);
out.flush();
}
long payloadLength = pc.getContentLength();
if (payloadLength == -1 || !getLengthOnly
|| !payloadEncoding.equalsIgnoreCase("binary")) {
InputStream in = pc.getDataHandler().getInputStream();
byte[] b = new byte[4096];
int bytesRead;
long totalBytes = 0;
try {
os = MimeUtility.encode(out, payloadEncoding);
} catch (Exception e) {
throw new SOAPException(
"Content-Transfer-Encoding encode error: "
+ e.getMessage());
}
while ((bytesRead = in.read(b)) > 0) {
totalBytes += bytesRead;
if (!getLengthOnly) {
os.write(b, 0, bytesRead);
os.flush();
}
}
payloadLength = totalBytes;
}
totalLength += payloadLength;
bytes = Constants.CRLF.getBytes(Constants.CHARACTER_ENCODING);
totalLength += bytes.length;
if (!getLengthOnly) {
out.write(bytes);
}
}
// print last boundary
buffer = Constants.MIME_BOUNDARY_PREFIX + mimeBoundary + "--"
+ Constants.CRLF;
bytes = buffer.getBytes(Constants.CHARACTER_ENCODING);
totalLength += bytes.length;
if (!getLengthOnly) {
out.write(bytes);
}
return totalLength;
*/
soapMessage.writeTo(out);
return 0;
}
/**
* Writes the encapsulated <code>SOAPMessage</code> to the given output
* stream. The externalization format is as defined by the SOAP 1.1 with
* Attachments Specification.
*
* @param out
* <code>OutputStream</code> to write the message to.
* @throws IOException
* Description of the Exception
* @throws SOAPException
* Description of the Exception
*/
public void writeTo(OutputStream out) throws IOException, SOAPException {
// we now keep the SOAP message object away from attachment to avoid
// it to load the payload to memory, therefore we are doing our own
// writeTo() here
// soapMessage.writeTo(out);
serialize(out, Constants.DEFAULT_CONTENT_TRANSFER_ENCODING,
Constants.DEFAULT_CONTENT_TRANSFER_ENCODING, false);
}
/**
* Writes the encapsulated <code>SOAPMessage</code> to the given output
* stream. The externalization format is as defined by the SOAP 1.1 with
* Attachments Specification.
*
* @param out
* <code>OutputStream</code> to write the message to.
* @param soapEncoding
* Description of the Parameter
* @param payloadEncoding
* Description of the Parameter
* @throws IOException
* Description of the Exception
* @throws SOAPException
* Description of the Exception
*/
public void writeTo(OutputStream out, String soapEncoding,
String payloadEncoding) throws IOException, SOAPException {
// we now keep the SOAP message object away from attachment to avoid
// it to load the payload to memory, therefore we are doing our own
// writeTo() here
// soapMessage.writeTo(out);
serialize(out, soapEncoding, payloadEncoding, false);
}
/**
* Checks whether the number of payloads in the SOAP message matches with
* the Manifest element in the header or not.
*
* @return true if the number of payloads is consistent, false otherwise.
*/
/*
* public boolean isNumPayloadConsistent() { Manifest manifest =
* headerContainer.getManifest(); if (manifest == null) { / no manifest
* exist.. assume ok. return true; } ArrayList contentIDs = new ArrayList();
* Iterator i = getPayloadContainers(); while (i.hasNext()) {
* PayloadContainer pc = (PayloadContainer) i.next();
* contentIDs.add(pc.getContentId()); } i = manifest.getReferences(); while
* (i.hasNext()) { Reference r = (Reference) i.next(); String cid =
* r.getHref(); if (cid.startsWith("cid:")) { cid = cid.substring(4); } if
* (!contentIDs.contains(cid)) { payloadInError = cid; return false; } }
* return true; }
*/
/**
* Checks whether the number of payloads in the SOAP message matches with
* the Manifest element in the header or not, and return the Content-ID of
* the inconsistent payload.
*
* @return content-id of the inconsistent payload; null if all payloads are
* consistent.
*/
public String getPayloadInError() {
Manifest manifest = headerContainer.getManifest();
if (manifest == null) {
// no manifest exist.. assume ok.
return null;
}
ArrayList contentIDs = new ArrayList();
Iterator i = getPayloadContainers();
while (i.hasNext()) {
PayloadContainer pc = (PayloadContainer) i.next();
contentIDs.add(pc.getContentId());
}
i = manifest.getReferences();
while (i.hasNext()) {
Reference r = (Reference) i.next();
String cid = r.getHref();
if (cid.startsWith("cid:")) {
cid = cid.substring(4);
}
if (!contentIDs.contains(cid)) {
return cid;
}
}
return null;
}
/**
* Sets the fileName attribute of the EbxmlMessage object. This function
* will only be used by the Hermes Server itself, and it is not expected for
* the client to call it.
*
* @param filename
* The new fileName value
*/
public void setFileName(String filename) {
this.filename = filename;
}
/**
* Gets the fileName attribute of the EbxmlMessage object. This function
* will only be used by the Hermes Server itself, and it is not expected for
* the client to call it.
*
* @return The fileName value
*/
public String getFileName() {
return filename;
}
/**
* Get the soap envelope in bytes. This function will only be used by the
* Hermes Server itself, and it is not expected for the client to call it.
*/
byte[] getSoapEnvelopeBytes() {
return soapEnvelopeBytes;
}
/**
* set the soap envelope in bytes. Those bytes will be used to verify This
* function will only be used by the Hermes Server itself, and it is not
* expected for the client to call it. the signature.
*/
public void setSoapEnvelopeBytes(byte[] soapEnvelopeBytes) {
this.soapEnvelopeBytes = soapEnvelopeBytes;
}
/**
* set the persistence info to the message This function will only be used
* by the Hermes Server itself, and it is not expected for the client to
* call it.
*
* @param persistenceName
* the name on the persistence handler
* @param handler
* the persistence handler
*/
public void setPersistenceInfo(String persistenceName, Object handler,
DataSource datasource) {
this.persistenceName = persistenceName;
persistenceHandler = handler;
this.datasource = datasource;
}
/**
* get the Persistence name if it is stored. This function will only be used
* by the Hermes Server itself, and it is not expected for the client to
* call it.
*
* @return the persitence name
*/
public String getPersistenceName() {
return persistenceName;
}
/**
* get the persistence handler if it is stored. This function will only be
* used by the Hermes Server itself, and it is not expected for the client
* to call it.
*
* @return the persistence handler
*/
public Object getPersistenceHandler() {
return persistenceHandler;
}
public static Object getMessageFromDataSource(DataSource dataSource,
boolean withAttachments) throws SOAPException, IOException {
return getMessageFromDataSource(dataSource, withAttachments, null);
}
/**
* Gets the messageFromDataSource attribute of the MessageServer class
*
* @param dataSource
* Description of the Parameter
* @param withAttachments
* Description of the Parameter
* @return The messageFromDataSource value
* @throws SOAPException
* Description of the Exception
*/
private static Object getMessageFromDataSource(DataSource dataSource,
boolean withAttachments, EbxmlMessage ebxmlMessage)
throws SOAPException, IOException {
InputStream fis = null;
PushbackInputStream fileStream = null;
try {
fis = dataSource.getInputStream();
MessageSemiParsedOutput parsedOutput = parseSoapEnvelopeOnly(fis);
fileStream = parsedOutput.getInputStream();
byte[] soapMessageBytes = parsedOutput.getSoapMessageBytes();
soapMessageBytes = getSoapEnvelopeBytesFromParsedOutput(parsedOutput);
int soapMessageFileOffset = 0;
int soapMessageLength = soapMessageBytes.length;
int lastIndex = parsedOutput.getLastIndex();
String boundary = parsedOutput.getBoundary();
/*
* final MimeHeaders headers = new MimeHeaders();
* headers.addHeader(Constants.CONTENT_TYPE,
* Constants.TEXT_XML_TYPE);
*/
final MimeHeaders headers = parsedOutput.getMimeHeaders();
/**
* added for parsing message without payload. For such case,
*/
if (headers.getHeader(Constants.CONTENT_TYPE) == null) {
headers.addHeader(Constants.CONTENT_TYPE,
Constants.TEXT_XML_TYPE);
}
final SOAPMessage soapMessage;
soapMessage = MessageFactory.newInstance()
.createMessage(
headers,
new ByteArrayInputStream(soapMessageBytes, 0,
lastIndex + 1));
ArrayList payloads = new ArrayList();
if (boundary != null && withAttachments) {
byte[] line = parsedOutput.getLastLine();
long offset = parsedOutput.getOffset();
lastIndex = line.length - 1;
for (; lastIndex >= 0; lastIndex--) {
if (line[lastIndex] != 0xA && line[lastIndex] != 0xD) {
break;
}
}
String s = new String(line, 0, lastIndex + 1);
while (!s.endsWith(boundary + Constants.MIME_BOUNDARY_PREFIX)) {
/*
* Find the empty line delimiter separating the MIME header
* and the attachment content
*/
final MimeHeaders attachmentHeaders = new MimeHeaders();
line = readLine(fileStream);
offset += line.length;
while (line.length > 0 && line[0] != 0xA && line[0] != 0xD) {
String lineString = new String(line).trim(), name;
int colonIndex = lineString.indexOf(':');
if (colonIndex >= 0) {
name = lineString.substring(0, colonIndex).trim();
String value = lineString.substring(colonIndex + 1)
.trim();
/*
* final StringTokenizer t = new StringTokenizer
* (new String(line), "\t\n\r\f: "); if
* (t.hasMoreTokens()) { final String name =
* t.nextToken(); String value = t.nextToken();
*/
if (name.equalsIgnoreCase(Constants.CONTENT_ID)) {
if (value.startsWith("<")
&& !EbxmlMessage.needPatch) {
value = value.substring(1);
if (value.endsWith(">")) {
value = value.substring(0, value
.length() - 1);
}
}
}
attachmentHeaders.addHeader(name, value);
}
line = readLine(fileStream);
offset += line.length;
}
if (line.length == 0) {
throw new SOAPException(
"missing empty line delimiter of MIME header");
}
long length = 0;
byte[] previousLine = null;
line = readLine(fileStream);
s = new String(line);
while (line.length > 0
&& !(s.startsWith(Constants.MIME_BOUNDARY_PREFIX
+ boundary))) {
length += line.length;
previousLine = line;
line = readLine(fileStream);
s = new String(line);
}
if (line.length == 0) {
throw new SOAPException("missing ending MIME boundary");
}
lastIndex = previousLine.length - 1;
for (; lastIndex >= 0; lastIndex--) {
if (previousLine[lastIndex] != 0xA
&& previousLine[lastIndex] != 0xD) {
break;
}
}
String[] ahs = attachmentHeaders
.getHeader(Constants.CONTENT_TYPE);
String contentType = null;
if (ahs == null || ahs.length == 0) {
throw new SOAPException("missing "
+ Constants.CONTENT_TYPE + " attachment");
} else if (ahs.length == 1) {
contentType = ahs[0];
} else {
throw new SOAPException("more than one "
+ Constants.CONTENT_TYPE + " in attachment");
}
ahs = attachmentHeaders
.getHeader(Constants.CONTENT_TRANSFER_ENCODING);
String encoding = null;
if (ahs != null) {
if (ahs.length == 1) {
encoding = ahs[0];
} else if (ahs.length > 1) {
throw new SOAPException("more than one "
+ Constants.CONTENT_TRANSFER_ENCODING
+ " in attachment");
}
}
final AttachmentDataSource ads = new AttachmentDataSource(
dataSource, offset, length
- (previousLine.length - 1 - lastIndex),
contentType, encoding, false);
final DataHandler dh = new DataHandler(ads);
String contentId = null;
ahs = attachmentHeaders.getHeader(Constants.CONTENT_ID);
if (ahs != null) {
contentId = ahs[0];
}
PayloadContainer attachment = new PayloadContainer(dh,
contentId, null);
for (Iterator i = attachmentHeaders.getAllHeaders(); i
.hasNext();) {
final MimeHeader header = (MimeHeader) i.next();
final String name = header.getName();
if (!name.equals(Constants.CONTENT_TYPE)
&& !name.equals(Constants.CONTENT_ID)) {
attachment.setMimeHeader(name, header.getValue());
}
}
payloads.add(attachment);
// add the attachment to soap message
AttachmentPart attachmentPart = soapMessage
.createAttachmentPart();
attachmentPart.setContentId(needPatch ? " <" + contentId +
">" : contentId);
attachmentPart.setDataHandler(dh);
soapMessage.addAttachmentPart(attachmentPart);
offset += (length + line.length);
lastIndex = line.length - 1;
for (; lastIndex >= 0; lastIndex--) {
if (line[lastIndex] != 0xA && line[lastIndex] != 0xD) {
break;
}
}
s = new String(line, 0, lastIndex + 1);
}
}
if (withAttachments) {
EbxmlMessage message;
if (ebxmlMessage == null) {
message = new EbxmlMessage(soapMessage);
} else {
ebxmlMessage.init(soapMessage);
message = ebxmlMessage;
}
message.setPayloadContainers(payloads);
message.setSoapEnvelopeBytes(soapMessageBytes);
return message;
}
return soapMessage;
} catch (IOException e) {
throw new SOAPException(e.toString());
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new SOAPException(e.toString());
}
}
if (fileStream != null) {
try {
fileStream.close();
} catch (IOException e) {
throw new SOAPException(e.toString());
}
}
}
}
/**
* The function which parse the soap envelope only from the inputstream.
*/
private static MessageSemiParsedOutput parseSoapEnvelopeOnly(InputStream fis)
throws SOAPException, IOException {
PushbackInputStream fileStream = new PushbackInputStream(fis);
String boundary = null;
int soapMessageFileOffset = 0;
int soapMessageLength = 0;
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] line = readLine(fileStream);
long offset = line.length;
String s = new String(line);
while (line.length > 0
&& !(s.startsWith(Constants.MIME_BOUNDARY_PREFIX))) {
out.write(line);
line = readLine(fileStream);
offset += line.length;
s = new String(line);
}
byte[] soapMessageBytes = out.toByteArray();
soapMessageLength = soapMessageBytes.length;
int lastIndex = soapMessageBytes.length - 1;
MimeHeaders soapEnvelopeHeaders = new MimeHeaders();
if (line.length > 0) {
lastIndex = line.length - 1;
for (; lastIndex >= 0; lastIndex--) {
if (line[lastIndex] != 0xA && line[lastIndex] != 0xD) {
break;
}
}
boundary = new String(line,
Constants.MIME_BOUNDARY_PREFIX.length(), lastIndex
- Constants.MIME_BOUNDARY_PREFIX.length() + 1);
/*
* Find the empty line delimiter separating the MIME header and the
* SOAPPart content
*/
line = readLine(fileStream);
MimeHeader header = parseMimeHeader(line);
if (header != null) {
soapEnvelopeHeaders.addHeader(header.getName(), header
.getValue());
}
offset += line.length;
while (line.length > 0 && line[0] != 0xA && line[0] != 0xD) {
line = readLine(fileStream);
header = parseMimeHeader(line);
if (header != null) {
soapEnvelopeHeaders.addHeader(header.getName(), header
.getValue());
}
offset += line.length;
}
if (line.length == 0) {
throw new SOAPException(
"missing empty line delimiter of MIME header");
}
/*
* Find the location and the length of the SOAPPart content with
* offset being the beginning position
*/
soapMessageFileOffset = (int) offset;
out = new ByteArrayOutputStream();
line = readLine(fileStream);
offset += line.length;
s = new String(line);
while (line.length > 0
&& !(s
.startsWith(Constants.MIME_BOUNDARY_PREFIX
+ boundary))) {
out.write(line);
line = readLine(fileStream);
offset += line.length;
s = new String(line);
}
if (line.length == 0) {
throw new SOAPException("missing ending MIME boundary");
}
soapMessageBytes = out.toByteArray();
soapMessageLength = soapMessageBytes.length;
lastIndex = soapMessageBytes.length - 1;
for (; lastIndex >= 0; lastIndex--) {
if (soapMessageBytes[lastIndex] != 0xA
&& soapMessageBytes[lastIndex] != 0xD) {
break;
}
}
}
return new MessageSemiParsedOutput(fileStream, lastIndex,
soapMessageBytes, soapMessageFileOffset, boundary, line,
offset, soapEnvelopeHeaders);
}
private static MimeHeader parseMimeHeader(byte[] line) {
String lineString = new String(line).trim();
int colonIndex = lineString.indexOf(':');
if (colonIndex >= 0) {
String header = lineString.substring(0, colonIndex).trim();
String value = lineString.substring(colonIndex + 1).trim();
return new MimeHeader(header, value);
} else {
return null;
}
}
/**
* parse the message from InputStream and get the byte array of SOAP
* Envelope
*
* @param stream
* the InputStream contains the message
* @return the byte array of the Soap Envelope
* @throws MessageServerException
* throw if there is error on parsing
*/
public static byte[] getSoapEnvelopeBytesFromStream(InputStream stream)
throws SOAPException {
try {
MessageSemiParsedOutput parsedOutput = parseSoapEnvelopeOnly(stream);
return getSoapEnvelopeBytesFromParsedOutput(parsedOutput);
} catch (IOException e) {
throw new SOAPException(e.toString());
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
throw new SOAPException(e.toString());
}
}
}
}
/**
* parse the message from InputStream and get the byte array of SOAP
* Envelope
*
* @param parsedOutput
* the message semi parsed output
* @return the byte array of the Soap Envelope
* @throws MessageServerException
* throw if there is error on parsing
*/
private static byte[] getSoapEnvelopeBytesFromParsedOutput(
MessageSemiParsedOutput parsedOutput) throws SOAPException {
InputStream pStream = null;
try {
byte[] soapEnvelopeBytes = parsedOutput.getSoapMessageBytes();
String[] encodingHeaders = parsedOutput.getMimeHeaders().getHeader(
Constants.CONTENT_TRANSFER_ENCODING);
String encoding = null;
if (encodingHeaders != null) {
if (encodingHeaders.length == 1) {
encoding = encodingHeaders[0];
} else {
throw new IOException(
"More than one encoding on soap envelope");
}
}
if (encoding != null && !encoding.equals("binary")) {
ByteArrayInputStream bais = new ByteArrayInputStream(
soapEnvelopeBytes);
pStream = MimeUtility.decode(bais, encoding);
bais.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read = pStream.read(buffer);
while (read != -1) {
baos.write(buffer, 0, read);
read = pStream.read(buffer);
}
return baos.toByteArray();
} else {
return soapEnvelopeBytes;
}
} catch (MessagingException e) {
throw new SOAPException(e.toString());
} catch (IOException e) {
throw new SOAPException(e.toString());
} finally {
if (pStream != null) {
try {
pStream.close();
} catch (IOException e) {
throw new SOAPException(e.toString());
}
}
}
}
/**
* Description of the Method
*
* @param in
* Description of the Parameter
* @return Description of the Return Value
* @throws IOException
* Description of the Exception
*/
private static byte[] readLine(PushbackInputStream in) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
int c = in.read();
for (; c != 0xA && c != 0xD && c != -1; c = in.read()) {
out.write(c);
}
if (c == 0xD) {
out.write(c);
c = in.read();
if (c == 0xA) {
out.write(c);
} else if (c != -1) {
in.unread(c);
}
} else if (c == 0xA) {
out.write(c);
}
return out.toByteArray();
}
/**
* class represent the data returned from the parseSoapEnvelopeOnly
*/
private static class MessageSemiParsedOutput {
private PushbackInputStream istream;
private byte[] soapMessage;
private int soapMessageOffset;
private String boundary;
private int lastIndex;
private byte[] endLine;
private long offset;
private MimeHeaders headers;
public MessageSemiParsedOutput(PushbackInputStream istream,
int lastIndex, byte[] soapMessage, int soapMessageOffset,
String boundary, byte[] endLine, long offset,
MimeHeaders headers) {
this.istream = istream;
this.soapMessage = soapMessage;
this.soapMessageOffset = soapMessageOffset;
this.boundary = boundary;
this.lastIndex = lastIndex;
this.endLine = endLine;
this.offset = offset;
this.headers = headers;
}
/**
* get the mime headers
*
* @return the mime headers
*/
public MimeHeaders getMimeHeaders() {
return headers;
}
/**
* get the offset up on parsing
*/
public long getOffset() {
return offset;
}
/**
* get the last line up on parsing
*/
public byte[] getLastLine() {
return endLine;
}
/**
* get the last index to read the soap message
*/
public int getLastIndex() {
return lastIndex;
}
/**
* get the remain stream which is not parsed
*/
public PushbackInputStream getInputStream() {
return istream;
}
/**
* get the byte array that contains the soap message
*/
public byte[] getSoapMessageBytes() {
return soapMessage;
}
/**
* get the soap message offset from the started stream
*/
public int getSoapMessageOffset() {
return soapMessageOffset;
}
/**
* get the mime boundary
*/
public String getBoundary() {
return boundary;
}
}
}