/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.component;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Sub-class of the standard {@link OpenGammaComponentServer} that works with the
* Advanced Installer service wrappers when installed on Windows.
*/
public class OpenGammaComponentService extends OpenGammaComponentServer {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(OpenGammaComponentService.class);
/** Logger. */
private static final Logger s_startupLogger = LoggerFactory.getLogger(ComponentManager.class);
/**
* Single instance.
*/
private static final OpenGammaComponentService INSTANCE = new OpenGammaComponentService();
/**
* Latch used when stopping.
*/
private final CountDownLatch _stopNotify = new CountDownLatch(1);
/**
* Latch used when stopping.
*/
private final CountDownLatch _stopConfirm = new CountDownLatch(1);
/**
* The component repository.
*/
private final AtomicReference<ComponentRepository> _repository = new AtomicReference<ComponentRepository>();
//-------------------------------------------------------------------------
/**
* Starts the service, blocking until the stop signal is received.
*
* @param args the command line arguments, the last element is the service name
*/
public static void main(final String[] args) { // CSIGNORE
s_logger.info("Starting service {}", args[args.length - 1]);
final String[] runArgs = new String[args.length - 1];
System.arraycopy(args, 0, runArgs, 0, runArgs.length);
try {
if (!INSTANCE.run(runArgs)) {
s_logger.error("One or more errors occurred starting the service");
System.exit(1);
//} else {
//System.exit(0);
}
} catch (Throwable e) {
s_logger.error("Couldn't start service", e);
System.exit(1);
}
}
/**
* Stops the service.
*/
public static void stop() {
s_logger.info("Stopping service");
INSTANCE.serverStopping();
s_logger.info("Service stopped");
// This is bad. Not everything currently responds nicely to the "stop" and non-daemon threads
// keep the process alive. Remove this hack when there are no more non-daemon threads that can
// outlive their components and prevent process termination when running as a service.
int aliveCount = 0, nonDaemon = 0;
for (Map.Entry<Thread, StackTraceElement[]> active : Thread.getAllStackTraces().entrySet()) {
final Thread t = active.getKey();
if (t.isAlive()) {
if (!t.isDaemon()) {
s_logger.debug("Thread {} still active", t);
for (StackTraceElement stack : active.getValue()) {
s_logger.debug("Stack: {}", stack);
}
nonDaemon++;
}
aliveCount++;
}
}
if (nonDaemon > 0) {
s_logger.error("{} non-daemon thread(s) (of {}) still active at shutdown, calling system.exit", nonDaemon, aliveCount);
System.exit(1);
} else {
s_logger.info("No non-daemon threads (of {}) active at shutdown", aliveCount);
}
}
//-------------------------------------------------------------------------
@Override
public boolean run(final String[] args) {
if (!super.run(args)) {
return false;
}
s_logger.info("Service started -- waiting for stop signal");
try {
_stopNotify.await();
s_logger.info("Service stopped");
_stopConfirm.countDown();
return true;
} catch (InterruptedException e) {
s_logger.warn("Service interrupted");
return false;
}
}
@Override
protected ComponentLogger createLogger(int verbosity) {
return new ComponentLogger.Slf4JLogger(s_startupLogger);
}
@Override
protected void serverStarting(final ComponentManager manager) {
s_logger.debug("Server starting - got component repository");
final ComponentRepository previous = _repository.getAndSet(manager.getRepository());
assert (previous == null);
}
protected void serverStopping() {
final ComponentRepository repository = _repository.getAndSet(null);
if (repository != null) {
s_logger.info("Stopping components");
try {
repository.stop();
} catch (Throwable e) {
s_logger.error("Couldn't stop components", e);
}
s_logger.debug("Releasing main thread");
_stopNotify.countDown();
s_logger.info("Waiting for confirmation signal");
try {
_stopConfirm.await();
} catch (InterruptedException e) {
s_logger.warn("Service interrupted");
System.exit(1);
}
} else {
s_logger.warn("Stop signal received before service startup completed");
System.exit(1);
}
}
}