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 java.util.concurrent.TimeUnit.MILLISECONDS; import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.Validate.isTrue; import static org.apache.commons.lang.Validate.notNull; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler; import org.apache.geode.lang.AttachAPINotFoundException; /** * Controls a {@link ControllableProcess} using files to communicate between processes. * * @since GemFire 8.0 */ class FileProcessController implements ProcessController { static final long DEFAULT_STATUS_TIMEOUT_MILLIS = 60 * 1000; private final long statusTimeoutMillis; private final FileControllerParameters parameters; private final int pid; /** * Constructs an instance for controlling a local process. * * @param parameters details about the controllable process * @param pid process id identifying the process to control * * @throws IllegalArgumentException if pid is not a positive integer */ FileProcessController(final FileControllerParameters parameters, final int pid) { this(parameters, pid, DEFAULT_STATUS_TIMEOUT_MILLIS, MILLISECONDS); } /** * Constructs an instance for controlling a local process. * * @param parameters details about the controllable process * @param pid process id identifying the process to control * @param timeout the timeout that operations must complete within * @param units the units of the timeout * * @throws IllegalArgumentException if pid is not a positive integer */ FileProcessController(final FileControllerParameters parameters, final int pid, final long timeout, final TimeUnit units) { notNull(parameters, "Invalid parameters '" + parameters + "' specified"); isTrue(pid > 0, "Invalid pid '" + pid + "' specified"); isTrue(timeout >= 0, "Invalid timeout '" + timeout + "' specified"); notNull(units, "Invalid units '" + units + "' specified"); this.pid = pid; this.parameters = parameters; this.statusTimeoutMillis = units.toMillis(timeout); } @Override public int getProcessId() { return pid; } @Override public String status() throws UnableToControlProcessException, IOException, InterruptedException, TimeoutException { return status(parameters.getDirectory(), parameters.getProcessType().getStatusRequestFileName(), parameters.getProcessType().getStatusFileName()); } @Override public void stop() throws UnableToControlProcessException, IOException { stop(parameters.getDirectory(), parameters.getProcessType().getStopRequestFileName()); } @Override public void checkPidSupport() { throw new AttachAPINotFoundException( LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE.toLocalizedString()); } long getStatusTimeoutMillis() { return statusTimeoutMillis; } private void stop(final File workingDir, final String stopRequestFileName) throws IOException { File stopRequestFile = new File(workingDir, stopRequestFileName); if (!stopRequestFile.exists()) { stopRequestFile.createNewFile(); } } private String status(final File workingDir, final String statusRequestFileName, final String statusFileName) throws IOException, InterruptedException, TimeoutException { // monitor for statusFile File statusFile = new File(workingDir, statusFileName); AtomicReference<String> statusRef = new AtomicReference<>(); ControlRequestHandler statusHandler = () -> { // read the statusFile StringBuilder lines = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(statusFile))) { reader.lines().forEach(lines::append); } finally { statusRef.set(lines.toString()); } }; ControlFileWatchdog statusFileWatchdog = new ControlFileWatchdog(workingDir, statusFileName, statusHandler, true); statusFileWatchdog.start(); File statusRequestFile = new File(workingDir, statusRequestFileName); if (!statusRequestFile.exists()) { statusRequestFile.createNewFile(); } // if timeout invoke stop and then throw TimeoutException long start = System.currentTimeMillis(); while (statusFileWatchdog.isAlive()) { Thread.sleep(10); if (System.currentTimeMillis() >= start + statusTimeoutMillis) { statusFileWatchdog.stop(); throw new TimeoutException("Timed out waiting for process to create " + statusFile); } } String lines = statusRef.get(); if (isBlank(lines)) { throw new IllegalStateException("Status file '" + statusFile + "' is blank"); } return lines; } }