001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *   Granite Data Services is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2.1 of the License, or (at your option) any later version.
011 *
012 *   Granite Data Services is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 *   General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public
018 *   License along with this library; if not, write to the Free Software
019 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 *   USA, or see <http://www.gnu.org/licenses/>.
021 */
022package org.granite.gravity;
023
024import java.util.ArrayList;
025import java.util.List;
026import java.util.concurrent.LinkedBlockingQueue;
027import java.util.concurrent.RejectedExecutionException;
028import java.util.concurrent.ThreadPoolExecutor;
029import java.util.concurrent.TimeUnit;
030
031import org.granite.logging.Logger;
032
033/**
034 * @author Franck WOLFF
035 */
036public class GravityPool {
037
038    private static final Logger log = Logger.getLogger(GravityPool.class);
039
040    public static final int DEFAULT_CORE_POOL_SIZE = 5;
041    public static final int DEFAULT_MAXIMUM_POOL_SIZE = 20;
042    public static final long DEFAULT_KEEP_ALIVE_TIME = 10000L;
043    public static final int DEFAULT_QUEUE_CAPACITY = Integer.MAX_VALUE;
044
045    private final ThreadPoolExecutor pool;
046    private final int queueCapacity;
047
048    public GravityPool() {
049        this(DEFAULT_CORE_POOL_SIZE, DEFAULT_MAXIMUM_POOL_SIZE, DEFAULT_KEEP_ALIVE_TIME, DEFAULT_QUEUE_CAPACITY);
050    }
051
052    public GravityPool(GravityConfig config) {
053        this(config.getCorePoolSize(), config.getMaximumPoolSize(), config.getKeepAliveTimeMillis(), config.getQueueCapacity());
054    }
055
056    public GravityPool(int corePoolSize, int maximumPoolSize, long keepAliveTimeMillis, int queueCapacity) {
057        log.info(
058            "Starting Gravity Pool (corePoolSize=%d, maximumPoolSize=%d, keepAliveTimeMillis=%d, queueCapacity=%d)...",
059            corePoolSize, maximumPoolSize, keepAliveTimeMillis, queueCapacity
060        );
061
062        this.queueCapacity = queueCapacity;
063        this.pool = new ThreadPoolExecutor(
064            corePoolSize,
065            maximumPoolSize,
066            keepAliveTimeMillis,
067            TimeUnit.MILLISECONDS,
068            new LinkedBlockingQueue<Runnable>(queueCapacity),
069            new ThreadPoolExecutor.AbortPolicy()
070        );
071    }
072    
073    public int getQueueCapacity() {
074        return queueCapacity;
075    }
076    
077    public int getQueueRemainingCapacity() {
078        return pool.getQueue().remainingCapacity();
079    }
080    
081    public int getQueueSize() {
082        return pool.getQueue().size();
083    }
084
085    public int getCorePoolSize() {
086                return pool.getCorePoolSize();
087        }
088    public void setCorePoolSize(int corePoolSize) {
089        pool.setCorePoolSize(corePoolSize);
090    }
091
092        public int getMaximumPoolSize() {
093                return pool.getMaximumPoolSize();
094        }
095        public void setMaximumPoolSize(int maximumPoolSize) {
096                pool.setMaximumPoolSize(maximumPoolSize);
097        }
098
099        public long getKeepAliveTimeMillis() {
100                return pool.getKeepAliveTime(TimeUnit.MILLISECONDS);
101        }
102        public void setKeepAliveTimeMillis(long keepAliveTimeMillis) {
103                pool.setKeepAliveTime(keepAliveTimeMillis, TimeUnit.MILLISECONDS);
104        }
105        
106        public void reconfigure(GravityConfig config) {
107                pool.setCorePoolSize(config.getCorePoolSize());
108                pool.setKeepAliveTime(config.getKeepAliveTimeMillis(), TimeUnit.MILLISECONDS);
109                pool.setMaximumPoolSize(config.getMaximumPoolSize());
110        }
111
112        public void execute(AsyncChannelRunner runner) {
113                if (runner == null)
114                        throw new NullPointerException("runner cannot be null");
115
116                if (!pool.isShutdown()) {
117                        try {
118                                pool.execute(runner);
119                        }
120                        catch (RejectedExecutionException e) {
121                                runner.reset();
122                                throw e;
123                        }
124                }
125                else
126                        runner.reset();
127    }
128
129    public boolean contains(AsyncChannelRunner runner) {
130        return pool.getQueue().contains(runner);
131    }
132
133    public boolean remove(AsyncChannelRunner runner) {
134        if (pool.getQueue().remove(runner)) {
135                runner.reset();
136                return true;
137        }
138        return false;
139    }
140    
141    public void clear() {
142        List<Runnable> runnables = new ArrayList<Runnable>(pool.getQueue().size());
143        pool.getQueue().drainTo(runnables);
144        for (Runnable runnable : runnables)
145                ((AsyncChannelRunner)runnable).reset();
146    }
147
148    public boolean isShutdown() {
149        return pool.isShutdown();
150    }
151
152    public boolean isTerminated() {
153        return pool.isTerminated();
154    }
155
156    public void shutdown() {
157        log.info("Stopping Gravity Pool...");
158        pool.shutdown();
159    }
160    
161    public List<AsyncChannelRunner> shutdownNow() {
162        log.info("Stopping Gravity Pool Now...");
163        List<Runnable> runnables = pool.shutdownNow();
164        List<AsyncChannelRunner> runners = new ArrayList<AsyncChannelRunner>(runnables.size());
165        for (Runnable runnable : runnables) {
166                AsyncChannelRunner runner = (AsyncChannelRunner)runnable;
167                runner.reset();
168                runners.add(runner);
169        }
170        return runners;
171    }
172}