blob: d76ec620833d3241dcb09ab5994233c4647de0d6 [file] [log] [blame]
package com.gemstone.gemfire.internal.process;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.gemstone.gemfire.internal.util.IOUtils;
import com.gemstone.gemfire.internal.util.StopWatch;
/**
* File wrapper that adds support for reading process id (pid) from a pid file
* written to disk by GemFire processes.
*
* @author Kirk Lund
* @since 8.2
*/
public class PidFile {
private static final long SLEEP_INTERVAL_MILLIS = 10;
private final File pidFile;
/**
* Constructs a PidFile for reading pid stored in a file.
*
* @param file the file containing the pid of the process
*
* @throws FileNotFoundException if the specified file name is not found within the directory
*/
public PidFile(final File file) throws FileNotFoundException {
if (!file.exists() || !file.isFile()) {
throw new FileNotFoundException("Unable to find PID file '" + file + "'");
}
this.pidFile = file;
}
File getFile() {
return this.pidFile;
}
/**
* Constructs a PidFile for reading pid stored in a file.
*
* @param directory directory containing a file of name pidFileName
* @param filename name of the file containing the pid of the process to stop
*
* @throws FileNotFoundException if the specified file name is not found within the directory
* @throws IllegalStateException if dir is not an existing directory
*/
public PidFile(final File directory, final String filename) throws FileNotFoundException {
if (!directory.isDirectory() && directory.exists()) {
throw new IllegalArgumentException("Argument '" + directory + "' must be an existing directory!");
}
final File file = new File(directory, filename);
if (!file.exists() || file.isDirectory()) {
throw new FileNotFoundException("Unable to find PID file '" + filename + "' in directory " + directory);
}
this.pidFile = file;
}
/**
* Reads in the pid from the specified file.
*
* @return the process id (pid) contained within the pidFile
*
* @throws IllegalArgumentException if the pid in the pidFile is not a positive integer
* @throws IOException if unable to read from the specified file
*/
public int readPid() throws IOException {
BufferedReader fileReader = null;
String pidValue = null;
try {
fileReader = new BufferedReader(new FileReader(this.pidFile));
pidValue = fileReader.readLine();
final int pid = Integer.parseInt(pidValue);
if (pid < 1) {
throw new IllegalArgumentException("Invalid pid '" + pid + "' found in " + this.pidFile.getCanonicalPath());
}
return pid;
}
catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid pid '" + pidValue + "' found in " + this.pidFile.getCanonicalPath());
}
finally {
IOUtils.close(fileReader);
}
}
/**
* Reads in the pid from the specified file, retrying until the specified timeout.
*
* @param timeout the maximum time to spend trying to read the pidFile
* @param unit the unit of timeout
*
* @return the process id (pid) contained within the pidFile
*
* @throws IllegalArgumentException if the pid in the pidFile is not a positive integer
* @throws IOException if unable to read from the specified file
* @throws InterruptedException if interrupted
* @throws TimeoutException if operation times out
*/
public int readPid(final long timeout, final TimeUnit unit) throws IOException, InterruptedException, TimeoutException {
IllegalArgumentException iae = null;
IOException ioe = null;
int pid = 0;
final long timeoutMillis = unit.toMillis(timeout);
final StopWatch stopWatch = new StopWatch(true);
while (pid <= 0) {
try {
pid = readPid();
} catch (IllegalArgumentException e) {
iae = e;
} catch (IOException e) {
ioe = e;
}
if (stopWatch.elapsedTimeMillis() > timeoutMillis) {
if (iae != null) {
throw new TimeoutException(iae.getMessage());
}
if (ioe != null) {
throw new TimeoutException(ioe.getMessage());
}
} else {
try {
Thread.sleep(SLEEP_INTERVAL_MILLIS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
if (iae != null) {
throw new InterruptedException(iae.getMessage());
}
if (ioe != null) {
throw new InterruptedException(ioe.getMessage());
}
throw e;
}
}
}
return pid;
}
}