Java tutorial
package org.apache.ojb.broker.core; /* Copyright 2003-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.util.Properties; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.apache.commons.pool.KeyedObjectPool; import org.apache.commons.pool.KeyedPoolableObjectFactory; import org.apache.commons.pool.impl.GenericKeyedObjectPool; import org.apache.ojb.broker.PBFactoryException; import org.apache.ojb.broker.PBKey; import org.apache.ojb.broker.PBState; import org.apache.ojb.broker.PersistenceBroker; import org.apache.ojb.broker.PersistenceBrokerInternal; import org.apache.ojb.broker.util.BrokerHelper; import org.apache.ojb.broker.util.logging.Logger; import org.apache.ojb.broker.util.logging.LoggerFactory; /** * This is the default implementation of the {@link PersistenceBrokerFactoryIF} * interface. * <p> * This implementation use a pool of {@link org.apache.ojb.broker.PersistenceBroker} * instances [abbr. PB]. Each pooled PB instance (the implementation class was specified * in OJB configuration file) is wrapped by {@link PoolablePersistenceBroker} class * before add to pool. * </p> * <p> * When calling {@link #createPersistenceBroker} or {@link #defaultPersistenceBroker} the pooled-PB * instance (<tt>PoolablePersistenceBroker</tt>) on its part was wrapped with {@link PersistenceBrokerHandle} * handle. * </p> * <p> * When a client do a PB.close() call on the handle the wrapped <tt>PoolablePersistenceBroker</tt> will * be closed and returned to pool. All further method calls on the handle * (except <tt>PB.isClosed()</tt> and <tt>PB.isInTransaction()</tt>) result in an exception. * </p> * Each different {@link org.apache.ojb.broker.PBKey} (based on <code>PBKey.equals(...)</code> method) * get its own PB-pool. * * @see PersistenceBrokerFactoryBaseImpl * * @author <a href="mailto:thma@apache.org">Thomas Mahler<a> * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a> * @version $Id: PersistenceBrokerFactoryDefaultImpl.java,v 1.11.2.4 2005/12/21 22:25:00 tomdz Exp $ */ public class PersistenceBrokerFactoryDefaultImpl extends PersistenceBrokerFactoryBaseImpl { private static Logger log = LoggerFactory.getLogger(PersistenceBrokerFactoryDefaultImpl.class); private GenericKeyedObjectPool brokerPool; private PBPoolInfo poolConfig; public PersistenceBrokerFactoryDefaultImpl() { super(); // get PB-pool configuration properties from OJB.properties poolConfig = new PBPoolInfo(); // setup pool for PB instances brokerPool = this.createPool(); log.info("Create PersistenceBroker instance pool, pool configuration was " + getPoolConfiguration()); } /** * Return broker instance from pool. If given {@link PBKey} was not found in pool * a new pool for given * @param pbKey * @return * @throws PBFactoryException */ public PersistenceBrokerInternal createPersistenceBroker(PBKey pbKey) throws PBFactoryException { if (log.isDebugEnabled()) log.debug("Obtain broker from pool, used PBKey is " + pbKey); PersistenceBrokerInternal broker = null; /* try to find a valid PBKey, if given key does not full match */ pbKey = BrokerHelper.crossCheckPBKey(pbKey); try { /* get a pooled PB instance, the pool is reponsible to create new PB instances if not found in pool */ broker = ((PersistenceBrokerInternal) brokerPool.borrowObject(pbKey)); /* now warp pooled PB instance with a handle to avoid PB corruption of closed PB instances. */ broker = wrapRequestedBrokerInstance(broker); } catch (Exception e) { try { // if something going wrong, tryto close broker if (broker != null) broker.close(); } catch (Exception ignore) { //ignore it } throw new PBFactoryException("Borrow broker from pool failed, using PBKey " + pbKey, e); } return broker; } /** * Each real pooled {@link PersistenceBroker} instance was wrapped by a * pooling handle when a new instance was created. * * @see PoolablePersistenceBroker * @param broker real {@link PersistenceBroker} instance * @param pool use {@link KeyedObjectPool} * @return wrapped broker instance */ protected PersistenceBrokerInternal wrapBrokerWithPoolingHandle(PersistenceBrokerInternal broker, KeyedObjectPool pool) { return new PoolablePersistenceBroker(broker, pool); } /** * Wraps the requested pooled broker instance. The returned handle * warps a pooled broker instance to avoid corruption * of already closed broker instances. * * @see PersistenceBrokerHandle * @param broker * @return The broker handle. */ protected PersistenceBrokerInternal wrapRequestedBrokerInstance(PersistenceBrokerInternal broker) { return new PersistenceBrokerHandle(broker); } /** * @see PersistenceBrokerFactoryIF#releaseAllInstances() */ public synchronized void releaseAllInstances() { log.warn("Release all instances referenced by this object"); super.releaseAllInstances(); try { brokerPool.close(); brokerPool = this.createPool(); } catch (Exception e) { log.error("Error while release all pooled broker instances and refresh pool", e); } } public void shutdown() { try { brokerPool.close(); brokerPool = null; } catch (Exception e) { log.error("Error while shutdown of broker pool", e); } super.shutdown(); } public int activePersistenceBroker() { return brokerPool.getNumActive(); } /** * could be used for monitoring * TODO: is this useful? */ public Properties getPoolConfiguration() { return poolConfig; } /** * could be used for runtime configuration * TODO: is this useful? */ public void setPoolConfiguration(Properties prop) { poolConfig = new PBPoolInfo(prop); log.info("Change pooling configuration properties: " + poolConfig.getKeyedObjectPoolConfig()); brokerPool.setConfig(poolConfig.getKeyedObjectPoolConfig()); } /** * Create the {@link org.apache.commons.pool.KeyedObjectPool}, pooling * the {@link PersistenceBroker} instances - override this method to * implement your own pool and {@link org.apache.commons.pool.KeyedPoolableObjectFactory}. */ private GenericKeyedObjectPool createPool() { GenericKeyedObjectPool.Config conf = poolConfig.getKeyedObjectPoolConfig(); if (log.isDebugEnabled()) log.debug("PersistenceBroker pool will be setup with the following configuration " + ToStringBuilder.reflectionToString(conf, ToStringStyle.MULTI_LINE_STYLE)); GenericKeyedObjectPool pool = new GenericKeyedObjectPool(null, conf); pool.setFactory(new PersistenceBrokerFactoryDefaultImpl.PBKeyedPoolableObjectFactory(this, pool)); return pool; } //************************************************************************************** // Inner classes //************************************************************************************** // /** * This is a {@link org.apache.commons.pool.KeyedPoolableObjectFactory} implementation, * manage the life-cycle of {@link PersistenceBroker} instances * hold in an {@link org.apache.commons.pool.KeyedObjectPool}. * * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a> */ class PBKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory { private PersistenceBrokerFactoryDefaultImpl pbf; private KeyedObjectPool pool; public PBKeyedPoolableObjectFactory(PersistenceBrokerFactoryDefaultImpl pbf, KeyedObjectPool pool) { this.pbf = pbf; this.pool = pool; } public Object makeObject(Object key) throws Exception { return wrapBrokerWithPoolingHandle(pbf.createNewBrokerInstance((PBKey) key), pool); } /** * Do all cleanup stuff here. */ public void destroyObject(Object key, Object obj) throws Exception { PoolablePersistenceBroker pb = (PoolablePersistenceBroker) obj; PersistenceBroker broker = pb.getInnermostDelegate(); if (broker instanceof PersistenceBrokerImpl) { log.info("Destroy PersistenceBroker instance " + obj); ((PersistenceBrokerImpl) broker).destroy(); } pb.destroy(); } /** * Check if the given PersistenceBroker instance * was already in transaction. * Was called when * {@link PBPoolInfo#init} * method does set <code>testOnBorrow(true)</code>. * (Default was false, thus this method wasn't called) * See documentation jakarta-connons-pool api. */ public boolean validateObject(Object key, Object obj) { // here we could validate the PB instance // if corresponding configuration properties are set if (((PersistenceBroker) obj).isInTransaction()) { log.error("Illegal broker state! This broker instance was already in transaction."); return false; } return true; } /** * Called before borrow object from pool. */ public void activateObject(Object key, Object obj) throws Exception { ((PBState) obj).setClosed(false); } /** * Called before return object to pool. */ public void passivateObject(Object key, Object obj) throws Exception { ((PBState) obj).setClosed(true); } } }