/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.blur.concurrent; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.blur.log.Log; import org.apache.blur.log.LogFactory; public class BlurThreadPoolExecutor extends ThreadPoolExecutor { private static final Log LOG = LogFactory.getLog(BlurThreadPoolExecutor.class); private final List<ThreadBoundaryProcessor> _processorCollection = new ArrayList<ThreadBoundaryProcessor>(); public BlurThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public void add(ThreadBoundaryProcessor processor) { _processorCollection.add(processor); } public void remove(ThreadBoundaryProcessor processor) { _processorCollection.remove(processor); } public List<ThreadBoundaryProcessor> getPrePostCollection() { return _processorCollection; } @Override public void execute(Runnable command) { super.execute(wrapRunnable(command)); } @Override public Future<?> submit(Runnable task) { return super.submit(wrapRunnable(task)); } @Override public <T> Future<T> submit(Runnable task, T result) { return super.submit(wrapRunnable(task), result); } @Override public <T> Future<T> submit(Callable<T> task) { return super.submit(wrapCallable(task)); } private Runnable wrapRunnable(final Runnable runnable) { final Object[] vars = preprocessCallingThread(); return new Runnable() { @Override public void run() { Closeable[] closeables = preprocessNewThread(vars); try { runnable.run(); } finally { cleanup(closeables); } } }; } protected void cleanup(Closeable[] closeables) { for (Closeable closeable : closeables) { cleanup(closeable); } } private void cleanup(Closeable closeable) { try { closeable.close(); } catch (IOException e) { LOG.error("Error during quiet close of [" + closeable + "] [" + e.getMessage() + "]"); } } private Closeable[] preprocessNewThread(Object[] vars) { int size = _processorCollection.size(); Closeable[] closeables = new Closeable[size]; for (int i = 0; i < size; i++) { closeables[i] = _processorCollection.get(i).preprocessNewThread(vars[i]); } return closeables; } private Object[] preprocessCallingThread() { int size = _processorCollection.size(); Object[] vars = new Object[size]; for (int i = 0; i < size; i++) { vars[i] = _processorCollection.get(i).preprocessCallingThread(); } return vars; } private <T> Callable<T> wrapCallable(final Callable<T> callable) { final Object[] vars = preprocessCallingThread(); return new Callable<T>() { @Override public T call() throws Exception { Closeable[] closeables = preprocessNewThread(vars); try { return callable.call(); } finally { cleanup(closeables); } } }; } }