001 /*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016 package org.opengion.fukurou.util;
017
018 import java.util.MissingResourceException;
019 import java.util.Map;
020 import java.util.HashMap;
021 // import java.util.Date;
022 import java.util.List;
023 import java.util.ArrayList;
024 import java.util.Iterator;
025 // import java.util.Locale ;
026
027 // import java.text.DateFormat;
028 // import java.text.SimpleDateFormat;
029
030 /**
031 * AbstractObjectPool は、生成された Object をã?ールするキャãƒ?‚·ュクラスですã?
032 * サブクラスで、各クラスごとにオブジェクトを生æ??�å?期化?�終äº?�™るよã�?�«å�?ƒ¡ソãƒ?ƒ‰ã‚?
033 * コーãƒ?‚£ングしなおしてくださいã€?
034 * サブクラスでは、Object createInstance() と、oid objectInitial( Object obj )ã€?
035 * void objectFinal( Object obj ) ã‚?オーバã?ライドしてくださいã€?
036 *
037 * @version 4.0
038 * @author Kazuhiko Hasegawa
039 * @since JDK5.0,
040 */
041 abstract public class AbstractObjectPool<E> {
042 /** å†?ƒ¨でオブジェクトをプã?ルしてã�?‚‹配å?ã€? */
043 private List<E> pool = null; // プã?ルしてã�?‚‹オブジェクãƒ?
044 private Map<Integer,TimeStampObject> poolBack = null; // 作æ?したオブジェクトã?タイãƒ?‚¹タンプ管ç�?
045
046 /** プã?ル自体を拡張可能かどã�?�‹を決める変数。拡張制é™?true)?�無制é™?false) */
047 private boolean limit ;
048
049 /** æœ?¤§オブジェクト数 */
050 private int maxsize ;
051
052 /** 生æ?したオブジェクトã?寿命(ç§?を指定しますã? 0 は、制限なしですã?*/
053 private int limitTime ; // 3.5.4.3 (2004/01/05) キャãƒ?‚·ュの寿命を指定しますã?
054
055 /** 制限なしã?場合でもã?実質こã?値以上ã?キャãƒ?‚·ュは、許可しませんã€?/
056 private static final int MAX_LIMIT_COUNT = 1000 ; // 3.6.0.8 (2004/11/19)
057
058 /**
059 * 初期化メソãƒ?ƒ‰
060 *
061 * 初期オブジェクト数、最大オブジェクト数、拡張制限をæŒ?®šしますã?
062 *
063 * 初期オブジェクト数は、ã?ールを作æ?すると同時に確保するオブジェクトã?個数ですã?
064 * オブジェクトã?生æ?に時間がかかり、かつ、å¿?�šè¤?•°使用するのであれば,
065 * 予めè¤?•°確保しておけば、パフォーマンスが向上しますã?
066 * æœ?¤§オブジェクト数は、拡張制限が、無制é™?limit = false )の場合ã?ã€?
067 * 無視されますã?制限ありã?場合ã?、この値を上限に、オブジェクトを増やしますã?
068 * 拡張制限ã?、生成するオブジェクト数に制限をかけるかどã�?�‹を指定しますã?
069 * ä¸?ˆ¬に、コネクション等ã?リソースを確保するå?合ã?、拡張制限をåŠ?�ˆてã€?
070 * 生æ?するオブジェクト数を制限しますã?
071 *
072 * @param minsize 初期オブジェクト数
073 * @param maxsize æœ?¤§オブジェクト数
074 * @param limit 拡張制é™?true)?�無制é™?false)
075 */
076 protected synchronized void init( final int minsize, final int maxsize, final boolean limit ) {
077 init( minsize, maxsize, limit,0 ) ;
078 }
079
080 /**
081 * 初期化メソãƒ?ƒ‰
082 *
083 * 初期オブジェクト数、å?期é?列数、拡張制限ã?オブジェクトã?寿命を指定しますã?
084 *
085 * 初期オブジェクト数、å?期é?列数、拡張制限ã?までは、{@link #init( int , int , boolean ) init}
086 * を参照してくださいã€?
087 * オブジェクトã?寿命は、生成された時間からの経過時間(ç§?ã�?�‘、キャãƒ?‚·ュしておく
088 * 場合に使用しますã?
089 * 例えば、コネクション等でã€?•·期間のプã?リングがリソースを圧迫する場合やã€?
090 * 接続å?自身がã?タイマã?でåˆ?–する場合など、オブジェクトã?生存期間を
091 * æŒ?®šして管ç�?�™るå¿?¦�がありますã?
092 *
093 * @param minsize 初期オブジェクト数
094 * @param maxsize 初期配å?数
095 * @param limit 拡張制é™?true)?�無制é™?false)
096 * @param limitTime オブジェクトã?寿命の時間制限å?(ç§?
097 * @see #init( int , int , boolean )
098 */
099 protected synchronized void init( final int minsize, final int maxsize,
100 final boolean limit,final int limitTime ) {
101 pool = new ArrayList<E>( maxsize );
102 poolBack = new HashMap<Integer,TimeStampObject>();
103 this.maxsize = maxsize;
104 this.limit = limit;
105 this.limitTime = limitTime;
106 for( int i=0; i<minsize; i++ ) {
107 E obj = createInstance();
108 pool.add( obj );
109
110 Integer key = Integer.valueOf( obj.hashCode() );
111 poolBack.put( key,new TimeStampObject( obj,limitTime ) );
112 }
113 }
114
115 /**
116 * キャãƒ?‚·ュのインスタンスを返しますã?
117 *
118 * なおã?拡張制限をしてã�?‚‹場合に、最初に確保した数以上ã?オブジェクト生成ã?
119 * 要求があったå?合ã??¤ MissingResourceException ã�?throw されますã?
120 * まã�?オブジェクトが寿命をè¶?�ˆてã�?‚‹場合ã?、削除した後ã?新たに次の
121 * オブジェクトã?生æ?を行いますã?
122 *
123 * @og.rev 4.0.0.1 (2007/12/03) 生æ?リミットチェãƒ?‚¯を厳å¯?�«行うã€?
124 * @og.rev 4.0.0.1 (2007/12/03) 生æ?リミットエラー時に、タイãƒ?‚¢ウトをチェãƒ?‚¯するã€?
125 *
126 * @return キャãƒ?‚·ュのインスタンス
127 * @throws MissingResourceException 拡張制限により、新しいインスタンスを生成できなã�??å�?
128 */
129 public synchronized E newInstance() throws MissingResourceException {
130 final E rtnobj ;
131 if( pool.isEmpty() ) {
132 if( limit && poolBack.size() >= maxsize ) {
133 String errMsg = "生æ?リミットいっぱã�?�§新たに生æ?できませんã€?"
134 + poolBack.size() + "]";
135
136 // 4.0.0.1 (2007/12/03) 生æ?リミットエラー時に、タイãƒ?‚¢ウトをチェãƒ?‚¯するã€?
137 Iterator<TimeStampObject> itr = poolBack.values().iterator();
138 while( itr.hasNext() ) {
139 TimeStampObject tso = itr.next();
140 if( tso == null || tso.isTimeOver() ) {
141 itr.remove();
142 }
143 }
144
145 throw new MissingResourceException( errMsg,getClass().getName(),"limit" );
146 }
147 else if( poolBack.size() > MAX_LIMIT_COUNT ) {
148 clear(); // 全件キャãƒ?‚·ュをç?æ£?�—ますã?
149 String errMsg = "ObjectPool で、メモリリークの可能性がありますã?["
150 + poolBack.size() + "]";
151 throw new RuntimeException( errMsg );
152 }
153 // 新規作æ?
154 rtnobj = createInstance();
155 Integer key = Integer.valueOf( rtnobj.hashCode() );
156 poolBack.put( key,new TimeStampObject( rtnobj,limitTime ) );
157 }
158 else {
159 // 既存取りå?ã�?
160 rtnobj = pool.remove(0);
161 if( rtnobj != null ) {
162 Integer key = Integer.valueOf( rtnobj.hashCode() );
163 TimeStampObject tso = poolBack.get( key );
164 if( tso == null || tso.isTimeOver() ) {
165 remove( rtnobj );
166 return newInstance();
167 }
168 }
169 else {
170 // 通常ありえなã�??
171 String errMsg = "オブジェクトã?取得に失敗しましたã€? ;
172 throw new MissingResourceException( errMsg,getClass().getName(),"pool" );
173 }
174 }
175
176 return rtnobj;
177 }
178
179 /**
180 * 具体的に新しいインスタンスを生成するメソãƒ?ƒ‰ã€?
181 *
182 * サブクラスで具体的に記述するå¿?¦�がありますã?
183 *
184 * @return 新しいインスタンス
185 */
186 abstract protected E createInstance();
187
188 /**
189 * オブジェクトを、オブジェクトã?ールに戻しますã?
190 * 戻すべきオブジェクトが null の場合ã?,削除されたと判断しますã?
191 * <del>よって、生成されたオブジェクトã?総数もã?ひとつ減らしますã?</del>
192 *
193 * @param obj オブジェクトã?ールに戻すオブジェクãƒ?
194 */
195 public synchronized void release( final E obj ) {
196 E obj2 = objectInitial( obj );
197 if( obj2 != null ) {
198 Integer key = Integer.valueOf( obj2.hashCode() );
199 TimeStampObject tso = poolBack.get( key );
200 if( tso != null ) {
201 pool.add( obj2 );
202 }
203 else { // 3.5.6.2 (2004/07/05) 追åŠ?
204 LogWriter.log( "ObjectPool で、メモリリークの可能性があるã?[" + obj2 + "]" );
205 remove( obj2 );
206 }
207 }
208 }
209
210 /**
211 * オブジェクトを、オブジェクトã?ールから削除しますã?
212 * remove されるオブジェクトã?、すでにキャãƒ?‚·ュから取り出された後なのでã€?
213 * そã?まま、何もしなければ自然消æ»?GC)されますã?
214 * 自然消æ»?�™る前に、objectFinal( Object ) が呼ばれますã?
215 * 生æ?されたオブジェクトã?総数もã?ひとつ減らしますã?
216 *
217 * @param obj 削除するオブジェクãƒ?
218 */
219 public synchronized void remove( final E obj ) {
220 if( obj != null ) {
221 Integer key = Integer.valueOf( obj.hashCode() );
222 poolBack.remove( key );
223 }
224
225 objectFinal( obj );
226 }
227
228 /**
229 * オブジェクトã?ールの要ç´?•°を返しますã?
230 *
231 * @return プã?ルの要ç´?•°
232 */
233 public synchronized int size() {
234 return poolBack.size();
235 }
236
237 /**
238 * オブジェクトã?ールが要ç´?‚’持たなã�?�‹どã�?�‹を判定しますã?
239 *
240 * @return オブジェクトã?ールが要ç´?‚’持ってã�?�ªã�??つまりそのサイズã�?0 の場合にã�?�‘ true、そã�?�§なã�??合ã? false
241 */
242 public synchronized boolean isEmpty() {
243 return poolBack.isEmpty() ;
244 }
245
246 /**
247 * すべての要ç´?‚’ オブジェクトã?ールから削除しますã?
248 * 貸しå?し中のオブジェクトã?、クリアしません。よって、返り値はã€?
249 * すべてのオブジェクトをクリアできた場合ã?、true 、貸しå?し中の
250 * オブジェクトが存在した場å�?クリアできなかったå?å�?は、false ですã?
251 *
252 * @return すべてクリア(true)/貸しå?し中のオブジェクトが残ってã�?‚‹(false)
253 */
254 public synchronized boolean clear() {
255 Iterator<E> itr = pool.iterator();
256 while( itr.hasNext() ) {
257 remove( itr.next() );
258 }
259 pool.clear();
260
261 // 貸しå?し中の場合ã?、remove 出来なã�?‚º、poolBack に残ってã�?‚‹ã€?
262 // それでもã?poolBack をクリアすることで、release 返却時にもã?
263 // remove されるよã�?�«なりますã?
264 // ただしã?作æ?オブジェクト数がã?ä¸?—¦ 0 にリセãƒ?ƒˆされる為ã€?
265 // æœ?¤§貸しå?し可能数がã?ä¸?™‚çš?�«増えてしまã�?�¾すã?
266 boolean flag = poolBack.isEmpty();
267 poolBack.clear();
268
269 return flag;
270 }
271
272 /**
273 * オブジェクトã?ールから削除するときに呼ばれますã?
274 * こã?メソãƒ?ƒ‰でå�?‚ªブジェクトごとの終äº??ç�?‚’行いますã?
275 * 例えば?¤ãƒ??タベã?スコネクションであれば?¤close() 処ç�?�ªどですã?
276 *
277 * ãƒ?ƒ•ォルトでは、なにも行いませんã€?
278 *
279 * @param obj 終äº??ç�?‚’行うオブジェクãƒ?
280 */
281 protected synchronized void objectFinal( final E obj ) {
282 // ここでは処ç�?‚’行いませんã€?
283 }
284
285 /**
286 * オブジェクトã?ールに戻すとã�?release するとã�?に呼ばれますã?
287 * こã?メソãƒ?ƒ‰でå�?‚ªブジェクトごとの初期処ç�?‚’行いますã?
288 * オブジェクトã?ールに戻すときには?¤初期化して?¤次の貸しå?しに
289 * 対応できるように、å?期å?ç�?�—ておくå¿?¦�がありますã?
290 *
291 * ãƒ?ƒ•ォルトでは、引数のオブジェクトをそã?まま返しますã?
292 *
293 * @param obj 初期処ç�?‚’行うオブジェクãƒ?
294 *
295 * @return 初期処ç�?‚’行ったオブジェクãƒ?
296 */
297 protected synchronized E objectInitial( final E obj ) {
298 return obj;
299 }
300
301 /**
302 * å†?ƒ¨状況を簡易的に表現したæ–?—å?を返しますã?
303 *
304 * @return こã?オブジェクトã?ールのæ–?—å?表現
305 */
306 @Override
307 public synchronized String toString() {
308 StringBuilder buf = new StringBuilder();
309 buf.append( " freeCount = [" ).append( pool.size() ).append( "]\n" );
310 buf.append( " createCount = [" ).append( poolBack.size() ).append( "]" );
311 buf.append( " ( max=[" ).append( maxsize ).append( "] )\n" );
312 buf.append( " limiter = [" ).append( limit ).append( "]\n" );
313 buf.append( " limitTime = [" ).append( limitTime ).append( "](s)\n" );
314
315 Iterator<E> itr = pool.iterator();
316 buf.append( "Free Objects \n" );
317 while( itr.hasNext() ) {
318 E obj = itr.next();
319 if( obj != null ) {
320 Integer key = Integer.valueOf( obj.hashCode() );
321 buf.append( " " );
322 buf.append( poolBack.get( key ) );
323 buf.append( " " ).append( obj );
324 buf.append( "\n" );
325 }
326 }
327 return buf.toString();
328 }
329 }
330
331 /**
332 * TimeStampObject は、生成された Object をã?生æ?時刻とともに管ç�?�™るクラスですã?
333 * å†?ƒ¨のハッシュキーは、登録するオブジェクトと同ä¸?�§、管ç�?�§きるのは、異なるオブジェクãƒ?
334 * のみですã?
335 *
336 * @version 4.0
337 * @author Kazuhiko Hasegawa
338 * @since JDK5.0,
339 */
340 class TimeStampObject implements Comparable<TimeStampObject> { // 4.3.3.6 (2008/11/15) Generics警告対å¿?
341 private final long timeStamp ;
342 private final long limitTime ;
343 private final int hcode ;
344
345 /**
346 * コンストラクターã€?
347 *
348 * @param obj 管ç�?�™るオブジェクãƒ?
349 * @param limit オブジェクトã?寿命(ç§?
350 * @throws IllegalArgumentException
351 */
352 public TimeStampObject( final Object obj,final int limit ) {
353 if( obj == null ) {
354 String errMsg = "TimeStampObject のインスタンスに、NULL はセãƒ?ƒˆできませんã€? ;
355 throw new IllegalArgumentException( errMsg );
356 }
357
358 timeStamp = System.currentTimeMillis();
359 if( limit > 0 ) {
360 limitTime = timeStamp + limit * 1000L ;
361 }
362 else {
363 limitTime = Long.MAX_VALUE ;
364 }
365
366 hcode = (int)((timeStamp)&(Integer.MAX_VALUE))^(obj.hashCode()) ;
367 }
368
369 /**
370 * å†?ƒ¨管ç�?�—てã�?‚‹オブジェクトã?生æ?時刻を返しますã?
371 *
372 * @return 生æ?時刻(ms)
373 */
374 public long getTimeStamp() {
375 return timeStamp;
376 }
377
378 /**
379 * オブジェクトã?寿命がきたかどã�?�‹を返しますã?
380 *
381 * @return 寿命判å®?true:寿命/false:まã�?½¿える)
382 */
383 public boolean isTimeOver() {
384 return (System.currentTimeMillis() > limitTime );
385 }
386
387 /**
388 * オブジェクトが同じかどã�?�‹を判定しますã?
389 *
390 * å†?ƒ¨オブジェクトã? equals() メソãƒ?ƒ‰と、作æ?時刻の両方を判断しますã?
391 * å†?ƒ¨オブジェクトã? equals() が同じでもã?作æ?時刻が異なるとã€?
392 * false を返しますã?これは、å?く同ä¸?‚ªブジェクトを管ç�?�™るå?合でもã?
393 * タイãƒ?‚¹タンプを差し替える事で、異なるオブジェクトとして
394 * 認識させるとã�?�†ことですã?
395 *
396 * @param obj Object
397 *
398 * @return true:同じ/false:異なるã?
399 */
400 public boolean equals( final Object obj ) {
401 if( obj instanceof TimeStampObject ) {
402 TimeStampObject other = (TimeStampObject)obj ;
403 return ( hcode == other.hcode ) && ( timeStamp == other.timeStamp ) ;
404 }
405 return false ;
406 }
407
408 /**
409 * ハッシュコードを返しますã?
410 *
411 * ここで返すのは、è?åˆ??身のハッシュコードではなくã?
412 * å†?ƒ¨管ç�??オブジェクトã?ハッシュコードですã?
413 *
414 * hashcode = (int)((timeStamp)&(Integer.MAX_VALUE))^(obj.hashCode())
415 *
416 * こã?計算式ã?、変更される可能性がありますã?
417 *
418 * @return å†?ƒ¨管ç�??オブジェクトã?ハッシュコーãƒ?
419 */
420 public int hashCode() { return hcode; }
421
422 /**
423 * こã?オブジェクトとæŒ?®šされたオブジェクトã?é ?º�を比è¼?�—ますã?
424 *
425 * こã?オブジェクトがæŒ?®šされたオブジェクトより小さã�??合ã?è²??整数ã€?
426 * 等しã�??合ã?ゼロ、大きい場合ã?正の整数を返しますã?
427 *
428 * @param other TimeStampObject オブジェクãƒ?
429 *
430 * @return é ?º�比è¼??値
431 * @throws ClassCastException
432 * @see Comparable#compareTo(Object)
433 */
434 // public int compareTo( final Object obj ) {
435 public int compareTo( final TimeStampObject other ) { // 4.3.3.6 (2008/11/15) Generics警告対å¿?
436 // TimeStampObject other = (TimeStampObject)obj;
437 long diff = (timeStamp - other.timeStamp);
438
439 if( diff > 0 ) { return 1; }
440 else if( diff < 0 ) { return -1; }
441 else {
442 if( equals( other ) ) { return 0; }
443 else { return (hcode - other.hcode); }
444 }
445 }
446
447 /**
448 * こã?オブジェクトã?å†?ƒ¨表現を返しますã?
449 *
450 * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正しますã?
451 *
452 * @return オブジェクトã?å†?ƒ¨表現æ–?—å?
453 */
454 public String toString() {
455 // Create Timeは、ä¸?º¦求めれã?変わらなã�??で、キャãƒ?‚·ュしても良ã�??
456 // DateFormat formatter = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss",Locale.JAPAN );
457
458 // return ( "[Create Time = " + formatter.format( new Date( timeStamp ) )
459 // + " , Time Over = " + (int)((limitTime - System.currentTimeMillis())/1000.0) + "(S)]" );
460
461 return ( "[Create Time = " + HybsDateUtil.getDate( timeStamp,"yyyy/MM/dd HH:mm:ss" )
462 + " , Time Over = " + (int)((limitTime - System.currentTimeMillis())/1000.0) + "(S)]" );
463 }
464 }