001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/framework/util/ObjectPool.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.framework.util;
045    
046    import java.io.IOException;
047    import java.io.InputStream;
048    import java.util.ArrayList;
049    import java.util.Collections;
050    import java.util.HashMap;
051    import java.util.List;
052    import java.util.Map;
053    import java.util.Properties;
054    import java.util.Timer;
055    import java.util.TimerTask;
056    
057    import org.deegree.framework.log.ILogger;
058    import org.deegree.framework.log.LoggerFactory;
059    
060    /**
061     * class to manage the object pool. this is part of the combination of the object pool pattern an
062     * the singelton pattern.
063     * 
064     * @version $Revision: 9339 $
065     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
066     * @author last edited by: $Author: apoth $
067     *
068     * @version 1.0. $Revision: 9339 $, $Date: 2007-12-27 13:31:52 +0100 (Do, 27 Dez 2007) $
069     *
070     * @since 2.0
071     */
072    public abstract class ObjectPool extends TimerTask {
073    
074        private static final ILogger LOG = LoggerFactory.getLogger( ObjectPool.class );
075    
076        protected List<Object> available = null;
077    
078        protected List<Object> in_use = null;
079    
080        protected Map<Object,Long> startLifeTime = null;
081    
082        protected Map<Object,Long> startUsageTime = null;
083    
084        protected int existingInstances = 0;
085    
086        private int maxInstances = 50;
087    
088        // min * sec * millisec. example: 15*60*1000 = 15 minutes
089        private int maxLifeTime = 15 * 60 * 1000;
090    
091        // min * sec * millisec. example: 5*60*1000 = 5 minutes
092        private int maxUsageTime = 5 * 60 * 1000;
093    
094        // milliseconds
095        private int updateInterval = 15000;
096    
097        /**
098         * Creates a new ObjectPool object.
099         */
100        protected ObjectPool() {
101            available = Collections.synchronizedList( new ArrayList<Object>( maxInstances ) );
102            in_use = Collections.synchronizedList( new ArrayList<Object>( maxInstances ) );
103            startLifeTime = Collections.synchronizedMap( new HashMap<Object,Long>( maxInstances ) );
104            startUsageTime = Collections.synchronizedMap( new HashMap<Object,Long>( maxInstances ) );
105            Timer timer = new Timer();
106            timer.scheduleAtFixedRate( this, 10000, updateInterval );
107            InputStream is = ObjectPool.class.getResourceAsStream( "pool.properties" );
108            if ( is != null ) {
109                Properties props = new Properties();
110                try {
111                    props.load( is );
112                    is.close();
113                } catch ( IOException e ) {
114                    LOG.logInfo( "could not load pool properties" );
115                    return;
116                }
117                maxInstances = Integer.parseInt( props.getProperty( "maxInstances" ) );
118                maxLifeTime = Integer.parseInt( props.getProperty( "maxLifeTime" ) );
119                maxUsageTime = Integer.parseInt( props.getProperty( "maxUsageTime" ) );
120                updateInterval = Integer.parseInt( props.getProperty( "updateInterval" ) );
121                LOG.logInfo( "pool configuration read from pool.properties" );            
122                LOG.logDebug( "pool properties", this.toString() );
123            }
124        }
125    
126        /**
127         * dummy
128         * 
129         * @return null
130         */
131        public static ObjectPool getInstance() {
132            return null;
133        }
134    
135        /**
136         * clears the complete pool. objects in used while the clear() method has been called won't be
137         * put back to the pool if released back through the <tt>releaseObject</tt> method.
138         */
139        public void clear() {
140            synchronized ( in_use ) {
141                synchronized ( available ) {
142                    synchronized ( startUsageTime ) {
143                        synchronized ( startLifeTime ) {
144                            in_use.clear();
145                            available.clear();
146                            startUsageTime.clear();
147                            startLifeTime.clear();
148                        }
149                    }
150                }
151            }
152        }
153    
154        /**
155         * release an object back to the pool so it is available for other requests.
156         */
157        public void releaseObject( Object object ) throws Exception {
158    
159            if ( in_use.contains( object ) ) {
160                // remove the object from the 'in use' container
161                in_use.remove( object );
162                // remove the objects entry from the 'usage star time' container
163                startUsageTime.remove( object );
164                // push the object to the list of available objects
165                available.add( object );
166            }
167    
168        }
169    
170        /**
171         * this method will be called when the submitted object will be removed from the pool
172         */
173        public abstract void onObjectKill( Object o );
174    
175        /**
176         * @return
177         */
178        public int getMaxLifeTime() {
179            return ( this.maxLifeTime );
180        }
181    
182        /**
183         * @param maxLifeTime
184         */
185        public void setMaxLifeTime( int maxLifeTime ) {
186            this.maxLifeTime = maxLifeTime;
187        }
188    
189        /**
190         * @return
191         */
192        public int getMaxUsageTime() {
193            return ( this.maxUsageTime );
194        }
195    
196        /**
197         * @param maxUsageTime
198         */
199        public void setMaxUsageTime( int maxUsageTime ) {
200            this.maxUsageTime = maxUsageTime;
201        }
202    
203        /**
204         * @return
205         */
206        public int getUpdateInterval() {
207            return ( this.updateInterval );
208        }
209    
210        /**
211         * @param updateInterval
212         */
213        public void setUpdateInterval( int updateInterval ) {
214            this.updateInterval = updateInterval;
215        }
216    
217        /**
218         * @return
219         */
220        public int getMaxInstances() {
221            return ( this.maxInstances );
222        }
223    
224        /**
225         * @param maxInstances
226         */
227        public void setMaxInstances( int maxInstances ) {
228            this.maxInstances = maxInstances;
229        }
230    
231        /**
232         * 
233         * 
234         * @return
235         */
236        public String toString() {
237            String ret = getClass().getName() + "\n";
238            ret = "startLifeTime = " + startLifeTime + "\n";
239            ret += ( "startUsageTime = " + startUsageTime + "\n" );
240            ret += ( "maxLifeTime = " + maxLifeTime + "\n" );
241            ret += ( "maxUsageTime = " + maxUsageTime + "\n" );
242            ret += ( "updateInterval = " + updateInterval + "\n" );
243            ret += ( "maxInstances = " + maxInstances + "\n" );
244            return ret;
245        }
246    
247        public void run() {
248            cleaner();
249            usage();
250        }
251    
252        private void cleaner() {
253    
254            try {
255                synchronized ( available ) {
256                    synchronized ( startLifeTime ) {
257                        Object[] os = available.toArray();
258                        for ( int i = 0; i < os.length; i++ ) {
259                            Object o = os[i];
260                            Long lng = startLifeTime.get( o );
261                            long l = System.currentTimeMillis();
262                            if ( lng == null || ( l - lng.longValue() ) > maxLifeTime ) {
263                                if ( o != null ) {
264                                    available.remove( o );
265                                    startLifeTime.remove( o );
266                                    onObjectKill( o );
267                                }
268                                existingInstances--;
269                            }
270                        }
271                    }
272                }
273    
274            } catch ( Exception e ) {
275                LOG.logError( "ObjectPool Cleaner ", e );
276            }
277    
278        }
279    
280        private void usage() {
281            try {
282                synchronized ( in_use ) {
283                    synchronized ( startUsageTime ) {
284                        synchronized ( startLifeTime ) {
285                            Object[] os = in_use.toArray();
286                            for ( int i = 0; i < os.length; i++ ) {
287                                Object o = os[i];
288                                Long lng = startUsageTime.get( o );
289                                long l = System.currentTimeMillis();                            
290                                if ( lng == null || ( l - lng.longValue() ) > maxUsageTime ) {
291                                    if ( o != null ) {
292                                        in_use.remove( o );
293                                        startUsageTime.remove( o );
294                                        startLifeTime.remove( o );
295                                        onObjectKill( o );
296                                    }
297                                }
298                            }
299                        }
300                    }
301                }
302            } catch ( Exception e ) {
303                LOG.logError( "UsageChecker ", e );
304            }
305    
306        }
307    
308    }