package osgi.enroute.executor.provider;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import osgi.enroute.logging.messages.api.Format;
import osgi.enroute.logging.messages.api.LogBook;
import aQute.bnd.annotation.component.Activate;
import aQute.bnd.annotation.component.Component;
import aQute.bnd.annotation.component.ConfigurationPolicy;
import aQute.bnd.annotation.component.Deactivate;
import aQute.bnd.annotation.component.Reference;
import aQute.bnd.annotation.metatype.Configurable;
import aQute.bnd.annotation.metatype.Meta.AD;
import aQute.bnd.annotation.metatype.Meta.OCD;
/**
* This bundle provides a java.util.concurrent.Executor service that can be
* configured and is shared between all bundles.
*
*/
@Component(designate = ExecutorImpl.Config.class, name = "osgi.enroute.executor.provider", configurationPolicy = ConfigurationPolicy.require)
public class ExecutorImpl implements Executor {
ExecutorService es;
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
/*
* Configuration parameters expected from the Config Admin
*/
@OCD(description = "Configuration for the enRoute::Executor")
interface Config {
@AD(description = "The minimum number of threads allocated to this pool", deflt = "20")
int coreSize();
@AD(description = "Maximum number of threads allocated to this pool", deflt = "0")
int maximumPoolSize();
@AD(description = "Nr of seconds an idle free thread should survive before being destroyed", deflt = "60")
long keepAliveTime();
}
/*
* Defines the log messages
*/
interface EnRouteExecutor extends LogBook {
@Format("Was shutdown while there were still tasks running: %s")
INFO shutdownWhileTasksRunning(List<Runnable> running);
}
EnRouteExecutor log;
/*
* Creates a new instance of the underlying implementation of the executor
* service (depending on the configuration parameters) if needed, or returns
* a pre-existing instance of this service, shared by all bundles.
*
* @param properties
* Configuration parameters, passed by the framework
*/
@Activate
void activate(Map<String,Object> properties) {
Config config = Configurable.createConfigurable(Config.class, properties);
es = new ThreadPoolExecutor( //
Math.max(config.coreSize(), 10), //
Math.max(Runtime.getRuntime().availableProcessors() * 2, config.maximumPoolSize()),//
Math.max(config.keepAliveTime(), 10), //
TimeUnit.SECONDS, //
queue, //
new ThreadPoolExecutor.CallerRunsPolicy());
}
/*
* Cancels the tasks submitted by the exiting bundle, shutting down the
* executor service if no more bundle is using it
*
*/
@Deactivate
void deactivate() {
List<Runnable> running = es.shutdownNow();
if (!running.isEmpty())
log.shutdownWhileTasksRunning(running);
}
/*
* Execute a runnable
*/
@Override
public void execute(Runnable command) {
es.submit(command);
}
/*
* Reference to the log
*/
@Reference
void setLogBook(LogBook log) {
this.log = log.scoped(EnRouteExecutor.class, null);
}
}