/**
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.apache.axis.message;

// $Id: SOAPMessageImpl.java,v 1.1.1.1 2004/08/20 18:44:02 tdiesler Exp $

import org.apache.axis.AxisFault;
import org.apache.axis.attachments.AttachmentSupport;
import org.apache.axis.attachments.Attachments;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.transport.http.HTTPConstants;
import org.apache.axis.utils.Messages;
import org.apache.commons.logging.Log;

import javax.xml.soap.AttachmentPart;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;

/**
 * An implemenation of the abstract SOAPMessage.
 * <p/>
 * This class should not expose functionality that is not part of
 * {@link SOAPMessage}. Client code should use <code>SOAPMessage</code> whenever possible.
 *
 * @author Thomas Diesler (thomas.diesler@jboss.org)
 * @since 31-May-2004
 */
public class SOAPMessageImpl extends SOAPMessage
{
   /**
    * The <code>Log</code> that this class uses for logging all messages.
    */
   private static Log log = LogFactory.getLog(SOAPMessageAxisImpl.class.getName());

   // This Message's SOAPPart.
   protected javax.xml.soap.SOAPPart mSOAPPart;
   // This Message's Attachments object, which manages the attachments contained in this Message.
   protected Attachments mAttachments;
   //  The MimeHeaders
   protected MimeHeadersImpl headers;

   private Hashtable mProps = new Hashtable();
   private boolean saveRequired = true;

   protected SOAPMessageImpl()
   {
   }

   /**
    * 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 os the <CODE>OutputStream</CODE>
    *           object to which this <CODE>SOAPMessage</CODE> object will
    *           be written
    * @throws javax.xml.soap.SOAPException if there was a problem in
    *                                      externalizing this SOAP message
    * @throws java.io.IOException          if an I/O error
    *                                      occurs
    */
   public void writeTo(OutputStream os) throws SOAPException, IOException
   {
      //Do it the old fashion way.
/*
        if (mAttachments == null || 0 == mAttachments.getAttachmentCount()) {
            try {
                String charEncoding = (String)getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
                if(charEncoding == null){
                    charEncoding = "UTF-8";
                }
                Writer writer = new OutputStreamWriter(os,charEncoding);
                writer = new BufferedWriter(writer);

                // write the xml declaration header
                String incXMLDecl = (String)getProperty(SOAPMessage.WRITE_XML_DECLARATION);
                if(incXMLDecl == null){
                    incXMLDecl = "false";
                }
                if(incXMLDecl.equalsIgnoreCase("true")){
                    writer.write("<?xml version=\"1.0\" encoding=\"" + charEncoding +"\"?>");
                }
                mSOAPPart.writeTo(writer);
                writer.flush();
            } catch (IOException e) {
                log.error(Messages.getMessage("javaIOException00"), e);
            }
        } else {
            try {
                mAttachments.writeContentToStream(os);
            } catch (Exception e) {
                log.error(Messages.getMessage("exception00"), e);
            }
        }
*/
   }

   public SOAPBody getSOAPBody() throws SOAPException
   {
      return mSOAPPart.getEnvelope().getBody();
   }

   public SOAPHeader getSOAPHeader() throws SOAPException
   {
      return mSOAPPart.getEnvelope().getHeader();
   }

   public void setProperty(String property, Object value) throws SOAPException
   {
      mProps.put(property, value);
   }

   public Object getProperty(String property) throws SOAPException
   {
      return mProps.get(property);
   }

   /**
    * 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(String) setContentDescription(java.lang.String)
    */
   public String getContentDescription()
   {
      String values[] = headers.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)
   {
      headers.setHeader(HTTPConstants.HEADER_CONTENT_DESCRIPTION, description);
   }

   /**
    * 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 javax.xml.soap.SOAPException if there
    *                                      was a problem saving changes to this message.
    */
   public void saveChanges() throws SOAPException
   {
/*
        if (mAttachments != null && 0 < mAttachments.getAttachmentCount()) {
            try {
                headers.setHeader("Content-Type",mAttachments.getContentType());
            } catch (AxisFault af){
                log.error(Messages.getMessage("exception00"), af);
            }
        }
        saveRequired = false;
        try {
            // Fix for Bug 16418 - Start from scratch
            getSOAPPartAsString();
        } catch (AxisFault axisFault) {
            log.error(Messages.getMessage("exception00"), axisFault);
        }
*/
   }

   /**
    * Indicates whether this <CODE>SOAPMessage</CODE> object
    * has had the method <CODE>saveChanges</CODE> 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;
   }

   /**
    * 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 MimeHeaders getMimeHeaders()
   {
      return headers;
   }

   public javax.xml.soap.SOAPPart getSOAPPart()
   {
      return mSOAPPart;
   }

   /**
    * 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()
   {
      mAttachments.removeAllAttachments();
   }

   /**
    * 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 mAttachments == null ? 0 : mAttachments.getAttachmentCount();
   }

   /**
    * 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()
   {
      try
      {
         if (mAttachments != null && 0 != mAttachments.getAttachmentCount())
         {
            return mAttachments.getAttachments().iterator();
         }
      }
      catch (AxisFault af)
      {
         log.error(Messages.getMessage("exception00"), af);
      }
      return Collections.EMPTY_LIST.iterator();
   }

   /**
    * Retrieves all the <CODE>AttachmentPart</CODE> 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 <CODE>MimeHeaders</CODE>
    *                object containing the MIME headers for which to
    *                search
    * @return an iterator over all attachments that have a header
    *         that matches one of the given headers
    */
   public Iterator getAttachments(javax.xml.soap.MimeHeaders headers)
   {
      return mAttachments.getAttachments(headers);
   }

   /**
    * 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 IllegalArgumentException
    */
   public void addAttachmentPart(AttachmentPart attachmentpart)
   {
      try
      {
         mAttachments.addAttachmentPart((org.apache.axis.Part)attachmentpart);
      }
      catch (AxisFault af)
      {
         log.error(Messages.getMessage("exception00"), af);
      }
   }

   /**
    * 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()
   {
      if (!AttachmentSupport.isAttachmentSupportEnabled())
      {
         throw new RuntimeException(Messages.getMessage("noAttachments"));
      }

      try
      {
         return (AttachmentPart)mAttachments.createAttachmentPart();
      }
      catch (AxisFault af)
      {
         log.error(Messages.getMessage("exception00"), af);
      }
      return null;
   }
}
