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)&amp;(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    }