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.mime4j.storage;
21  
22  import java.io.IOException;
23  import java.io.OutputStream;
24  
25  /**
26   * This class implements an output stream that can be used to create a
27   * {@link Storage} object. An instance of this class is obtained by calling
28   * {@link StorageProvider#createStorageOutputStream()}. The user can then write
29   * data to this instance and invoke {@link #toStorage()} to retrieve a
30   * {@link Storage} object that contains the data that has been written.
31   * <p>
32   * Note that the <code>StorageOutputStream</code> does not have to be closed
33   * explicitly because {@link #toStorage()} invokes {@link #close()} if
34   * necessary. Also note that {@link #toStorage()} may be invoked only once. One
35   * <code>StorageOutputStream</code> can create only one <code>Storage</code>
36   * instance.
37   */
38  public abstract class StorageOutputStream extends OutputStream {
39  
40      private byte[] singleByte;
41      private boolean closed;
42      private boolean usedUp;
43  
44      /**
45       * Sole constructor.
46       */
47      protected StorageOutputStream() {
48      }
49  
50      /**
51       * Closes this output stream if it has not already been closed and returns a
52       * {@link Storage} object which contains the bytes that have been written to
53       * this output stream.
54       * <p>
55       * Note that this method may not be invoked a second time. This is because
56       * for some implementations it is not possible to create another
57       * <code>Storage</code> object that can be read from and deleted
58       * independently (e.g. if the implementation writes to a file).
59       * 
60       * @return a <code>Storage</code> object as described above.
61       * @throws IOException
62       *             if an I/O error occurs.
63       * @throws IllegalStateException
64       *             if this method has already been called.
65       */
66      public final Storage toStorage() throws IOException {
67          if (usedUp)
68              throw new IllegalStateException(
69                      "toStorage may be invoked only once");
70  
71          if (!closed)
72              close();
73  
74          usedUp = true;
75          return toStorage0();
76      }
77  
78      @Override
79      public final void write(int b) throws IOException {
80          if (closed)
81              throw new IOException("StorageOutputStream has been closed");
82  
83          if (singleByte == null)
84              singleByte = new byte[1];
85  
86          singleByte[0] = (byte) b;
87          write0(singleByte, 0, 1);
88      }
89  
90      @Override
91      public final void write(byte[] buffer) throws IOException {
92          if (closed)
93              throw new IOException("StorageOutputStream has been closed");
94  
95          if (buffer == null)
96              throw new NullPointerException();
97  
98          if (buffer.length == 0)
99              return;
100 
101         write0(buffer, 0, buffer.length);
102     }
103 
104     @Override
105     public final void write(byte[] buffer, int offset, int length)
106             throws IOException {
107         if (closed)
108             throw new IOException("StorageOutputStream has been closed");
109 
110         if (buffer == null)
111             throw new NullPointerException();
112 
113         if (offset < 0 || length < 0 || offset + length > buffer.length)
114             throw new IndexOutOfBoundsException();
115 
116         if (length == 0)
117             return;
118 
119         write0(buffer, offset, length);
120     }
121 
122     /**
123      * Closes this output stream. Subclasses that override this method have to
124      * invoke <code>super.close()</code>.
125      * <p>
126      * This implementation never throws an {@link IOException} but a subclass
127      * might.
128      * 
129      * @throws IOException
130      *             if an I/O error occurs.
131      */
132     @Override
133     public void close() throws IOException {
134         closed = true;
135     }
136 
137     /**
138      * Has to implemented by a concrete subclass to write bytes from the given
139      * byte array to this <code>StorageOutputStream</code>. This method gets
140      * called by {@link #write(int)}, {@link #write(byte[])} and
141      * {@link #write(byte[], int, int)}. All the required preconditions have
142      * already been checked by these methods, including the check if the output
143      * stream has already been closed.
144      * 
145      * @param buffer
146      *            buffer containing bytes to write.
147      * @param offset
148      *            start offset in the buffer.
149      * @param length
150      *            number of bytes to write.
151      * @throws IOException
152      *             if an I/O error occurs.
153      */
154     protected abstract void write0(byte[] buffer, int offset, int length)
155             throws IOException;
156 
157     /**
158      * Has to be implemented by a concrete subclass to create a {@link Storage}
159      * object from the bytes that have been written to this
160      * <code>StorageOutputStream</code>. This method gets called by
161      * {@link #toStorage()} after the preconditions have been checked. The
162      * implementation can also be sure that this methods gets invoked only once.
163      * 
164      * @return a <code>Storage</code> object as described above.
165      * @throws IOException
166      *             if an I/O error occurs.
167      */
168     protected abstract Storage toStorage0() throws IOException;
169 
170 }