Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.apache.geode.internal.process; import static org.apache.commons.lang.Validate.notNull; import static org.apache.geode.internal.process.ProcessUtils.identifyPid; import java.io.File; import java.io.FileWriter; import java.io.IOException; import org.apache.geode.distributed.internal.DistributionConfig; /** * Creates a pid file and writes the process id to the pid file. * * <p> * Related articles and libraries: * * <ul> * <li>http://barelyenough.org/blog/2005/03/java-daemon/ * <li>http://stackoverflow.com/questions/534648/how-to-daemonize-a-java-program * <li>http://commons.apache.org/daemon/ * <li>http://wrapper.tanukisoftware.com/ * <li>http://weblogs.java.net/blog/kohsuke/archive/2009/01/writing_a_unix.html * <li>http://www.enderunix.org/docs/eng/daemon.php * </ul> * * @since GemFire 7.0 */ class LocalProcessLauncher { static final String PROPERTY_IGNORE_IS_PID_ALIVE = DistributionConfig.GEMFIRE_PREFIX + "test.LocalProcessLauncher.ignoreIsPidAlive"; private final int pid; private final File pidFile; /** * Constructs a new ProcessLauncher. Parses this process's RuntimeMXBean name for the pid (process * id). * * @param pidFile the file to create and write pid into * @param force if true then the pid file will be replaced if it already exists * * @throws FileAlreadyExistsException if the pid file already exists and force is false * @throws IOException if unable to write pid (process id) to pid file * @throws PidUnavailableException if the pid cannot be parsed from the RuntimeMXBean name * * @see java.lang.management.RuntimeMXBean */ LocalProcessLauncher(final File pidFile, final boolean force) throws FileAlreadyExistsException, IOException, PidUnavailableException { notNull(pidFile, "Invalid pidFile '" + pidFile + "' specified"); this.pid = identifyPid(); this.pidFile = pidFile; writePid(force); } /** * Returns the process id (pid). * * @return the process id (pid) */ int getPid() { return pid; } /** * Returns the pid file. * * @return the pid file */ File getPidFile() { return pidFile; } /** * Delete the pid file now. {@link java.io.File#deleteOnExit()} is set on the pid file. * */ void close() { pidFile.delete(); } /** * Delete the pid file now. {@link java.io.File#deleteOnExit()} is set on the pid file. * * @param deletePidFileOnClose if true then the pid file will be deleted now instead of during JVM * exit */ void close(final boolean deletePidFileOnClose) { if (deletePidFileOnClose) { pidFile.delete(); } } /** * Creates a new pid file and writes this process's pid into it. * * @param force if true then the pid file will be replaced if it already exists it * * @throws FileAlreadyExistsException if the pid file already exists and force is false * @throws IOException if unable to create or write to the file */ private void writePid(final boolean force) throws FileAlreadyExistsException, IOException { if (pidFile.exists()) { if (!force) { checkOtherPid(readOtherPid()); } pidFile.delete(); } File tempPidFile = new File(pidFile.getParent(), pidFile.getName() + ".tmp"); tempPidFile.createNewFile(); try (FileWriter writer = new FileWriter(tempPidFile)) { writer.write(String.valueOf(pid)); writer.flush(); } tempPidFile.renameTo(pidFile); pidFile.deleteOnExit(); } private int readOtherPid() { int otherPid = 0; try { otherPid = ProcessUtils.readPid(pidFile); } catch (NumberFormatException | IOException ignore) { // suppress } return otherPid; } private void checkOtherPid(final int otherPid) throws FileAlreadyExistsException { if (ignoreIsPidAlive() || otherPid != 0 && isProcessAlive(otherPid)) { throw new FileAlreadyExistsException("Pid file already exists: " + pidFile + " for " + (otherPid > 0 ? "process " + otherPid : "unknown process")); } } private boolean isProcessAlive(final int pid) { return ignoreIsPidAlive() || ProcessUtils.isProcessAlive(pid); } private static boolean ignoreIsPidAlive() { return Boolean.getBoolean(PROPERTY_IGNORE_IS_PID_ALIVE); } }