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 8641 2012-09-27 06:45:17Z 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( 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( long pos ) throws IOException
131     {
132         this.assertNotClosed();
133 
134         this.getRandomAccessFile().seek( pos );
135     }
136 
137     public void write( byte[] buf, int off, int len ) throws IOException
138     {
139         this.assertNotClosed();
140 
141         final RandomAccessFile file = this.getRandomAccessFile();
142         final long pointer = file.getFilePointer();
143 
144         file.write( buf, off, len );
145 
146         if ( this.cachedLength != NO_CACHEDLENGTH &&
147              pointer + len > this.cachedLength )
148         {
149             this.cachedLength = file.length();
150         }
151     }
152 
153     public int read( byte[] buf, int off, int len ) throws IOException
154     {
155         this.assertNotClosed();
156 
157         return this.getRandomAccessFile().read( buf, off, len );
158     }
159 
160     public void read( final OutputStream out ) throws IOException
161     {
162         if ( out == null )
163         {
164             throw new NullPointerException( "out" );
165         }
166 
167         this.assertNotClosed();
168 
169         int read;
170         long toRead = this.getLength();
171         final byte[] buf = this.getStreamBuffer();
172 
173         if ( toRead > 0L )
174         {
175             this.setFilePointer( 0L );
176             do
177             {
178                 read = this.read( buf, 0, buf.length );
179 
180                 assert read != FileOperations.EOF : "Unexpected end of file.";
181 
182                 toRead -= read;
183                 out.write( buf, 0, read );
184             }
185             while ( toRead > 0L );
186         }
187     }
188 
189     public void write( final InputStream in ) throws IOException
190     {
191         if ( in == null )
192         {
193             throw new NullPointerException( "in" );
194         }
195 
196         this.assertNotClosed();
197 
198         int read;
199         final byte[] buf = this.getStreamBuffer();
200 
201         while ( ( read = in.read( buf, 0, buf.length ) ) != FileOperations.EOF )
202         {
203             this.write( buf, 0, read );
204         }
205     }
206 
207     /**
208      * {@inheritDoc}
209      * Closes the {@code RandomAccessFile} backing the instance.
210      *
211      * @throws IOException if closing the {@code RandomAccessFile} backing the
212      * instance fails.
213      */
214     public void close() throws IOException
215     {
216         this.assertNotClosed();
217 
218         this.getRandomAccessFile().close();
219         this.closed = true;
220     }
221 
222     //----------------------------------------------------------FileOperations--
223     //--RandomAccessFileOperations----------------------------------------------
224 
225     /** Stream buffer. */
226     private byte[] streamBuffer;
227 
228     /** Flags the instance as beeing closed. */
229     private boolean closed;
230 
231     /** {@code RandomAccessFile} requirement. */
232     private RandomAccessFile randomAccessFile;
233 
234     /**
235      * Creates a new {@code RandomAccessFileOperations} instance adapting
236      * {@code file}.
237      *
238      * @param file an {@code RandomAccessFile} instance to use as a
239      * {@code FileOperations} implementation.
240      *
241      * @throws NullPointerException if {@code file} is {@code null}.
242      */
243     public RandomAccessFileOperations( final RandomAccessFile file )
244     {
245         super();
246 
247         if ( file == null )
248         {
249             throw new NullPointerException( "file" );
250         }
251 
252         this.randomAccessFile = file;
253     }
254 
255     /**
256      * Gets the random access file operations are performed with.
257      *
258      * @return the {@code RandomAccessFile} instance operations are performed
259      * with or {@code null}.
260      */
261     public RandomAccessFile getRandomAccessFile()
262     {
263         return this.randomAccessFile;
264     }
265 
266     /**
267      * Checks that the instance is not closed.
268      *
269      * @throws IOException if the instance is closed.
270      */
271     private void assertNotClosed() throws IOException
272     {
273         if ( this.closed )
274         {
275             throw new IOException( this.getAlreadyClosedMessage(
276                 this.getLocale() ) );
277 
278         }
279     }
280 
281     /**
282      * Gets a buffer for buffering streams.
283      *
284      * @return a buffer for buffering streams.
285      */
286     private byte[] getStreamBuffer()
287     {
288         if ( this.streamBuffer == null )
289         {
290             this.streamBuffer = this.getMemoryManager().
291                 allocateBytes( this.getStreamBufferSize() < 0
292                                ? 0
293                                : this.getStreamBufferSize() );
294 
295         }
296 
297         return this.streamBuffer;
298     }
299 
300     //----------------------------------------------RandomAccessFileOperations--
301     //--Messages----------------------------------------------------------------
302 
303 // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages
304     // This section is managed by jdtaus-container-mojo.
305 
306     /**
307      * Gets the text of message <code>alreadyClosed</code>.
308      * <blockquote><pre>Instanz geschlossen - keine E/A-Operationen möglich.</pre></blockquote>
309      * <blockquote><pre>Instance closed - cannot perform I/O.</pre></blockquote>
310      *
311      * @param locale The locale of the message instance to return.
312      *
313      * @return Message stating that an instance is already closed.
314      */
315     private String getAlreadyClosedMessage( final Locale locale )
316     {
317         return ContainerFactory.getContainer().
318             getMessage( this, "alreadyClosed", locale, null );
319 
320     }
321 
322 // </editor-fold>//GEN-END:jdtausMessages
323 
324     //----------------------------------------------------------------Messages--
325 }