View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * Unless otherwise indicated, all code in ModeShape is licensed
10   * to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.jcr;
25  
26  import java.io.IOException;
27  import java.io.InputStream;
28  import net.jcip.annotations.NotThreadSafe;
29  import org.modeshape.graph.property.Binary;
30  
31  /**
32   * An {@link InputStream} implementation that can be used to access the content of a supplied {@link Binary} value. An instance of
33   * this class immediately {@link Binary#acquire() acquires} the binary's lock, and allows the InputStream to be processed and used
34   * normally. This class, however, guarantees that the binary lock is {@link Binary#release() released} whenever this class throws
35   * an exception or when the instance is {@link #close() closed}.
36   * <p>
37   * The draft version of the JSR-283 specification outlines a new mechanism for obtaining a lock on a binary value, and in fact
38   * this mechanism was used as the baseline for the design of ModeShape's Binary value. Therefore, when ModeShape's JCR
39   * implementation supports JCR-283, this class will probably no longer be needed.
40   * </p>
41   */
42  @NotThreadSafe
43  class SelfClosingInputStream extends InputStream {
44  
45      private final Binary binary;
46      private final InputStream stream;
47  
48      /**
49       * Create a self-closing {@link InputStream} to access the content of the supplied {@link Binary} value. This construct
50       * immediately {@link Binary#acquire() acquires} the binary's lock, which is {@link Binary#release() released} whenever this
51       * class throws an exception or when the instance is {@link #close() closed}.
52       * 
53       * @param binary the {@link Binary} object that this stream accesses; may not be null
54       */
55      public SelfClosingInputStream( Binary binary ) {
56          assert binary != null;
57          this.binary = binary;
58          this.binary.acquire();
59          this.stream = binary.getStream();
60      }
61  
62      /**
63       * {@inheritDoc}
64       * 
65       * @see java.io.InputStream#available()
66       */
67      @Override
68      public int available() throws IOException {
69          try {
70              return stream.available();
71          } catch (IOException e) {
72              this.binary.release();
73              throw e;
74          } catch (RuntimeException e) {
75              this.binary.release();
76              throw e;
77          }
78      }
79  
80      /**
81       * {@inheritDoc}
82       * 
83       * @see java.io.InputStream#close()
84       */
85      @Override
86      public void close() throws IOException {
87          try {
88              stream.close();
89          } finally {
90              this.binary.release();
91          }
92      }
93  
94      /**
95       * {@inheritDoc}
96       * 
97       * @see java.lang.Object#equals(java.lang.Object)
98       */
99      @Override
100     public boolean equals( Object obj ) {
101         return stream.equals(obj);
102     }
103 
104     /**
105      * {@inheritDoc}
106      * 
107      * @see java.lang.Object#hashCode()
108      */
109     @Override
110     public int hashCode() {
111         return stream.hashCode();
112     }
113 
114     /**
115      * {@inheritDoc}
116      * 
117      * @see java.io.InputStream#mark(int)
118      */
119     @Override
120     public void mark( int readlimit ) {
121         try {
122             stream.mark(readlimit);
123         } catch (RuntimeException e) {
124             this.binary.release();
125             throw e;
126         }
127     }
128 
129     /**
130      * {@inheritDoc}
131      * 
132      * @see java.io.InputStream#markSupported()
133      */
134     @Override
135     public boolean markSupported() {
136         return stream.markSupported();
137     }
138 
139     /**
140      * {@inheritDoc}
141      * 
142      * @see java.io.InputStream#read(byte[], int, int)
143      */
144     @Override
145     public int read( byte[] b,
146                      int off,
147                      int len ) throws IOException {
148         try {
149             int result = stream.read(b, off, len);
150             if (result == -1) {
151                 // the end of the stream has been reached ...
152                 this.binary.release();
153             }
154             return result;
155         } catch (IOException e) {
156             this.binary.release();
157             throw e;
158         } catch (RuntimeException e) {
159             this.binary.release();
160             throw e;
161         }
162     }
163 
164     /**
165      * {@inheritDoc}
166      * 
167      * @see java.io.InputStream#read(byte[])
168      */
169     @Override
170     public int read( byte[] b ) throws IOException {
171         try {
172             int result = stream.read(b);
173             if (result == -1) {
174                 // the end of the stream has been reached ...
175                 this.binary.release();
176             }
177             return result;
178         } catch (IOException e) {
179             this.binary.release();
180             throw e;
181         } catch (RuntimeException e) {
182             this.binary.release();
183             throw e;
184         }
185     }
186 
187     /**
188      * {@inheritDoc}
189      * 
190      * @see java.io.InputStream#read()
191      */
192     @Override
193     public int read() throws IOException {
194         try {
195             int result = stream.read();
196             if (result == -1) {
197                 // the end of the stream has been reached ...
198                 this.binary.release();
199             }
200             return result;
201         } catch (IOException e) {
202             this.binary.release();
203             throw e;
204         } catch (RuntimeException e) {
205             this.binary.release();
206             throw e;
207         }
208     }
209 
210     /**
211      * {@inheritDoc}
212      * 
213      * @see java.io.InputStream#reset()
214      */
215     @Override
216     public void reset() throws IOException {
217         try {
218             stream.reset();
219         } catch (IOException e) {
220             this.binary.release();
221             throw e;
222         } catch (RuntimeException e) {
223             this.binary.release();
224             throw e;
225         }
226     }
227 
228     /**
229      * {@inheritDoc}
230      * 
231      * @see java.io.InputStream#skip(long)
232      */
233     @Override
234     public long skip( long n ) throws IOException {
235         try {
236             return stream.skip(n);
237         } catch (IOException e) {
238             this.binary.release();
239             throw e;
240         } catch (RuntimeException e) {
241             this.binary.release();
242             throw e;
243         }
244     }
245 
246     /**
247      * {@inheritDoc}
248      * 
249      * @see java.lang.Object#toString()
250      */
251     @Override
252     public String toString() {
253         try {
254             return stream.toString();
255         } catch (RuntimeException e) {
256             this.binary.release();
257             throw e;
258         }
259     }
260 }