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 }