/*
* This file or a portion of this file is licensed under the terms of
* the Globus Toolkit Public License, found in file GTPL, or at
* http://www.globus.org/toolkit/download/license.html. This notice must
* appear in redistributions of this file, with or without modification.
*
* Redistributions of this Software, with or without modification, must
* reproduce the GTPL in: (1) the Software, or (2) the Documentation or
* some other similar material which is provided with the Software (if
* any).
*
* Copyright 1999-2004 University of Chicago and The University of
* Southern California. All rights reserved.
*/
package org.griphyn.vdl.util;
import org.griphyn.vdl.util.*;
import java.util.*;
import java.io.*;
/**
* This class allows access to a set of files. With the constructor, the
* basename of the fileset is specified. From this file, a set of 10
* files can be accessed and constructed, with suffices ".0" to ".9". A
* cursor file, suffix ".nr", points to the currently active file in the
* ring.<p>
*
* In read mode, the cursor file gets locked temporarily while the stream
* is opened. If no cursor file exists, it is assumed that the basename
* is also the filename of the database. A lock file for the opened database
* will be created.<p>
*
* In write mode, the cursor file gets locked until the writer is being
* closed again. Thus, parallel access by other writers or readers are
* prohibited. The cursor is advanced at stream close. The database stream
* points to the next file beyong the cursor. If no cursor file existed, it
* will point to suffix ".0".<p>
*
* All access to the files must go through the respective open and close
* methods provided by this class in order to guarantee proper locking!
*
* @author Jens-S. Vöckler
* @author Yong Zhao
* @version $Revision$
*
* @see java.io.File
* @see LockHelper
*/
abstract public class FileHelper
{
/**
* base name of the fileset to access.
*/
protected String m_database;
/**
* description of the cursor file for the given basename set.
*/
protected File m_number;
/**
* Primary ctor: obtain access to a database cycle via basename.
* @param basename is the name of the database without digit suffix.
*/
public FileHelper( String basename )
{
this.m_database = basename;
this.m_number = new File( basename + ".nr" );
}
/**
* Reads the cursor file and obtains the current cycle position.
* The contract requires you to hold the lock for the cursor file.
*
* @return the current cycle position, or -1 to indicate failure.
*/
protected int readCount()
{
int result = -1;
try {
LineNumberReader lnr =
new LineNumberReader( new FileReader(this.m_number) );
result = Integer.parseInt(lnr.readLine());
lnr.close();
} catch ( IOException ioe ) {
Logging.instance().log( "lock", 2, "unable to process " +
this.m_number.getPath() + ": " +
ioe.getMessage() );
result = -1; // make extra sure
} catch ( NumberFormatException nfe ) {
result = -1; // make extra sure
}
return result;
}
/**
* Updates the cursor file with a new cycle position. The contract
* requires you to hold the lock for the cursor file.
*
* @param number is the new cursor position.
* @return true, if the file was updated all right, false,
* if an error occured during update.
*/
protected boolean writeCount( int number )
{
boolean result = false;
try {
FileWriter fw = new FileWriter(this.m_number);
fw.write( Integer.toString(number) +
System.getProperty( "line.separator", "\r\n" ) );
fw.close();
result = true;
}
catch ( IOException ioe ) {
Logging.instance().log( "lock", 2, "unable to update " +
this.m_number.getPath() + ": " +
ioe.getMessage() );
result = false;
}
return result;
}
/**
* Opens a reader for the basename, adjusting the database cycles.
* The access can be shared with other simultaneous readers.
* @return a reader opened to the basename, or null for failure.
*/
abstract public File openReader();
/**
* Closes a previously obtained reader, and releases internal
* locking resources. Only if the reader was found in the internal
* state, any closing of the stream will be attempted.
*
* @param r is the reader that was created by {@link #openReader()}.
* @return true, if unlocking went smoothly, or false in the presence
* of an error. The only error that can happen it to use a File
* instance which was not returned by this instance.
*/
abstract public boolean closeReader( File r );
/**
* Opens a writer for the basename, adjusting the database cycles
* The access is exclusive, and cannot be shared with readers nor
* writers.
*
* @return a writer opened for the basename, or null for failure.
*/
abstract public File openWriter();
/**
* Closes a previously obtained writer, and releases internal
* locking resources. Error conditions can be either a missing
* instance that passed, or the inability to update the cursor file.
*
* @param w is the instance that was returned by {@link #openWriter()}.
* @return true, if the closing went smoothly, false in the presence
* of an error.
*/
abstract public boolean closeWriter( File w );
}