Java tutorial
/* * Copyright (C) 2016 Keith M. Hughes * Copyright (C) 2014 Google Inc. * * Licensed 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 io.smartspaces.util.process; import io.smartspaces.SimpleSmartSpacesException; import io.smartspaces.system.SmartSpacesEnvironment; import io.smartspaces.util.process.NativeApplicationRunner.NativeApplicationRunnerState; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import com.google.common.collect.Lists; /** * A collection of {@link NativeApplicationRunner} instances. * * <p> * This collection ensures the runners are properly sampled and shutdown * properly, do not attempt to handle them yourself. * * @author Keith M. Hughes */ public class StandardNativeApplicationRunnerCollection implements NativeApplicationRunnerCollection { /** * The count for the countdown latch for * {@link #runNativeApplicationRunner(NativeApplicationDescription, long)}. */ public static final int BLOCKING_RUN_COUNTDOWN_COUNT = 1; /** * The default for how often to sample the runners to see if they are still * running, in milliseconds. */ public static final long SAMPLING_PERIOD_DEFAULT = 500; /** * How often to sample the runners to see if they are still running, in * milliseconds. */ private long samplingPeriod = SAMPLING_PERIOD_DEFAULT; /** * The parser for native applications. */ private NativeApplicationRunnerParser runnerParser = new StandardNativeApplicationRunnerParser(); /** * The space environment to use. */ private final SmartSpacesEnvironment spaceEnvironment; /** * The logger for issues. */ private final Log log; /** * All runners currently running. */ private final List<NativeApplicationRunner> runners = Lists.newCopyOnWriteArrayList(); /** * The factory for new runners. */ private final NativeApplicationRunnerFactory runnerFactory; /** * The future used to control the sampling thread. */ private Future<?> samplingFuture; /** * Construct a new collection. * * @param spaceEnvironment * the space environment for the collection to use * @param log * the logger */ public StandardNativeApplicationRunnerCollection(SmartSpacesEnvironment spaceEnvironment, Log log) { this.spaceEnvironment = spaceEnvironment; this.log = log; runnerFactory = new SimpleNativeApplicationRunnerFactory(runnerParser, spaceEnvironment); } @Override public synchronized void startup() { if (samplingFuture == null) { for (NativeApplicationRunner runner : runners) { runner.startup(); } samplingFuture = spaceEnvironment.getExecutorService().scheduleAtFixedRate(new Runnable() { @Override public void run() { sampleRunners(); } }, samplingPeriod, samplingPeriod, TimeUnit.MILLISECONDS); } } @Override public synchronized void shutdown() { if (samplingFuture != null) { samplingFuture.cancel(true); samplingFuture = null; } for (NativeApplicationRunner runner : runners) { runner.shutdown(); } } @Override public NativeApplicationRunner addNativeApplicationRunner(NativeApplicationDescription description) { NativeApplicationRunner runner = newNativeApplicationRunner(); runner.configure(description); addNativeApplicationRunner(runner); return runner; } @Override public synchronized void addNativeApplicationRunner(NativeApplicationRunner runner) { runners.add(runner); if (samplingFuture != null) { runner.startup(); } } @Override public NativeApplicationRunner newNativeApplicationRunner() { return runnerFactory.newPlatformNativeApplicationRunner(log); } @Override public NativeApplicationRunnerState runNativeApplicationRunner(NativeApplicationDescription description, long waitTime) { NativeApplicationRunner runner = newNativeApplicationRunner(); runner.configure(description); final CountDownLatch runnerComplete = new CountDownLatch(BLOCKING_RUN_COUNTDOWN_COUNT); runner.addNativeApplicationRunnerListener(new BaseNativeApplicationRunnerListener() { @Override public void onNativeApplicationRunnerStartupFailed(NativeApplicationRunner runner) { runnerComplete.countDown(); } @Override public void onNativeApplicationRunnerShutdown(NativeApplicationRunner runner) { runnerComplete.countDown(); } }); addNativeApplicationRunner(runner); try { if (!runnerComplete.await(waitTime, TimeUnit.MILLISECONDS)) { SimpleSmartSpacesException.throwFormattedException("The command %s did not complete in %d msec", description, waitTime); } } catch (SimpleSmartSpacesException e) { throw e; } catch (InterruptedException e) { SimpleSmartSpacesException.throwFormattedException("The command %s wait was interrupted", description); } return runner.getState(); } /** * Sample all runners and see if they are still running. */ private void sampleRunners() { // No need to synchronize as the collection is properly threadsafe. for (NativeApplicationRunner runner : runners) { if (!runner.isRunning()) { // This works because of the copy on write runners.remove(runner); } } } }