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 *
192 * @param obj オブジェクト?ールに戻すオブジェク?
193 */
194 public synchronized void release( final E obj ) {
195 E obj2 = objectInitial( obj );
196 if( obj2 != null ) {
197 Integer key = Integer.valueOf( obj2.hashCode() );
198 TimeStampObject tso = poolBack.get( key );
199 if( tso != null ) {
200 pool.add( obj2 );
201 }
202 else { // 3.5.6.2 (2004/07/05) 追?
203 LogWriter.log( "ObjectPool で、メモリリークの可能性がある?[" + obj2 + "]" );
204 remove( obj2 );
205 }
206 }
207 }
208
209 /**
210 * オブジェクトを、オブジェクト?ールから削除します?
211 * remove されるオブジェクト?、すでにキャ?ュから取り出された後なので?
212 * そ?まま、何もしなければ自然消?GC)されます?
213 * 自然消?る前に、objectFinal( Object ) が呼ばれます?
214 * 生?されたオブジェクト?総数も?ひとつ減らします?
215 *
216 * @param obj 削除するオブジェク?
217 */
218 public synchronized void remove( final E obj ) {
219 if( obj != null ) {
220 Integer key = Integer.valueOf( obj.hashCode() );
221 poolBack.remove( key );
222 }
223
224 objectFinal( obj );
225 }
226
227 /**
228 * オブジェクト?ールの要?を返します?
229 *
230 * @return プ?ルの要?
231 */
232 public synchronized int size() {
233 return poolBack.size();
234 }
235
236 /**
237 * オブジェクト?ールが要?持たな?ど?を判定します?
238 *
239 * @return オブジェクト?ールが要?持って???つまりそのサイズ?0 の場合に? true、そ?な??合? false
240 */
241 public synchronized boolean isEmpty() {
242 return poolBack.isEmpty() ;
243 }
244
245 /**
246 * すべての要? オブジェクト?ールから削除します?
247 * 貸し?し中のオブジェクト?、クリアしません。よって、返り値は?
248 * すべてのオブジェクトをクリアできた場合?、true 、貸し?し中の
249 * オブジェクトが存在した場?クリアできなかった??は、false です?
250 *
251 * @return すべてクリア(true)/貸し?し中のオブジェクトが残って?(false)
252 */
253 public synchronized boolean clear() {
254 Iterator<E> itr = pool.iterator();
255 while( itr.hasNext() ) {
256 remove( itr.next() );
257 }
258 pool.clear();
259
260 // 貸し?し中の場合?、remove 出来な?、poolBack に残って??
261 // それでも?poolBack をクリアすることで、release 返却時にも?
262 // remove されるよ?なります?
263 // ただし?作?オブジェクト数が?? 0 にリセ?される為?
264 // ?貸し?し可能数が???増えてしま?す?
265 boolean flag = poolBack.isEmpty();
266 poolBack.clear();
267
268 return flag;
269 }
270
271 /**
272 * オブジェクト?ールから削除するときに呼ばれます?
273 * こ?メソ?で?ブジェクトごとの終???行います?
274 * 例えば???タベ?スコネクションであれば?close() 処?どです?
275 *
276 * ?ォルトでは、なにも行いません?
277 *
278 * @param obj 終???行うオブジェク?
279 */
280 protected synchronized void objectFinal( final E obj ) {
281 // ここでは処?行いません?
282 }
283
284 /**
285 * オブジェクト?ールに戻すと?release すると?に呼ばれます?
286 * こ?メソ?で?ブジェクトごとの初期処?行います?
287 * オブジェクト?ールに戻すときには?初期化して?次の貸し?しに
288 * 対応できるように、?期??ておく?があります?
289 *
290 * ?ォルトでは、引数のオブジェクトをそ?まま返します?
291 *
292 * @param obj 初期処?行うオブジェク?
293 *
294 * @return 初期処?行ったオブジェク?
295 */
296 protected synchronized E objectInitial( final E obj ) {
297 return obj;
298 }
299
300 /**
301 * ?状況を簡易的に表現した??を返します?
302 *
303 * @return こ?オブジェクト?ールの??表現
304 */
305 @Override
306 public synchronized String toString() {
307 StringBuilder buf = new StringBuilder();
308 buf.append( " freeCount = [" ).append( pool.size() ).append( "]\n" );
309 buf.append( " createCount = [" ).append( poolBack.size() ).append( "]" );
310 buf.append( " ( max=[" ).append( maxsize ).append( "] )\n" );
311 buf.append( " limiter = [" ).append( limit ).append( "]\n" );
312 buf.append( " limitTime = [" ).append( limitTime ).append( "](s)\n" );
313
314 Iterator<E> itr = pool.iterator();
315 buf.append( "Free Objects \n" );
316 while( itr.hasNext() ) {
317 E obj = itr.next();
318 if( obj != null ) {
319 Integer key = Integer.valueOf( obj.hashCode() );
320 buf.append( " " );
321 buf.append( poolBack.get( key ) );
322 buf.append( " " ).append( obj );
323 buf.append( "\n" );
324 }
325 }
326 return buf.toString();
327 }
328 }
329
330 /**
331 * TimeStampObject は、生成された Object を?生?時刻とともに管?るクラスです?
332 * ?のハッシュキーは、登録するオブジェクトと同?、管?きるのは、異なるオブジェク?
333 * のみです?
334 *
335 * @version 4.0
336 * @author Kazuhiko Hasegawa
337 * @since JDK5.0,
338 */
339 class TimeStampObject implements Comparable<TimeStampObject> { // 4.3.3.6 (2008/11/15) Generics警告対?
340 private final long timeStamp ;
341 private final long limitTime ;
342 private final int hcode ;
343
344 /**
345 * コンストラクター?
346 *
347 * @param obj 管?るオブジェク?
348 * @param limit オブジェクト?寿命(?
349 * @throws IllegalArgumentException TimeStampObject のインスタンスに、NULL はセ?できません?
350 */
351 public TimeStampObject( final Object obj,final int limit ) {
352 if( obj == null ) {
353 String errMsg = "TimeStampObject のインスタンスに、NULL はセ?できません? ;
354 throw new IllegalArgumentException( errMsg );
355 }
356
357 timeStamp = System.currentTimeMillis();
358 if( limit > 0 ) {
359 limitTime = timeStamp + limit * 1000L ;
360 }
361 else {
362 limitTime = Long.MAX_VALUE ;
363 }
364
365 hcode = (int)((timeStamp)&(Integer.MAX_VALUE))^(obj.hashCode()) ;
366 }
367
368 /**
369 * ?管?て?オブジェクト?生?時刻を返します?
370 *
371 * @return 生?時刻(ms)
372 */
373 public long getTimeStamp() {
374 return timeStamp;
375 }
376
377 /**
378 * オブジェクト?寿命がきたかど?を返します?
379 *
380 * @return 寿命判?true:寿命/false:ま?える)
381 */
382 public boolean isTimeOver() {
383 return (System.currentTimeMillis() > limitTime );
384 }
385
386 /**
387 * オブジェクトが同じかど?を判定します?
388 *
389 * ?オブジェクト? equals() メソ?と、作?時刻の両方を判断します?
390 * ?オブジェクト? equals() が同じでも?作?時刻が異なると?
391 * false を返します?これは、?く同?ブジェクトを管?る?合でも?
392 * タイ?タンプを差し替える事で、異なるオブジェクトとして
393 * 認識させると?ことです?
394 *
395 * @param obj Object
396 *
397 * @return true:同じ/false:異なる?
398 */
399 public boolean equals( final Object obj ) {
400 if( obj instanceof TimeStampObject ) {
401 TimeStampObject other = (TimeStampObject)obj ;
402 return ( hcode == other.hcode ) && ( timeStamp == other.timeStamp ) ;
403 }
404 return false ;
405 }
406
407 /**
408 * ハッシュコードを返します?
409 *
410 * ここで返すのは、???身のハッシュコードではなく?
411 * ?管??オブジェクト?ハッシュコードです?
412 *
413 * hashcode = (int)((timeStamp)&(Integer.MAX_VALUE))^(obj.hashCode())
414 *
415 * こ?計算式?、変更される可能性があります?
416 *
417 * @return ?管??オブジェクト?ハッシュコー?
418 */
419 public int hashCode() { return hcode; }
420
421 /**
422 * こ?オブジェクトと?されたオブジェクト??を比?ます?
423 *
424 * こ?オブジェクトが?されたオブジェクトより小さ??合???整数?
425 * 等し??合?ゼロ、大きい場合?正の整数を返します?
426 *
427 * @param other TimeStampObject オブジェク?
428 *
429 * @return ?比??値
430 * @throws ClassCastException ?されたオブジェクトがキャストできな??合?
431 * @see Comparable#compareTo(Object)
432 */
433 // public int compareTo( final Object obj ) {
434 public int compareTo( final TimeStampObject other ) { // 4.3.3.6 (2008/11/15) Generics警告対?
435 // TimeStampObject other = (TimeStampObject)obj;
436 long diff = (timeStamp - other.timeStamp);
437
438 if( diff > 0 ) { return 1; }
439 else if( diff < 0 ) { return -1; }
440 else {
441 if( equals( other ) ) { return 0; }
442 else { return (hcode - other.hcode); }
443 }
444 }
445
446 /**
447 * こ?オブジェクト??表現を返します?
448 *
449 * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します?
450 *
451 * @return オブジェクト??表現??
452 */
453 public String toString() {
454 // Create Timeは、?求めれ?変わらな??で、キャ?ュしても良??
455 // DateFormat formatter = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss",Locale.JAPAN );
456
457 // return ( "[Create Time = " + formatter.format( new Date( timeStamp ) )
458 // + " , Time Over = " + (int)((limitTime - System.currentTimeMillis())/1000.0) + "(S)]" );
459
460 return ( "[Create Time = " + HybsDateUtil.getDate( timeStamp,"yyyy/MM/dd HH:mm:ss" )
461 + " , Time Over = " + (int)((limitTime - System.currentTimeMillis())/1000.0) + "(S)]" );
462 }
463 }