You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by se...@apache.org on 2001/08/06 05:40:07 UTC

cvs commit: jakarta-james/src/java/org/apache/james/core MimeMessageWrapper.java MimeMessageSource.java MimeMessageInputStreamSource.java

serge       01/08/05 20:40:07

  Added:       src/java/org/apache/james/core MimeMessageWrapper.java
                        MimeMessageSource.java
                        MimeMessageInputStreamSource.java
  Log:
  New implementations for significant memory and CPU usage reductions.
  
  Revision  Changes    Path
  1.1                  jakarta-james/src/java/org/apache/james/core/MimeMessageWrapper.java
  
  Index: MimeMessageWrapper.java
  ===================================================================
  package org.apache.james.core;
  
  import java.io.*;
  import java.text.ParseException;
  import java.util.*;
  import javax.activation.*;
  import javax.mail.*;
  import javax.mail.internet.*;
  import org.apache.james.MailHeaders;
  
  public class MimeMessageWrapper extends MimeMessage {
  
      /**
       * Can provide an input stream to the data
       */
      MimeMessageSource source = null;
      /**
       * The Internet headers in memory
       */
      MailHeaders headers = null;
      /**
       * The mime message in memory
       */
      MimeMessage message = null;
      /**
       * Record whether a change was made to this message
       */
      boolean modified = false;
      /**
       * How to format a mail date
       */
      MailDateFormat mailDateFormat = new MailDateFormat();
  
      public MimeMessageWrapper(MimeMessageSource source) {
          super(javax.mail.Session.getDefaultInstance(System.getProperties(), null));
          this.source = source;
      }
  
      public MimeMessageWrapper(Session session, MimeMessageSource source) {
          super(session);
          this.source = source;
      }
  
      /**
       * Instantiate the headers
       */
      private synchronized void loadHeaders() throws MessagingException {
          if (headers != null) {
              //Another thread has already loaded these headers
              return;
          }
          //System.err.println("parsing headers of " + this);
          try {
              InputStream in = source.getInputStream();
              headers = new MailHeaders(in);
              in.close();
          } catch (IOException ioe) {
              ioe.printStackTrace();
              throw new MessagingException("Unable to parse headers from stream: " + ioe.getMessage());
          }
      }
  
      /**
       * Internal implementations
       */
      private synchronized void loadMessage() throws MessagingException {
          if (message != null) {
              //Another thread has already loaded this message
              return;
          }
          //System.err.println("parsing headers and message of " + this);
          try {
              InputStream in = source.getInputStream();
              headers = new MailHeaders(in);
  
              ByteArrayInputStream headersIn
                      = new ByteArrayInputStream(headers.toByteArray());
              in = new SequenceInputStream(headersIn, in);
  
              message = new MimeMessage(session, in);
              in.close();
          } catch (IOException ioe) {
              ioe.printStackTrace();
              throw new MessagingException("Unable to parse stream: " + ioe.getMessage());
          }
      }
  
      /**
       * Internal implementation to get InternetAddress headers
       */
      private Address[] getAddressHeader(String name) throws MessagingException {
          String addr = getHeader(name, ",");
          if (addr == null) {
              return null;
          } else {
              return InternetAddress.parse(addr);
          }
      }
  
  
      /**
       * Internal implementation to find headers
       */
      private String getHeaderName(Message.RecipientType recipienttype) throws MessagingException {
          String s;
          if (recipienttype == javax.mail.Message.RecipientType.TO) {
              s = "To";
          } else if (recipienttype == javax.mail.Message.RecipientType.CC) {
              s = "Cc";
          } else if (recipienttype == javax.mail.Message.RecipientType.BCC) {
              s = "Bcc";
          } else if (recipienttype == RecipientType.NEWSGROUPS) {
              s = "Newsgroups";
          } else {
              throw new MessagingException("Invalid Recipient Type");
          }
          return s;
      }
  
  
      /**
       * Special methods you can call
       */
      public boolean isModified() {
          return modified;
      }
  
      /**
       * Rewritten for optimization purposes
       */
      public void writeTo(OutputStream os) throws IOException, MessagingException {
          if (message == null || !isModified()) {
              //We do not want to instantiate the message... just read from source
              //  and write to this outputstream
              byte[] block = new byte[1024];
              int read = 0;
              InputStream in = source.getInputStream();
              while ((read = in.read(block)) > 0) {
                  os.write(block, 0, read);
              }
              in.close();
          } else {
              message.saveChanges();
              message.writeTo(os);
          }
      }
  
      /**
       * Rewritten for optimization purposes
       */
      public void writeTo(OutputStream os, String[] ignoreList) throws IOException, MessagingException {
          writeTo(os, os, ignoreList);
      }
  
      /**
       * Write
       */
      public void writeTo(OutputStream headerOs, OutputStream bodyOs) throws IOException, MessagingException {
          writeTo(headerOs, bodyOs, new String[0]);
      }
  
      public void writeTo(OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
          if (message == null || !isModified()) {
              //We do not want to instantiate the message... just read from source
              //  and write to this outputstream
  
              //First handle the headers
              InputStream in = source.getInputStream();
              InternetHeaders headers = new InternetHeaders(in);
              PrintStream pos = new PrintStream(headerOs);
              for (Enumeration e = headers.getNonMatchingHeaderLines(ignoreList); e.hasMoreElements(); ) {
                  String header = (String)e.nextElement();
                  pos.print(header);
                  pos.print("\r\n");
              }
              pos.print("\r\n");
              pos.flush();
              byte[] block = new byte[1024];
              int read = 0;
              while ((read = in.read(block)) > 0) {
                  bodyOs.write(block, 0, read);
              }
              in.close();
          } else {
              writeTo(message, headerOs, bodyOs, ignoreList);
          }
      }
  
      /**
       * Convenience method to take any MimeMessage and write the headers and body to two
       * different output streams
       */
      public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs) throws IOException, MessagingException {
          writeTo(message, headerOs, bodyOs, null);
      }
  
      /**
       * Convenience method to take any MimeMessage and write the headers and body to two
       * different output streams, with an ignore list
       */
      public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
          if (message instanceof MimeMessageWrapper) {
              MimeMessageWrapper wrapper = (MimeMessageWrapper)message;
              wrapper.writeTo(headerOs, bodyOs, ignoreList);
          } else {
              message.saveChanges();
  
              //Write the headers (minus ignored ones)
              Enumeration headers = message.getNonMatchingHeaderLines(ignoreList);
              PrintStream pos = new PrintStream(headerOs);
              while (headers.hasMoreElements()) {
                  pos.print((String)headers.nextElement());
                  pos.print("\r\n");
              }
              pos.flush();
  
              //Write the message without any headers
  
              //Get a list of all headers
              Vector headerNames = new Vector();
              Enumeration allHeaders = message.getAllHeaders();
              while (allHeaders.hasMoreElements()) {
                  Header header = (Header)allHeaders.nextElement();
                  headerNames.add(header.getName());
              }
              String headerNamesArray[] = (String[])headerNames.toArray(new String[0]);
  
              //Write message to bodyOs, ignoring all headers (without writing any headers)
              message.writeTo(bodyOs, headerNamesArray);
          }
      }
  
  
      /**
       * Various reader methods
       */
  
      public Address[] getFrom() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          Address from[] = getAddressHeader("From");
          if(from == null) {
              from = getAddressHeader("Sender");
          }
          return from;
      }
  
      public Address[] getRecipients(Message.RecipientType type) throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          if (type == RecipientType.NEWSGROUPS) {
              String s = headers.getHeader("Newsgroups", ",");
              if(s == null) {
                  return null;
              } else {
                  return NewsAddress.parse(s);
              }
          } else {
              return getAddressHeader(getHeaderName(type));
          }
      }
  
      public Address[] getAllRecipients() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          Address toAddresses[] = getRecipients(RecipientType.TO);
          Address ccAddresses[] = getRecipients(RecipientType.CC);
          Address bccAddresses[] = getRecipients(RecipientType.BCC);
          Address newsAddresses[] = getRecipients(RecipientType.NEWSGROUPS);
          if(ccAddresses == null && bccAddresses == null && newsAddresses == null) {
              return toAddresses;
          }
          int i = (toAddresses == null ? 0 : toAddresses.length)
                  + (ccAddresses == null ? 0 : ccAddresses.length)
                  + (bccAddresses == null ? 0 : bccAddresses.length)
                  + (newsAddresses == null ? 0 : newsAddresses.length);
          Address allAddresses[] = new Address[i];
          int j = 0;
          if (toAddresses != null) {
              System.arraycopy(toAddresses, 0, allAddresses, j, toAddresses.length);
              j += toAddresses.length;
          }
          if(ccAddresses != null) {
              System.arraycopy(ccAddresses, 0, allAddresses, j, ccAddresses.length);
              j += ccAddresses.length;
          }
          if(bccAddresses != null) {
              System.arraycopy(bccAddresses, 0, allAddresses, j, bccAddresses.length);
              j += bccAddresses.length;
          }
          if(newsAddresses != null) {
              System.arraycopy(newsAddresses, 0, allAddresses, j, newsAddresses.length);
              j += newsAddresses.length;
          }
          return allAddresses;
      }
  
      public Address[] getReplyTo() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          Address replyTo[] = getAddressHeader("Reply-To");
          if(replyTo == null) {
              replyTo = getFrom();
          }
          return replyTo;
      }
  
      public String getSubject() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          String subject = getHeader("Subject", null);
          if (subject == null) {
              return null;
          }
          try {
              return MimeUtility.decodeText(subject);
          } catch(UnsupportedEncodingException _ex) {
              return subject;
          }
      }
  
      public Date getSentDate() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          String header = getHeader("Date", null);
          if(header != null) {
              try {
                  synchronized(mailDateFormat) {
                      Date date = mailDateFormat.parse(header);
                      return date;
                  }
              } catch(ParseException _ex) {
                  return null;
              }
          } else {
              return null;
          }
      }
  
      public Date getReceivedDate() throws MessagingException {
          //if (headers == null) {
          //    loadHeaders();
          //}
          return null;
      }
  
      public int getSize() throws MessagingException {
          try {
              if (message == null) {
                  return (int)source.getSize();
              } else {
                  //Would be better to use in memory mimemessage
                  //Need to figure out size of message plus size of headers...
                  return message.getSize();
                  //return source.getSize();
              }
          } catch (IOException ioe) {
              ioe.printStackTrace();
              throw new MessagingException("Trouble in getSize", ioe);
          }
      }
  
      /**
       * Corrects JavaMail 1.1 version which always returns -1.
       * Only corrected for content less than 5000 bytes,
       * to avoid memory hogging.
       */
      public int getLineCount() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          int size = content.length; // size of byte array
          int lineCount = 0;
          if (size < 5000) {
              for (int i=0; i < size -1; i++) {
                  if (content[i] == '\r' && content[i+1] == '\n') {
                      lineCount++;
                  }
              }
          } else {
              lineCount = -1;
          }
          return lineCount;
      }
  
      /**
       * Returns size of message, ie headers and content. Current implementation
       * actually returns number of characters in headers plus number of bytes
       * in the internal content byte array.
       */
      public int getMessageSize() throws MessagingException {
          int contentSize = content.length;
          int headerSize = 0;
          Enumeration e = getAllHeaderLines();
          while (e.hasMoreElements()) {
              headerSize += ((String)e.nextElement()).length();
          }
          return headerSize + contentSize;
      }
  
      public String getContentType() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          String value = getHeader("Content-Type", null);
          if (value == null) {
              return "text/plain";
          } else {
              return value;
          }
      }
  
      public boolean isMimeType(String mimeType) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.isMimeType(mimeType);
      }
  
      public String getDisposition() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getDisposition();
      }
  
      public String getEncoding() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getEncoding();
      }
  
      public String getContentID() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return getHeader("Content-Id", null);
      }
  
      public String getContentMD5() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return getHeader("Content-MD5", null);
      }
  
      public String getDescription() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getDescription();
      }
  
      public String[] getContentLanguage() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getContentLanguage();
      }
  
      public String getMessageID() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return getHeader("Message-ID", null);
      }
  
      public String getFileName() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getFileName();
      }
  
      public InputStream getInputStream() throws IOException, MessagingException {
          if (message == null) {
              return source.getInputStream();
          } else {
              return message.getInputStream();
          }
      }
  
      public DataHandler getDataHandler() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getDataHandler();
      }
  
      public Object getContent() throws IOException, MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getContent();
      }
  
      public String[] getHeader(String name) throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getHeader(name);
      }
  
      public String getHeader(String name, String delimiter) throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getHeader(name, delimiter);
      }
  
      public Enumeration getAllHeaders() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getAllHeaders();
      }
  
      public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getMatchingHeaders(names);
      }
  
      public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getNonMatchingHeaders(names);
      }
  
      public Enumeration getAllHeaderLines() throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getAllHeaderLines();
      }
  
      public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getMatchingHeaderLines(names);
      }
  
      public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
          if (headers == null) {
              loadHeaders();
          }
          return headers.getNonMatchingHeaderLines(names);
      }
  
      public Flags getFlags() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.getFlags();
      }
  
      public boolean isSet(Flags.Flag flag) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          return message.isSet(flag);
      }
  
  
      /**
       * Writes content only, ie not headers, to the specified outputstream.
       */
      public void writeContentTo(OutputStream outs)
              throws java.io.IOException, MessagingException {
          int size = content.length; // size of byte array
          int chunk = 1000; //arbitrary choice - ideas welcome
          int pointer = 0;
          while (pointer < size) {
              if ((size - pointer) > chunk) {
                  outs.write(content, pointer, chunk);
              } else {
                  outs.write(content, pointer, size-pointer);
              }
              pointer += chunk;
          }
      }
  
  
  
  
  
  
  
  
  
  
  
  
      /**
       * Various writer methods
       */
      public void setFrom(Address address) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setFrom(address);
      }
  
      public void setFrom() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setFrom();
      }
  
      public void addFrom(Address[] addresses) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.addFrom(addresses);
      }
  
      public void setRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setRecipients(type, addresses);
      }
  
      public void addRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.addRecipients(type, addresses);
      }
  
      public void setReplyTo(Address[] addresses) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setReplyTo(addresses);
      }
  
      public void setSubject(String subject) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setSubject(subject);
      }
  
      public void setSubject(String subject, String charset) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setSubject(subject, charset);
      }
  
      public void setSentDate(Date d) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setSentDate(d);
      }
  
      public void setDisposition(String disposition) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setDisposition(disposition);
      }
  
      public void setContentID(String cid) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setContentID(cid);
      }
  
      public void setContentMD5(String md5) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setContentMD5(md5);
      }
  
      public void setDescription(String description) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setDescription(description);
      }
  
      public void setDescription(String description, String charset) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setDescription(description, charset);
      }
  
      public void setContentLanguage(String[] languages) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setContentLanguage(languages);
      }
  
      public void setFileName(String filename) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setFileName(filename);
      }
  
      public void setDataHandler(DataHandler dh) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setDataHandler(dh);
      }
  
      public void setContent(Object o, String type) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setContent(o, type);
      }
  
      public void setText(String text) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setText(text);
      }
  
      public void setText(String text, String charset) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setText(text, charset);
      }
  
      public void setContent(Multipart mp) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setContent(mp);
      }
  
      public Message reply(boolean replyToAll) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          return message.reply(replyToAll);
      }
  
      public void setHeader(String name, String value) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setHeader(name, value);
      }
  
      public void addHeader(String name, String value) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.addHeader(name, value);
      }
  
      public void removeHeader(String name) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.removeHeader(name);
      }
  
      public void addHeaderLine(String line) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          message.addHeaderLine(line);
      }
  
      public void setFlags(Flags flag, boolean set) throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.setFlags(flag, set);
      }
  
      public void saveChanges() throws MessagingException {
          if (message == null) {
              loadMessage();
          }
          modified = true;
          message.saveChanges();
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/core/MimeMessageSource.java
  
  Index: MimeMessageSource.java
  ===================================================================
  package org.apache.james.core;
  
  import java.io.IOException;
  import java.io.InputStream;
  
  public abstract class MimeMessageSource {
  	/**
  	 * Return an input stream to the data
  	 */
      public abstract InputStream getInputStream() throws IOException;
  
      /**
       * Return the size of all the data.
       * Default implementation... others can override to do this much faster
       */
      public long getSize() throws IOException {
  		int size = 0;
  		InputStream in = getInputStream();
  		int read = 0;
  		byte[] data = new byte[1024];
  		while ((read = in.read(data)) > 0) {
  			size += read;
  		}
          //System.err.println("size of " + this + " is " + size);
  		return size;
  	}
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/core/MimeMessageInputStreamSource.java
  
  Index: MimeMessageInputStreamSource.java
  ===================================================================
  package org.apache.james.core;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  
  public class MimeMessageInputStreamSource extends MimeMessageSource {
  
      String key = null;
  	InputStream in = null;
      File file = null;
  
      //If you try to access this size first, it will load it into a temp file
      //  and work from there.
  
  	public MimeMessageInputStreamSource(String key, InputStream in) {
          this.key = key;
  		this.in = in;
  	}
  
  	/**
  	 * Return an input stream to the data
  	 */
      public synchronized InputStream getInputStream() throws IOException {
          if (file == null) {
              return in;
          } else {
              return new FileInputStream(file);
          }
  	}
  
      /**
       * If not already, read the stream into a temp file
       */
      public synchronized long getSize() throws IOException {
          if (file == null) {
              //Create a temp file and channel the input stream into it
              file = File.createTempFile(key, ".m64");
              FileOutputStream fout = new FileOutputStream(file);
              int b = -1;
              while ((b = in.read()) != -1) {
                  fout.write(b);
              }
              fout.close();
              in.close();
              file.deleteOnExit();
          }
          return file.length();
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: james-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: james-dev-help@jakarta.apache.org