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 }