001/* 002 * jDTAUS Core Utilities 003 * Copyright (C) 2005 Christian Schulte 004 * <cs@schulte.it> 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 019 * 020 */ 021package org.jdtaus.core.io.util; 022 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.OutputStream; 026import java.io.RandomAccessFile; 027import java.util.Locale; 028import org.jdtaus.core.container.ContainerFactory; 029import org.jdtaus.core.io.FileOperations; 030import org.jdtaus.core.lang.spi.MemoryManager; 031 032/** 033 * Adapts a {@link java.io.RandomAccessFile} to {@code FileOperations}. 034 * 035 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 036 * @version $JDTAUS: RandomAccessFileOperations.java 8641 2012-09-27 06:45:17Z schulte $ 037 */ 038public final class RandomAccessFileOperations implements FileOperations 039{ 040 //--Dependencies------------------------------------------------------------ 041 042// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies 043 // This section is managed by jdtaus-container-mojo. 044 045 /** 046 * Gets the configured <code>MemoryManager</code> implementation. 047 * 048 * @return The configured <code>MemoryManager</code> implementation. 049 */ 050 private MemoryManager getMemoryManager() 051 { 052 return (MemoryManager) ContainerFactory.getContainer(). 053 getDependency( this, "MemoryManager" ); 054 055 } 056 057 /** 058 * Gets the configured <code>Locale</code> implementation. 059 * 060 * @return The configured <code>Locale</code> implementation. 061 */ 062 private Locale getLocale() 063 { 064 return (Locale) ContainerFactory.getContainer(). 065 getDependency( this, "Locale" ); 066 067 } 068 069// </editor-fold>//GEN-END:jdtausDependencies 070 071 //------------------------------------------------------------Dependencies-- 072 //--Properties-------------------------------------------------------------- 073 074// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties 075 // This section is managed by jdtaus-container-mojo. 076 077 /** 078 * Gets the value of property <code>streamBufferSize</code>. 079 * 080 * @return Size of the buffer for buffering streams. 081 */ 082 private int getStreamBufferSize() 083 { 084 return ( (java.lang.Integer) ContainerFactory.getContainer(). 085 getProperty( this, "streamBufferSize" ) ).intValue(); 086 087 } 088 089// </editor-fold>//GEN-END:jdtausProperties 090 091 //--------------------------------------------------------------Properties-- 092 //--FileOperations---------------------------------------------------------- 093 094 /** Cache for the value of property {@code length}. */ 095 private transient long cachedLength = NO_CACHEDLENGTH; 096 097 private static final long NO_CACHEDLENGTH = Long.MIN_VALUE; 098 099 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}