001: package org.apache.ojb.broker.core;
002:
003: /* Copyright 2003-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.util.Properties;
019:
020: import org.apache.commons.lang.builder.ToStringBuilder;
021: import org.apache.commons.lang.builder.ToStringStyle;
022: import org.apache.commons.pool.KeyedObjectPool;
023: import org.apache.commons.pool.KeyedPoolableObjectFactory;
024: import org.apache.commons.pool.impl.GenericKeyedObjectPool;
025: import org.apache.ojb.broker.PBFactoryException;
026: import org.apache.ojb.broker.PBKey;
027: import org.apache.ojb.broker.PBState;
028: import org.apache.ojb.broker.PersistenceBroker;
029: import org.apache.ojb.broker.PersistenceBrokerInternal;
030: import org.apache.ojb.broker.util.BrokerHelper;
031: import org.apache.ojb.broker.util.logging.Logger;
032: import org.apache.ojb.broker.util.logging.LoggerFactory;
033:
034: /**
035: * This is the default implementation of the {@link PersistenceBrokerFactoryIF}
036: * interface.
037: * <p>
038: * This implementation use a pool of {@link org.apache.ojb.broker.PersistenceBroker}
039: * instances [abbr. PB]. Each pooled PB instance (the implementation class was specified
040: * in OJB configuration file) is wrapped by {@link PoolablePersistenceBroker} class
041: * before add to pool.
042: * </p>
043: * <p>
044: * When calling {@link #createPersistenceBroker} or {@link #defaultPersistenceBroker} the pooled-PB
045: * instance (<tt>PoolablePersistenceBroker</tt>) on its part was wrapped with {@link PersistenceBrokerHandle}
046: * handle.
047: * </p>
048: * <p>
049: * When a client do a PB.close() call on the handle the wrapped <tt>PoolablePersistenceBroker</tt> will
050: * be closed and returned to pool. All further method calls on the handle
051: * (except <tt>PB.isClosed()</tt> and <tt>PB.isInTransaction()</tt>) result in an exception.
052: * </p>
053: * Each different {@link org.apache.ojb.broker.PBKey} (based on <code>PBKey.equals(...)</code> method)
054: * get its own PB-pool.
055: *
056: * @see PersistenceBrokerFactoryBaseImpl
057: *
058: * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
059: * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
060: * @version $Id: PersistenceBrokerFactoryDefaultImpl.java,v 1.11.2.4 2005/12/21 22:25:00 tomdz Exp $
061: */
062: public class PersistenceBrokerFactoryDefaultImpl extends
063: PersistenceBrokerFactoryBaseImpl {
064: private static Logger log = LoggerFactory
065: .getLogger(PersistenceBrokerFactoryDefaultImpl.class);
066: private GenericKeyedObjectPool brokerPool;
067: private PBPoolInfo poolConfig;
068:
069: public PersistenceBrokerFactoryDefaultImpl() {
070: super ();
071: // get PB-pool configuration properties from OJB.properties
072: poolConfig = new PBPoolInfo();
073: // setup pool for PB instances
074: brokerPool = this .createPool();
075: log
076: .info("Create PersistenceBroker instance pool, pool configuration was "
077: + getPoolConfiguration());
078: }
079:
080: /**
081: * Return broker instance from pool. If given {@link PBKey} was not found in pool
082: * a new pool for given
083: * @param pbKey
084: * @return
085: * @throws PBFactoryException
086: */
087: public PersistenceBrokerInternal createPersistenceBroker(PBKey pbKey)
088: throws PBFactoryException {
089: if (log.isDebugEnabled())
090: log
091: .debug("Obtain broker from pool, used PBKey is "
092: + pbKey);
093: PersistenceBrokerInternal broker = null;
094:
095: /*
096: try to find a valid PBKey, if given key does not full match
097: */
098: pbKey = BrokerHelper.crossCheckPBKey(pbKey);
099:
100: try {
101: /*
102: get a pooled PB instance, the pool is reponsible to create new
103: PB instances if not found in pool
104: */
105: broker = ((PersistenceBrokerInternal) brokerPool
106: .borrowObject(pbKey));
107: /*
108: now warp pooled PB instance with a handle to avoid PB corruption
109: of closed PB instances.
110: */
111: broker = wrapRequestedBrokerInstance(broker);
112:
113: } catch (Exception e) {
114: try {
115: // if something going wrong, tryto close broker
116: if (broker != null)
117: broker.close();
118: } catch (Exception ignore) {
119: //ignore it
120: }
121: throw new PBFactoryException(
122: "Borrow broker from pool failed, using PBKey "
123: + pbKey, e);
124: }
125: return broker;
126: }
127:
128: /**
129: * Each real pooled {@link PersistenceBroker} instance was wrapped by a
130: * pooling handle when a new instance was created.
131: *
132: * @see PoolablePersistenceBroker
133: * @param broker real {@link PersistenceBroker} instance
134: * @param pool use {@link KeyedObjectPool}
135: * @return wrapped broker instance
136: */
137: protected PersistenceBrokerInternal wrapBrokerWithPoolingHandle(
138: PersistenceBrokerInternal broker, KeyedObjectPool pool) {
139: return new PoolablePersistenceBroker(broker, pool);
140: }
141:
142: /**
143: * Wraps the requested pooled broker instance. The returned handle
144: * warps a pooled broker instance to avoid corruption
145: * of already closed broker instances.
146: *
147: * @see PersistenceBrokerHandle
148: * @param broker
149: * @return The broker handle.
150: */
151: protected PersistenceBrokerInternal wrapRequestedBrokerInstance(
152: PersistenceBrokerInternal broker) {
153: return new PersistenceBrokerHandle(broker);
154: }
155:
156: /**
157: * @see PersistenceBrokerFactoryIF#releaseAllInstances()
158: */
159: public synchronized void releaseAllInstances() {
160: log.warn("Release all instances referenced by this object");
161: super .releaseAllInstances();
162: try {
163: brokerPool.close();
164: brokerPool = this .createPool();
165: } catch (Exception e) {
166: log
167: .error(
168: "Error while release all pooled broker instances and refresh pool",
169: e);
170: }
171: }
172:
173: public void shutdown() {
174: try {
175: brokerPool.close();
176: brokerPool = null;
177: } catch (Exception e) {
178: log.error("Error while shutdown of broker pool", e);
179: }
180: super .shutdown();
181: }
182:
183: public int activePersistenceBroker() {
184: return brokerPool.getNumActive();
185: }
186:
187: /**
188: * could be used for monitoring
189: * TODO: is this useful?
190: */
191: public Properties getPoolConfiguration() {
192: return poolConfig;
193: }
194:
195: /**
196: * could be used for runtime configuration
197: * TODO: is this useful?
198: */
199: public void setPoolConfiguration(Properties prop) {
200: poolConfig = new PBPoolInfo(prop);
201: log.info("Change pooling configuration properties: "
202: + poolConfig.getKeyedObjectPoolConfig());
203: brokerPool.setConfig(poolConfig.getKeyedObjectPoolConfig());
204: }
205:
206: /**
207: * Create the {@link org.apache.commons.pool.KeyedObjectPool}, pooling
208: * the {@link PersistenceBroker} instances - override this method to
209: * implement your own pool and {@link org.apache.commons.pool.KeyedPoolableObjectFactory}.
210: */
211: private GenericKeyedObjectPool createPool() {
212: GenericKeyedObjectPool.Config conf = poolConfig
213: .getKeyedObjectPoolConfig();
214: if (log.isDebugEnabled())
215: log
216: .debug("PersistenceBroker pool will be setup with the following configuration "
217: + ToStringBuilder.reflectionToString(conf,
218: ToStringStyle.MULTI_LINE_STYLE));
219: GenericKeyedObjectPool pool = new GenericKeyedObjectPool(null,
220: conf);
221: pool
222: .setFactory(new PersistenceBrokerFactoryDefaultImpl.PBKeyedPoolableObjectFactory(
223: this , pool));
224: return pool;
225: }
226:
227: //**************************************************************************************
228: // Inner classes
229: //**************************************************************************************
230: //
231:
232: /**
233: * This is a {@link org.apache.commons.pool.KeyedPoolableObjectFactory} implementation,
234: * manage the life-cycle of {@link PersistenceBroker} instances
235: * hold in an {@link org.apache.commons.pool.KeyedObjectPool}.
236: *
237: * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
238: */
239: class PBKeyedPoolableObjectFactory implements
240: KeyedPoolableObjectFactory {
241: private PersistenceBrokerFactoryDefaultImpl pbf;
242: private KeyedObjectPool pool;
243:
244: public PBKeyedPoolableObjectFactory(
245: PersistenceBrokerFactoryDefaultImpl pbf,
246: KeyedObjectPool pool) {
247: this .pbf = pbf;
248: this .pool = pool;
249: }
250:
251: public Object makeObject(Object key) throws Exception {
252: return wrapBrokerWithPoolingHandle(pbf
253: .createNewBrokerInstance((PBKey) key), pool);
254: }
255:
256: /**
257: * Do all cleanup stuff here.
258: */
259: public void destroyObject(Object key, Object obj)
260: throws Exception {
261: PoolablePersistenceBroker pb = (PoolablePersistenceBroker) obj;
262: PersistenceBroker broker = pb.getInnermostDelegate();
263: if (broker instanceof PersistenceBrokerImpl) {
264: log.info("Destroy PersistenceBroker instance " + obj);
265: ((PersistenceBrokerImpl) broker).destroy();
266: }
267: pb.destroy();
268: }
269:
270: /**
271: * Check if the given PersistenceBroker instance
272: * was already in transaction.
273: * Was called when
274: * {@link PBPoolInfo#init}
275: * method does set <code>testOnBorrow(true)</code>.
276: * (Default was false, thus this method wasn't called)
277: * See documentation jakarta-connons-pool api.
278: */
279: public boolean validateObject(Object key, Object obj) {
280: // here we could validate the PB instance
281: // if corresponding configuration properties are set
282: if (((PersistenceBroker) obj).isInTransaction()) {
283: log
284: .error("Illegal broker state! This broker instance was already in transaction.");
285: return false;
286: }
287: return true;
288: }
289:
290: /**
291: * Called before borrow object from pool.
292: */
293: public void activateObject(Object key, Object obj)
294: throws Exception {
295: ((PBState) obj).setClosed(false);
296: }
297:
298: /**
299: * Called before return object to pool.
300: */
301: public void passivateObject(Object key, Object obj)
302: throws Exception {
303: ((PBState) obj).setClosed(true);
304: }
305: }
306: }
|