http://git-wip-us.apache.org/repos/asf/james-project/blob/936746b9/server/container/core/src/main/java/org/apache/james/core/MailImpl.java ---------------------------------------------------------------------- diff --git a/server/container/core/src/main/java/org/apache/james/core/MailImpl.java b/server/container/core/src/main/java/org/apache/james/core/MailImpl.java deleted file mode 100644 index c7ecd83..0000000 --- a/server/container/core/src/main/java/org/apache/james/core/MailImpl.java +++ /dev/null @@ -1,691 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.core; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OptionalDataException; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.UUID; - -import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.ParseException; - -import org.apache.james.lifecycle.api.Disposable; -import org.apache.james.lifecycle.api.LifecycleUtil; -import org.apache.mailet.Mail; -import org.apache.mailet.MailAddress; -import org.apache.mailet.PerRecipientHeaders; -import org.apache.mailet.PerRecipientHeaders.Header; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * <p> - * Wraps a MimeMessage adding routing information (from SMTP) and some simple - * API enhancements. - * </p> - * <p> - * From James version > 2.2.0a8 "mail attributes" have been added. Backward and - * forward compatibility is supported: - * <ul> - * <li>messages stored in file repositories <i>without</i> attributes by James - * version <= 2.2.0a8 will be processed by later versions as having an empty - * attributes hashmap;</li> - * <li>messages stored in file repositories <i>with</i> attributes by James - * version > 2.2.0a8 will be processed by previous versions, ignoring the - * attributes.</li> - * </ul> - * </p> - */ -public class MailImpl implements Disposable, Mail { - - private static final Logger LOGGER = LoggerFactory.getLogger(MailImpl.class); - - /** - * We hardcode the serialVersionUID so that from James 1.2 on, MailImpl will - * be deserializable (so your mail doesn't get lost) - */ - public static final long serialVersionUID = -4289663364703986260L; - /** - * The error message, if any, associated with this mail. - */ - private String errorMessage; - /** - * The state of this mail, which determines how it is processed. - */ - private String state; - /** - * The MimeMessage that holds the mail data. - */ - private MimeMessage message; - /** - * The sender of this mail. - */ - private MailAddress sender; - /** - * The collection of recipients to whom this mail was sent. - */ - private Collection<MailAddress> recipients; - /** - * The identifier for this mail message - */ - private String name; - /** - * The remote host from which this mail was sent. - */ - private String remoteHost = "localhost"; - /** - * The remote address from which this mail was sent. - */ - private String remoteAddr = "127.0.0.1"; - /** - * The last time this message was updated. - */ - private Date lastUpdated = new Date(); - /** - * Attributes added to this MailImpl instance - */ - private Map<String, Object> attributes; - /** - * Specific headers for some recipients - * These headers will be added at delivery time - */ - private PerRecipientHeaders perRecipientSpecificHeaders; - - /** - * A constructor that creates a new, uninitialized MailImpl - */ - public MailImpl() { - setState(Mail.DEFAULT); - attributes = new HashMap<>(); - perRecipientSpecificHeaders = new PerRecipientHeaders(); - } - - /** - * A constructor that creates a MailImpl with the specified name, sender, - * and recipients. - * - * @param name the name of the MailImpl - * @param sender the sender for this MailImpl - * @param recipients the collection of recipients of this MailImpl - */ - public MailImpl(String name, MailAddress sender, Collection<MailAddress> recipients) { - this(); - this.name = name; - this.sender = sender; - this.recipients = null; - - // Copy the recipient list - if (recipients != null) { - this.recipients = new ArrayList<>(); - this.recipients.addAll(recipients); - } - } - - /** - * Create a copy of the input mail and assign it a new name - * - * @param mail original mail - * @throws MessagingException when the message is not clonable - */ - public MailImpl(Mail mail) throws MessagingException { - this(mail, newName(mail)); - } - - /** - * @param mail - * @param newName - * @throws MessagingException - */ - @SuppressWarnings("unchecked") - public MailImpl(Mail mail, String newName) throws MessagingException { - this(newName, mail.getSender(), mail.getRecipients(), mail.getMessage()); - setRemoteHost(mail.getRemoteHost()); - setRemoteAddr(mail.getRemoteAddr()); - setLastUpdated(mail.getLastUpdated()); - try { - if (mail instanceof MailImpl) { - setAttributesRaw((HashMap<String, Object>) cloneSerializableObject(((MailImpl) mail).getAttributesRaw())); - } else { - HashMap<String, Object> attribs = new HashMap<>(); - for (Iterator<String> i = mail.getAttributeNames(); i.hasNext(); ) { - String hashKey = i.next(); - attribs.put(hashKey, cloneSerializableObject(mail.getAttribute(hashKey))); - } - setAttributesRaw(attribs); - } - } catch (IOException | ClassNotFoundException e) { - LOGGER.error("Error while deserializing attributes", e); - setAttributesRaw(new HashMap<>()); - } - } - - /** - * A constructor that creates a MailImpl with the specified name, sender, - * recipients, and message data. - * - * @param name the name of the MailImpl - * @param sender the sender for this MailImpl - * @param recipients the collection of recipients of this MailImpl - * @param messageIn a stream containing the message source - */ - public MailImpl(String name, MailAddress sender, Collection<MailAddress> recipients, InputStream messageIn) throws MessagingException { - this(name, sender, recipients); - MimeMessageSource source = new MimeMessageInputStreamSource(name, messageIn); - // if MimeMessageCopyOnWriteProxy throws an error in the constructor we - // have to manually care disposing our source. - try { - this.setMessage(new MimeMessageCopyOnWriteProxy(source)); - } catch (MessagingException e) { - LifecycleUtil.dispose(source); - throw e; - } - } - - /** - * A constructor that creates a MailImpl with the specified name, sender, - * recipients, and MimeMessage. - * - * @param name the name of the MailImpl - * @param sender the sender for this MailImpl - * @param recipients the collection of recipients of this MailImpl - * @param message the MimeMessage associated with this MailImpl - */ - public MailImpl(String name, MailAddress sender, Collection<MailAddress> recipients, MimeMessage message) { - this(name, sender, recipients); - this.setMessage(new MimeMessageCopyOnWriteProxy(message)); - } - - /** - * Duplicate the MailImpl. - * - * @return a MailImpl that is a duplicate of this one - */ - public Mail duplicate() { - return duplicate(name); - } - - /** - * Duplicate the MailImpl, replacing the mail name with the one passed in as - * an argument. - * - * @param newName the name for the duplicated mail - * @return a MailImpl that is a duplicate of this one with a different name - */ - public Mail duplicate(String newName) { - try { - return new MailImpl(this, newName); - } catch (MessagingException me) { - // Ignored. Return null in the case of an error. - } - return null; - } - - /** - * Get the error message associated with this MailImpl. - * - * @return the error message associated with this MailImpl - */ - @Override - public String getErrorMessage() { - return errorMessage; - } - - /** - * Get the MimeMessage associated with this MailImpl. - * - * @return the MimeMessage associated with this MailImpl - */ - @Override - public MimeMessage getMessage() throws MessagingException { - return message; - } - - /** - * Set the name of this MailImpl. - * - * @param name the name of this MailImpl - */ - @Override - public void setName(String name) { - this.name = name; - } - - /** - * Get the name of this MailImpl. - * - * @return the name of this MailImpl - */ - @Override - public String getName() { - return name; - } - - /** - * Get the recipients of this MailImpl. - * - * @return the recipients of this MailImpl - */ - @Override - public Collection<MailAddress> getRecipients() { - return recipients; - } - - /** - * Get the sender of this MailImpl. - * - * @return the sender of this MailImpl - */ - @Override - public MailAddress getSender() { - return sender; - } - - /** - * Get the state of this MailImpl. - * - * @return the state of this MailImpl - */ - @Override - public String getState() { - return state; - } - - /** - * Get the remote host associated with this MailImpl. - * - * @return the remote host associated with this MailImpl - */ - @Override - public String getRemoteHost() { - return remoteHost; - } - - /** - * Get the remote address associated with this MailImpl. - * - * @return the remote address associated with this MailImpl - */ - @Override - public String getRemoteAddr() { - return remoteAddr; - } - - /** - * Get the last updated time for this MailImpl. - * - * @return the last updated time for this MailImpl - */ - @Override - public Date getLastUpdated() { - return lastUpdated; - } - - /** - * <p> - * Return the size of the message including its headers. - * MimeMessage.getSize() method only returns the size of the message body. - * </p> - * <p/> - * <p> - * Note: this size is not guaranteed to be accurate - see Sun's - * documentation of MimeMessage.getSize(). - * </p> - * - * @return approximate size of full message including headers. - * @throws MessagingException if a problem occurs while computing the message size - */ - @Override - public long getMessageSize() throws MessagingException { - return MimeMessageUtil.getMessageSize(message); - } - - /** - * Set the error message associated with this MailImpl. - * - * @param msg the new error message associated with this MailImpl - */ - @Override - public void setErrorMessage(String msg) { - this.errorMessage = msg; - } - - /** - * Set the MimeMessage associated with this MailImpl. - * - * @param message the new MimeMessage associated with this MailImpl - */ - @Override - public void setMessage(MimeMessage message) { - - // TODO: We should use the MimeMessageCopyOnWriteProxy - // everytime we set the MimeMessage. We should - // investigate if we should wrap it here - - if (this.message != message) { - // If a setMessage is called on a Mail that already have a message - // (discouraged) we have to make sure that the message we remove is - // correctly unreferenced and disposed, otherwise it will keep locks - if (this.message != null) { - LifecycleUtil.dispose(this.message); - } - this.message = message; - } - } - - /** - * Set the recipients for this MailImpl. - * - * @param recipients the recipients for this MailImpl - */ - @Override - public void setRecipients(Collection<MailAddress> recipients) { - this.recipients = recipients; - } - - /** - * Set the sender of this MailImpl. - * - * @param sender the sender of this MailImpl - */ - public void setSender(MailAddress sender) { - this.sender = sender; - } - - /** - * Set the state of this MailImpl. - * - * @param state the state of this MailImpl - */ - public void setState(String state) { - this.state = state; - } - - /** - * Set the remote address associated with this MailImpl. - * - * @param remoteHost the new remote host associated with this MailImpl - */ - public void setRemoteHost(String remoteHost) { - this.remoteHost = remoteHost; - } - - /** - * Set the remote address associated with this MailImpl. - * - * @param remoteAddr the new remote address associated with this MailImpl - */ - public void setRemoteAddr(String remoteAddr) { - this.remoteAddr = remoteAddr; - } - - /** - * Set the date this mail was last updated. - * - * @param lastUpdated the date the mail was last updated - */ - public void setLastUpdated(Date lastUpdated) { - // Make a defensive copy to ensure that the date - // doesn't get changed external to the class - if (lastUpdated != null) { - lastUpdated = new Date(lastUpdated.getTime()); - } - this.lastUpdated = lastUpdated; - } - - /** - * Writes the message out to an OutputStream. - * - * @param out the OutputStream to which to write the content - * @throws MessagingException if the MimeMessage is not set for this MailImpl - * @throws IOException if an error occurs while reading or writing from the stream - */ - public void writeMessageTo(OutputStream out) throws IOException, MessagingException { - if (message != null) { - message.writeTo(out); - } else { - throw new MessagingException("No message set for this MailImpl."); - } - } - - // Serializable Methods - // TODO: These need some work. Currently very tightly coupled to - // the internal representation. - - /** - * Read the MailImpl from an <code>ObjectInputStream</code>. - * - * @param in the ObjectInputStream from which the object is read - * @throws IOException if an error occurs while reading from the stream - * @throws ClassNotFoundException ? - * @throws ClassCastException if the serialized objects are not of the appropriate type - */ - @SuppressWarnings("unchecked") - private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { - try { - Object obj = in.readObject(); - if (obj == null) { - sender = null; - } else if (obj instanceof String) { - sender = new MailAddress((String) obj); - } else if (obj instanceof MailAddress) { - sender = (MailAddress) obj; - } - } catch (ParseException pe) { - throw new IOException("Error parsing sender address: " + pe.getMessage()); - } - recipients = (Collection<MailAddress>) in.readObject(); - state = (String) in.readObject(); - errorMessage = (String) in.readObject(); - name = (String) in.readObject(); - remoteHost = (String) in.readObject(); - remoteAddr = (String) in.readObject(); - setLastUpdated((Date) in.readObject()); - // the following is under try/catch to be backwards compatible - // with messages created with James version <= 2.2.0a8 - try { - attributes = (HashMap<String, Object>) in.readObject(); - } catch (OptionalDataException ode) { - if (ode.eof) { - attributes = new HashMap<>(); - } else { - throw ode; - } - } - } - - /** - * Write the MailImpl to an <code>ObjectOutputStream</code>. - * - * @param out the ObjectOutputStream to which the object is written - * @throws IOException if an error occurs while writing to the stream - */ - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - out.writeObject(sender); - out.writeObject(recipients); - out.writeObject(state); - out.writeObject(errorMessage); - out.writeObject(name); - out.writeObject(remoteHost); - out.writeObject(remoteAddr); - out.writeObject(lastUpdated); - out.writeObject(attributes); - } - - @Override - public void dispose() { - LifecycleUtil.dispose(message); - message = null; - } - - /** - * <p> - * This method is necessary, when Mail repositories needs to deal explicitly - * with storing Mail attributes as a Serializable - * </p> - * <p> - * <strong>Note</strong>: This method is not exposed in the Mail interface, - * it is for internal use by James only. - * </p> - * - * @return Serializable of the entire attributes collection - * @since 2.2.0 - */ - public Map<String, Object> getAttributesRaw() { - return attributes; - } - - /** - * <p> - * This method is necessary, when Mail repositories needs to deal explicitly - * with retriving Mail attributes as a Serializable - * </p> - * <p> - * <strong>Note</strong>: This method is not exposed in the Mail interface, - * it is for internal use by James only. - * </p> - * - * @param attr Serializable of the entire attributes collection - * @since 2.2.0 - */ - public void setAttributesRaw(HashMap<String, Object> attr) { - this.attributes = (attr == null) ? new HashMap<>() : attr; - } - - @Override - public Serializable getAttribute(String key) { - return (Serializable) attributes.get(key); - } - - @Override - public Serializable setAttribute(String key, Serializable object) { - return (Serializable) attributes.put(key, object); - } - - @Override - public Serializable removeAttribute(String key) { - return (Serializable) attributes.remove(key); - } - - @Override - public void removeAllAttributes() { - attributes.clear(); - } - - @Override - public Iterator<String> getAttributeNames() { - return attributes.keySet().iterator(); - } - - @Override - public boolean hasAttributes() { - return !attributes.isEmpty(); - } - - /** - * This methods provide cloning for serializable objects. Mail Attributes - * are Serializable but not Clonable so we need a deep copy - * - * @param o Object to be cloned - * @return the cloned Object - * @throws IOException - * @throws ClassNotFoundException - */ - private static Object cloneSerializableObject(Object o) throws IOException, ClassNotFoundException { - ByteArrayOutputStream b = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(b); - out.writeObject(o); - out.flush(); - out.close(); - ByteArrayInputStream bi = new ByteArrayInputStream(b.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bi); - return in.readObject(); - } - - private static final java.util.Random random = new java.util.Random(); // Used - // to - // generate - // new - // mail - // names - - /** - * Create a unique new primary key name for the given MailObject. - * - * @param mail the mail to use as the basis for the new mail name - * @return a new name - */ - public static String newName(Mail mail) throws MessagingException { - String oldName = mail.getName(); - - // Checking if the original mail name is too long, perhaps because of a - // loop caused by a configuration error. - // it could cause a "null pointer exception" in AvalonMailRepository - // much - // harder to understand. - if (oldName.length() > 76) { - int count = 0; - int index = 0; - while ((index = oldName.indexOf('!', index + 1)) >= 0) { - count++; - } - // It looks like a configuration loop. It's better to stop. - if (count > 7) { - throw new MessagingException("Unable to create a new message name: too long." + " Possible loop in config.xml."); - } else { - oldName = oldName.substring(0, 76); - } - } - - return oldName + "-!" + random.nextInt(1048576); - } - - /** - * Generate a new identifier/name for a mail being processed by this server. - * - * @return the new identifier - */ - public static String getId() { - return "Mail" + System.currentTimeMillis() + "-" + UUID.randomUUID(); - } - - @Override - public PerRecipientHeaders getPerRecipientSpecificHeaders() { - return perRecipientSpecificHeaders; - } - - @Override - public void addSpecificHeaderForRecipient(Header header, MailAddress recipient) { - perRecipientSpecificHeaders.addHeaderForRecipient(header, recipient); - } -}
http://git-wip-us.apache.org/repos/asf/james-project/blob/936746b9/server/container/core/src/main/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java ---------------------------------------------------------------------- diff --git a/server/container/core/src/main/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java b/server/container/core/src/main/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java deleted file mode 100644 index f75d7dd..0000000 --- a/server/container/core/src/main/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java +++ /dev/null @@ -1,561 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.core; - -import javax.activation.DataHandler; -import javax.mail.Address; -import javax.mail.Flags; -import javax.mail.Folder; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Flags.Flag; -import javax.mail.internet.MimeMessage; -import javax.mail.search.SearchTerm; - -import org.apache.james.lifecycle.api.Disposable; -import org.apache.james.lifecycle.api.LifecycleUtil; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Date; -import java.util.Enumeration; - -/** - * This object wraps a "possibly shared" MimeMessage tracking copies and - * automatically cloning it (if shared) when a write operation is invoked. - */ -public class MimeMessageCopyOnWriteProxy extends MimeMessage implements Disposable { - - /** - * Used internally to track the reference count It is important that this is - * static otherwise it will keep a reference to the parent object. - */ - protected static class MessageReferenceTracker { - - /** - * reference counter - */ - private int referenceCount = 1; - - /** - * The mime message in memory - */ - private MimeMessage wrapped = null; - - public MessageReferenceTracker(MimeMessage ref) { - wrapped = ref; - } - - protected synchronized void incrementReferenceCount() { - referenceCount++; - } - - protected synchronized void decrementReferenceCount() { - referenceCount--; - if (referenceCount <= 0) { - LifecycleUtil.dispose(wrapped); - wrapped = null; - } - } - - protected synchronized int getReferenceCount() { - return referenceCount; - } - - public synchronized MimeMessage getWrapped() { - return wrapped; - } - - } - - protected MessageReferenceTracker refCount; - - public MimeMessageCopyOnWriteProxy(MimeMessage original) { - this(original, false); - } - - public MimeMessageCopyOnWriteProxy(MimeMessageSource original) throws MessagingException { - this(new MimeMessageWrapper(original), true); - } - - /** - * Private constructor providing an external reference counter. - */ - private MimeMessageCopyOnWriteProxy(MimeMessage original, boolean writeable) { - super(Session.getDefaultInstance(System.getProperties(), null)); - - if (original instanceof MimeMessageCopyOnWriteProxy) { - refCount = ((MimeMessageCopyOnWriteProxy) original).refCount; - } else { - refCount = new MessageReferenceTracker(original); - } - - if (!writeable) { - refCount.incrementReferenceCount(); - } - } - - /** - * Check the number of references over the MimeMessage and clone it if - * needed before returning the reference - * - * @throws MessagingException - * exception - */ - protected synchronized MimeMessage getWrappedMessageForWriting() throws MessagingException { - if (refCount.getReferenceCount() > 1) { - refCount.decrementReferenceCount(); - refCount = new MessageReferenceTracker(new MimeMessageWrapper(refCount.getWrapped())); - } - return refCount.getWrapped(); - } - - /** - * Return wrapped mimeMessage - * - * @return wrapped return the wrapped mimeMessage - */ - public synchronized MimeMessage getWrappedMessage() { - return refCount.getWrapped(); - } - - @Override - public synchronized void dispose() { - if (refCount != null) { - refCount.decrementReferenceCount(); - refCount = null; - } - } - - @Override - public void writeTo(OutputStream os) throws IOException, MessagingException { - getWrappedMessage().writeTo(os); - } - - /** - * Rewritten for optimization purposes - */ - @Override - public void writeTo(OutputStream os, String[] ignoreList) throws IOException, MessagingException { - getWrappedMessage().writeTo(os, ignoreList); - } - - /* - * Various reader methods - */ - - @Override - public Address[] getFrom() throws MessagingException { - return getWrappedMessage().getFrom(); - } - - @Override - public Address[] getRecipients(Message.RecipientType type) throws MessagingException { - return getWrappedMessage().getRecipients(type); - } - - @Override - public Address[] getAllRecipients() throws MessagingException { - return getWrappedMessage().getAllRecipients(); - } - - @Override - public Address[] getReplyTo() throws MessagingException { - return getWrappedMessage().getReplyTo(); - } - - @Override - public String getSubject() throws MessagingException { - return getWrappedMessage().getSubject(); - } - - @Override - public Date getSentDate() throws MessagingException { - return getWrappedMessage().getSentDate(); - } - - @Override - public Date getReceivedDate() throws MessagingException { - return getWrappedMessage().getReceivedDate(); - } - - @Override - public int getSize() throws MessagingException { - return getWrappedMessage().getSize(); - } - - @Override - public int getLineCount() throws MessagingException { - return getWrappedMessage().getLineCount(); - } - - @Override - public String getContentType() throws MessagingException { - return getWrappedMessage().getContentType(); - } - - @Override - public boolean isMimeType(String mimeType) throws MessagingException { - return getWrappedMessage().isMimeType(mimeType); - } - - @Override - public String getDisposition() throws MessagingException { - return getWrappedMessage().getDisposition(); - } - - @Override - public String getEncoding() throws MessagingException { - return getWrappedMessage().getEncoding(); - } - - @Override - public String getContentID() throws MessagingException { - return getWrappedMessage().getContentID(); - } - - @Override - public String getContentMD5() throws MessagingException { - return getWrappedMessage().getContentMD5(); - } - - @Override - public String getDescription() throws MessagingException { - return getWrappedMessage().getDescription(); - } - - @Override - public String[] getContentLanguage() throws MessagingException { - return getWrappedMessage().getContentLanguage(); - } - - @Override - public String getMessageID() throws MessagingException { - return getWrappedMessage().getMessageID(); - } - - @Override - public String getFileName() throws MessagingException { - return getWrappedMessage().getFileName(); - } - - @Override - public InputStream getInputStream() throws IOException, MessagingException { - return getWrappedMessage().getInputStream(); - } - - @Override - public DataHandler getDataHandler() throws MessagingException { - return getWrappedMessage().getDataHandler(); - } - - @Override - public Object getContent() throws IOException, MessagingException { - return getWrappedMessage().getContent(); - } - - @Override - public String[] getHeader(String name) throws MessagingException { - return getWrappedMessage().getHeader(name); - } - - @Override - public String getHeader(String name, String delimiter) throws MessagingException { - return getWrappedMessage().getHeader(name, delimiter); - } - - @SuppressWarnings("unchecked") - @Override - public Enumeration<String> getAllHeaders() throws MessagingException { - return getWrappedMessage().getAllHeaders(); - } - - @SuppressWarnings("unchecked") - @Override - public Enumeration<String> getMatchingHeaders(String[] names) throws MessagingException { - return getWrappedMessage().getMatchingHeaders(names); - } - - @SuppressWarnings("unchecked") - @Override - public Enumeration<String> getNonMatchingHeaders(String[] names) throws MessagingException { - return getWrappedMessage().getNonMatchingHeaders(names); - } - - @SuppressWarnings("unchecked") - @Override - public Enumeration<String> getAllHeaderLines() throws MessagingException { - return getWrappedMessage().getAllHeaderLines(); - } - - @SuppressWarnings("unchecked") - @Override - public Enumeration<String> getMatchingHeaderLines(String[] names) throws MessagingException { - return getWrappedMessage().getMatchingHeaderLines(names); - } - - @SuppressWarnings("unchecked") - @Override - public Enumeration<String> getNonMatchingHeaderLines(String[] names) throws MessagingException { - return getWrappedMessage().getNonMatchingHeaderLines(names); - } - - @Override - public Flags getFlags() throws MessagingException { - return getWrappedMessage().getFlags(); - } - - @Override - public boolean isSet(Flags.Flag flag) throws MessagingException { - return getWrappedMessage().isSet(flag); - } - - @Override - public Address getSender() throws MessagingException { - return getWrappedMessage().getSender(); - } - - @Override - public boolean match(SearchTerm arg0) throws MessagingException { - return getWrappedMessage().match(arg0); - } - - @Override - public InputStream getRawInputStream() throws MessagingException { - return getWrappedMessage().getRawInputStream(); - } - - @Override - public Folder getFolder() { - return getWrappedMessage().getFolder(); - } - - @Override - public int getMessageNumber() { - return getWrappedMessage().getMessageNumber(); - } - - @Override - public boolean isExpunged() { - return getWrappedMessage().isExpunged(); - } - - @Override - public boolean equals(Object arg0) { - return getWrappedMessage().equals(arg0); - } - - @Override - public int hashCode() { - return getWrappedMessage().hashCode(); - } - - @Override - public String toString() { - return getWrappedMessage().toString(); - } - - @Override - public void setFrom(Address address) throws MessagingException { - getWrappedMessageForWriting().setFrom(address); - } - - @Override - public void setFrom() throws MessagingException { - getWrappedMessageForWriting().setFrom(); - } - - @Override - public void addFrom(Address[] addresses) throws MessagingException { - getWrappedMessageForWriting().addFrom(addresses); - } - - @Override - public void setRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException { - getWrappedMessageForWriting().setRecipients(type, addresses); - } - - @Override - public void addRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException { - getWrappedMessageForWriting().addRecipients(type, addresses); - } - - @Override - public void setReplyTo(Address[] addresses) throws MessagingException { - getWrappedMessageForWriting().setReplyTo(addresses); - } - - @Override - public void setSubject(String subject) throws MessagingException { - getWrappedMessageForWriting().setSubject(subject); - } - - @Override - public void setSubject(String subject, String charset) throws MessagingException { - getWrappedMessageForWriting().setSubject(subject, charset); - } - - @Override - public void setSentDate(Date d) throws MessagingException { - getWrappedMessageForWriting().setSentDate(d); - } - - @Override - public void setDisposition(String disposition) throws MessagingException { - getWrappedMessageForWriting().setDisposition(disposition); - } - - @Override - public void setContentID(String cid) throws MessagingException { - getWrappedMessageForWriting().setContentID(cid); - } - - @Override - public void setContentMD5(String md5) throws MessagingException { - getWrappedMessageForWriting().setContentMD5(md5); - } - - @Override - public void setDescription(String description) throws MessagingException { - getWrappedMessageForWriting().setDescription(description); - } - - @Override - public void setDescription(String description, String charset) throws MessagingException { - getWrappedMessageForWriting().setDescription(description, charset); - } - - @Override - public void setContentLanguage(String[] languages) throws MessagingException { - getWrappedMessageForWriting().setContentLanguage(languages); - } - - @Override - public void setFileName(String filename) throws MessagingException { - getWrappedMessageForWriting().setFileName(filename); - } - - @Override - public void setDataHandler(DataHandler dh) throws MessagingException { - getWrappedMessageForWriting().setDataHandler(dh); - } - - @Override - public void setContent(Object o, String type) throws MessagingException { - getWrappedMessageForWriting().setContent(o, type); - } - - @Override - public void setText(String text) throws MessagingException { - getWrappedMessageForWriting().setText(text); - } - - @Override - public void setText(String text, String charset) throws MessagingException { - getWrappedMessageForWriting().setText(text, charset); - } - - @Override - public void setContent(Multipart mp) throws MessagingException { - getWrappedMessageForWriting().setContent(mp); - } - - /** - * This does not need a writable message - */ - @Override - public Message reply(boolean replyToAll) throws MessagingException { - return getWrappedMessage().reply(replyToAll); - } - - @Override - public void setHeader(String name, String value) throws MessagingException { - getWrappedMessageForWriting().setHeader(name, value); - } - - @Override - public void addHeader(String name, String value) throws MessagingException { - getWrappedMessageForWriting().addHeader(name, value); - } - - @Override - public void removeHeader(String name) throws MessagingException { - getWrappedMessageForWriting().removeHeader(name); - } - - @Override - public void addHeaderLine(String line) throws MessagingException { - getWrappedMessageForWriting().addHeaderLine(line); - } - - @Override - public void setFlags(Flags flag, boolean set) throws MessagingException { - getWrappedMessageForWriting().setFlags(flag, set); - } - - @Override - public void saveChanges() throws MessagingException { - getWrappedMessageForWriting().saveChanges(); - } - - /* - * Since JavaMail 1.2 - */ - - @Override - public void addRecipients(Message.RecipientType type, String addresses) throws MessagingException { - getWrappedMessageForWriting().addRecipients(type, addresses); - } - - @Override - public void setRecipients(Message.RecipientType type, String addresses) throws MessagingException { - getWrappedMessageForWriting().setRecipients(type, addresses); - } - - @Override - public void setSender(Address arg0) throws MessagingException { - getWrappedMessageForWriting().setSender(arg0); - } - - public void addRecipient(RecipientType arg0, Address arg1) throws MessagingException { - getWrappedMessageForWriting().addRecipient(arg0, arg1); - } - - @Override - public void setFlag(Flag arg0, boolean arg1) throws MessagingException { - getWrappedMessageForWriting().setFlag(arg0, arg1); - } - - public long getMessageSize() throws MessagingException { - return MimeMessageUtil.getMessageSize(getWrappedMessage()); - } - - /** - * Since javamail 1.4 - */ - @Override - public void setText(String text, String charset, String subtype) throws MessagingException { - getWrappedMessage().setText(text, charset, subtype); - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/936746b9/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStream.java ---------------------------------------------------------------------- diff --git a/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStream.java b/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStream.java deleted file mode 100644 index f4ea3a7..0000000 --- a/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStream.java +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.core; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; - -/** - * Provide an {@link InputStream} over an {@link MimeMessage} - */ -public class MimeMessageInputStream extends InputStream { - private final InputStream in; - - /** - * Provide an {@link InputStream} over a {@link MimeMessage}. - * - * @param message - * the message to wrap - * @param tryCast - * try to cast the {@link MimeMessage} to - * {@link MimeMessageCopyOnWriteProxy} / - * {@link MimeMessageWrapper} to do some optimized processing if - * possible - * @throws MessagingException - */ - public MimeMessageInputStream(MimeMessage message, boolean tryCast) throws MessagingException { - MimeMessage m = message; - - // check if we need to use the wrapped message - if (tryCast && m instanceof MimeMessageCopyOnWriteProxy) { - m = ((MimeMessageCopyOnWriteProxy) m).getWrappedMessage(); - } - - // check if we can use optimized operations - if (tryCast && m instanceof MimeMessageWrapper) { - in = ((MimeMessageWrapper) m).getMessageInputStream(); - } else { - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - message.writeTo(out); - in = new ByteArrayInputStream(out.toByteArray()); - } catch (IOException e1) { - throw new MessagingException("Unable to read message " + message, e1); - } - - } - - } - - /** - * Use true as tryCast parameter - * - * {@link #MimeMessageInputStream(MimeMessage, boolean)} - */ - public MimeMessageInputStream(MimeMessage message) throws MessagingException { - this(message, true); - } - - @Override - public int read() throws IOException { - return in.read(); - } - - @Override - public void close() throws IOException { - in.close(); - } - - @Override - public int available() throws IOException { - return in.available(); - } - - @Override - public void mark(int readlimit) { - in.mark(readlimit); - } - - @Override - public boolean markSupported() { - return in.markSupported(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - return in.read(b, off, len); - } - - @Override - public int read(byte[] b) throws IOException { - return in.read(b); - } - - @Override - public void reset() throws IOException { - in.reset(); - } - - @Override - public long skip(long n) throws IOException { - return in.skip(n); - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/936746b9/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java ---------------------------------------------------------------------- diff --git a/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java b/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java deleted file mode 100644 index 46d1afd..0000000 --- a/server/container/core/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.core; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import javax.mail.MessagingException; -import javax.mail.util.SharedByteArrayInputStream; -import javax.mail.util.SharedFileInputStream; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.DeferredFileOutputStream; -import org.apache.james.lifecycle.api.Disposable; - -/** - * Takes an input stream and creates a repeatable input stream source for a - * MimeMessageWrapper. It does this by completely reading the input stream and - * saving that to data to an {@link DeferredFileOutputStream} with its threshold set to 100kb - */ -public class MimeMessageInputStreamSource extends MimeMessageSource implements Disposable { - - private final List<InputStream> streams = new ArrayList<>(); - - /** - * A temporary file used to hold the message stream - */ - private DeferredFileOutputStream out; - - /** - * The full path of the temporary file - */ - private final String sourceId; - - /** - * 100kb threshold for the stream. - */ - private final static int THRESHOLD = 1024 * 100; - - /** - * Temporary directory to use - */ - private final static File TMPDIR = new File(System.getProperty("java.io.tmpdir")); - - /** - * Construct a new MimeMessageInputStreamSource from an - * <code>InputStream</code> that contains the bytes of a MimeMessage. - * - * @param key the prefix for the name of the temp file - * @param in the stream containing the MimeMessage - * @throws MessagingException if an error occurs while trying to store the stream - */ - public MimeMessageInputStreamSource(String key, InputStream in) throws MessagingException { - super(); - // We want to immediately read this into a temporary file - // Create a temp file and channel the input stream into it - try { - out = new DeferredFileOutputStream(THRESHOLD, "mimemessage-" + key, ".m64", TMPDIR); - IOUtils.copy(in, out); - sourceId = key; - } catch (IOException ioe) { - File file = out.getFile(); - if (file != null) { - FileUtils.deleteQuietly(file); - } - throw new MessagingException("Unable to retrieve the data: " + ioe.getMessage(), ioe); - } finally { - try { - if (out != null) { - out.close(); - } - } catch (IOException ioe) { - // Ignored - logging unavailable to log this non-fatal error. - } - - try { - if (in != null) { - in.close(); - } - } catch (IOException ioe) { - // Ignored - logging unavailable to log this non-fatal error. - } - - } - } - - public MimeMessageInputStreamSource(String key) { - super(); - out = new DeferredFileOutputStream(THRESHOLD, key, ".m64", TMPDIR); - sourceId = key; - } - - /** - * Returns the unique identifier of this input stream source - * - * @return the unique identifier for this MimeMessageInputStreamSource - */ - public String getSourceId() { - return sourceId; - } - - /** - * Get an input stream to retrieve the data stored in the temporary file - * - * @return a <code>BufferedInputStream</code> containing the data - */ - public synchronized InputStream getInputStream() throws IOException { - InputStream in; - if (out.isInMemory()) { - in = new SharedByteArrayInputStream(out.getData()); - } else { - in = new SharedFileInputStream(out.getFile()); - } - streams.add(in); - return in; - } - - /** - * Get the size of the temp file - * - * @return the size of the temp file - * @throws IOException if an error is encoutered while computing the size of the - * message - */ - @Override - public long getMessageSize() throws IOException { - return out.getByteCount(); - } - - public OutputStream getWritableOutputStream() { - return out; - } - - @Override - public void dispose() { - // explicit close all streams - for (InputStream stream : streams) { - IOUtils.closeQuietly(stream); - } - - if (out != null) { - IOUtils.closeQuietly(out); - File file = out.getFile(); - if (file != null) { - FileUtils.deleteQuietly(file); - file = null; - } - out = null; - } - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/936746b9/server/container/core/src/main/java/org/apache/james/core/MimeMessageSource.java ---------------------------------------------------------------------- diff --git a/server/container/core/src/main/java/org/apache/james/core/MimeMessageSource.java b/server/container/core/src/main/java/org/apache/james/core/MimeMessageSource.java deleted file mode 100644 index 57e1e23..0000000 --- a/server/container/core/src/main/java/org/apache/james/core/MimeMessageSource.java +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.core; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This defines a reusable datasource that can supply an input stream with - * MimeMessage data. This allows a MimeMessageWrapper or other classes to grab - * the underlying data. - * - * @see MimeMessageWrapper - */ -public abstract class MimeMessageSource { - - /** - * Returns a unique String ID that represents the location from where this - * file is loaded. This will be used to identify where the data is, - * primarily to avoid situations where this data would get overwritten. - * - * @return the String ID - */ - public abstract String getSourceId(); - - /** - * Get an input stream to retrieve the data stored in the datasource - * - * @return a <code>InputStream</code> containing the data - * - * @throws IOException - * if an error occurs while generating the InputStream - */ - public abstract InputStream getInputStream() throws IOException; - - /** - * Return the size of all the data. Default implementation... others can - * override to do this much faster - * - * @return the size of the data represented by this source - * @throws IOException - * if an error is encountered while computing the message size - */ - public long getMessageSize() throws IOException { - int size = 0; - InputStream in = null; - try { - in = getInputStream(); - int read; - byte[] data = new byte[1024]; - while ((read = in.read(data)) > 0) { - size += read; - } - } finally { - try { - if (in != null) { - in.close(); - } - } catch (IOException ioe) { - // Exception ignored because logging is - // unavailable - } - } - return size; - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/936746b9/server/container/core/src/main/java/org/apache/james/core/MimeMessageUtil.java ---------------------------------------------------------------------- diff --git a/server/container/core/src/main/java/org/apache/james/core/MimeMessageUtil.java b/server/container/core/src/main/java/org/apache/james/core/MimeMessageUtil.java deleted file mode 100644 index 5ee7a49..0000000 --- a/server/container/core/src/main/java/org/apache/james/core/MimeMessageUtil.java +++ /dev/null @@ -1,311 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.core; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Enumeration; - -import javax.activation.UnsupportedDataTypeException; -import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeUtility; - -import org.apache.commons.io.IOUtils; - -/** - * Utility class to provide optimized write methods for the various MimeMessage - * implementations. - */ -public class MimeMessageUtil { - - /** - * Convenience method to take any MimeMessage and write the headers and body - * to two different output streams - * - * @param message - * the MimeMessage reading from - * @param headerOs - * the OutputStream writting the headers to - * @param bodyOs - * the OutputStream writting the body to - * @throws IOException - * get thrown if an IO Error detected while writing to the - * streams - * @throws MessagingException - * get thrown if an error detected while reading the message - */ - 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 - * - * @param message - * the MimeMessage reading from - * @param headerOs - * the OutputStream writting the headers to - * @param bodyOs - * the OutputStream writting the body to - * @param ignoreList - * the String[] which contains headers which should be ignored - * @throws IOException - * get thrown if an IO Error detected while writing to the - * streams - * @throws MessagingException - * get thrown if an error detected while reading the message - */ - public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException { - MimeMessage testMessage = message; - if (message instanceof MimeMessageCopyOnWriteProxy) { - MimeMessageCopyOnWriteProxy wr = (MimeMessageCopyOnWriteProxy) message; - testMessage = wr.getWrappedMessage(); - } - if (testMessage instanceof MimeMessageWrapper) { - MimeMessageWrapper wrapper = (MimeMessageWrapper) testMessage; - if (!wrapper.isModified()) { - wrapper.writeTo(headerOs, bodyOs, ignoreList); - return; - } - } - writeToInternal(message, headerOs, bodyOs, ignoreList); - } - - /** - * - * @param message - * @param headerOs - * @param bodyOs - * @param ignoreList - * @throws MessagingException - * @throws IOException - * @throws UnsupportedDataTypeException - */ - public static void writeToInternal(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws MessagingException, IOException { - if (message.getMessageID() == null) { - message.saveChanges(); - } - - writeHeadersTo(message, headerOs, ignoreList); - - // Write the body to the output stream - writeMessageBodyTo(message, bodyOs); - } - - /** - * Write message body of given mimeessage to the given outputStream - * - * @param message - * the MimeMessage used as input - * @param bodyOs - * the OutputStream to write the message body to - * @throws IOException - * @throws UnsupportedDataTypeException - * @throws MessagingException - */ - public static void writeMessageBodyTo(MimeMessage message, OutputStream bodyOs) throws IOException, MessagingException { - OutputStream bos; - InputStream bis; - - try { - // Get the message as a stream. This will encode - // objects as necessary, and we have some input from - // decoding an re-encoding the stream. I'd prefer the - // raw stream, but see - bos = MimeUtility.encode(bodyOs, message.getEncoding()); - bis = message.getInputStream(); - } catch (UnsupportedDataTypeException | MessagingException udte) { - /* - * If we get an UnsupportedDataTypeException try using the raw input - * stream as a "best attempt" at rendering a message. - * - * WARNING: JavaMail v1.3 getRawInputStream() returns INVALID - * (unchanged) content for a changed message. getInputStream() works - * properly, but in this case has failed due to a missing - * DataHandler. - * - * MimeMessage.getRawInputStream() may throw a "no content" - * MessagingException. In JavaMail v1.3, when you initially create a - * message using MimeMessage APIs, there is no raw content - * available. getInputStream() works, but getRawInputStream() throws - * an exception. If we catch that exception, throw the UDTE. It - * should mean that someone has locally constructed a message part - * for which JavaMail doesn't have a DataHandler. - */ - - try { - bis = message.getRawInputStream(); - bos = bodyOs; - } catch (javax.mail.MessagingException ignored) { - throw udte; - } - } - - try { - IOUtils.copy(bis, bos); - } finally { - IOUtils.closeQuietly(bis); - } - } - - /** - * Write the message headers to the given outputstream - * - * @param message - * the MimeMessage to read from - * @param headerOs - * the OutputStream to which the headers get written - * @param ignoreList - * the String[] which holds headers which should be ignored - * @throws MessagingException - */ - private static void writeHeadersTo(MimeMessage message, OutputStream headerOs, String[] ignoreList) throws MessagingException { - // Write the headers (minus ignored ones) - @SuppressWarnings("unchecked") - Enumeration<String> headers = message.getNonMatchingHeaderLines(ignoreList); - writeHeadersTo(headers, headerOs); - } - - /** - * Write the message headers to the given outputstream - * - * @param headers - * the Enumeration which holds the headers - * @param headerOs - * the OutputStream to which the headers get written - * @throws MessagingException - */ - public static void writeHeadersTo(Enumeration<String> headers, OutputStream headerOs) throws MessagingException { - try { - IOUtils.copy(new InternetHeadersInputStream(headers), headerOs); - } catch (IOException e) { - throw new MessagingException("Unable to write headers to stream", e); - } - } - - /** - * Get an InputStream which holds all headers of the given MimeMessage - * - * @param message - * the MimeMessage used as source - * @param ignoreList - * the String[] which holds headers which should be ignored - * @return stream the InputStream which holds the headers - * @throws MessagingException - */ - @SuppressWarnings("unchecked") - public static InputStream getHeadersInputStream(MimeMessage message, String[] ignoreList) throws MessagingException { - return new InternetHeadersInputStream(message.getNonMatchingHeaderLines(ignoreList)); - } - - /** - * Slow method to calculate the exact size of a message! - */ - private static final class SizeCalculatorOutputStream extends OutputStream { - long size = 0; - - public void write(int arg0) throws IOException { - size++; - } - - public long getSize() { - return size; - } - - public void write(byte[] arg0, int arg1, int arg2) throws IOException { - size += arg2; - } - - public void write(byte[] arg0) throws IOException { - size += arg0.length; - } - } - - /** - * Return the full site of an mimeMessage - * - * @return size of full message including headers - * @throws MessagingException - * if a problem occours while computing the message size - */ - public static long getMessageSize(MimeMessage message) throws MessagingException { - // If we have a MimeMessageWrapper, then we can ask it for just the - // message size and skip calculating it - long size = -1; - - if (message instanceof MimeMessageWrapper) { - MimeMessageWrapper wrapper = (MimeMessageWrapper) message; - size = wrapper.getMessageSize(); - } else if (message instanceof MimeMessageCopyOnWriteProxy) { - MimeMessageCopyOnWriteProxy wrapper = (MimeMessageCopyOnWriteProxy) message; - size = wrapper.getMessageSize(); - } - - if (size == -1) { - size = calculateMessageSize(message); - } - - return size; - } - - /** - * Calculate the size of the give mimeMessage - * - * @param message - * the MimeMessage - * @return size the calculated size - * @throws MessagingException - * if a problem occours while calculate the message size - */ - public static long calculateMessageSize(MimeMessage message) throws MessagingException { - long size; - // SK: Should probably eventually store this as a locally - // maintained value (so we don't have to load and reparse - // messages each time). - size = message.getSize(); - if (size != -1) { - Enumeration<?> e = message.getAllHeaderLines(); - if (e.hasMoreElements()) { - size += 2; - } - while (e.hasMoreElements()) { - // add 2 bytes for the CRLF - size += ((String) e.nextElement()).length() + 2; - } - } - - if (size == -1) { - SizeCalculatorOutputStream out = new SizeCalculatorOutputStream(); - try { - message.writeTo(out); - } catch (IOException e) { - // should never happen as SizeCalculator does not actually throw - // IOExceptions. - throw new MessagingException("IOException wrapped by getMessageSize", e); - } - size = out.getSize(); - } - return size; - } - -} --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org