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    }