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    }