View Javadoc

1   /*
2    *  jDTAUS Core Utilities
3    *  Copyright (C) 2005 Christian Schulte
4    *  <cs@schulte.it>
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19   *
20   */
21  package org.jdtaus.core.io.util;
22  
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.io.RandomAccessFile;
27  import java.util.Locale;
28  import org.jdtaus.core.container.ContainerFactory;
29  import org.jdtaus.core.io.FileOperations;
30  import org.jdtaus.core.lang.spi.MemoryManager;
31  
32  /**
33   * Adapts a {@link java.io.RandomAccessFile} to {@code FileOperations}.
34   *
35   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
36   * @version $JDTAUS: RandomAccessFileOperations.java 8743 2012-10-07 03:06:20Z schulte $
37   */
38  public final class RandomAccessFileOperations implements FileOperations
39  {
40      //--Dependencies------------------------------------------------------------
41  
42  // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
43      // This section is managed by jdtaus-container-mojo.
44  
45      /**
46       * Gets the configured <code>MemoryManager</code> implementation.
47       *
48       * @return The configured <code>MemoryManager</code> implementation.
49       */
50      private MemoryManager getMemoryManager()
51      {
52          return (MemoryManager) ContainerFactory.getContainer().
53              getDependency( this, "MemoryManager" );
54  
55      }
56  
57      /**
58       * Gets the configured <code>Locale</code> implementation.
59       *
60       * @return The configured <code>Locale</code> implementation.
61       */
62      private Locale getLocale()
63      {
64          return (Locale) ContainerFactory.getContainer().
65              getDependency( this, "Locale" );
66  
67      }
68  
69  // </editor-fold>//GEN-END:jdtausDependencies
70  
71      //------------------------------------------------------------Dependencies--
72      //--Properties--------------------------------------------------------------
73  
74  // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
75      // This section is managed by jdtaus-container-mojo.
76  
77      /**
78       * Gets the value of property <code>streamBufferSize</code>.
79       *
80       * @return Size of the buffer for buffering streams.
81       */
82      private int getStreamBufferSize()
83      {
84          return ( (java.lang.Integer) ContainerFactory.getContainer().
85              getProperty( this, "streamBufferSize" ) ).intValue();
86  
87      }
88  
89  // </editor-fold>//GEN-END:jdtausProperties
90  
91      //--------------------------------------------------------------Properties--
92      //--FileOperations----------------------------------------------------------
93  
94      /** Cache for the value of property {@code length}. */
95      private transient long cachedLength = NO_CACHEDLENGTH;
96  
97      private static final long NO_CACHEDLENGTH = Long.MIN_VALUE;
98  
99      public long getLength() throws IOException
100     {
101         this.assertNotClosed();
102 
103         return this.cachedLength != NO_CACHEDLENGTH
104                ? this.cachedLength
105                : ( this.cachedLength =
106             this.getRandomAccessFile().length() );
107 
108     }
109 
110     public void setLength( final long newLength ) throws IOException
111     {
112         if ( newLength < 0L )
113         {
114             throw new IllegalArgumentException( Long.toString( newLength ) );
115         }
116 
117         this.assertNotClosed();
118 
119         this.getRandomAccessFile().setLength( newLength );
120         this.cachedLength = newLength;
121     }
122 
123     public long getFilePointer() throws IOException
124     {
125         this.assertNotClosed();
126 
127         return this.getRandomAccessFile().getFilePointer();
128     }
129 
130     public void setFilePointer( final long pos ) throws IOException
131     {
132         this.assertNotClosed();
133 
134         this.getRandomAccessFile().seek( pos );
135     }
136 
137     public void write( final byte[] buf, final int off, final int len )
138         throws IOException
139     {
140         this.assertNotClosed();
141 
142         final RandomAccessFile file = this.getRandomAccessFile();
143         final long pointer = file.getFilePointer();
144 
145         file.write( buf, off, len );
146 
147         if ( this.cachedLength != NO_CACHEDLENGTH &&
148              pointer + len > this.cachedLength )
149         {
150             this.cachedLength = file.length();
151         }
152     }
153 
154     public int read( final byte[] buf, final int off, final int len )
155         throws IOException
156     {
157         this.assertNotClosed();
158 
159         return this.getRandomAccessFile().read( buf, off, len );
160     }
161 
162     public void read( final OutputStream out ) throws IOException
163     {
164         if ( out == null )
165         {
166             throw new NullPointerException( "out" );
167         }
168 
169         this.assertNotClosed();
170 
171         int read;
172         long toRead = this.getLength();
173         final byte[] buf = this.getStreamBuffer();
174 
175         if ( toRead > 0L )
176         {
177             this.setFilePointer( 0L );
178             do
179             {
180                 read = this.read( buf, 0, buf.length );
181 
182                 assert read != FileOperations.EOF : "Unexpected end of file.";
183 
184                 toRead -= read;
185                 out.write( buf, 0, read );
186             }
187             while ( toRead > 0L );
188         }
189     }
190 
191     public void write( final InputStream in ) throws IOException
192     {
193         if ( in == null )
194         {
195             throw new NullPointerException( "in" );
196         }
197 
198         this.assertNotClosed();
199 
200         int read;
201         final byte[] buf = this.getStreamBuffer();
202 
203         while ( ( read = in.read( buf, 0, buf.length ) ) != FileOperations.EOF )
204         {
205             this.write( buf, 0, read );
206         }
207     }
208 
209     /**
210      * {@inheritDoc}
211      * Closes the {@code RandomAccessFile} backing the instance.
212      *
213      * @throws IOException if closing the {@code RandomAccessFile} backing the
214      * instance fails.
215      */
216     public void close() throws IOException
217     {
218         this.assertNotClosed();
219 
220         this.getRandomAccessFile().close();
221         this.closed = true;
222     }
223 
224     //----------------------------------------------------------FileOperations--
225     //--RandomAccessFileOperations----------------------------------------------
226 
227     /** Stream buffer. */
228     private byte[] streamBuffer;
229 
230     /** Flags the instance as beeing closed. */
231     private boolean closed;
232 
233     /** {@code RandomAccessFile} requirement. */
234     private RandomAccessFile randomAccessFile;
235 
236     /**
237      * Creates a new {@code RandomAccessFileOperations} instance adapting
238      * {@code file}.
239      *
240      * @param file an {@code RandomAccessFile} instance to use as a
241      * {@code FileOperations} implementation.
242      *
243      * @throws NullPointerException if {@code file} is {@code null}.
244      */
245     public RandomAccessFileOperations( final RandomAccessFile file )
246     {
247         super();
248 
249         if ( file == null )
250         {
251             throw new NullPointerException( "file" );
252         }
253 
254         this.randomAccessFile = file;
255     }
256 
257     /**
258      * Gets the random access file operations are performed with.
259      *
260      * @return the {@code RandomAccessFile} instance operations are performed
261      * with or {@code null}.
262      */
263     public RandomAccessFile getRandomAccessFile()
264     {
265         return this.randomAccessFile;
266     }
267 
268     /**
269      * Checks that the instance is not closed.
270      *
271      * @throws IOException if the instance is closed.
272      */
273     private void assertNotClosed() throws IOException
274     {
275         if ( this.closed )
276         {
277             throw new IOException( this.getAlreadyClosedMessage(
278                 this.getLocale() ) );
279 
280         }
281     }
282 
283     /**
284      * Gets a buffer for buffering streams.
285      *
286      * @return a buffer for buffering streams.
287      */
288     private byte[] getStreamBuffer()
289     {
290         if ( this.streamBuffer == null )
291         {
292             this.streamBuffer = this.getMemoryManager().
293                 allocateBytes( this.getStreamBufferSize() < 0
294                                ? 0
295                                : this.getStreamBufferSize() );
296 
297         }
298 
299         return this.streamBuffer;
300     }
301 
302     //----------------------------------------------RandomAccessFileOperations--
303     //--Messages----------------------------------------------------------------
304 
305 // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages
306     // This section is managed by jdtaus-container-mojo.
307 
308     /**
309      * Gets the text of message <code>alreadyClosed</code>.
310      * <blockquote><pre>Instanz geschlossen - keine E/A-Operationen möglich.</pre></blockquote>
311      * <blockquote><pre>Instance closed - cannot perform I/O.</pre></blockquote>
312      *
313      * @param locale The locale of the message instance to return.
314      *
315      * @return Message stating that an instance is already closed.
316      */
317     private String getAlreadyClosedMessage( final Locale locale )
318     {
319         return ContainerFactory.getContainer().
320             getMessage( this, "alreadyClosed", locale, null );
321 
322     }
323 
324 // </editor-fold>//GEN-END:jdtausMessages
325 
326     //----------------------------------------------------------------Messages--
327 }