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.math.BigDecimal; 025import java.util.Locale; 026import javax.swing.event.EventListenerList; 027import org.jdtaus.core.container.ContainerFactory; 028import org.jdtaus.core.io.FileOperations; 029import org.jdtaus.core.io.StructuredFile; 030import org.jdtaus.core.io.StructuredFileListener; 031import org.jdtaus.core.lang.spi.MemoryManager; 032import org.jdtaus.core.messages.DeletesBlocksMessage; 033import org.jdtaus.core.messages.InsertsBlocksMessage; 034import org.jdtaus.core.monitor.spi.Task; 035import org.jdtaus.core.monitor.spi.TaskMonitor; 036 037/** 038 * {@code StructuredFile} implementation based on {@code FileOperations}. 039 * <p>Pre {@code FlushableFileOperations} and its implementations this 040 * implementation performed read-ahead caching. This behaviour got changed 041 * in favour of {@code ReadAheadFileOperations} and 042 * {@code CoalescingFileOperations} which are generalized replacements for any 043 * cacheing formerly performed by this implementation. Since this class does 044 * not implement any cacheing anymore, the {@link #flush()} method will write 045 * out pending changes of an underlying {@code FlushableFileOperations} 046 * implementation, if any, by calling the corresponding {@code flush()} method 047 * of that {@code FlushableFileOperations} instance.</p> 048 * <p>This implementation uses task monitoring for the {@code deleteBlocks()} 049 * and {@code insertBlocks()} methods. Task monitoring is controlled by 050 * property {@code monitoringThreshold} holding the number of bytes which 051 * need to minimally be copied to enable any task monitoring during the 052 * copy operation (defaults to 5242880 - 5MB).</p> 053 * 054 * <p><b>Note:</b><br> 055 * This implementation is not thread-safe and concurrent changes to the 056 * underlying {@code FileOperations} implementation are not supported.</p> 057 * 058 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 059 * @version $JDTAUS: StructuredFileOperations.java 8641 2012-09-27 06:45:17Z schulte $ 060 * 061 * @see CoalescingFileOperations 062 * @see ReadAheadFileOperations 063 */ 064public final class StructuredFileOperations implements StructuredFile 065{ 066 //--Fields------------------------------------------------------------------ 067 068 /** Pre-allocated temporary buffer. */ 069 private byte[] defaultBuffer; 070 071 /** Caches the value of property blockCount. */ 072 private long cachedBlockCount = NO_CACHED_BLOCKCOUNT; 073 074 private static final long NO_CACHED_BLOCKCOUNT = Long.MIN_VALUE; 075 076 /** List for {@code StructuredFileListener}s. */ 077 private final EventListenerList fileListeners = new EventListenerList(); 078 079 /** Value of property {@code blockSize} as a {@code BigDecimal}. */ 080 private final BigDecimal decimalBlockSize; 081 082 //------------------------------------------------------------------Fields-- 083 //--Dependencies------------------------------------------------------------ 084 085// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies 086 // This section is managed by jdtaus-container-mojo. 087 088 /** 089 * Gets the configured <code>MemoryManager</code> implementation. 090 * 091 * @return The configured <code>MemoryManager</code> implementation. 092 */ 093 private MemoryManager getMemoryManager() 094 { 095 return (MemoryManager) ContainerFactory.getContainer(). 096 getDependency( this, "MemoryManager" ); 097 098 } 099 100 /** 101 * Gets the configured <code>Locale</code> implementation. 102 * 103 * @return The configured <code>Locale</code> implementation. 104 */ 105 private Locale getLocale() 106 { 107 return (Locale) ContainerFactory.getContainer(). 108 getDependency( this, "Locale" ); 109 110 } 111 112 /** 113 * Gets the configured <code>TaskMonitor</code> implementation. 114 * 115 * @return The configured <code>TaskMonitor</code> implementation. 116 */ 117 private TaskMonitor getTaskMonitor() 118 { 119 return (TaskMonitor) ContainerFactory.getContainer(). 120 getDependency( this, "TaskMonitor" ); 121 122 } 123 124// </editor-fold>//GEN-END:jdtausDependencies 125 126 //------------------------------------------------------------Dependencies-- 127 //--Properties-------------------------------------------------------------- 128 129// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties 130 // This section is managed by jdtaus-container-mojo. 131 132 /** 133 * Gets the value of property <code>defaultMonitoringThreshold</code>. 134 * 135 * @return Number of bytes which need to minimally be copied to enable any task monitoring during copy operations. 136 */ 137 private java.lang.Integer getDefaultMonitoringThreshold() 138 { 139 return (java.lang.Integer) ContainerFactory.getContainer(). 140 getProperty( this, "defaultMonitoringThreshold" ); 141 142 } 143 144 /** 145 * Gets the value of property <code>defaultBufferSize</code>. 146 * 147 * @return Size of the pre-alocated default buffer in byte. 148 */ 149 private int getDefaultBufferSize() 150 { 151 return ( (java.lang.Integer) ContainerFactory.getContainer(). 152 getProperty( this, "defaultBufferSize" ) ).intValue(); 153 154 } 155 156// </editor-fold>//GEN-END:jdtausProperties 157 158 //--------------------------------------------------------------Properties-- 159 //--StructuredFile---------------------------------------------------------- 160 161 public int getBlockSize() 162 { 163 return this.blockSize; 164 } 165 166 public long getBlockCount() throws IOException 167 { 168 this.assertNotClosed(); 169 170 if ( this.cachedBlockCount == NO_CACHED_BLOCKCOUNT ) 171 { 172 this.cachedBlockCount = BigDecimal.valueOf( 173 this.getFileOperations().getLength() ).divide( 174 this.decimalBlockSize, BigDecimal.ROUND_UNNECESSARY ). 175 longValue(); 176 177 // TODO JDK 1.5 longValueExact() 178 } 179 180 return this.cachedBlockCount; 181 } 182 183 public void deleteBlocks( final long index, 184 final long count ) throws IOException 185 { 186 final long blockCount = this.getBlockCount(); 187 188 // Preconditions. 189 if ( index < 0L || index > blockCount - count ) 190 { 191 throw new ArrayIndexOutOfBoundsException( (int) index ); 192 } 193 if ( count <= 0 || count > blockCount - index ) 194 { 195 throw new ArrayIndexOutOfBoundsException( (int) count ); 196 } 197 198 this.assertNotClosed(); 199 200 this.deleteBlocksImpl( index, count, blockCount ); 201 } 202 203 private void deleteBlocksImpl( final long index, final long count, 204 final long blockCount ) throws IOException 205 { 206 final long block = index + count; 207 final Task task = new Task(); 208 long toMoveByte = ( blockCount - block ) * this.getBlockSize(); 209 long readPos = block * this.getBlockSize(); 210 long writePos = index * this.getBlockSize(); 211 long progress = 0L; 212 long progressDivisor = 1L; 213 long maxProgress = toMoveByte; 214 215 // Clear the cached block count. 216 this.cachedBlockCount = NO_CACHED_BLOCKCOUNT; 217 218 // No blocks are following the ones to remove. 219 if ( toMoveByte == 0L ) 220 { 221 this.getFileOperations().setLength( 222 this.getFileOperations().getLength() - count * 223 this.getBlockSize() ); 224 225 this.fireBlocksDeleted( index, count ); 226 return; 227 } 228 229 final byte[] buf = this.getBuffer( toMoveByte > Integer.MAX_VALUE 230 ? Integer.MAX_VALUE 231 : (int) toMoveByte ); 232 233 while ( maxProgress > Integer.MAX_VALUE ) 234 { 235 maxProgress /= 2L; 236 progressDivisor *= 2L; 237 } 238 239 task.setIndeterminate( false ); 240 task.setCancelable( false ); 241 task.setMinimum( 0 ); 242 task.setMaximum( (int) maxProgress ); 243 task.setProgress( (int) progress ); 244 task.setDescription( new DeletesBlocksMessage() ); 245 246 final boolean monitoring = toMoveByte > this.getMonitoringThreshold(); 247 if ( monitoring ) 248 { 249 this.getTaskMonitor().monitor( task ); 250 } 251 252 try 253 { 254 // Move following blocks to the position of the first block to 255 // remove. 256 while ( toMoveByte > 0L ) 257 { 258 this.getFileOperations().setFilePointer( readPos ); 259 final int len = toMoveByte <= buf.length 260 ? (int) toMoveByte 261 : buf.length; 262 263 int read = 0; 264 int total = 0; 265 do 266 { 267 read = this.getFileOperations(). 268 read( buf, total, len - total ); 269 270 assert read != FileOperations.EOF : 271 "Unexpected end of file."; 272 273 total += read; 274 275 } 276 while ( total < len ); 277 278 // Move the block count blocks to the beginning. 279 this.getFileOperations().setFilePointer( writePos ); 280 this.getFileOperations().write( buf, 0, len ); 281 282 readPos += len; 283 writePos += len; 284 toMoveByte -= len; 285 progress += len; 286 287 task.setProgress( (int) ( progress / progressDivisor ) ); 288 } 289 290 // Truncate the file. 291 this.getFileOperations().setLength( this.getFileOperations(). 292 getLength() - count * 293 this.getBlockSize() ); 294 295 this.fireBlocksDeleted( index, count ); 296 } 297 finally 298 { 299 if ( monitoring ) 300 { 301 this.getTaskMonitor().finish( task ); 302 } 303 } 304 } 305 306 public void insertBlocks( final long index, 307 final long count ) throws IOException 308 { 309 final long blockCount = this.getBlockCount(); 310 311 // Preconditions. 312 if ( index < 0L || index > blockCount ) 313 { 314 throw new ArrayIndexOutOfBoundsException( (int) index ); 315 } 316 if ( count <= 0L || count > Long.MAX_VALUE - blockCount ) 317 { 318 throw new ArrayIndexOutOfBoundsException( (int) count ); 319 } 320 321 this.assertNotClosed(); 322 323 this.insertBlocksImpl( index, count, blockCount ); 324 } 325 326 private void insertBlocksImpl( final long index, final long count, 327 final long blockCount ) throws IOException 328 { 329 final Task task = new Task(); 330 long toMoveByte = ( blockCount - index ) * this.getBlockSize(); 331 long readPos = blockCount * this.getBlockSize(); 332 long writePos = readPos + count * this.getBlockSize(); 333 long progress = 0L; 334 long progressDivisor = 1L; 335 long maxProgress = toMoveByte; 336 337 // Clear the cached block count. 338 this.cachedBlockCount = NO_CACHED_BLOCKCOUNT; 339 340 // Increase the length of the file. 341 this.getFileOperations().setLength( this.getFileOperations(). 342 getLength() + this.getBlockSize() * 343 count ); 344 345 // New blocks are inserted at the end of the file. 346 if ( toMoveByte <= 0L ) 347 { 348 this.fireBlocksInserted( index, count ); 349 return; 350 } 351 352 final byte[] buf = this.getBuffer( toMoveByte > Integer.MAX_VALUE 353 ? Integer.MAX_VALUE 354 : (int) toMoveByte ); 355 356 while ( maxProgress > Integer.MAX_VALUE ) 357 { 358 maxProgress /= 2L; 359 progressDivisor *= 2L; 360 } 361 362 task.setIndeterminate( false ); 363 task.setCancelable( false ); 364 task.setMinimum( 0 ); 365 task.setMaximum( (int) maxProgress ); 366 task.setProgress( (int) progress ); 367 task.setDescription( new InsertsBlocksMessage() ); 368 369 final boolean monitoring = toMoveByte > this.getMonitoringThreshold(); 370 if ( monitoring ) 371 { 372 this.getTaskMonitor().monitor( task ); 373 } 374 375 try 376 { 377 // Move all blocks from index inclusive count blocks to the end of 378 // the file. 379 while ( toMoveByte > 0L ) 380 { 381 final int moveLen = buf.length >= toMoveByte 382 ? (int) toMoveByte 383 : buf.length; 384 385 readPos -= moveLen; 386 writePos -= moveLen; 387 this.getFileOperations().setFilePointer( readPos ); 388 int read = 0; 389 int total = 0; 390 391 do 392 { 393 read = this.getFileOperations(). 394 read( buf, total, moveLen - total ); 395 396 assert read != FileOperations.EOF : 397 "Unexpected end of file."; 398 399 total += read; 400 401 } 402 while ( total < moveLen ); 403 404 // Move the block count blocks to the end. 405 this.getFileOperations().setFilePointer( writePos ); 406 this.getFileOperations().write( buf, 0, moveLen ); 407 408 toMoveByte -= moveLen; 409 progress += moveLen; 410 411 task.setProgress( (int) ( progress / progressDivisor ) ); 412 } 413 414 this.fireBlocksInserted( index, count ); 415 } 416 finally 417 { 418 if ( monitoring ) 419 { 420 this.getTaskMonitor().finish( task ); 421 } 422 } 423 } 424 425 public void readBlock( final long block, final int off, 426 final byte[] buf ) throws IOException 427 { 428 this.readBlock( block, off, buf, 0, buf.length ); 429 } 430 431 public void readBlock( final long block, final int off, final byte[] buf, 432 final int index, final int length ) 433 throws IOException 434 { 435 this.assertValidArguments( block, off, buf, index, length ); 436 this.assertNotClosed(); 437 438 int totalRead = 0; 439 int toRead = length; 440 441 this.getFileOperations().setFilePointer( 442 block * this.getBlockSize() + off ); 443 444 do 445 { 446 final int read = this.getFileOperations(). 447 read( buf, index + totalRead, toRead ); 448 449 assert read != FileOperations.EOF : 450 "Unexpected end of file."; 451 452 totalRead += read; 453 toRead -= read; 454 455 } 456 while ( totalRead < length ); 457 } 458 459 public void writeBlock( final long block, final int off, 460 final byte[] buf ) throws IOException 461 { 462 this.writeBlock( block, off, buf, 0, buf.length ); 463 } 464 465 public void writeBlock( final long block, final int off, 466 final byte[] buf, 467 final int index, final int length ) 468 throws IOException 469 { 470 this.assertValidArguments( block, off, buf, index, length ); 471 this.assertNotClosed(); 472 473 this.getFileOperations().setFilePointer( 474 block * this.getBlockSize() + off ); 475 476 this.getFileOperations().write( buf, index, length ); 477 } 478 479 /** 480 * {@inheritDoc} 481 * Flushes the instance and closes the {@code FileOperations} implementation 482 * backing the instance. 483 * 484 * @throws IOException if closing the {@code FileOperations} implementation 485 * backing the instance fails, or if the instance already is closed. 486 */ 487 public void close() throws IOException 488 { 489 this.assertNotClosed(); 490 491 this.flush(); 492 this.getFileOperations().close(); 493 this.closed = true; 494 } 495 496 public void addStructuredFileListener( 497 final StructuredFileListener listener ) 498 { 499 this.fileListeners.add( StructuredFileListener.class, listener ); 500 } 501 502 public void removeStructuredFileListener( 503 final StructuredFileListener listener ) 504 { 505 this.fileListeners.remove( StructuredFileListener.class, listener ); 506 } 507 508 public StructuredFileListener[] getStructuredFileListeners() 509 { 510 return (StructuredFileListener[]) this.fileListeners.getListeners( 511 StructuredFileListener.class ); 512 513 } 514 515 //----------------------------------------------------------StructuredFile-- 516 //--StructuredFileOperations------------------------------------------------ 517 518 /** Number of bytes per block. */ 519 private int blockSize; 520 521 /** Mininum number of bytes to copy to start any task monitoring. */ 522 private Integer monitoringThreshold; 523 524 /** {@code FileOperations} backing the instance. */ 525 private FileOperations fileOperations; 526 527 /** Flags the instance as beeing closed. */ 528 private boolean closed; 529 530 /** 531 * Creates a new {@code StructuredFileOperations} instance taking the size 532 * of one block in byte and the {@code FileOperations} operations are to be 533 * performed with. 534 * 535 * @param blockSize Number of bytes per block. 536 * @param fileOperations {@code FileOperations} implementation to operate 537 * on. 538 * 539 * @throws NullPointerException if {@code fileOperations} is {@code null}. 540 * @throws IllegalArgumentException if {@code blockSize} is incompatible 541 * with the length of {@code fileOperations}. 542 * @throws IOException if getting the length from the {@code fileOperations} 543 * fails. 544 */ 545 public StructuredFileOperations( final int blockSize, 546 final FileOperations fileOperations ) 547 throws IOException 548 { 549 super(); 550 551 if ( fileOperations == null ) 552 { 553 throw new NullPointerException( "fileOperations" ); 554 } 555 if ( blockSize <= 0 ) 556 { 557 throw new IllegalArgumentException( Integer.toString( blockSize ) ); 558 } 559 560 this.blockSize = blockSize; 561 this.decimalBlockSize = BigDecimal.valueOf( blockSize ); 562 this.fileOperations = fileOperations; 563 this.assertValidFileLength(); 564 } 565 566 /** 567 * Creates a new {@code StructuredFileOperations} instance taking the size 568 * of one block in byte, task monitoring configuration and the 569 * {@code FileOperations} operations are to be performed with. 570 * 571 * @param blockSize Number of bytes per block. 572 * @param monitoringThreshold the mininum number of bytes to copy to start 573 * any task monitoring. 574 * @param fileOperations {@code FileOperations} implementation to operate 575 * on. 576 * 577 * @throws NullPointerException if {@code fileOperations} is {@code null}. 578 * @throws IllegalArgumentException if {@code blockSize} is incompatible 579 * with the length of {@code fileOperations}. 580 * @throws IOException if getting the length from the {@code fileOperations} 581 * fails. 582 */ 583 public StructuredFileOperations( final int blockSize, 584 final int monitoringThreshold, 585 final FileOperations fileOperations ) 586 throws IOException 587 { 588 super(); 589 590 if ( fileOperations == null ) 591 { 592 throw new NullPointerException( "fileOperations" ); 593 } 594 if ( blockSize <= 0 ) 595 { 596 throw new IllegalArgumentException( Integer.toString( blockSize ) ); 597 } 598 599 this.blockSize = blockSize; 600 this.decimalBlockSize = BigDecimal.valueOf( blockSize ); 601 this.fileOperations = fileOperations; 602 603 if ( monitoringThreshold > 0 ) 604 { 605 this.monitoringThreshold = new Integer( monitoringThreshold ); 606 } 607 608 this.assertValidFileLength(); 609 } 610 611 /** 612 * Gets the {@code FileOperations} implementation operations are performed 613 * with. 614 * 615 * @return the {@code FileOperations} implementation operations are 616 * performed with. 617 */ 618 public FileOperations getFileOperations() 619 { 620 return this.fileOperations; 621 } 622 623 /** 624 * Calls the {@code flush()} method of an underlying 625 * {@code FlushableFileOperations} instance, if any. 626 * 627 * @throws IOException if reading or writing fails. 628 */ 629 public void flush() throws IOException 630 { 631 this.assertNotClosed(); 632 633 if ( this.getFileOperations() instanceof FlushableFileOperations ) 634 { 635 ( (FlushableFileOperations) this.getFileOperations() ).flush(); 636 } 637 } 638 639 /** 640 * Checks arguments provided to the {@code readBlock} and {@code writeBlock} 641 * methods. 642 * 643 * @throws NullPointerException if {@code buf} is {@code null}. 644 * @throws IndexOutOfBoundsException if {@code block} is negative, 645 * greater than or equal to {@code getBlockCount()}, or {@code off} is 646 * negative, greater than or equal to {@code getBlockSize()}, or 647 * {@code index} is negative, greater than or equal to the length of 648 * {@code buf}, or {@code length} is negative or greater than the 649 * length of {@code buf} minus {@code index} or greater than 650 * {@code getBlockSize() minus {@code off}. 651 */ 652 private void assertValidArguments( final long block, final int off, 653 final byte[] buf, final int index, 654 final int length ) throws 655 NullPointerException, IndexOutOfBoundsException, IOException 656 { 657 final long blockCount = this.getBlockCount(); 658 659 if ( buf == null ) 660 { 661 throw new NullPointerException( "buf" ); 662 } 663 if ( block < 0 || block >= blockCount ) 664 { 665 throw new ArrayIndexOutOfBoundsException( (int) block ); 666 } 667 if ( off < 0 || off >= this.getBlockSize() ) 668 { 669 throw new ArrayIndexOutOfBoundsException( off ); 670 } 671 if ( index < 0 || index >= buf.length ) 672 { 673 throw new ArrayIndexOutOfBoundsException( index ); 674 } 675 if ( length < 0L || length > buf.length - index || 676 length > this.getBlockSize() - off ) 677 { 678 throw new ArrayIndexOutOfBoundsException( length ); 679 } 680 } 681 682 /** 683 * Checks the length of the provided {@code FileOperations} implementation 684 * against property {@code blockSize}. 685 * 686 * @throws IllegalArgumentException if the combination of property 687 * {@code blockSize} and {@code getFileOperations().getLength()} is invalid. 688 * @throws IOException if the getting the length fails. 689 */ 690 private void assertValidFileLength() throws IOException 691 { 692 if ( this.getFileOperations() != null && 693 this.getFileOperations().getLength() % this.getBlockSize() != 0L ) 694 { 695 throw new IllegalArgumentException( 696 Long.toString( this.getFileOperations().getLength() % 697 this.getBlockSize() ) ); 698 699 } 700 } 701 702 /** 703 * Checks that the instance is not closed. 704 * 705 * @throws IOException if the instance is closed. 706 */ 707 private void assertNotClosed() throws IOException 708 { 709 if ( this.closed ) 710 { 711 throw new IOException( this.getAlreadyClosedMessage( 712 this.getLocale() ) ); 713 714 } 715 } 716 717 /** 718 * Gets the value of property {@code monitoringThreshold}. 719 * 720 * @return the mininum number of bytes to copy to start any task monitoring. 721 */ 722 public int getMonitoringThreshold() 723 { 724 if ( this.monitoringThreshold == null ) 725 { 726 this.monitoringThreshold = this.getDefaultMonitoringThreshold(); 727 } 728 729 return this.monitoringThreshold.intValue(); 730 } 731 732 /** 733 * Notifies all registered {@code StructuredFileListener}s about inserted 734 * blocks. 735 * 736 * @param index the index new blocks were inserted. 737 * @param insertedBlocks the number of blocks which were inserted at 738 * {@code index}. 739 * 740 * @throws IOException if reading or writing fails. 741 */ 742 private void fireBlocksInserted( 743 final long index, final long insertedBlocks ) throws IOException 744 { 745 final Object[] listeners = this.fileListeners.getListenerList(); 746 for ( int i = listeners.length - 2; i >= 0; i -= 2 ) 747 { 748 if ( listeners[i] == StructuredFileListener.class ) 749 { 750 ( (StructuredFileListener) listeners[i + 1] ).blocksInserted( 751 index, insertedBlocks ); 752 753 } 754 } 755 } 756 757 /** 758 * Notifies all registered {@code StructuredFileListener}s about deleted 759 * blocks. 760 * 761 * @param index the index blocks were deleted at. 762 * @param deletedBlocks the number of blocks which were deleted starting at 763 * {@code index}. 764 * 765 * @throws IOException if reading or writing fails. 766 */ 767 private void fireBlocksDeleted( 768 final long index, final long deletedBlocks ) throws IOException 769 { 770 final Object[] listeners = this.fileListeners.getListenerList(); 771 for ( int i = listeners.length - 2; i >= 0; i -= 2 ) 772 { 773 if ( listeners[i] == StructuredFileListener.class ) 774 { 775 ( (StructuredFileListener) listeners[i + 1] ).blocksDeleted( 776 index, deletedBlocks ); 777 778 } 779 } 780 } 781 782 private byte[] getBuffer( final int requested ) throws IOException 783 { 784 final long length = this.getFileOperations().getLength(); 785 786 if ( requested <= 0 || requested > length ) 787 { 788 throw new IllegalArgumentException( Integer.toString( requested ) ); 789 } 790 791 if ( this.defaultBuffer == null ) 792 { 793 this.defaultBuffer = this.getMemoryManager(). 794 allocateBytes( this.getDefaultBufferSize() ); 795 796 } 797 798 return requested <= this.defaultBuffer.length || 799 this.getMemoryManager().getAvailableBytes() < requested 800 ? this.defaultBuffer 801 : this.getMemoryManager().allocateBytes( requested ); 802 803 } 804 805 //------------------------------------------------StructuredFileOperations-- 806 //--Messages---------------------------------------------------------------- 807 808// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausMessages 809 // This section is managed by jdtaus-container-mojo. 810 811 /** 812 * Gets the text of message <code>alreadyClosed</code>. 813 * <blockquote><pre>Instanz geschlossen - keine E/A-Operationen möglich.</pre></blockquote> 814 * <blockquote><pre>Instance closed - cannot perform I/O.</pre></blockquote> 815 * 816 * @param locale The locale of the message instance to return. 817 * 818 * @return Message stating that an instance is already closed. 819 */ 820 private String getAlreadyClosedMessage( final Locale locale ) 821 { 822 return ContainerFactory.getContainer(). 823 getMessage( this, "alreadyClosed", locale, null ); 824 825 } 826 827// </editor-fold>//GEN-END:jdtausMessages 828 829 //----------------------------------------------------------------Messages-- 830}