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