Author: norman Date: Wed Aug 24 18:12:17 2011 New Revision: 1161215 URL: http://svn.apache.org/viewvc?rev=1161215&view=rev Log: Add Message.getFullContent() to retrieve full message content. The AbstractMessage does implement this with a SequenceInputStream but subclasses MAY override this for a more performant solution. Beside this Message.getHeaderContent() now MUST include the empy line as last bytes to be able to use it directly later without the need to modify it an futher. All of this allows later implementation of zero-copy file transfer by casting to FileInputStream when possible and access the FileChannel.See MAILBOX-128
Added: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/LimitingFileInputStream.java (with props) Removed: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/LazySkippingInputStream.java Modified: james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMessage.java james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAMessage.java james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAStreamingMessage.java james/mailbox/trunk/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MessageResultImpl.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MimeDescriptorImpl.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/AbstractMessage.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/InputStreamContent.java james/mailbox/trunk/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java Modified: james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMessage.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMessage.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMessage.java (original) +++ james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMessage.java Wed Aug 24 18:12:17 2011 @@ -40,12 +40,10 @@ import org.apache.jackrabbit.commons.Jcr import org.apache.james.mailbox.MailboxException; import org.apache.james.mailbox.jcr.JCRImapConstants; import org.apache.james.mailbox.jcr.Persistent; -import org.apache.james.mailbox.store.ResultUtils; import org.apache.james.mailbox.store.mail.model.AbstractMessage; import org.apache.james.mailbox.store.mail.model.Message; import org.apache.james.mailbox.store.mail.model.Property; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; -import org.apache.james.mailbox.store.streaming.LazySkippingInputStream; import org.slf4j.Logger; /** @@ -142,7 +140,7 @@ public class JCRMessage extends Abstract this.modSeq = modSeq; this.logger = logger; try { - this.content = new SharedByteArrayInputStream(IOUtils.toByteArray(ResultUtils.toInput(message))); + this.content = new SharedByteArrayInputStream(IOUtils.toByteArray(message.getFullContent())); } catch (IOException e) { throw new MailboxException("Unable to parse message",e); } @@ -679,7 +677,8 @@ public class JCRMessage extends Abstract } - protected InputStream getFullContent() throws IOException { + @Override + public InputStream getFullContent() throws IOException { if (isPersistent()) { try { //TODO: Maybe we should cache this somehow... @@ -697,7 +696,9 @@ public class JCRMessage extends Abstract * @see org.apache.james.mailbox.store.mail.model.Message#getBodyContent() */ public InputStream getBodyContent() throws IOException { - return new LazySkippingInputStream(getFullContent(), getBodyStartOctet()); + InputStream body = getFullContent(); + IOUtils.skipFully(body, getBodyStartOctet()); + return body; } /* @@ -754,7 +755,7 @@ public class JCRMessage extends Abstract * @see org.apache.james.mailbox.store.mail.model.Message#getHeaderContent() */ public InputStream getHeaderContent() throws IOException { - long limit = getBodyStartOctet() -2; + long limit = getBodyStartOctet(); if (limit < 0) { limit = 0; } Modified: james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAMessage.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAMessage.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAMessage.java (original) +++ james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAMessage.java Wed Aug 24 18:12:17 2011 @@ -61,7 +61,7 @@ public class JPAMessage extends Abstract public JPAMessage(JPAMailbox mailbox,Date internalDate, int size, Flags flags, SharedInputStream content, int bodyStartOctet, final PropertyBuilder propertyBuilder) throws MailboxException { super(mailbox, internalDate, flags, size ,bodyStartOctet, propertyBuilder); try { - int headerEnd = bodyStartOctet -2; + int headerEnd = bodyStartOctet; if (headerEnd < 0) { headerEnd = 0; } Modified: james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAStreamingMessage.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAStreamingMessage.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAStreamingMessage.java (original) +++ james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/JPAStreamingMessage.java Wed Aug 24 18:12:17 2011 @@ -33,7 +33,6 @@ import javax.persistence.Table; import org.apache.commons.io.IOUtils; import org.apache.james.mailbox.MailboxException; import org.apache.james.mailbox.jpa.mail.model.JPAMailbox; -import org.apache.james.mailbox.store.ResultUtils; import org.apache.james.mailbox.store.mail.model.Message; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.openjpa.persistence.Persistent; @@ -89,7 +88,7 @@ public class JPAStreamingMessage extends public JPAStreamingMessage(JPAMailbox mailbox, long uid, long modSeq, Message<?> message) throws MailboxException { super(mailbox, uid, modSeq, message); try { - this.content = new SharedByteArrayInputStream(IOUtils.toByteArray(ResultUtils.toInput(message))); + this.content = new SharedByteArrayInputStream(IOUtils.toByteArray(message.getFullContent())); this.header = getHeaderContent(); this.body = getBodyContent(); } catch (IOException e) { Modified: james/mailbox/trunk/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java (original) +++ james/mailbox/trunk/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java Wed Aug 24 18:12:17 2011 @@ -56,7 +56,6 @@ import org.apache.james.mailbox.SearchQu import org.apache.james.mailbox.SearchQuery.NumericRange; import org.apache.james.mailbox.SearchQuery.UidCriterion; import org.apache.james.mailbox.UnsupportedSearchException; -import org.apache.james.mailbox.store.ResultUtils; import org.apache.james.mailbox.store.mail.MessageMapperFactory; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.Message; @@ -637,7 +636,7 @@ public class LuceneMessageSearchIndex<Id try { // parse the message to index headers and body - parser.parse(ResultUtils.toInput(membership)); + parser.parse(membership.getFullContent()); } catch (MimeException e) { // This should never happen as it was parsed before too without problems. throw new MailboxException("Unable to index content of message", e); Modified: james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java (original) +++ james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java Wed Aug 24 18:12:17 2011 @@ -45,7 +45,6 @@ import org.apache.james.mailbox.maildir. import org.apache.james.mailbox.maildir.MaildirMessageName; import org.apache.james.mailbox.maildir.MaildirStore; import org.apache.james.mailbox.maildir.mail.model.MaildirMessage; -import org.apache.james.mailbox.store.ResultUtils; import org.apache.james.mailbox.store.SimpleMessageMetaData; import org.apache.james.mailbox.store.mail.AbstractMessageMapper; import org.apache.james.mailbox.store.mail.model.Mailbox; @@ -298,7 +297,7 @@ public class MaildirMessageMapper extend try { messageFile.createNewFile(); fos = new FileOutputStream(messageFile); - input = ResultUtils.toInput(message); + input = message.getFullContent(); byte[] b = new byte[BUF_SIZE]; int len = 0; while ((len = input.read(b)) != -1) Modified: james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java (original) +++ james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java Wed Aug 24 18:12:17 2011 @@ -31,7 +31,6 @@ import javax.mail.Flags; import javax.mail.util.SharedFileInputStream; import org.apache.commons.io.IOUtils; -import org.apache.commons.io.input.BoundedInputStream; import org.apache.james.mailbox.maildir.MaildirFolder; import org.apache.james.mailbox.maildir.MaildirMessageName; import org.apache.james.mailbox.store.mail.model.AbstractMessage; @@ -39,7 +38,7 @@ import org.apache.james.mailbox.store.ma import org.apache.james.mailbox.store.mail.model.Property; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.streaming.CountingInputStream; -import org.apache.james.mailbox.store.streaming.LazySkippingInputStream; +import org.apache.james.mailbox.store.streaming.LimitingFileInputStream; import org.apache.james.mime4j.MimeException; import org.apache.james.mime4j.message.DefaultBodyDescriptorBuilder; import org.apache.james.mime4j.message.MaximalBodyDescriptor; @@ -424,7 +423,11 @@ public class MaildirMessage extends Abst return messageName.getInternalDate(); } - private InputStream getFullContent() throws IOException { + /** + * Return the full content of the message via a {@link FileInputStream} + */ + @Override + public InputStream getFullContent() throws IOException { return new FileInputStream(messageName.getFile()); } @@ -434,7 +437,9 @@ public class MaildirMessage extends Abst */ public InputStream getBodyContent() throws IOException { parseMessage(); - return new LazySkippingInputStream(getFullContent(), bodyStartOctet); + FileInputStream body = new FileInputStream(messageName.getFile()); + IOUtils.skipFully(body, bodyStartOctet); + return body; } @@ -450,11 +455,11 @@ public class MaildirMessage extends Abst @Override public InputStream getHeaderContent() throws IOException { parseMessage(); - long limit = getBodyStartOctet() -2; + long limit = getBodyStartOctet(); if (limit < 0) { limit = 0; } - return new BoundedInputStream(getFullContent(), limit); + return new LimitingFileInputStream(messageName.getFile(), limit); } Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MessageResultImpl.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MessageResultImpl.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MessageResultImpl.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MessageResultImpl.java Wed Aug 24 18:12:17 2011 @@ -394,7 +394,7 @@ public class MessageResultImpl implement @Override public long size() { - return msg.getFullContentOctets() - msg.getBodyOctets() -2; + return msg.getFullContentOctets() - msg.getBodyOctets(); } @Override Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MimeDescriptorImpl.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MimeDescriptorImpl.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MimeDescriptorImpl.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/MimeDescriptorImpl.java Wed Aug 24 18:12:17 2011 @@ -335,6 +335,7 @@ public class MimeDescriptorImpl implemen throw new IOException("Unable to read headers", e); } } + sb.append("\r\n"); return new ByteArrayInputStream(sb.toString().getBytes(US_ASCII)); } @@ -348,6 +349,9 @@ public class MimeDescriptorImpl implemen result += 2; } } + + // Add for CLRF + result +=2; return result; } } Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/ResultUtils.java Wed Aug 24 18:12:17 2011 @@ -19,15 +19,11 @@ package org.apache.james.mailbox.store; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.SequenceInputStream; import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; import org.apache.james.mailbox.Content; @@ -94,8 +90,7 @@ public class ResultUtils { } }); try { - // add the header seperator to the stream to mime4j don't log a warning - parser.parse(new SequenceInputStream(document.getHeaderContent(), new ByteArrayInputStream(BYTES_NEW_LINE))); + parser.parse(document.getHeaderContent()); } catch (MimeException e) { throw new IOException("Unable to parse headers of message " + document, e); } @@ -103,20 +98,7 @@ public class ResultUtils { } - - /** - * Return an {@link InputStream} which holds the full content of the message - * @param message - * @return - * @throws IOException - */ - public static InputStream toInput(final Message<?> message) throws IOException{ - return toInput(message.getHeaderContent(), message.getBodyContent()); - } - - public static InputStream toInput(final InputStream header, final InputStream body) { - return new SequenceInputStream(Collections.enumeration(Arrays.asList(header, new ByteArrayInputStream(BYTES_NEW_LINE), body))); - } + /** * Return the {@link MessageResult} for the given {@link MailboxMembership} and {@link FetchGroup} @@ -198,7 +180,7 @@ public class ResultUtils { private static PartContentBuilder build(int[] path, final Message<?> message) throws IOException, MimeException { - final InputStream stream = toInput(message); + final InputStream stream = message.getFullContent(); PartContentBuilder result = new PartContentBuilder(); result.parse(stream); try { Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/AbstractMessage.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/AbstractMessage.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/AbstractMessage.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/AbstractMessage.java Wed Aug 24 18:12:17 2011 @@ -18,6 +18,10 @@ ****************************************************************/ package org.apache.james.mailbox.store.mail.model; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; + import javax.mail.Flags; @@ -100,6 +104,21 @@ public abstract class AbstractMessage<Id */ protected abstract int getBodyStartOctet(); + + + + /** + * This implementation just concat {@link #getHeaderContent()} and {@link #getBodyContent()}. + * + * Implementation should override this if they can provide a more performant solution + * + * @return content + * @throws exception + */ + public InputStream getFullContent() throws IOException { + return new SequenceInputStream(getHeaderContent(), getBodyContent()); + } + } Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java Wed Aug 24 18:12:17 2011 @@ -177,7 +177,7 @@ public interface Message<Id> extends Com public Long getTextualLineCount(); /** - * Gets the header as {@link InputStream}. This MUST exclude the CRLF terminator + * Gets the header as {@link InputStream}. This MUST INCLUDE the CRLF terminator * * Be aware that this method need to return a new fresh {@link InputStream} * on every call @@ -188,6 +188,18 @@ public interface Message<Id> extends Com InputStream getHeaderContent() throws IOException; /** + *Returns the full raw content of the Message via an {@link InputStream}. + * + * Be aware that this method need to return a new fresh {@link InputStream} + * on every call + * + * @return content + * @throws IOException + */ + InputStream getFullContent() throws IOException; + + + /** * Gets a read-only list of meta-data properties. * For properties with multiple values, this list will contain * several enteries with the same namespace and local name. Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java Wed Aug 24 18:12:17 2011 @@ -31,7 +31,6 @@ import javax.mail.util.SharedByteArrayIn import org.apache.commons.io.IOUtils; import org.apache.james.mailbox.MailboxException; -import org.apache.james.mailbox.store.ResultUtils; import org.apache.james.mailbox.store.mail.model.AbstractMessage; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.Message; @@ -79,7 +78,7 @@ public class SimpleMessage<Id> extends A this.mailboxId = mailbox.getMailboxId(); setFlags(original.createFlags()); try { - this.content = new SharedByteArrayInputStream(IOUtils.toByteArray(ResultUtils.toInput(original))); + this.content = new SharedByteArrayInputStream(IOUtils.toByteArray(original.getFullContent())); } catch (IOException e) { throw new MailboxException("Unable to parse message",e); } @@ -247,7 +246,7 @@ public class SimpleMessage<Id> extends A @Override public InputStream getHeaderContent() throws IOException { - long headerEnd = getBodyStartOctet() -2; + long headerEnd = getBodyStartOctet(); if (headerEnd < 0) { headerEnd = 0; } Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java Wed Aug 24 18:12:17 2011 @@ -190,7 +190,7 @@ public class MessageSearches implements private static boolean bodyContains(String value, Message<?> message, Logger log) throws IOException, MimeException { - final InputStream input = ResultUtils.toInput(message); + final InputStream input = message.getFullContent(); final boolean result = isInMessage(value, input, false, log); return result; } @@ -208,7 +208,7 @@ public class MessageSearches implements private static boolean messageContains(String value, Message<?> message, Logger log) throws IOException, MimeException { - final InputStream input = ResultUtils.toInput(message); + final InputStream input = message.getFullContent(); final boolean result = isInMessage(value, input, true, log); return result; } Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/InputStreamContent.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/InputStreamContent.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/InputStreamContent.java (original) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/InputStreamContent.java Wed Aug 24 18:12:17 2011 @@ -18,16 +18,10 @@ ****************************************************************/ package org.apache.james.mailbox.store.streaming; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.WritableByteChannel; -import org.apache.commons.io.input.BoundedInputStream; import org.apache.james.mailbox.Content; -import org.apache.james.mailbox.store.ResultUtils; import org.apache.james.mailbox.store.mail.model.Message; /** @@ -70,76 +64,11 @@ public final class InputStreamContent im // wrap the streams in a BoundedInputStream to make sure it really match with the stored size. switch (type) { case Full: - return new BoundedInputStream(ResultUtils.toInput(m), size()); + return m.getFullContent(); default: - return new BoundedInputStream(m.getBodyContent(), size()); + return m.getBodyContent(); } } - /* - * (non-Javadoc) - * @see org.apache.james.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel) - */ - public void writeTo(WritableByteChannel channel) throws IOException { - InputStream in = null; - InputStream wrapped = null; - long skipped = 0; - try { - switch (type) { - case Full: - in = ResultUtils.toInput(m); - break; - default: - in = m.getBodyContent(); - break; - } - - if (in instanceof LazySkippingInputStream) { - skipped = ((LazySkippingInputStream) in).getSkippedBytes(); - wrapped = ((LazySkippingInputStream) in).getWrapped(); - } else { - wrapped = in; - } - - if (wrapped instanceof FileInputStream) { - FileChannel fileChannel = ((FileInputStream)wrapped).getChannel(); - fileChannel.transferTo(skipped, fileChannel.size(), channel); - fileChannel.close(); - } else { - int i = 0; - - // read all the content of the underlying InputStream in 16384 byte chunks, wrap them - // in a ByteBuffer and finally write the Buffer to the channel - byte[] buf = new byte[16384]; - while ((i = in.read(buf)) != -1) { - - ByteBuffer buffer = ByteBuffer.wrap(buf); - // set the limit of the buffer to the returned bytes - buffer.limit(i); - channel.write(buffer); - } - } - } finally { - if(in != null) { - try { - in.close(); - } catch (IOException e) { - - } - } - - if(wrapped != null) { - try { - wrapped.close(); - } catch (IOException e) { - - } - } - - } - - } - - } Added: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/LimitingFileInputStream.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/LimitingFileInputStream.java?rev=1161215&view=auto ============================================================================== --- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/LimitingFileInputStream.java (added) +++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/LimitingFileInputStream.java Wed Aug 24 18:12:17 2011 @@ -0,0 +1,276 @@ +/**************************************************************** + * 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.mailbox.store.streaming; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +public class LimitingFileInputStream extends FileInputStream{ + private long pos = 0; + private final long limit; + + public LimitingFileInputStream(File file, long limit) throws FileNotFoundException { + super(file); + this.limit = limit; + } + + public LimitingFileInputStream(FileDescriptor fdObj, long limit) { + super(fdObj); + this.limit = limit; + + } + + public LimitingFileInputStream(String name, long limit) throws FileNotFoundException { + super(name); + this.limit = limit; + + } + + @Override + public int read() throws IOException { + if (pos >= limit) { + return -1; + } + pos++; + return super.read(); + } + + @Override + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (pos >= limit) { + return -1; + } + int readLimit; + if (pos + len >= limit) { + readLimit = (int) limit - (int) pos; + } else { + readLimit = len; + } + + int i = super.read(b, off, readLimit); + pos += i; + return i; + } + + @Override + public long skip(long n) throws IOException { + long currentPos = pos; + long i = super.skip(n); + if (currentPos == pos) { + pos += i; + } + return i; + } + + @Override + public int available() throws IOException { + int i = super.available(); + if (i == -1) { + return -1; + } else { + if (i >= limit) { + return (int) limit - (int) pos; + } else { + return i; + } + } + } + + + /** + * Return the limit + * + * @return limit + */ + public long getLimit() { + return limit; + } + + /** + * Return a READ-ONLY {@link FileChannel} which is limited also in the size + * + * @return channel + */ + @Override + public FileChannel getChannel() { + return new LimitingFileChannel(super.getChannel()); + } + + + /** + * A {@link FileChannel} implementation which wrapps another {@link FileChannel} and limit the access to it + * + * + */ + private final class LimitingFileChannel extends FileChannel { + + private final FileChannel channel; + + public LimitingFileChannel(FileChannel channel) { + this.channel = channel; + } + + @Override + public int read(ByteBuffer dst) throws IOException { + int bufLimit = dst.limit(); + int left = (int) bytesLeft(); + int r; + if (bufLimit > left) { + dst.limit(left); + r = channel.read(dst); + dst.limit(bufLimit); + } else { + r = channel.read(dst); + } + return r; + + } + + @Override + public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { + long r = 0; + for (int a = offset; a < length; a++) { + r += read(dsts[a]); + } + + return r; + } + + @Override + public int write(ByteBuffer src) throws IOException { + throw new IOException("Read-Only FileChannel"); + } + + @Override + public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { + throw new IOException("Read-Only FileChannel"); + } + + @Override + public long position() throws IOException { + return channel.position(); + } + + @Override + public FileChannel position(long newPosition) throws IOException { + if (newPosition <= limit) { + channel.position(newPosition); + } + return LimitingFileChannel.this ; + } + + @Override + public long size() throws IOException { + return limit; + } + + @Override + public FileChannel truncate(long size) throws IOException { + throw new IOException("Read-Only FileChannel"); + } + + @Override + public void force(boolean metaData) throws IOException { + channel.force(metaData); + } + + @Override + public long transferTo(long position, long count, WritableByteChannel target) throws IOException { + if (position > limit) { + return 0; + } else { + long left = bytesLeft(); + + if (count > left) { + count = left; + } + return channel.transferTo(position, count, target); + } + } + + @Override + public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException { + throw new IOException("Read-Only FileChannel"); + } + + @Override + public int read(ByteBuffer dst, long position) throws IOException { + if (position > size()) { + return 0; + } + int bufLimit = dst.limit(); + int left = (int) bytesLeft(); + int r; + if (bufLimit > left) { + dst.limit(left); + r = channel.read(dst, position); + dst.limit(bufLimit); + } else { + r = channel.read(dst, position); + } + return r; + } + + @Override + public int write(ByteBuffer src, long position) throws IOException { + throw new IOException("Read-Only FileChannel"); + + } + + @Override + public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException { + return channel.map(mode, position, size); + } + + @Override + public FileLock lock(long position, long size, boolean shared) throws IOException { + return channel.lock(position, size, shared); + } + + @Override + public FileLock tryLock(long position, long size, boolean shared) throws IOException { + return channel.tryLock(position, size, shared); + } + + @Override + protected void implCloseChannel() throws IOException { + channel.close(); + } + + private long bytesLeft() throws IOException { + return limit - position(); + } + } + + +} Propchange: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/streaming/LimitingFileInputStream.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: james/mailbox/trunk/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java?rev=1161215&r1=1161214&r2=1161215&view=diff ============================================================================== --- james/mailbox/trunk/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java (original) +++ james/mailbox/trunk/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java Wed Aug 24 18:12:17 2011 @@ -23,6 +23,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; +import java.io.SequenceInputStream; import java.io.Writer; import java.util.ArrayList; import java.util.Date; @@ -264,6 +265,7 @@ public class SimpleMailboxMembership imp writer.write(header.getValue()); writer.write(NEW_LINE); } + writer.write(NEW_LINE); writer.flush(); return new ByteArrayInputStream(baos.toByteArray()); @@ -312,6 +314,11 @@ public class SimpleMailboxMembership imp public void setUid(long uid) { this.uid = uid; } + + @Override + public InputStream getFullContent() throws IOException { + return new SequenceInputStream(getHeaderContent(), getBodyContent()); + } --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org