Coverage report

  %line %branch
org.apache.jcs.utils.threadpool.ThreadPoolManager$MyThreadFactory
100% 
100% 

 1  
 package org.apache.jcs.utils.threadpool;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.util.ArrayList;
 23  
 import java.util.HashMap;
 24  
 import java.util.Iterator;
 25  
 import java.util.Properties;
 26  
 import java.util.Set;
 27  
 
 28  
 import org.apache.commons.logging.Log;
 29  
 import org.apache.commons.logging.LogFactory;
 30  
 import org.apache.jcs.utils.props.PropertyLoader;
 31  
 import org.apache.jcs.utils.threadpool.behavior.IPoolConfiguration;
 32  
 
 33  
 import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
 34  
 import EDU.oswego.cs.dl.util.concurrent.Channel;
 35  
 import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
 36  
 import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
 37  
 import EDU.oswego.cs.dl.util.concurrent.ThreadFactory;
 38  
 
 39  
 /**
 40  
  * This manages threadpools for an application using Doug Lea's Util Concurrent
 41  
  * package.
 42  
  * http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
 43  
  * <p>
 44  
  * It is a singleton since threads need to be managed vm wide.
 45  
  * <p>
 46  
  * This manager forces you to use a bounded queue. By default it uses the
 47  
  * current thread for execuion when the buffer is full and no free threads can
 48  
  * be created.
 49  
  * <p>
 50  
  * You can specify the props file to use or pass in a properties object prior to
 51  
  * configuration. By default it looks for configuration information in
 52  
  * thread_pool.properties.
 53  
  * <p>
 54  
  * If set, the Properties object will take precedence.
 55  
  * <p>
 56  
  * If a value is not set for a particular pool, the hard coded defaults will be
 57  
  * used.
 58  
  *
 59  
  * <pre>
 60  
  * int boundarySize_DEFAULT = 2000;
 61  
  *
 62  
  * int maximumPoolSize_DEFAULT = 150;
 63  
  *
 64  
  * int minimumPoolSize_DEFAULT = 4;
 65  
  *
 66  
  * int keepAliveTime_DEFAULT = 1000 * 60 * 5;
 67  
  *
 68  
  * boolean abortWhenBlocked = false;
 69  
  *
 70  
  * String whenBlockedPolicy_DEFAULT = IPoolConfiguration.POLICY_RUN;
 71  
  *
 72  
  * int startUpSize_DEFAULT = 4;
 73  
  * </pre>
 74  
  *
 75  
  * You can configure default settings by specifying a default pool in the
 76  
  * properties, ie "cache.ccf"
 77  
  * <p>
 78  
  * @author Aaron Smuts
 79  
  */
 80  
 public class ThreadPoolManager
 81  
 {
 82  
     private static final Log log = LogFactory.getLog( ThreadPoolManager.class );
 83  
 
 84  
     // DEFAULT SETTINGS, these are not final since they can be set
 85  
     // via the Propeties file or object
 86  
     private static boolean useBoundary_DEFAULT = true;
 87  
 
 88  
     private static int boundarySize_DEFAULT = 2000;
 89  
 
 90  
     private static int maximumPoolSize_DEFAULT = 150;
 91  
 
 92  
     private static int minimumPoolSize_DEFAULT = 4;
 93  
 
 94  
     private static int keepAliveTime_DEFAULT = 1000 * 60 * 5;
 95  
 
 96  
     private static String whenBlockedPolicy_DEFAULT = IPoolConfiguration.POLICY_RUN;
 97  
 
 98  
     private static int startUpSize_DEFAULT = 4;
 99  
 
 100  
     private static PoolConfiguration defaultConfig;
 101  
 
 102  
     // This is the default value. Setting this after
 103  
     // inialization will have no effect
 104  
     private static String propsFileName = "cache.ccf";
 105  
 
 106  
     // the root property name
 107  
     private static String PROP_NAME_ROOT = "thread_pool";
 108  
 
 109  
     private static String DEFAULT_PROP_NAME_ROOT = "thread_pool.default";
 110  
 
 111  
     // You can specify the properties to be used to configure
 112  
     // the thread pool. Setting this post initialization will have
 113  
     // no effect.
 114  
     private static Properties props = null;
 115  
 
 116  
     private static HashMap pools = new HashMap();
 117  
 
 118  
     // singleton instance
 119  
     private static ThreadPoolManager INSTANCE = null;
 120  
 
 121  
     /**
 122  
      * No instances please. This is a singleton.
 123  
      */
 124  
     private ThreadPoolManager()
 125  
     {
 126  
         configure();
 127  
     }
 128  
 
 129  
     /**
 130  
      * Creates a pool based on the configuration info.
 131  
      * <p>
 132  
      * @param config
 133  
      * @return A ThreadPoll wrapper
 134  
      */
 135  
     private ThreadPool createPool( PoolConfiguration config )
 136  
     {
 137  
         PooledExecutor pool = null;
 138  
         Channel queue = null;
 139  
         if ( config.isUseBoundary() )
 140  
         {
 141  
             if ( log.isDebugEnabled() )
 142  
             {
 143  
                 log.debug( "Creating a Bounded Buffer to use for the pool" );
 144  
             }
 145  
             queue = new BoundedBuffer( config.getBoundarySize() );
 146  
             pool = new PooledExecutor( queue, config.getMaximumPoolSize() );
 147  
             pool.setThreadFactory( new MyThreadFactory() );
 148  
         }
 149  
         else
 150  
         {
 151  
             if ( log.isDebugEnabled() )
 152  
             {
 153  
                 log.debug( "Creating a non bounded Linked Queue to use for the pool" );
 154  
             }
 155  
             queue = new LinkedQueue();
 156  
             pool = new PooledExecutor( queue, config.getMaximumPoolSize() );
 157  
         }
 158  
 
 159  
         pool.setMinimumPoolSize( config.getMinimumPoolSize() );
 160  
         pool.setKeepAliveTime( config.getKeepAliveTime() );
 161  
 
 162  
         // when blocked policy
 163  
         if ( config.getWhenBlockedPolicy().equals( IPoolConfiguration.POLICY_ABORT ) )
 164  
         {
 165  
             pool.abortWhenBlocked();
 166  
         }
 167  
         else if ( config.getWhenBlockedPolicy().equals( IPoolConfiguration.POLICY_RUN ) )
 168  
         {
 169  
             pool.runWhenBlocked();
 170  
         }
 171  
         else if ( config.getWhenBlockedPolicy().equals( IPoolConfiguration.POLICY_WAIT ) )
 172  
         {
 173  
             pool.waitWhenBlocked();
 174  
         }
 175  
         else if ( config.getWhenBlockedPolicy().equals( IPoolConfiguration.POLICY_ABORT ) )
 176  
         {
 177  
             pool.abortWhenBlocked();
 178  
         }
 179  
         else if ( config.getWhenBlockedPolicy().equals( IPoolConfiguration.POLICY_DISCARDOLDEST ) )
 180  
         {
 181  
             pool.discardOldestWhenBlocked();
 182  
         }
 183  
 
 184  
         pool.createThreads( config.getStartUpSize() );
 185  
 
 186  
         return new ThreadPool( pool, queue );
 187  
     }
 188  
 
 189  
     /**
 190  
      * Returns a configured instance of the ThreadPoolManger To specify a
 191  
      * configuation file or Properties object to use call the appropriate setter
 192  
      * prior to calling getInstance.
 193  
      * <p>
 194  
      * @return The single instance of the ThreadPoolManager
 195  
      */
 196  
     public static synchronized ThreadPoolManager getInstance()
 197  
     {
 198  
         if ( INSTANCE == null )
 199  
         {
 200  
             INSTANCE = new ThreadPoolManager();
 201  
         }
 202  
         return INSTANCE;
 203  
     }
 204  
 
 205  
     /**
 206  
      * Returns a pool by name. If a pool by this name does not exist in the
 207  
      * configuration file or properties, one will be created using the default
 208  
      * values.
 209  
      * <p>
 210  
      * Pools are lazily created.
 211  
      * <p>
 212  
      * @param name
 213  
      * @return The thread pool configured for the name.
 214  
      */
 215  
     public ThreadPool getPool( String name )
 216  
     {
 217  
         ThreadPool pool = null;
 218  
 
 219  
         synchronized ( pools )
 220  
         {
 221  
             pool = (ThreadPool) pools.get( name );
 222  
             if ( pool == null )
 223  
             {
 224  
                 if ( log.isDebugEnabled() )
 225  
                 {
 226  
                     log.debug( "Creating pool for name [" + name + "]" );
 227  
                 }
 228  
                 PoolConfiguration config = this.loadConfig( PROP_NAME_ROOT + "." + name );
 229  
                 pool = createPool( config );
 230  
 
 231  
                 if ( pool != null )
 232  
                 {
 233  
                     pools.put( name, pool );
 234  
                 }
 235  
 
 236  
                 if ( log.isDebugEnabled() )
 237  
                 {
 238  
                     log.debug( "PoolName = " + getPoolNames() );
 239  
                 }
 240  
             }
 241  
         }
 242  
 
 243  
         return pool;
 244  
     }
 245  
 
 246  
     /**
 247  
      * Returns the names of all configured pools.
 248  
      * <p>
 249  
      * @return ArrayList of string names
 250  
      */
 251  
     public ArrayList getPoolNames()
 252  
     {
 253  
         ArrayList poolNames = new ArrayList();
 254  
         synchronized ( pools )
 255  
         {
 256  
             Set names = pools.keySet();
 257  
             Iterator it = names.iterator();
 258  
             while ( it.hasNext() )
 259  
             {
 260  
                 poolNames.add( it.next() );
 261  
             }
 262  
         }
 263  
         return poolNames;
 264  
     }
 265  
 
 266  
     /**
 267  
      * Setting this post initialization will have no effect.
 268  
      * <p>
 269  
      * @param propsFileName
 270  
      *            The propsFileName to set.
 271  
      */
 272  
     public static void setPropsFileName( String propsFileName )
 273  
     {
 274  
         ThreadPoolManager.propsFileName = propsFileName;
 275  
     }
 276  
 
 277  
     /**
 278  
      * Returns the name of the properties file that we used to initialize the
 279  
      * pools. If the value was set post-initialization, then it may not be the
 280  
      * file used.
 281  
      * <p>
 282  
      * @return Returns the propsFileName.
 283  
      */
 284  
     public static String getPropsFileName()
 285  
     {
 286  
         return propsFileName;
 287  
     }
 288  
 
 289  
     /**
 290  
      * This will be used if it is not null on initialzation. Setting this post
 291  
      * initialization will have no effect.
 292  
      * <p>
 293  
      * @param props
 294  
      *            The props to set.
 295  
      */
 296  
     public static void setProps( Properties props )
 297  
     {
 298  
         ThreadPoolManager.props = props;
 299  
     }
 300  
 
 301  
     /**
 302  
      * @return Returns the props.
 303  
      */
 304  
     public static Properties getProps()
 305  
     {
 306  
         return props;
 307  
     }
 308  
 
 309  
     /**
 310  
      * Intialize the ThreadPoolManager and create all the pools defined in the
 311  
      * configuration.
 312  
      */
 313  
     protected void configure()
 314  
     {
 315  
         if ( log.isDebugEnabled() )
 316  
         {
 317  
             log.debug( "Initializing ThreadPoolManager" );
 318  
         }
 319  
 
 320  
         if ( props == null )
 321  
         {
 322  
             try
 323  
             {
 324  
                 props = PropertyLoader.loadProperties( propsFileName );
 325  
 
 326  
                 if ( log.isDebugEnabled() )
 327  
                 {
 328  
                     log.debug( "File contained " + props.size() + " properties" );
 329  
                 }
 330  
             }
 331  
             catch ( Exception e )
 332  
             {
 333  
                 log.error( "Problem loading properties. propsFileName [" + propsFileName + "]", e );
 334  
             }
 335  
         }
 336  
 
 337  
         if ( props == null )
 338  
         {
 339  
             log.warn( "No configuration settings found.  Using hardcoded default values for all pools." );
 340  
             props = new Properties();
 341  
         }
 342  
 
 343  
         // set intial default and then override if new
 344  
         // settings are available
 345  
         defaultConfig = new PoolConfiguration( useBoundary_DEFAULT, boundarySize_DEFAULT, maximumPoolSize_DEFAULT,
 346  
                                                minimumPoolSize_DEFAULT, keepAliveTime_DEFAULT,
 347  
                                                whenBlockedPolicy_DEFAULT, startUpSize_DEFAULT );
 348  
 
 349  
         defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT );
 350  
     }
 351  
 
 352  
     /**
 353  
      * Configures the default PoolConfiguration settings.
 354  
      * <p>
 355  
      * @param root
 356  
      * @return PoolConfiguration
 357  
      */
 358  
     protected PoolConfiguration loadConfig( String root )
 359  
     {
 360  
         PoolConfiguration config = (PoolConfiguration) defaultConfig.clone();
 361  
 
 362  
         if ( props.containsKey( root + ".useBoundary" ) )
 363  
         {
 364  
             try
 365  
             {
 366  
                 config.setUseBoundary( Boolean.valueOf( (String) props.get( root + ".useBoundary" ) ).booleanValue() );
 367  
             }
 368  
             catch ( NumberFormatException nfe )
 369  
             {
 370  
                 log.error( "useBoundary not a boolean.", nfe );
 371  
             }
 372  
         }
 373  
 
 374  
         // load default if they exist
 375  
         if ( props.containsKey( root + ".boundarySize" ) )
 376  
         {
 377  
             try
 378  
             {
 379  
                 config.setBoundarySize( Integer.parseInt( (String) props.get( root + ".boundarySize" ) ) );
 380  
             }
 381  
             catch ( NumberFormatException nfe )
 382  
             {
 383  
                 log.error( "boundarySize not a number.", nfe );
 384  
             }
 385  
         }
 386  
 
 387  
         // maximum pool size
 388  
         if ( props.containsKey( root + ".maximumPoolSize" ) )
 389  
         {
 390  
             try
 391  
             {
 392  
                 config.setMaximumPoolSize( Integer.parseInt( (String) props.get( root + ".maximumPoolSize" ) ) );
 393  
             }
 394  
             catch ( NumberFormatException nfe )
 395  
             {
 396  
                 log.error( "maximumPoolSize not a number.", nfe );
 397  
             }
 398  
         }
 399  
 
 400  
         // minimum pool size
 401  
         if ( props.containsKey( root + ".minimumPoolSize" ) )
 402  
         {
 403  
             try
 404  
             {
 405  
                 config.setMinimumPoolSize( Integer.parseInt( (String) props.get( root + ".minimumPoolSize" ) ) );
 406  
             }
 407  
             catch ( NumberFormatException nfe )
 408  
             {
 409  
                 log.error( "minimumPoolSize not a number.", nfe );
 410  
             }
 411  
         }
 412  
 
 413  
         // keep alive
 414  
         if ( props.containsKey( root + ".keepAliveTime" ) )
 415  
         {
 416  
             try
 417  
             {
 418  
                 config.setKeepAliveTime( Integer.parseInt( (String) props.get( root + ".keepAliveTime" ) ) );
 419  
             }
 420  
             catch ( NumberFormatException nfe )
 421  
             {
 422  
                 log.error( "keepAliveTime not a number.", nfe );
 423  
             }
 424  
         }
 425  
 
 426  
         // when blocked
 427  
         if ( props.containsKey( root + ".whenBlockedPolicy" ) )
 428  
         {
 429  
             config.setWhenBlockedPolicy( (String) props.get( root + ".whenBlockedPolicy" ) );
 430  
         }
 431  
 
 432  
         // startupsize
 433  
         if ( props.containsKey( root + ".startUpSize" ) )
 434  
         {
 435  
             try
 436  
             {
 437  
                 config.setStartUpSize( Integer.parseInt( (String) props.get( root + ".startUpSize" ) ) );
 438  
             }
 439  
             catch ( NumberFormatException nfe )
 440  
             {
 441  
                 log.error( "startUpSize not a number.", nfe );
 442  
             }
 443  
         }
 444  
 
 445  
         if ( log.isInfoEnabled() )
 446  
         {
 447  
             log.info( root + " PoolConfiguration = " + config );
 448  
         }
 449  
 
 450  
         return config;
 451  
     }
 452  
 
 453  
     /**
 454  
      * Allows us to set the daemon status on the threads.
 455  
      * <p>
 456  
      * @author aaronsm
 457  
      */
 458  64
     class MyThreadFactory
 459  
         implements ThreadFactory
 460  
     {
 461  
         /*
 462  
          * (non-Javadoc)
 463  
          *
 464  
          * @see EDU.oswego.cs.dl.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
 465  
          */
 466  
         public Thread newThread( Runnable runner )
 467  
         {
 468  272
             Thread t = new Thread( runner );
 469  272
             t.setDaemon( true );
 470  272
             return t;
 471  
         }
 472  
     }
 473  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.