/*
* Copyright 2004 Carnegie Mellon University.
* Portions Copyright 2004 Sun Microsystems, Inc.
* Portions Copyright 2004 Mitsubishi Electric Research Laboratories.
* All Rights Reserved. Use is subject to license terms.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*
*/
package edu.cmu.sphinx.util;
import java.io.*;
import java.net.InetAddress;
import java.nio.channels.FileLock;
import java.util.List;
/** A simple implementation of the batch manager suitable for single threaded batch processing */
public class PooledBatchManager implements BatchManager {
private final String batchFile;
private final int skip;
private File processingFile;
private final static File topDir = new File("tests");
private final static File inputDir = new File(topDir, "ToRun");
private final static File inProcessDir = new File(topDir, "InProcess");
private final static File completedDir = new File(topDir, "Completed");
private final static File resultsDir = new File(topDir, "Results");
private final static File lockFile = new File(".lock");
private FileLock lock;
private PrintStream oldOut;
private final FileFilter testFileFilter = new TestFileFilter();
/**
* Creates a pooled batch manager
*
* @param filename the name of the batch file
* @param skip items to skip between runs
*/
public PooledBatchManager(String filename, int skip) {
this.batchFile = filename;
this.skip = skip;
}
/** Starts processing the batch */
public void start() throws IOException {
// redirect standard out to a file
lock();
try {
createDirectories();
redirectStdout();
} finally {
unlock();
}
}
/**
* Gets the next available batch item or null if no more are available
*
* @return the next available batch item
* @throws IOException if an I/O error occurs while reading the next item from the batch file.
*/
public BatchItem getNextItem() throws IOException {
lock();
try {
// move the last 'in process' file to the 'completed'
// tests section.
if (processingFile != null) {
File completedFile = getCompletedFile(processingFile);
processingFile.renameTo(completedFile);
processingFile = null;
}
File testFile = getNextFile();
if (testFile != null) {
processingFile = getProcessingFile(testFile);
testFile.renameTo(processingFile);
System.out.println("Processing: " + processingFile);
return getBatchItem(processingFile);
} else {
return null;
}
} finally {
unlock();
}
}
/** Stops processing the batch */
public void stop() throws IOException {
lock();
try {
closeStdout();
} finally {
unlock();
}
}
/**
* Returns the name of the file
*
* @return the filename
*/
public String getFilename() {
return batchFile;
}
/** Creates the test directories as necessary */
private void createDirectories() throws IOException {
if (!topDir.isDirectory()) {
topDir.mkdir();
inProcessDir.mkdir();
completedDir.mkdir();
resultsDir.mkdir();
createInputDirectory();
}
}
/** Creates the input directory */
private void createInputDirectory() throws IOException {
inputDir.mkdir();
// read in the batch file
List<String> list = BatchFile.getLines(batchFile, skip);
for (int i = 0; i < list.size(); i++) {
String name = Integer.toString(i + 1);
String line = list.get(i);
createInputFile(inputDir, name, line);
}
}
/**
* Creates the individual batch files
*
* @param dir the directory to place the input file in
* @param name the name of the file
* @param line the contents of the file
*/
private void createInputFile(File dir, String name, String line)
throws IOException {
File path = new File(dir, name);
FileOutputStream fos = new FileOutputStream(path);
PrintStream ps = new PrintStream(fos);
ps.println(line);
ps.close();
}
/** Redirects standard out to a file in the results directory with a name 'Results_xxx.out' */
private void redirectStdout() throws IOException {
String myName = getMyName();
File resultFile = File.createTempFile(myName, ".out", resultsDir);
FileOutputStream fos = new FileOutputStream(resultFile);
PrintStream ps = new PrintStream(fos);
oldOut = System.out;
System.setOut(ps);
System.out.println("# These results collected on " + getMyName());
}
/**
* Gets my network name
*
* @return my network name
*/
private String getMyName() throws IOException {
return InetAddress.getLocalHost().getHostName();
}
/** Close the redirected stdout and restore it to what it was before we redirected it. */
private void closeStdout() throws IOException {
System.out.close();
System.setOut(oldOut);
}
/** Lock the test suite so we can manipulate the set of tests */
private void lock() throws IOException {
RandomAccessFile raf = new RandomAccessFile(lockFile, "rw");
lock = raf.getChannel().lock();
raf.close();
}
/** unlock the test suite so we can manipulate the set of tests */
private void unlock() throws IOException {
lock.release();
lock = null;
}
/**
* Given an 'in process' file, generate the corresponding completed file.
*
* @param file the in process file
* @return the completed file
*/
private File getCompletedFile(File file) {
return new File(completedDir, file.getName());
}
/**
* Given an 'input' file, generate the corresponding inProcess file.
*
* @param file the in process file
* @return the completed file
*/
private File getProcessingFile(File file) {
return new File(inProcessDir, file.getName());
}
/** returns the next batch item file in the input directory */
private File getNextFile() throws IOException {
File[] match = inputDir.listFiles(testFileFilter);
if (match.length > 0) {
return match[0];
}
return null;
}
/**
* Given a file parse the contents of the file into a BatchItem
*
* @param file the file to parse
* @return the contents in the form of a batch item
*/
private BatchItem getBatchItem(File file) throws IOException {
List<String> list = BatchFile.getLines(file.getPath());
if (list.size() != 1) {
throw new IOException("Bad batch file size");
}
String line = list.get(0);
return new BatchItem(BatchFile.getFilename(line),
BatchFile.getReference(line));
}
}
/** Filter that only yields filenames that are integer numbers */
class TestFileFilter implements FileFilter {
public boolean accept(File pathname) {
String name = pathname.getName();
try {
Integer.parseInt(name);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
}