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     */
022    package org.granite.gravity;
023    
024    import java.util.ArrayList;
025    import java.util.List;
026    import java.util.concurrent.LinkedBlockingQueue;
027    import java.util.concurrent.RejectedExecutionException;
028    import java.util.concurrent.ThreadPoolExecutor;
029    import java.util.concurrent.TimeUnit;
030    
031    import org.granite.logging.Logger;
032    
033    /**
034     * @author Franck WOLFF
035     */
036    public 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    }