EMMA Coverage Report (generated Tue Jan 14 02:29:45 CET 2014)
[all classes][org.jdtaus.core.io.util]

COVERAGE SUMMARY FOR SOURCE FILE [ReadAheadFileOperations.java]

nameclass, %method, %block, %line, %
ReadAheadFileOperations.java100% (1/1)77%  (17/22)77%  (407/531)79%  (89/113)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ReadAheadFileOperations100% (1/1)77%  (17/22)77%  (407/531)79%  (89/113)
close (): void 0%   (0/1)0%   (0/11)0%   (0/5)
getAlreadyClosedMessage (Locale): String 0%   (0/1)0%   (0/7)0%   (0/1)
getFileOperations (): FileOperations 0%   (0/1)0%   (0/3)0%   (0/1)
getLocale (): Locale 0%   (0/1)0%   (0/6)0%   (0/1)
read (OutputStream): void 0%   (0/1)0%   (0/12)0%   (0/4)
assertNotClosed (): void 100% (1/1)33%  (4/12)67%  (2/3)
flush (): void 100% (1/1)64%  (7/11)75%  (3/4)
ReadAheadFileOperations (FileOperations): void 100% (1/1)71%  (12/17)83%  (5/6)
write (byte [], int, int): void 100% (1/1)75%  (89/119)76%  (13.7/18)
read (byte [], int, int): int 100% (1/1)78%  (106/136)83%  (20.7/25)
<static initializer> 100% (1/1)80%  (12/15)80%  (0.8/1)
fillCache (): void 100% (1/1)92%  (61/66)98%  (12.8/13)
ReadAheadFileOperations (FileOperations, int): void 100% (1/1)100% (12/12)100% (4/4)
getCache (): byte [] 100% (1/1)100% (13/13)100% (3/3)
getCacheSize (): int 100% (1/1)100% (11/11)100% (3/3)
getDefaultCacheSize (): Integer 100% (1/1)100% (6/6)100% (1/1)
getFilePointer (): long 100% (1/1)100% (5/5)100% (2/2)
getLength (): long 100% (1/1)100% (6/6)100% (2/2)
getMemoryManager (): MemoryManager 100% (1/1)100% (6/6)100% (1/1)
setFilePointer (long): void 100% (1/1)100% (6/6)100% (3/3)
setLength (long): void 100% (1/1)100% (39/39)100% (8/8)
write (InputStream): void 100% (1/1)100% (12/12)100% (4/4)

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 */
21package org.jdtaus.core.io.util;
22 
23import java.io.IOException;
24import java.io.InputStream;
25import java.io.OutputStream;
26import java.util.Locale;
27import org.jdtaus.core.container.ContainerFactory;
28import org.jdtaus.core.io.FileOperations;
29import org.jdtaus.core.lang.spi.MemoryManager;
30 
31/**
32 * Read-ahead {@code FileOperations} cache.
33 * <p>This implementation implements a read-ahead cache for
34 * {@code FileOperations} implementations. The cache is controlled by
35 * configuration property {@code cacheSize} holding the number of bytes
36 * to read-ahead. By default property {@code cacheSize} is initialized to
37 * {@code 16384} leading to a cache size of 16 kB. All memory is allocated
38 * during instantiation so that an {@code OutOfMemoryError} may be thrown
39 * when constructing the cache but not when working with the instance.</p>
40 *
41 * <p><b>Note:</b><br>
42 * This implementation is not thread-safe and concurrent changes to the
43 * underlying {@code FileOperations} implementation are not supported.</p>
44 *
45 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
46 * @version $JDTAUS: ReadAheadFileOperations.java 8641 2012-09-27 06:45:17Z schulte $
47 */
48public final class ReadAheadFileOperations implements FlushableFileOperations
49{
50    //--Dependencies------------------------------------------------------------
51 
52// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
53    // This section is managed by jdtaus-container-mojo.
54 
55    /**
56     * Gets the configured <code>MemoryManager</code> implementation.
57     *
58     * @return The configured <code>MemoryManager</code> implementation.
59     */
60    private MemoryManager getMemoryManager()
61    {
62        return (MemoryManager) ContainerFactory.getContainer().
63            getDependency( this, "MemoryManager" );
64 
65    }
66 
67    /**
68     * Gets the configured <code>Locale</code> implementation.
69     *
70     * @return The configured <code>Locale</code> implementation.
71     */
72    private Locale getLocale()
73    {
74        return (Locale) ContainerFactory.getContainer().
75            getDependency( this, "Locale" );
76 
77    }
78 
79// </editor-fold>//GEN-END:jdtausDependencies
80 
81    //------------------------------------------------------------Dependencies--
82    //--Properties--------------------------------------------------------------
83 
84// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
85    // This section is managed by jdtaus-container-mojo.
86 
87    /**
88     * Gets the value of property <code>defaultCacheSize</code>.
89     *
90     * @return Default cache size in byte.
91     */
92    private java.lang.Integer getDefaultCacheSize()
93    {
94        return (java.lang.Integer) ContainerFactory.getContainer().
95            getProperty( this, "defaultCacheSize" );
96 
97    }
98 
99// </editor-fold>//GEN-END:jdtausProperties
100 
101    //--------------------------------------------------------------Properties--
102    //--FileOperations----------------------------------------------------------
103 
104    public long getLength() throws IOException
105    {
106        this.assertNotClosed();
107 
108        return this.fileOperations.getLength();
109    }
110 
111    public void setLength( final long newLength ) throws IOException
112    {
113        this.assertNotClosed();
114 
115        final long oldLength = this.getLength();
116        this.fileOperations.setLength( newLength );
117        if ( this.filePointer > newLength )
118        {
119            this.filePointer = newLength;
120        }
121 
122        if ( oldLength > newLength && this.cachePosition != NO_CACHEPOSITION &&
123             this.cachePosition + this.cacheLength >= newLength )
124        { // Discard the end of file cache.
125            this.cachePosition = NO_CACHEPOSITION;
126        }
127    }
128 
129    public long getFilePointer() throws IOException
130    {
131        this.assertNotClosed();
132 
133        return this.filePointer;
134    }
135 
136    public void setFilePointer( final long pos ) throws IOException
137    {
138        this.assertNotClosed();
139 
140        this.filePointer = pos;
141    }
142 
143    public int read( final byte[] buf, int off, int len )
144        throws IOException
145    {
146        if ( buf == null )
147        {
148            throw new NullPointerException( "buf" );
149        }
150        if ( off < 0 )
151        {
152            throw new IndexOutOfBoundsException( Integer.toString( off ) );
153        }
154        if ( len < 0 )
155        {
156            throw new IndexOutOfBoundsException( Integer.toString( len ) );
157        }
158        if ( off + len > buf.length )
159        {
160            throw new IndexOutOfBoundsException( Integer.toString( off + len ) );
161        }
162 
163        this.assertNotClosed();
164 
165        int read = FileOperations.EOF;
166 
167        final long fileLength = this.getLength();
168 
169        if ( len == 0 )
170        {
171            read = 0;
172        }
173        else if ( this.filePointer < fileLength )
174        {
175            if ( this.cachePosition == NO_CACHEPOSITION ||
176                 !( this.filePointer >= this.cachePosition &&
177                    this.filePointer < this.cachePosition + this.cacheLength ) )
178            { // Cache not initialized or file pointer outside the cached area.
179                this.fillCache();
180            }
181 
182            final long cacheStart = this.filePointer - this.cachePosition;
183 
184            assert cacheStart <= Integer.MAX_VALUE :
185                "Unexpected implementation limit reached.";
186 
187            final int cachedLength = len > this.cacheLength -
188                                           (int) cacheStart
189                                     ? this.cacheLength - (int) cacheStart
190                                     : len;
191 
192            System.arraycopy( this.getCache(), (int) cacheStart, buf, off,
193                              cachedLength );
194 
195            len -= cachedLength;
196            off += cachedLength;
197            read = cachedLength;
198            this.filePointer += cachedLength;
199        }
200 
201        return read;
202    }
203 
204    public void write( final byte[] buf, final int off, final int len )
205        throws IOException
206    {
207        if ( buf == null )
208        {
209            throw new NullPointerException( "buf" );
210        }
211        if ( off < 0 )
212        {
213            throw new IndexOutOfBoundsException( Integer.toString( off ) );
214        }
215        if ( len < 0 )
216        {
217            throw new IndexOutOfBoundsException( Integer.toString( len ) );
218        }
219        if ( off + len > buf.length )
220        {
221            throw new IndexOutOfBoundsException( Integer.toString( off + len ) );
222        }
223 
224        this.assertNotClosed();
225 
226        if ( this.cachePosition != NO_CACHEPOSITION &&
227             this.filePointer >= this.cachePosition &&
228             this.filePointer < this.cachePosition + this.cacheLength )
229        { // Cache needs updating.
230            final long cacheStart = this.filePointer - this.cachePosition;
231 
232            assert cacheStart <= Integer.MAX_VALUE :
233                "Unexpected implementation limit reached.";
234 
235            final int cachedLength = len > this.cacheLength -
236                                           (int) cacheStart
237                                     ? this.cacheLength - (int) cacheStart
238                                     : len;
239 
240            System.arraycopy( buf, off, this.getCache(), (int) cacheStart,
241                              cachedLength );
242 
243        }
244 
245        this.fileOperations.setFilePointer( this.filePointer );
246        this.fileOperations.write( buf, off, len );
247        this.filePointer += len;
248    }
249 
250    public void read( final OutputStream out ) throws IOException
251    {
252        this.assertNotClosed();
253 
254        this.fileOperations.read( out );
255        this.filePointer = this.fileOperations.getFilePointer();
256    }
257 
258    public void write( final InputStream in ) throws IOException
259    {
260        this.assertNotClosed();
261 
262        this.fileOperations.write( in );
263        this.filePointer = this.fileOperations.getFilePointer();
264    }
265 
266    /**
267     * {@inheritDoc}
268     * Flushes the cache and closes the {@code FileOperations} implementation
269     * backing the instance.
270     *
271     * @throws IOException if closing the {@code FileOperations} implementation
272     * backing the instance fails or if the instance already is closed.
273     */
274    public void close() throws IOException
275    {
276        this.assertNotClosed();
277 
278        this.flush();
279        this.getFileOperations().close();
280        this.closed = true;
281    }
282 
283    //----------------------------------------------------------FileOperations--
284    //--FlushableFileOperations-------------------------------------------------
285 
286    /**
287     * {@inheritDoc}
288     * This method calls the {@code flush()} method of an underlying
289     * {@code FlushableFileOperations} implementation, if any.
290     */
291    public void flush() throws IOException
292    {
293        this.assertNotClosed();
294 
295        if ( this.fileOperations instanceof FlushableFileOperations )
296        {
297            ( (FlushableFileOperations) this.fileOperations ).flush();
298        }
299    }
300 
301    //-------------------------------------------------FlushableFileOperations--
302    //--ReadAheadFileOperations-------------------------------------------------
303 
304    /** The {@code FileOperations} backing the instance. */
305    private final FileOperations fileOperations;
306 
307    /** Cached bytes. */
308    private byte[] cache;
309 
310    /** Position in the file {@code cache} starts. */
311    private long cachePosition;
312 
313    private static final long NO_CACHEPOSITION = Long.MIN_VALUE;
314 
315    /** Length of the cached data. */
316    private int cacheLength;
317 
318    /** File pointer value. */
319    private long filePointer;
320 
321    /** Flags the instance as beeing closed. */
322    private boolean closed;
323 
324    /** Cache size in byte. */
325    private Integer cacheSize;
326 
327    /**
328     * Creates a new {@code ReadAheadFileOperations} instance taking the
329     * {@code FileOperations} backing the instance.
330     *
331     * @param fileOperations the {@code FileOperations} backing the instance.
332     *
333     * @throws NullPointerException if {@code fileOperations} is {@code null}.
334     * @throws IOException if reading fails.
335     */
336    public ReadAheadFileOperations( final FileOperations fileOperations )
337        throws IOException
338    {
339        super();
340 
341        if ( fileOperations == null )
342        {
343            throw new NullPointerException( "fileOperations" );
344        }
345 
346        this.fileOperations = fileOperations;
347        this.filePointer = fileOperations.getFilePointer();
348    }
349 
350    /**
351     * Creates a new {@code ReadAheadFileOperations} instance taking the
352     * {@code FileOperations} backing the instance and the size of the cache.
353     *
354     * @param fileOperations the {@code FileOperations} backing the instance.
355     * @param cacheSize the number of bytes to read-ahead.
356     *
357     * @throws NullPointerException if {@code fileOperations} is {@code null}.
358     * @throws IOException if reading fails.
359     */
360    public ReadAheadFileOperations( final FileOperations fileOperations,
361                                    final int cacheSize ) throws IOException
362    {
363        this( fileOperations );
364 
365        if ( cacheSize > 0 )
366        {
367            this.cacheSize = new Integer( cacheSize );
368        }
369    }
370 
371    /**
372     * Gets the {@code FileOperations} implementation operations are performed
373     * with.
374     *
375     * @return the {@code FileOperations} implementation operations are
376     * performed with.
377     */
378    public FileOperations getFileOperations()
379    {
380        return this.fileOperations;
381    }
382 
383    /**
384     * Gets the size of the cache in byte.
385     *
386     * @return the size of the cache in byte.
387     */
388    public int getCacheSize()
389    {
390        if ( this.cacheSize == null )
391        {
392            this.cacheSize = this.getDefaultCacheSize();
393        }
394 
395        return this.cacheSize.intValue();
396    }
397 
398    /**
399     * Gets the cache buffer.
400     *
401     * @return the cache buffer.
402     */
403    private byte[] getCache()
404    {
405        if ( this.cache == null )
406        {
407            this.cache =
408                this.getMemoryManager().allocateBytes( this.getCacheSize() );
409 
410        }
411 
412        return this.cache;
413    }
414 
415    /**
416     * Checks that the instance is not closed.
417     *
418     * @throws IOException if the instance is closed.
419     */
420    private void assertNotClosed() throws IOException
421    {
422        if ( this.closed )
423        {
424            throw new IOException( this.getAlreadyClosedMessage(
425                this.getLocale() ) );
426 
427        }
428    }
429 
430    /**
431     * Fills the cache starting at the current file pointer value.
432     *
433     * @throws IOException if reading fails.
434     */
435    private void fillCache() throws IOException
436    {
437        final long delta = this.getLength() - this.filePointer;
438        final int toRead = delta > this.getCache().length
439                           ? this.getCache().length
440                           : (int) delta;
441 
442        this.cachePosition = this.filePointer;
443 
444        int totalRead = 0;
445        int readLength = toRead;
446 
447        do
448        {
449            this.fileOperations.setFilePointer( this.filePointer );
450            final int read = this.fileOperations.read(
451                this.getCache(), totalRead, readLength );
452 
453            assert read != FileOperations.EOF : "Unexpected end of file.";
454 
455            totalRead += read;
456            readLength -= read;
457 
458        }
459        while ( totalRead < toRead );
460 
461        this.cacheLength = toRead;
462    }
463 
464    //-------------------------------------------------ReadAheadFileOperations--
465    //--Messages----------------------------------------------------------------
466 
467// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages
468    // This section is managed by jdtaus-container-mojo.
469 
470    /**
471     * Gets the text of message <code>alreadyClosed</code>.
472     * <blockquote><pre>Instanz geschlossen - keine E/A-Operationen möglich.</pre></blockquote>
473     * <blockquote><pre>Instance closed - cannot perform I/O.</pre></blockquote>
474     *
475     * @param locale The locale of the message instance to return.
476     *
477     * @return Message stating that an instance is already closed.
478     */
479    private String getAlreadyClosedMessage( final Locale locale )
480    {
481        return ContainerFactory.getContainer().
482            getMessage( this, "alreadyClosed", locale, null );
483 
484    }
485 
486// </editor-fold>//GEN-END:jdtausMessages
487 
488    //----------------------------------------------------------------Messages--
489}

[all classes][org.jdtaus.core.io.util]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov