package osgi.executor.provider;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
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;
/**
* This bundle provides a java.util.concurrent.Executor service that can be
* configured and is shared between all bundles. It is registered as a private
* service that is then used between ExecutoreSubmitter services. This
* indirection is used so we can throttle bundles.
*/
@Component(immediate = true, provide = ExecutorImpl.class, designate = Configuration.class, name = "osgi.executor.provider", configurationPolicy = ConfigurationPolicy.optional)
public class ExecutorImpl {
ExecutorService es;
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
Logger 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) {
Configuration config = Configurable.createConfigurable(Configuration.class, properties);
int coreSize = config.coreSize();
int maxSize = config.maximumPoolSize();
long keepAlive = config.keepAliveTime();
int cores = Runtime.getRuntime().availableProcessors();
if (coreSize < 10 * cores)
coreSize = 30;
if (maxSize <= coreSize)
maxSize = coreSize * 4;
if (keepAlive < 10 || keepAlive > 1000)
keepAlive = 300;
es = new ThreadPoolExecutor(coreSize, maxSize, keepAlive, 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.warn("Shutting down while tasks %s are running", running);
}
/*
* Execute a runnable
*/
public void execute(Runnable command) {
es.submit(command);
}
/*
* Reference to the log
*/
@Reference
void setLogger(Logger log) {
this.log = log;
}
}