001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015:
016: package org.griphyn.vdl.util;
017:
018: import org.griphyn.vdl.util.*;
019: import java.util.*;
020: import java.io.*;
021:
022: /**
023: * This class allows access to a set of files. With the constructor, the
024: * basename of the fileset is specified. From this file, a set of 10
025: * files can be accessed and constructed, with suffices ".0" to ".9". A
026: * cursor file, suffix ".nr", points to the currently active file in the
027: * ring.<p>
028: *
029: * In read mode, the cursor file gets locked temporarily while the stream
030: * is opened. If no cursor file exists, it is assumed that the basename
031: * is also the filename of the database. A lock file for the opened database
032: * will be created.<p>
033: *
034: * In write mode, the cursor file gets locked until the writer is being
035: * closed again. Thus, parallel access by other writers or readers are
036: * prohibited. The cursor is advanced at stream close. The database stream
037: * points to the next file beyong the cursor. If no cursor file existed, it
038: * will point to suffix ".0".<p>
039: *
040: * All access to the files must go through the respective open and close
041: * methods provided by this class in order to guarantee proper locking!
042: *
043: * @author Jens-S. Vöckler
044: * @author Yong Zhao
045: * @version $Revision: 50 $
046: *
047: * @see java.io.File
048: * @see LockHelper
049: */
050: abstract public class FileHelper {
051: /**
052: * base name of the fileset to access.
053: */
054: protected String m_database;
055:
056: /**
057: * description of the cursor file for the given basename set.
058: */
059: protected File m_number;
060:
061: /**
062: * Primary ctor: obtain access to a database cycle via basename.
063: * @param basename is the name of the database without digit suffix.
064: */
065: public FileHelper(String basename) {
066: this .m_database = basename;
067: this .m_number = new File(basename + ".nr");
068: }
069:
070: /**
071: * Reads the cursor file and obtains the current cycle position.
072: * The contract requires you to hold the lock for the cursor file.
073: *
074: * @return the current cycle position, or -1 to indicate failure.
075: */
076: protected int readCount() {
077: int result = -1;
078: try {
079: LineNumberReader lnr = new LineNumberReader(new FileReader(
080: this .m_number));
081: result = Integer.parseInt(lnr.readLine());
082: lnr.close();
083: } catch (IOException ioe) {
084: Logging.instance().log(
085: "lock",
086: 2,
087: "unable to process " + this .m_number.getPath()
088: + ": " + ioe.getMessage());
089: result = -1; // make extra sure
090: } catch (NumberFormatException nfe) {
091: result = -1; // make extra sure
092: }
093: return result;
094: }
095:
096: /**
097: * Updates the cursor file with a new cycle position. The contract
098: * requires you to hold the lock for the cursor file.
099: *
100: * @param number is the new cursor position.
101: * @return true, if the file was updated all right, false,
102: * if an error occured during update.
103: */
104: protected boolean writeCount(int number) {
105: boolean result = false;
106: try {
107: FileWriter fw = new FileWriter(this .m_number);
108: fw.write(Integer.toString(number)
109: + System.getProperty("line.separator", "\r\n"));
110: fw.close();
111: result = true;
112: } catch (IOException ioe) {
113: Logging.instance().log(
114: "lock",
115: 2,
116: "unable to update " + this .m_number.getPath()
117: + ": " + ioe.getMessage());
118: result = false;
119: }
120: return result;
121: }
122:
123: /**
124: * Opens a reader for the basename, adjusting the database cycles.
125: * The access can be shared with other simultaneous readers.
126: * @return a reader opened to the basename, or null for failure.
127: */
128: abstract public File openReader();
129:
130: /**
131: * Closes a previously obtained reader, and releases internal
132: * locking resources. Only if the reader was found in the internal
133: * state, any closing of the stream will be attempted.
134: *
135: * @param r is the reader that was created by {@link #openReader()}.
136: * @return true, if unlocking went smoothly, or false in the presence
137: * of an error. The only error that can happen it to use a File
138: * instance which was not returned by this instance.
139: */
140: abstract public boolean closeReader(File r);
141:
142: /**
143: * Opens a writer for the basename, adjusting the database cycles
144: * The access is exclusive, and cannot be shared with readers nor
145: * writers.
146: *
147: * @return a writer opened for the basename, or null for failure.
148: */
149: abstract public File openWriter();
150:
151: /**
152: * Closes a previously obtained writer, and releases internal
153: * locking resources. Error conditions can be either a missing
154: * instance that passed, or the inability to update the cursor file.
155: *
156: * @param w is the instance that was returned by {@link #openWriter()}.
157: * @return true, if the closing went smoothly, false in the presence
158: * of an error.
159: */
160: abstract public boolean closeWriter(File w);
161: }
|