View Javadoc

1   /*****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.james.core;
21  
22  import javax.mail.MessagingException;
23  import javax.mail.util.SharedFileInputStream;
24  
25  import java.io.BufferedOutputStream;
26  import java.io.File;
27  import java.io.FileOutputStream;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.OutputStream;
31  
32  import org.apache.avalon.framework.activity.Disposable;
33  
34  /***
35   * Takes an input stream and creates a repeatable input stream source
36   * for a MimeMessageWrapper.  It does this by completely reading the
37   * input stream and saving that to a temporary file that should delete on exit,
38   * or when this object is GC'd.
39   *
40   * @see MimeMessageWrapper
41   *
42   *
43   */
44  public class MimeMessageInputStreamSource
45      extends MimeMessageSource
46      implements Disposable {
47  
48      /***
49       * A temporary file used to hold the message stream
50       */
51      File file;
52  
53      /***
54       * The full path of the temporary file
55       */
56      String sourceId;
57  
58      /***
59       * Construct a new MimeMessageInputStreamSource from an
60       * <code>InputStream</code> that contains the bytes of a
61       * MimeMessage.
62       *
63       * @param key the prefix for the name of the temp file
64       * @param in the stream containing the MimeMessage
65       *
66       * @throws MessagingException if an error occurs while trying to store
67       *                            the stream
68       */
69      public MimeMessageInputStreamSource(String key, InputStream in)
70              throws MessagingException {
71          //We want to immediately read this into a temporary file
72          //Create a temp file and channel the input stream into it
73          OutputStream fout = null;
74          try {
75              file = File.createTempFile(key, ".m64");
76              fout = new BufferedOutputStream(new FileOutputStream(file));
77              int b = -1;
78              while ((b = in.read()) != -1) {
79                  fout.write(b);
80              }
81              fout.flush();
82  
83              sourceId = file.getCanonicalPath();
84          } catch (IOException ioe) {
85              // We had an IOException preparing the temporary file, so
86              // don't just leave it around to garbage collect later.
87              // It isn't as if we are going to use it after we throw
88              // the MessagingException.
89              if (fout != null) try {
90                  fout.close();
91                  fout = null;
92              } catch (IOException _) {
93                  // Ignored - logging unavailable to log this error.
94              }
95  
96              if (file != null) {
97                  file.delete();
98                  file = null;
99              }
100 
101             throw new MessagingException("Unable to retrieve the data: " + ioe.getMessage(), 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 }