org.apache.sling.testing.serversetup.jarexec.ShutdownHookSingleProcessDestroyer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.testing.serversetup.jarexec.ShutdownHookSingleProcessDestroyer.java

Source

/*
 * 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.sling.testing.serversetup.jarexec;

import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.exec.ProcessDestroyer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Simple ProcessDestroyer for a single process, meant to be used
 *  with our JarExecutor. 
 */
class ShutdownHookSingleProcessDestroyer implements ProcessDestroyer, Runnable {

    private final Logger log = LoggerFactory.getLogger(getClass());
    private Thread shutdownHookThread;
    private Process process;
    private final int timeoutSeconds;
    private final String processInfo;
    private boolean waitOnShutdown = false;

    public ShutdownHookSingleProcessDestroyer(String processInfo, int timeoutSeconds) {
        this.processInfo = processInfo;
        this.timeoutSeconds = timeoutSeconds;
    }

    public boolean getWaitOnShutdown() {
        return waitOnShutdown;
    }

    public void setWaitOnShutdown(boolean waitOnShutdown) {
        this.waitOnShutdown = waitOnShutdown;
    }

    public synchronized boolean add(Process p) {
        if (process != null) {
            throw new IllegalStateException("Process already set: " + process);
        }

        if (shutdownHookThread == null) {
            shutdownHookThread = new Thread(this, getClass().getSimpleName());
            Runtime.getRuntime().addShutdownHook(shutdownHookThread);
        }

        process = p;
        return true;
    }

    public synchronized boolean remove(Process p) {
        p = null;
        return true;
    }

    public int size() {
        return 1;
    }

    public void run() {
        destroyProcess(waitOnShutdown);
    }

    public void destroyProcess(boolean waitForIt) {
        Process toDestroy = null;
        synchronized (this) {
            toDestroy = process;
            process = null;
        }

        if (toDestroy == null) {
            return;
        }

        toDestroy.destroy();

        if (waitForIt) {
            log.info("Waiting for destroyed process {} to exit (timeout={} seconds)", processInfo, timeoutSeconds);
            final Thread mainThread = Thread.currentThread();
            final Timer t = new Timer(true);
            final TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    mainThread.interrupt();
                }
            };
            t.schedule(task, timeoutSeconds * 1000L);
            try {
                toDestroy.waitFor();
                try {
                    final int exit = toDestroy.exitValue();
                    log.info("Process {} ended with exit code {}", processInfo, exit);
                } catch (IllegalStateException ise) {
                    log.error("Failed to destroy process " + processInfo);
                }
            } catch (InterruptedException e) {
                log.error("Timeout waiting for process " + processInfo + " to exit");
            } finally {
                t.cancel();
            }
        }
    }
}