TrueZIP 6.8.3

de.schlichtherle.io
Class ArchiveController

java.lang.Object
  extended by de.schlichtherle.io.ArchiveController
All Implemented Interfaces:
Archive, Entry
Direct Known Subclasses:
ArchiveFileSystemController

abstract class ArchiveController
extends Object
implements Archive, Entry

This is the base class for any archive controller, providing all the essential services required by the File class to implement its behaviour. Each instance of this class manages a globally unique archive file (the target file) in order to allow random access to it as if it were a regular directory in the real file system.

In terms of software patterns, an ArchiveController is similar to a Director in a Builder pattern, with the ArchiveDriver interface as its Builder or Abstract Factory. However, an archive controller does not necessarily build a new archive. It may also simply be used to access an existing archive for read-only operations, such as listing its top level directory, or reading entry data. Whatever type of operation it's used for, an archive controller provides and controls all access to any particular archive file by the client application and deals with the rather complex details of its states and transitions.

Each instance of this class maintains a virtual file system, provides input and output streams for the entries of the archive file and methods to update the contents of the virtual file system to the target file in the real file system. In cooperation with the File class, it also knows how to deal with nested archive files (such as "outer.zip/inner.tar.gz" and false positives, i.e. plain files or directories or file or directory entries in an enclosing archive file which have been incorrectly recognized to be prospective archive files by the ArchiveDetector interface.

To ensure that for each archive file there is at most one {code ArchiveController}, the path name of the archive file (called target) is canonicalized, so it doesn't matter whether the File class addresses an archive file as "archive.zip" or "/dir/archive.zip" if "/dir" is the client application's current directory.

Note that in general all of its methods are reentrant on exceptions. This is important because the File class may repeatedly call them, triggered by the client application. Of course, depending on the context, some or all of the archive file's data may be lost in this case. For more information, please refer to File.umount() and File.update().

This class is actually the abstract base class for any archive controller. It encapsulates all the code which is not depending on a particular entry synchronization strategy and the corresponding state of the controller. Though currently unused, this is intended to be helpful for future extensions of TrueZIP, where different synchronization strategies may be implemented.

Since:
TrueZIP 6.0
Author:
Christian Schlichtherle

Nested Class Summary
(package private)  class ArchiveController.ArchiveEntryFalsePositiveException
          Thrown if a controller's target file is a false positive archive file which actually exists as a plain file or directory in an enclosing archive file.
(package private)  class ArchiveController.ArchiveEntryNotFoundException
          Thrown if an archive entry does not exist or is not accessible.
(package private)  class ArchiveController.ArchiveFileNotFoundException
          Thrown if a controller's target file does not exist or is not accessible.
(package private)  class ArchiveController.DirectoryArchiveEntryFalsePositiveException
          Thrown if a controller's target file is a false positive archive file which actually exists as a plain directory in an enclosing archive file.
(package private)  class ArchiveController.FalsePositiveException
          Thrown if a controller's target file is a false positive archive file which actually exists as a plain file or directory in the real file system or in an enclosing archive file.
(package private)  class ArchiveController.FileArchiveEntryFalsePositiveException
          Thrown if a controller's target file is a false positive archive file which actually exists as a plain file in an enclosing archive file.
(package private)  class ArchiveController.RfsEntryFalsePositiveException
          Thrown if a controller's target file is a false positive archive file which actually exists as a plain file or directory in the real file system.
 
Field Summary
private  ArchiveDriver driver
          The ArchiveDriver to use for this controller's target file.
private  ArchiveController enclController
          The archive controller of the enclosing archive, if any.
private  String enclEntryName
          The name of the entry for this archive in the enclosing archive, if any.
private  ReentrantLock readLock
           
private  File target
          The canonicalized or at least normalized absolute path name representation of the target file.
private  WeakReference weakThis
          A weak reference to this archive controller.
private  ReentrantLock writeLock
           
 
Fields inherited from interface de.schlichtherle.io.Entry
ROOT_NAME, SEPARATOR, SEPARATOR_CHAR
 
Constructor Summary
ArchiveController(File target, ArchiveController enclController, String enclEntryName, ArchiveDriver driver)
          This constructor schedules this controller to be thrown away if no more File objects are referring to it.
 
Method Summary
(package private) abstract  ArchiveFileSystem autoMount(boolean create)
          Returns the virtual archive file system mounted from the target file.
(package private)  void autoUmount(String entryName)
          Unmounts the archive file only if the archive file has already new data for entryName.
(package private)  boolean canRead(String entryName)
           
private  boolean canRead0(String entryName)
           
(package private)  boolean canWrite(String entryName)
           
private  boolean canWrite0(String entryName)
           
(package private) abstract  InputStream createInputStream(ArchiveEntry entry, ArchiveEntry dstEntry)
          Important: This controller's read or write lock must be acquired.
(package private)  InputStream createInputStream(String entryName)
          A factory method returning an input stream which is positioned at the beginning of the given entry in the target archive file.
(package private)  InputStream createInputStream0(String entryName)
           
(package private)  boolean createNewFile(String entryName, boolean autoCreate)
           
private  boolean createNewFile0(String entryName, boolean autoCreate)
           
(package private) abstract  OutputStream createOutputStream(ArchiveEntry entry, ArchiveEntry srcEntry)
          Important: This controller's write lock must be acquired.
(package private)  OutputStream createOutputStream(String entryName, boolean append)
          A factory method returning an OutputStream allowing to (re)write the given entry in the target archive file.
(package private)  OutputStream createOutputStream0(String entryName, boolean append)
           
(package private)  boolean delete(String entryName)
           
private  void delete0(String entryName)
           
(package private)  String enclEntryName(String entryName)
           
(package private)  boolean exists(String entryName)
           
private  boolean exists0(String entryName)
           
(package private)  Icon getClosedIcon(String entryName)
           
private  Icon getClosedIcon0(String entryName)
           
(package private)  ArchiveDriver getDriver()
          Returns the driver instance which is used for the target archive.
 Archive getEnclArchive()
           
(package private)  ArchiveController getEnclController()
          Returns the ArchiveController of the enclosing archive file, if any.
(package private)  String getEnclEntryName()
          Returns the entry name of this controller within the enclosing archive file, if any.
(package private)  Icon getOpenIcon(String entryName)
           
private  Icon getOpenIcon0(String entryName)
           
 String getPath()
          Returns the canonical path of the archive file.
(package private)  File getTarget()
          Returns the canonical or at least normalized absolute java.io.File object for the archive file to control.
(package private) abstract  boolean hasNewData(String entryName)
          Tests if the archive entry with the given name has received or is currently receiving new data via an output stream.
(package private)  boolean isDirectory(String entryName)
           
private  boolean isDirectory0(String entryName)
           
private  boolean isEnclosedBy(ArchiveController wannabe)
           
(package private)  boolean isFile(String entryName)
           
private  boolean isFile0(String entryName)
           
(package private)  boolean isRfsEntryTarget()
          Returns true if and only if the target file of this controller should be considered to be a file or directory in the real file system (RFS).
(package private) static boolean isRoot(String entryName)
          Returns true iff the given entry name refers to the virtual root directory within this controller.
(package private) abstract  boolean isTouched()
          Returns true if and only if the file system has been touched.
(package private)  long lastModified(String entryName)
           
private  long lastModified0(String entryName)
           
(package private)  long length(String entryName)
           
private  long length0(String entryName)
           
(package private)  String[] list(String entryName)
           
(package private)  String[] list(String entryName, FilenameFilter filenameFilter, File dir)
           
private  String[] list0(String entryName)
           
private  String[] list0(String entryName, FilenameFilter filenameFilter, File dir)
           
(package private)  File[] listFiles(String entryName, FileFilter fileFilter, File dir, FileFactory factory)
           
(package private)  File[] listFiles(String entryName, FilenameFilter filenameFilter, File dir, FileFactory factory)
           
private  File[] listFiles0(String entryName, FileFilter fileFilter, File dir, FileFactory factory)
           
private  File[] listFiles0(String entryName, FilenameFilter filenameFilter, File dir, FileFactory factory)
           
(package private)  boolean mkdir(String entryName, boolean autoCreate)
           
private  void mkdir0(String entryName, boolean autoCreate)
           
(package private)  ReentrantLock readLock()
           
(package private) abstract  void reset()
          Resets the archive controller to its initial state - all changes to the archive file which have not yet been updated get lost!
(package private)  void runWriteLocked(IORunnable runnable)
          Runs the given IORunnable while this controller has acquired its write lock regardless of the state of its read lock.
(package private)  void setDriver(ArchiveDriver driver)
          Sets the driver instance which is used for the target archive.
(package private)  boolean setLastModified(String entryName, long time)
           
private  boolean setLastModified0(String entryName, long time)
           
(package private)  boolean setReadOnly(String entryName)
           
private  boolean setReadOnly0(String entryName)
           
(package private)  void setScheduled(boolean scheduled)
          (Re)schedules this archive controller for the next call to ArchiveControllers.umount(String, boolean, boolean, boolean, boolean, boolean).
 String toString()
           
(package private) abstract  void umount(ArchiveException exceptionChain, boolean waitInputStreams, boolean closeInputStreams, boolean waitOutputStreams, boolean closeOutputStreams, boolean umount, boolean reassemble)
          Synchronizes the contents of the target archive file managed by this archive controller to the real file system.
(package private) abstract  int waitAllInputStreamsByOtherThreads(long timeout)
           
(package private) abstract  int waitAllOutputStreamsByOtherThreads(long timeout)
           
(package private)  ReentrantLock writeLock()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

weakThis

private final WeakReference weakThis
A weak reference to this archive controller. This field is for exclusive use by setScheduled(boolean).


target

private final File target
The canonicalized or at least normalized absolute path name representation of the target file.


enclController

private final ArchiveController enclController
The archive controller of the enclosing archive, if any.


enclEntryName

private final String enclEntryName
The name of the entry for this archive in the enclosing archive, if any.


driver

private ArchiveDriver driver
The ArchiveDriver to use for this controller's target file.


readLock

private final ReentrantLock readLock

writeLock

private final ReentrantLock writeLock
Constructor Detail

ArchiveController

ArchiveController(File target,
                  ArchiveController enclController,
                  String enclEntryName,
                  ArchiveDriver driver)
This constructor schedules this controller to be thrown away if no more File objects are referring to it. The subclass must update this schedule according to the controller's state. For example, if the controller has started to update some entry data, it must call setScheduled(boolean) in order to force the controller to be updated on the next call to umount(de.schlichtherle.io.ArchiveException, boolean, boolean, boolean, boolean, boolean, boolean) even if no more File objects are referring to it. Otherwise, all changes may get lost!

See Also:
setScheduled(boolean)
Method Detail

readLock

final ReentrantLock readLock()

writeLock

final ReentrantLock writeLock()

runWriteLocked

final void runWriteLocked(IORunnable runnable)
                   throws IOException
Runs the given IORunnable while this controller has acquired its write lock regardless of the state of its read lock. You must use this method if this controller may have acquired a read lock in order to prevent a dead lock.

Warning: This method temporarily releases the read lock before the write lock is acquired and the runnable is run! Hence, the runnable should recheck the state of the controller before it proceeds with any write operations.

Parameters:
runnable - The IORunnable to run while the write lock is acquired. No read lock is acquired while it's running.
Throws:
IOException

getTarget

final File getTarget()
Returns the canonical or at least normalized absolute java.io.File object for the archive file to control.


getPath

public final String getPath()
Description copied from interface: Archive
Returns the canonical path of the archive file. A canonical path is both absolute and unique. The precise definition depends on the platform, but all elements in a canonical path are separated by File.separators.

This property may be used to determine some archive file specific parameters, such as passwords or similar. However, implementations must not assume that the file denoted by the path actually exists as a file in the native file system!

Specified by:
getPath in interface Archive
Returns:
A valid reference to a String object - never null.
See Also:
Archive.getEnclArchive()

getEnclArchive

public final Archive getEnclArchive()
Specified by:
getEnclArchive in interface Archive
Returns:
The enclosing archive or null if this archive is not enclosed in another archive

isRoot

static final boolean isRoot(String entryName)
Returns true iff the given entry name refers to the virtual root directory within this controller.


getEnclController

final ArchiveController getEnclController()
Returns the ArchiveController of the enclosing archive file, if any.


getEnclEntryName

final String getEnclEntryName()
Returns the entry name of this controller within the enclosing archive file, if any.


enclEntryName

final String enclEntryName(String entryName)

isEnclosedBy

private final boolean isEnclosedBy(ArchiveController wannabe)

getDriver

final ArchiveDriver getDriver()
Returns the driver instance which is used for the target archive. All access to this method must be externally synchronized on this controller's read lock!

Returns:
A valid reference to an ArchiveDriver object - never null.

setDriver

final void setDriver(ArchiveDriver driver)
Sets the driver instance which is used for the target archive. All access to this method must be externally synchronized on this controller's write lock!

Parameters:
driver - A valid reference to an ArchiveDriver object - never null.

isRfsEntryTarget

final boolean isRfsEntryTarget()
Returns true if and only if the target file of this controller should be considered to be a file or directory in the real file system (RFS). Note that the target doesn't need to exist for this method to return true.


isTouched

abstract boolean isTouched()
Returns true if and only if the file system has been touched.


setScheduled

final void setScheduled(boolean scheduled)
(Re)schedules this archive controller for the next call to ArchiveControllers.umount(String, boolean, boolean, boolean, boolean, boolean).

Parameters:
scheduled - If set to true, this controller and hence its target archive file is guaranteed to get updated during the next call to ArchiveControllers.umount() even if there are no more File instances referring to it meanwhile. Call this method with this parameter value whenever the virtual file system has been touched, i.e. modified.

If set to false, this controller is conditionally scheduled to get updated. In this case, the controller gets automatically removed from the controllers weak hash map and discarded once the last file object directly or indirectly referring to it has been discarded unless setScheduled(true) has been called meanwhile. Call this method if the archive controller has been newly created or successfully updated.


hasNewData

abstract boolean hasNewData(String entryName)
Tests if the archive entry with the given name has received or is currently receiving new data via an output stream. As an implication, the entry cannot receive new data from another output stream before the next call to umount(de.schlichtherle.io.ArchiveException, boolean, boolean, boolean, boolean, boolean, boolean). Note that for directories this method will always return false!


autoMount

abstract ArchiveFileSystem autoMount(boolean create)
                              throws IOException
Returns the virtual archive file system mounted from the target file. This method is reentrant with respect to any exceptions it may throw.

Warning: Either the read or the write lock of this controller must be acquired while this method is called! If only a read lock is acquired, but a write lock is required, this method will temporarily release all locks, so any preconditions must be checked again upon return to protect against concurrent modifications!

Parameters:
create - If the archive file does not exist and this is true, a new file system with only a virtual root directory is created with its last modification time set to the system's current time.
Returns:
A valid archive file system - null is never returned.
Throws:
ArchiveController.FalsePositiveException
IOException - On any other I/O related issue with the target file or the target file of any enclosing archive file's controller.

autoUmount

final void autoUmount(String entryName)
               throws ArchiveException
Unmounts the archive file only if the archive file has already new data for entryName.

Warning: As a side effect, all data structures returned by this controller get reset (filesystem, entries, streams, etc.)! As an implication, this method requires external synchronization on this controller's write lock!

TODO: Consider adding configuration switch to allow overwriting an archive entry to the same output archive multiple times, whereby only the last written entry would be added to the central directory of the archive (unless the archive type doesn't support this).

Throws:
ArchiveException
See Also:
umount(ArchiveException, boolean, boolean, boolean, boolean, boolean, boolean), ArchiveException

umount

abstract void umount(ArchiveException exceptionChain,
                     boolean waitInputStreams,
                     boolean closeInputStreams,
                     boolean waitOutputStreams,
                     boolean closeOutputStreams,
                     boolean umount,
                     boolean reassemble)
              throws ArchiveException
Synchronizes the contents of the target archive file managed by this archive controller to the real file system.

Warning: As a side effect, all data structures returned by this controller get reset (filesystem, entries, streams, etc.)! As an implication, this method requires external synchronization on this controller's write lock!

Parameters:
waitInputStreams - See ArchiveControllers.umount(java.lang.String, boolean, boolean, boolean, boolean, boolean).
closeInputStreams - See ArchiveControllers.umount(java.lang.String, boolean, boolean, boolean, boolean, boolean).
waitOutputStreams - See ArchiveControllers.umount(java.lang.String, boolean, boolean, boolean, boolean, boolean).
closeOutputStreams - See ArchiveControllers.umount(java.lang.String, boolean, boolean, boolean, boolean, boolean).
umount - See ArchiveControllers.umount(java.lang.String, boolean, boolean, boolean, boolean, boolean).
reassemble - Let's assume this archive file is enclosed in another archive file. Then if this parameter is true, the updated archive file is also written to its enclosing archive file. Note that this parameter must be set if umount is set as well. Failing to comply to this requirement may throw a AssertionError and will incur loss of data!
Throws:
ArchiveException - If any exception condition occurs throughout the course of this method, an ArchiveException is created, prepended to exceptionChain and finally thrown.
See Also:
autoUmount(java.lang.String), ArchiveException

waitAllInputStreamsByOtherThreads

abstract int waitAllInputStreamsByOtherThreads(long timeout)

waitAllOutputStreamsByOtherThreads

abstract int waitAllOutputStreamsByOtherThreads(long timeout)

reset

abstract void reset()
             throws IOException
Resets the archive controller to its initial state - all changes to the archive file which have not yet been updated get lost! Thereafter, the archive controller will behave as if it has just been created and any subsequent operations on its entries will remount the virtual file system from the archive file again.

This method should be overridden by subclasses, but must still be called when doing so.

Throws:
IOException

toString

public String toString()
Overrides:
toString in class Object

createInputStream

final InputStream createInputStream(String entryName)
                             throws FileNotFoundException
A factory method returning an input stream which is positioned at the beginning of the given entry in the target archive file.

Parameters:
entryName - An entry in the virtual archive file system - null or "" is not permitted.
Returns:
A valid InputStream object - null is never returned.
Throws:
FileNotFoundException - If the entry cannot get read for any reason.

createInputStream0

InputStream createInputStream0(String entryName)
                         throws IOException
Throws:
IOException

createInputStream

abstract InputStream createInputStream(ArchiveEntry entry,
                                       ArchiveEntry dstEntry)
                                throws IOException
Important:

createOutputStream

final OutputStream createOutputStream(String entryName,
                                      boolean append)
                               throws FileNotFoundException
A factory method returning an OutputStream allowing to (re)write the given entry in the target archive file.

Parameters:
entryName - An entry in the virtual archive file system - null or "" is not permitted.
Returns:
A valid OutputStream object - null is never returned.
Throws:
FileNotFoundException - If the entry cannot get (re)written for any reason.

createOutputStream0

OutputStream createOutputStream0(String entryName,
                                 boolean append)
                           throws IOException
Throws:
IOException

createOutputStream

abstract OutputStream createOutputStream(ArchiveEntry entry,
                                         ArchiveEntry srcEntry)
                                  throws IOException
Important:

exists

final boolean exists(String entryName)
              throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

exists0

private final boolean exists0(String entryName)
                       throws IOException
Throws:
IOException

isFile

final boolean isFile(String entryName)
              throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

isFile0

private final boolean isFile0(String entryName)
                       throws IOException
Throws:
IOException

isDirectory

final boolean isDirectory(String entryName)
                   throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

isDirectory0

private final boolean isDirectory0(String entryName)
                            throws IOException
Throws:
IOException

getOpenIcon

final Icon getOpenIcon(String entryName)
                throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

getOpenIcon0

private final Icon getOpenIcon0(String entryName)
                         throws IOException
Throws:
IOException

getClosedIcon

final Icon getClosedIcon(String entryName)
                  throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

getClosedIcon0

private final Icon getClosedIcon0(String entryName)
                           throws IOException
Throws:
IOException

canRead

final boolean canRead(String entryName)
               throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

canRead0

private final boolean canRead0(String entryName)
                        throws IOException
Throws:
IOException

canWrite

final boolean canWrite(String entryName)
                throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

canWrite0

private final boolean canWrite0(String entryName)
                         throws IOException
Throws:
IOException

length

final long length(String entryName)
           throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

length0

private final long length0(String entryName)
                    throws IOException
Throws:
IOException

lastModified

final long lastModified(String entryName)
                 throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

lastModified0

private final long lastModified0(String entryName)
                          throws IOException
Throws:
IOException

list

final String[] list(String entryName)
             throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

list0

private final String[] list0(String entryName)
                      throws IOException
Throws:
IOException

list

final String[] list(String entryName,
                    FilenameFilter filenameFilter,
                    File dir)
             throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

list0

private final String[] list0(String entryName,
                             FilenameFilter filenameFilter,
                             File dir)
                      throws IOException
Throws:
IOException

listFiles

final File[] listFiles(String entryName,
                       FilenameFilter filenameFilter,
                       File dir,
                       FileFactory factory)
                throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

listFiles0

private final File[] listFiles0(String entryName,
                                FilenameFilter filenameFilter,
                                File dir,
                                FileFactory factory)
                         throws IOException
Throws:
IOException

listFiles

final File[] listFiles(String entryName,
                       FileFilter fileFilter,
                       File dir,
                       FileFactory factory)
                throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

listFiles0

private final File[] listFiles0(String entryName,
                                FileFilter fileFilter,
                                File dir,
                                FileFactory factory)
                         throws IOException
Throws:
IOException

setReadOnly

final boolean setReadOnly(String entryName)
                   throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

setReadOnly0

private final boolean setReadOnly0(String entryName)
                            throws IOException
Throws:
IOException

setLastModified

final boolean setLastModified(String entryName,
                              long time)
                       throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

setLastModified0

private final boolean setLastModified0(String entryName,
                                       long time)
                                throws IOException
Throws:
IOException

createNewFile

final boolean createNewFile(String entryName,
                            boolean autoCreate)
                     throws IOException
Throws:
IOException

createNewFile0

private final boolean createNewFile0(String entryName,
                                     boolean autoCreate)
                              throws IOException
Throws:
IOException

mkdir

final boolean mkdir(String entryName,
                    boolean autoCreate)
             throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

mkdir0

private final void mkdir0(String entryName,
                          boolean autoCreate)
                   throws IOException
Throws:
IOException

delete

final boolean delete(String entryName)
              throws ArchiveController.RfsEntryFalsePositiveException
Throws:
ArchiveController.RfsEntryFalsePositiveException

delete0

private final void delete0(String entryName)
                    throws IOException
Throws:
IOException

TrueZIP 6.8.3

Copyright © 2005-2011 Schlichtherle IT Services. All Rights Reserved.