| /** |
| * |
| * Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com> |
| * |
| * ==================================================================== |
| * 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 org.jclouds.concurrent.config; |
| |
| import java.io.Closeable; |
| import java.io.IOException; |
| import java.util.List; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.LinkedBlockingQueue; |
| import java.util.concurrent.ThreadPoolExecutor; |
| import java.util.concurrent.TimeUnit; |
| |
| import javax.annotation.Resource; |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| |
| import org.jclouds.Constants; |
| import org.jclouds.lifecycle.Closer; |
| import org.jclouds.logging.Logger; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.util.concurrent.NamingThreadFactory; |
| import com.google.inject.AbstractModule; |
| import com.google.inject.Provides; |
| |
| /** |
| * Configures {@link ExecutorService}. |
| * |
| * Note that this uses threads |
| * |
| * @author Adrian Cole |
| */ |
| @ConfiguresExecutorService |
| public class ExecutorServiceModule extends AbstractModule { |
| |
| @VisibleForTesting |
| static final class ShutdownExecutorOnClose implements Closeable { |
| @Resource |
| protected Logger logger = Logger.NULL; |
| |
| private final ExecutorService service; |
| |
| private ShutdownExecutorOnClose(ExecutorService service) { |
| this.service = service; |
| } |
| |
| @Override |
| public void close() throws IOException { |
| List<Runnable> runnables = service.shutdownNow(); |
| if (runnables.size() > 0) |
| logger.warn("when shutting down executor %s, runnables outstanding: %s", service, |
| runnables); |
| } |
| } |
| |
| private final ExecutorService userExecutorFromConstructor; |
| private final ExecutorService ioExecutorFromConstructor; |
| |
| public ExecutorServiceModule( |
| @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, |
| @Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads) { |
| this.userExecutorFromConstructor = userThreads; |
| this.ioExecutorFromConstructor = ioThreads; |
| } |
| |
| public ExecutorServiceModule() { |
| this(null, null); |
| } |
| |
| @Override |
| protected void configure() { |
| } |
| |
| @Provides |
| @Singleton |
| @Named(Constants.PROPERTY_USER_THREADS) |
| ExecutorService provideExecutorService(@Named(Constants.PROPERTY_USER_THREADS) int count, |
| Closer closer) { |
| if (userExecutorFromConstructor != null) |
| return shutdownOnClose(userExecutorFromConstructor, closer); |
| return shutdownOnClose(newThreadPoolNamed("user thread %d", count), closer); |
| } |
| |
| @Provides |
| @Singleton |
| @Named(Constants.PROPERTY_IO_WORKER_THREADS) |
| ExecutorService provideIOExecutor(@Named(Constants.PROPERTY_IO_WORKER_THREADS) int count, |
| Closer closer) { |
| if (ioExecutorFromConstructor != null) |
| return shutdownOnClose(ioExecutorFromConstructor, closer); |
| return shutdownOnClose(newThreadPoolNamed("i/o thread %d", count), closer); |
| } |
| |
| @VisibleForTesting |
| static ExecutorService shutdownOnClose(final ExecutorService service, Closer closer) { |
| closer.addToClose(new ShutdownExecutorOnClose(service)); |
| return service; |
| } |
| |
| @VisibleForTesting |
| static ExecutorService newCachedThreadPoolNamed(String name) { |
| return Executors.newCachedThreadPool(new NamingThreadFactory(name)); |
| } |
| |
| @VisibleForTesting |
| static ExecutorService newThreadPoolNamed(String name, int count) { |
| return count == 0 ? newCachedThreadPoolNamed(name) : newFixedThreadPoolNamed(name, count); |
| } |
| |
| @VisibleForTesting |
| static ExecutorService newFixedThreadPoolNamed(String name, int maxCount) { |
| return new ThreadPoolExecutor(0, maxCount, 60L, TimeUnit.SECONDS, |
| new LinkedBlockingQueue<Runnable>(), new NamingThreadFactory(name)); |
| } |
| |
| } |