001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.core;
019:
020: import javax.mail.MessagingException;
021: import javax.mail.util.SharedFileInputStream;
022:
023: import java.io.BufferedOutputStream;
024: import java.io.File;
025: import java.io.FileOutputStream;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.OutputStream;
029:
030: import org.apache.avalon.framework.activity.Disposable;
031:
032: /**
033: * Takes an input stream and creates a repeatable input stream source
034: * for a MimeMessageWrapper. It does this by completely reading the
035: * input stream and saving that to a temporary file that should delete on exit,
036: * or when this object is GC'd.
037: *
038: * @see MimeMessageWrapper
039: *
040: *
041: */
042: public class MimeMessageInputStreamSource extends MimeMessageSource
043: implements Disposable {
044:
045: /**
046: * A temporary file used to hold the message stream
047: */
048: File file;
049:
050: /**
051: * The full path of the temporary file
052: */
053: String sourceId;
054:
055: /**
056: * Construct a new MimeMessageInputStreamSource from an
057: * <code>InputStream</code> that contains the bytes of a
058: * MimeMessage.
059: *
060: * @param key the prefix for the name of the temp file
061: * @param in the stream containing the MimeMessage
062: *
063: * @throws MessagingException if an error occurs while trying to store
064: * the stream
065: */
066: public MimeMessageInputStreamSource(String key, InputStream in)
067: throws MessagingException {
068: //We want to immediately read this into a temporary file
069: //Create a temp file and channel the input stream into it
070: OutputStream fout = null;
071: try {
072: file = File.createTempFile(key, ".m64");
073: fout = new BufferedOutputStream(new FileOutputStream(file));
074: int b = -1;
075: while ((b = in.read()) != -1) {
076: fout.write(b);
077: }
078: fout.flush();
079:
080: sourceId = file.getCanonicalPath();
081: } catch (IOException ioe) {
082: // We had an IOException preparing the temporary file, so
083: // don't just leave it around to garbage collect later.
084: // It isn't as if we are going to use it after we throw
085: // the MessagingException.
086: if (fout != null)
087: try {
088: fout.close();
089: fout = null;
090: } catch (IOException _) {
091: // Ignored - logging unavailable to log this error.
092: }
093:
094: if (file != null) {
095: file.delete();
096: file = null;
097: }
098:
099: throw new MessagingException(
100: "Unable to retrieve the data: " + ioe.getMessage(),
101: ioe);
102: } finally {
103: try {
104: if (fout != null) {
105: fout.close();
106: }
107: } catch (IOException ioe) {
108: // Ignored - logging unavailable to log this non-fatal error.
109: }
110:
111: try {
112: if (in != null) {
113: in.close();
114: }
115: } catch (IOException ioe) {
116: // Ignored - logging unavailable to log this non-fatal error.
117: }
118: }
119: }
120:
121: /**
122: * Returns the unique identifier of this input stream source
123: *
124: * @return the unique identifier for this MimeMessageInputStreamSource
125: */
126: public String getSourceId() {
127: return sourceId;
128: }
129:
130: /**
131: * Get an input stream to retrieve the data stored in the temporary file
132: *
133: * @return a <code>BufferedInputStream</code> containing the data
134: */
135: public synchronized InputStream getInputStream() throws IOException {
136: return new SharedFileInputStream(file);
137: }
138:
139: /**
140: * Get the size of the temp file
141: *
142: * @return the size of the temp file
143: *
144: * @throws IOException if an error is encoutered while computing the size of the message
145: */
146: public long getMessageSize() throws IOException {
147: return file.length();
148: }
149:
150: /**
151: * @see org.apache.avalon.framework.activity.Disposable#dispose()
152: */
153: public void dispose() {
154: try {
155: if (file != null && file.exists()) {
156: file.delete();
157: }
158: } catch (Exception e) {
159: //ignore
160: }
161: file = null;
162: }
163:
164: /**
165: * <p>Finalizer that closes and deletes the temp file. Very bad.</p>
166: * We're leaving this in temporarily, while also establishing a more
167: * formal mechanism for cleanup through use of the dispose() method.
168: * @throws Throwable
169: *
170: public void finalize() throws Throwable {
171: dispose();
172: super.finalize();
173: }
174: */
175: }
|