View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  
18  package org.apache.jdo.util;
19  
20  import java.util.Stack;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  /***
26  * A general purpose pooling class.
27  *
28  * @author Dave Bristor
29  */
30  public class Pool {
31      // Objects in the pool
32      private final Stack stack = new Stack();
33  
34      // Size of the pool
35      private final int size;
36  
37      // Number of elements release by Pool for client use
38      private int count = 0;
39      
40      /*** Number of millis to wait for a free entry
41       * Currently fixed; might be made configurable in future.
42       */
43      private int waitMillis = 1000;
44      
45      /*** Number of times to wait for a free entry
46       * Currently fixed; might be made configurable in future.
47       */
48      private int waitNumber = 5;
49  
50      /*** I18N */
51      private final static I18NHelper msg = I18NHelper.getInstance("org.apache.jdo.util.Bundle"); // NOI18N
52  
53      // For debugging TBD!!!
54      static final Log test = LogFactory.getFactory().getInstance(
55          "org.apache.jdo.util"); // NOI18N
56  
57      /***
58       * Constructs a pool that will limit the number of objects which it can
59       * contain.
60       * @param size The maximum number of items that can be put into the pool.
61       */
62      public Pool(int size) {
63          this.size = size;
64      }
65  
66      /***
67       * Puts the given object into the pool, if there the pool has fewer than
68       * the number of elements specifed when created.  If the pool is full,
69       * blocks until an element is removed. 
70       * @param o Object to be put in the pool.
71       * @throws InterruptedException
72       */
73      public synchronized void put(Object o) throws InterruptedException {
74         boolean debug = test.isDebugEnabled();
75          
76         if (debug) {
77             test.debug("Pool.put: " + o); // NOI18N
78         }
79         
80         if (count > size || count < 0) {
81             if (debug) {
82                 test.debug("Pool: count " + count + // NOI18N
83                              " out of range 0-" + size); // NOI18N
84             }
85             throw new RuntimeException(
86                 msg.msg(
87                     "EXC_CountOutOfRange", // NOI18N
88                     new Integer(count).toString(),
89                     new Integer(size).toString()));
90         }
91         
92         if (stack.contains(o)) {
93             if (debug) {
94                 test.debug("Pool: duplicate object"); // NOI18N
95             }
96             throw new RuntimeException(
97                 msg.msg(
98                     "EXC_DuplicateObject", o)); // NOI18N
99         }
100 
101        while (count == size) {
102            if (debug) {
103                test.debug("Pool.put: block"); // NOI18N
104            }
105            wait();
106        }
107        stack.push(o);
108        ++count;
109        notify();
110     }
111 
112     /***
113      * Gets an object from the pool, if one is available.  If an object is not
114      * available, waits until one is.  The waiting is governed by two
115      * variables, which are currently fixed: waitMillis and waitNumber.
116      * If no object is available from the pool within (waitNumber) times
117      * (waitMillis) milliseconds, then a RuntimeException is thrown.
118      * In future, the waitMillis and waitNumber should be configurable.
119      * @return An object from the pool.
120      */
121     public synchronized Object get() throws InterruptedException {
122         boolean debug = test.isDebugEnabled();
123         Object rc = null;
124 
125         if (count > size || count < 0) {
126             if (debug) {
127                 test.debug("Pool: count " + count + // NOI18N
128                            " out of range 0-" + size); // NOI18N
129             }
130             throw new RuntimeException(
131                 msg.msg(
132                     "EXC_CountOutOfRange", // NOI18N
133                     new Integer(count).toString(),
134                     new Integer(size).toString()));
135         }
136 
137         int timeouts = 0;
138         while (count == 0 && timeouts++ < waitNumber) {
139             if (debug) {
140                 test.debug("Pool.get: block " + timeouts); // NOI18N
141             }
142             wait(waitMillis);
143         }
144         if (timeouts >= waitNumber) {
145             throw new RuntimeException(
146                 msg.msg("EXC_PoolGetTimeout")); // NOI18N
147         }
148         rc = stack.pop();
149         --count;
150         notify();
151         if (debug) {
152             test.debug("Pool.get: " + rc); // NOI18N
153         }
154         return rc;
155     }
156 }