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    }