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