Clover Coverage Report - Atlassian Core
Coverage timestamp: Sun Nov 30 2008 18:33:35 CST
22   205   12   2.44
6   70   0.55   9
9     1.33  
1    
 
 
  DeferredFileOutputStream       Line # 40 22 12 51.4% 0.5135135
 
  (2)
 
1    /*
2    * Copyright 2001-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16   
17    package com.atlassian.core.spool;
18   
19    import java.io.*;
20   
21    import org.apache.commons.io.IOUtils;
22    import org.apache.commons.io.output.ThresholdingOutputStream;
23    import org.apache.commons.io.output.ByteArrayOutputStream;
24   
25   
26    /**
27    * <p>An output stream which will retain data in memory until a specified threshold is reached, and only then commit it
28    * to disk. If the stream is closed before the threshold is reached, the data will not be written to disk at all.</p>
29    * <p/>
30    * <p>This class originated in FileUpload processing. In this use case, you do not know in advance the size of the file
31    * being uploaded. If the file is small you want to store it in memory (for speed), but if the file is large you want to
32    * store it to file (to avoid memory issues).</p>
33    *
34    * <p>MODIFICATION: Made this class a bit more extensible and less stupid</p>
35    *
36    * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
37    * @author gaxzerow
38    * @author cowen
39    */
 
40    public class DeferredFileOutputStream
41    extends ThresholdingOutputStream
42    {
43   
44    // ----------------------------------------------------------- Data members
45   
46   
47    /**
48    * The output stream to which data will be written prior to the theshold being reached.
49    */
50    private ByteArrayOutputStream memoryOutputStream;
51   
52   
53    /**
54    * The output stream to which data will be written at any given time. This will always be one of
55    * <code>memoryOutputStream</code> or <code>diskOutputStream</code>.
56    */
57    private OutputStream currentOutputStream;
58   
59   
60    /**
61    * The file to which output will be directed if the threshold is exceeded.
62    */
63    protected File outputFile;
64   
65   
66    /**
67    * True when close() has been called successfully.
68    */
69    protected boolean closed = false;
70   
71    // ----------------------------------------------------------- Constructors
72   
73   
74    /**
75    * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a
76    * file beyond that point.
77    *
78    * @param threshold The number of bytes at which to trigger an event.
79    * @param outputFile The file to which data is saved beyond the threshold.
80    */
 
81  2 toggle public DeferredFileOutputStream(int threshold, File outputFile)
82    {
83  2 super(threshold);
84  2 this.outputFile = outputFile;
85   
86  2 memoryOutputStream = new ByteArrayOutputStream();
87  2 currentOutputStream = memoryOutputStream;
88    }
89   
90   
91    // --------------------------------------- ThresholdingOutputStream methods
92   
93   
94    /**
95    * Returns the current output stream. This may be memory based or disk based, depending on the current state with
96    * respect to the threshold.
97    *
98    * @return The underlying output stream.
99    * @throws IOException if an error occurs.
100    */
 
101  4 toggle protected OutputStream getStream() throws IOException
102    {
103  4 return currentOutputStream;
104    }
105   
106   
107    /**
108    * Switches the underlying output stream from a memory based stream to one that is backed by disk. This is the point
109    * at which we realise that too much data is being written to keep in memory, so we elect to switch to disk-based
110    * storage.
111    *
112    * @throws IOException if an error occurs.
113    */
 
114  1 toggle protected void thresholdReached() throws IOException
115    {
116  1 FileOutputStream fos = new FileOutputStream(getFile());
117  1 memoryOutputStream.writeTo(fos);
118  1 currentOutputStream = fos;
119  1 memoryOutputStream = null;
120    }
121   
122   
123    // --------------------------------------------------------- Public methods
124   
125   
126    /**
127    * Determines whether or not the data for this output stream has been retained in memory.
128    *
129    * @return <code>true</code> if the data is available in memory; <code>false</code> otherwise.
130    */
 
131  3 toggle public boolean isInMemory()
132    {
133  3 return (!isThresholdExceeded());
134    }
135   
136   
137    /**
138    * Returns the data for this output stream as an array of bytes, assuming that the data has been retained in memory.
139    * If the data was written to disk, this method returns <code>null</code>.
140    *
141    * @return The data for this output stream, or <code>null</code> if no such data is available.
142    */
 
143  0 toggle public byte[] getData()
144    {
145  0 if (memoryOutputStream != null)
146    {
147  0 return memoryOutputStream.toByteArray();
148    }
149  0 return null;
150    }
151   
152   
153    /**
154    * Returns the same output file specified in the constructor, even when threashold has not been reached.
155    *
156    * @return The file for this output stream, or <code>null</code> if no such file exists.
157    */
 
158  4 toggle public File getFile()
159    {
160  4 return outputFile;
161    }
162   
163   
164    /**
165    * Closes underlying output stream, and mark this as closed
166    *
167    * @throws IOException if an error occurs.
168    */
 
169  1 toggle public void close() throws IOException
170    {
171  1 super.close();
172  1 closed = true;
173    }
174   
 
175  0 toggle public InputStream getInputStream() throws IOException
176    {
177    // we may only need to check if this is closed if we are working with a file
178    // but we should force the habit of closing wether we are working with
179    // a file or memory.
180  0 if (!closed)
181    {
182  0 throw new IOException("Stream not closed");
183    }
184   
185  0 if (isInMemory())
186    {
187  0 return new ByteArrayInputStream(getData());
188    }
189    else
190    {
191  0 return new FileInputStream(getFile());
192    }
193    }
194   
195    /**
196    * Writes the data from this output stream to the specified output stream, after it has been closed.
197    *
198    * @param out output stream to write to.
199    * @throws IOException if this stream is not yet closed or an error occurs.
200    */
 
201  0 toggle public void writeTo(OutputStream out) throws IOException
202    {
203  0 IOUtils.copy(getInputStream(), out);
204    }
205    }