0001: /*
0002: * JBoss, Home of Professional Open Source.
0003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
0004: * as indicated by the @author tags. See the copyright.txt file in the
0005: * distribution for a full listing of individual contributors.
0006: *
0007: * This is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU Lesser General Public License as
0009: * published by the Free Software Foundation; either version 2.1 of
0010: * the License, or (at your option) any later version.
0011: *
0012: * This software is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public
0018: * License along with this software; if not, write to the Free
0019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
0021: */
0022: package org.jboss.resource.connectionmanager;
0023:
0024: import java.security.AccessController;
0025: import java.security.PrivilegedAction;
0026: import java.util.Iterator;
0027: import java.util.Map;
0028:
0029: import javax.management.Notification;
0030: import javax.management.NotificationFilter;
0031: import javax.management.NotificationListener;
0032: import javax.management.ObjectName;
0033: import javax.resource.ResourceException;
0034: import javax.resource.spi.ConnectionRequestInfo;
0035: import javax.resource.spi.ManagedConnectionFactory;
0036: import javax.security.auth.Subject;
0037: import javax.transaction.Transaction;
0038: import javax.transaction.TransactionManager;
0039:
0040: import org.jboss.deployment.DeploymentException;
0041: import org.jboss.logging.Logger;
0042: import org.jboss.mx.util.JMXExceptionDecoder;
0043: import org.jboss.resource.JBossResourceException;
0044: import org.jboss.resource.connectionmanager.InternalManagedConnectionPool.PoolParams;
0045: import org.jboss.system.ServiceMBeanSupport;
0046: import org.jboss.tm.TransactionLocal;
0047:
0048: import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
0049:
0050: /**
0051: * The JBossManagedConnectionPool mbean configures and supplies pooling of
0052: * JBossConnectionEventListeners to the BaseConnectionManager2 mbean.<p>
0053: *
0054: * It may be replaced by any mbean with a readable ManagedConnectionPool attribute
0055: * of type ManagedConnectionPool. Normal pooling parameters are supplied,
0056: * and the criteria to distinguish ManagedConnections is set in the Criteria attribute.
0057: *
0058: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
0059: * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
0060: * @author <a href="weston.price@jboss.com">Weston Price</a>
0061: *
0062: * @version $Revision: 59880 $
0063: */
0064: public class JBossManagedConnectionPool extends ServiceMBeanSupport
0065: implements JBossManagedConnectionPoolMBean,
0066: NotificationListener {
0067:
0068: /** The log */
0069: private static final Logger log = Logger
0070: .getLogger(JBossManagedConnectionPool.class);
0071:
0072: /** The managed connection factory name */
0073: private ObjectName managedConnectionFactoryName;
0074:
0075: /** The pooling criteria */
0076: private String criteria;
0077:
0078: /** The pooling strategy */
0079: private ManagedConnectionPool poolingStrategy;
0080:
0081: /** The pooling parameters */
0082: private final InternalManagedConnectionPool.PoolParams poolParams = new InternalManagedConnectionPool.PoolParams();
0083:
0084: /** Whether to use separate pools for transactional and non-transaction use */
0085: private boolean noTxSeparatePools;
0086:
0087: private String poolJndiName;
0088:
0089: public JBossManagedConnectionPool() {
0090: }
0091:
0092: public ManagedConnectionPool getManagedConnectionPool() {
0093: return poolingStrategy;
0094: }
0095:
0096: public ObjectName getManagedConnectionFactoryName() {
0097: return managedConnectionFactoryName;
0098: }
0099:
0100: public void setManagedConnectionFactoryName(
0101: ObjectName newManagedConnectionFactoryName) {
0102: this .managedConnectionFactoryName = newManagedConnectionFactoryName;
0103: }
0104:
0105: public long getAvailableConnectionCount() {
0106: return (poolingStrategy == null) ? 0 : poolingStrategy
0107: .getAvailableConnectionCount();
0108: }
0109:
0110: public long getMaxConnectionsInUseCount() {
0111: return (poolingStrategy == null) ? 0 : poolingStrategy
0112: .getMaxConnectionsInUseCount();
0113: }
0114:
0115: public long getInUseConnectionCount() {
0116: return (poolingStrategy == null) ? 0 : poolingStrategy
0117: .getInUseConnectionCount();
0118: }
0119:
0120: public int getMinSize() {
0121: return poolParams.minSize;
0122: }
0123:
0124: public void setMinSize(int newMinSize) {
0125: poolParams.minSize = newMinSize;
0126: }
0127:
0128: public int getMaxSize() {
0129: return poolParams.maxSize;
0130: }
0131:
0132: public void setMaxSize(int newMaxSize) {
0133: poolParams.maxSize = newMaxSize;
0134: }
0135:
0136: public int getBlockingTimeoutMillis() {
0137: return poolParams.blockingTimeout;
0138: }
0139:
0140: public void setBlockingTimeoutMillis(int newBlockingTimeout) {
0141: poolParams.blockingTimeout = newBlockingTimeout;
0142: }
0143:
0144: public long getIdleTimeoutMinutes() {
0145: return poolParams.idleTimeout / (1000 * 60);
0146: }
0147:
0148: public void setIdleTimeoutMinutes(long newIdleTimeoutMinutes) {
0149: poolParams.idleTimeout = newIdleTimeoutMinutes * 1000 * 60;
0150: }
0151:
0152: /**
0153: * Get the IdleTimeout value.
0154: *
0155: * @return the IdleTimeout value.
0156: */
0157: public long getIdleTimeout() {
0158: return poolParams.idleTimeout;
0159: }
0160:
0161: /**
0162: * Set the IdleTimeout value.
0163: *
0164: * @param newIdleTimeout The new IdleTimeout value.
0165: */
0166: public void setIdleTimeout(long newIdleTimeout) {
0167: poolParams.idleTimeout = newIdleTimeout;
0168: }
0169:
0170: public String getCriteria() {
0171: return criteria;
0172: }
0173:
0174: public void setCriteria(String newCriteria) {
0175: this .criteria = newCriteria;
0176: }
0177:
0178: public boolean getNoTxSeparatePools() {
0179: return noTxSeparatePools;
0180: }
0181:
0182: public void setNoTxSeparatePools(boolean value) {
0183: this .noTxSeparatePools = value;
0184: }
0185:
0186: public boolean getBackGroundValidation() {
0187: return poolParams.backgroundValidation;
0188: }
0189:
0190: public void setBackGroundValidation(boolean backgroundValidation) {
0191:
0192: poolParams.backgroundValidation = backgroundValidation;
0193:
0194: }
0195:
0196: public long getBackGroundValidationMinutes() {
0197:
0198: return poolParams.backgroundInterval / (1000 * 60);
0199: }
0200:
0201: public void setBackGroundValidationMinutes(
0202: long backgroundValidationInterval) {
0203:
0204: poolParams.backgroundInterval = backgroundValidationInterval * 1000 * 60;
0205:
0206: }
0207:
0208: public boolean getPreFill() {
0209: return this .poolParams.prefill;
0210: }
0211:
0212: public void setPreFill(boolean prefill) {
0213: this .poolParams.prefill = prefill;
0214: }
0215:
0216: public boolean getUseFastFail() {
0217: return this .poolParams.useFastFail;
0218: }
0219:
0220: public void setUseFastFail(boolean useFastFail) {
0221: this .poolParams.useFastFail = useFastFail;
0222: }
0223:
0224: public void flush() {
0225: if (poolingStrategy == null)
0226: throw new IllegalStateException(
0227: "The connection pool is not started");
0228:
0229: poolingStrategy.flush();
0230:
0231: if (poolingStrategy instanceof PreFillPoolSupport) {
0232: final PreFillPoolSupport pfs = (PreFillPoolSupport) poolingStrategy;
0233:
0234: if (pfs.shouldPreFill())
0235: pfs.prefill(noTxSeparatePools);
0236:
0237: }
0238: }
0239:
0240: public int getConnectionCount() {
0241: return (poolingStrategy == null) ? 0 : poolingStrategy
0242: .getConnectionCount();
0243: }
0244:
0245: public int getConnectionCreatedCount() {
0246: return (poolingStrategy == null) ? 0 : poolingStrategy
0247: .getConnectionCreatedCount();
0248: }
0249:
0250: public int getConnectionDestroyedCount() {
0251: return (poolingStrategy == null) ? 0 : poolingStrategy
0252: .getConnectionDestroyedCount();
0253: }
0254:
0255: public String getName() {
0256: return "JBossManagedConnectionPool";
0257: }
0258:
0259: public String getPoolJndiName() {
0260: return this .poolJndiName;
0261: }
0262:
0263: public void setPoolJndiName(String poolName) {
0264: this .poolJndiName = poolName;
0265: }
0266:
0267: protected void startService() throws Exception {
0268: ManagedConnectionFactory mcf = null;
0269: if (managedConnectionFactoryName == null)
0270: throw new DeploymentException(
0271: "ManagedConnectionFactory not set!");
0272:
0273: try {
0274: //We are getting the actual mcf instance itself. This will require
0275: //some work if the mcf is an xmbean of itself.
0276: mcf = (ManagedConnectionFactory) server.getAttribute(
0277: managedConnectionFactoryName, "McfInstance");
0278: } catch (Exception e) {
0279: JMXExceptionDecoder.rethrow(e);
0280: }
0281: getServer().addNotificationListener(
0282: managedConnectionFactoryName, this ,
0283: new NotificationFilter() {
0284: private static final long serialVersionUID = -9211456539783257343L;
0285:
0286: public boolean isNotificationEnabled(Notification n) {
0287: return RARDeployment.MCF_ATTRIBUTE_CHANGED_NOTIFICATION
0288: .equals(n.getType())
0289: && managedConnectionFactoryName
0290: .equals(n.getSource());
0291: }
0292: }, null);
0293:
0294: if ("ByContainerAndApplication".equals(criteria))
0295: poolingStrategy = new PoolBySubjectAndCri(mcf,
0296: poolJndiName, poolParams, noTxSeparatePools, log);
0297: else if ("ByContainer".equals(criteria))
0298: poolingStrategy = new PoolBySubject(mcf, poolJndiName,
0299: poolParams, noTxSeparatePools, log);
0300: else if ("ByApplication".equals(criteria))
0301: poolingStrategy = new PoolByCri(mcf, poolJndiName,
0302: poolParams, noTxSeparatePools, log);
0303: else if ("ByNothing".equals(criteria))
0304: poolingStrategy = new OnePool(mcf, poolJndiName,
0305: poolParams, noTxSeparatePools, log);
0306: else
0307: throw new DeploymentException("Unknown pooling criteria: "
0308: + criteria);
0309:
0310: }
0311:
0312: protected void stopService() throws Exception {
0313: if (poolingStrategy != null)
0314: poolingStrategy.shutdown();
0315:
0316: getServer().removeNotificationListener(
0317: managedConnectionFactoryName, this );
0318: poolingStrategy = null;
0319: }
0320:
0321: public void handleNotification(Notification notification,
0322: Object handback) {
0323: flush();
0324: }
0325:
0326: public static class SubPoolContext {
0327: /** The subpool */
0328: private InternalManagedConnectionPool subPool;
0329:
0330: /** The track by transaction transaction local */
0331: private TransactionLocal trackByTx;
0332:
0333: /**
0334: * Create a new SubPoolContext.
0335: *
0336: * @param tm the transaction manager
0337: * @param mcf the managed connection factory
0338: * @param clf the connection listener factory
0339: * @param subject the subject
0340: * @param cri the connection request info
0341: * @param poolParams the pool parameters
0342: * @param log the log
0343: */
0344: public SubPoolContext(TransactionManager tm,
0345: ManagedConnectionFactory mcf,
0346: ConnectionListenerFactory clf, Subject subject,
0347: ConnectionRequestInfo cri, PoolParams poolParams,
0348: Logger log) {
0349: subPool = new InternalManagedConnectionPool(mcf, clf,
0350: subject, cri, poolParams, log);
0351: if (tm != null)
0352: trackByTx = new TransactionLocal(tm);
0353: }
0354:
0355: /**
0356: * Get the sub pool
0357: *
0358: * @return the sub pool
0359: */
0360: public InternalManagedConnectionPool getSubPool() {
0361: return subPool;
0362: }
0363:
0364: /**
0365: * Get the track by transaction
0366: *
0367: * @return the transaction local
0368: */
0369: public TransactionLocal getTrackByTx() {
0370: return trackByTx;
0371: }
0372:
0373: /**
0374: * Initialize the subpool context
0375: */
0376: public void initialize() {
0377: subPool.initialize();
0378: }
0379: }
0380:
0381: /**
0382: * The base pool implementation
0383: */
0384: public abstract static class BasePool implements
0385: ManagedConnectionPool, PreFillPoolSupport {
0386: /** The subpools */
0387: private final Map subPools = new ConcurrentReaderHashMap();
0388:
0389: /** The managed connection factory */
0390: private final ManagedConnectionFactory mcf;
0391:
0392: /** The connection listener factory */
0393: private ConnectionListenerFactory clf;
0394:
0395: /** The pool parameters */
0396: protected final InternalManagedConnectionPool.PoolParams poolParams;
0397:
0398: /** Whether to use separate pools for transactional and non-transaction use */
0399: protected boolean noTxSeparatePools;
0400:
0401: /** The logger */
0402: private final Logger log;
0403:
0404: /** Is trace enabled */
0405: private boolean traceEnabled = false;
0406:
0407: /** The poolName */
0408: private String poolName;
0409:
0410: public BasePool(
0411: final ManagedConnectionFactory mcf,
0412: final InternalManagedConnectionPool.PoolParams poolParams,
0413: final boolean noTxSeparatePools, final Logger log) {
0414:
0415: this (mcf, null, poolParams, noTxSeparatePools, log);
0416:
0417: }
0418:
0419: /**
0420: * Create a new base pool
0421: *
0422: * @param mcf the managed connection factory
0423: * @param poolParams the pooling parameters
0424: * @param log the log
0425: */
0426: public BasePool(
0427: final ManagedConnectionFactory mcf,
0428: final String poolName,
0429: final InternalManagedConnectionPool.PoolParams poolParams,
0430: final boolean noTxSeparatePools, final Logger log) {
0431: this .mcf = mcf;
0432: this .poolParams = poolParams;
0433: this .noTxSeparatePools = noTxSeparatePools;
0434: this .log = log;
0435: this .traceEnabled = log.isTraceEnabled();
0436: this .poolName = poolName;
0437: }
0438:
0439: /**
0440: * Retrieve the key for this request
0441: *
0442: * @param subject the subject
0443: * @param cri the connection request information
0444: * @return the key
0445: * @throws ResourceException for any error
0446: */
0447: protected abstract Object getKey(Subject subject,
0448: ConnectionRequestInfo cri, boolean separateNoTx)
0449: throws ResourceException;
0450:
0451: public ManagedConnectionFactory getManagedConnectionFactory() {
0452: return mcf;
0453: }
0454:
0455: public void setConnectionListenerFactory(
0456: ConnectionListenerFactory clf) {
0457: this .clf = clf;
0458: }
0459:
0460: public ConnectionListener getConnection(
0461: Transaction trackByTransaction, Subject subject,
0462: ConnectionRequestInfo cri) throws ResourceException {
0463: // Determine the pool key for this request
0464: boolean separateNoTx = false;
0465: if (noTxSeparatePools)
0466: separateNoTx = clf.isTransactional();
0467: Object key = getKey(subject, cri, separateNoTx);
0468: SubPoolContext subPool = getSubPool(key, subject, cri);
0469:
0470: InternalManagedConnectionPool mcp = subPool.getSubPool();
0471:
0472: // Are we doing track by connection?
0473: TransactionLocal trackByTx = subPool.getTrackByTx();
0474:
0475: // Simple case
0476: if (trackByTransaction == null || trackByTx == null) {
0477: ConnectionListener cl = mcp.getConnection(subject, cri);
0478: if (traceEnabled)
0479: dump("Got connection from pool " + cl);
0480: return cl;
0481: }
0482:
0483: // Track by transaction
0484: try {
0485: trackByTx.lock(trackByTransaction);
0486: } catch (Throwable t) {
0487: JBossResourceException.rethrowAsResourceException(
0488: "Unable to get connection from the pool for tx="
0489: + trackByTransaction, t);
0490: }
0491: try {
0492: // Already got one
0493: ConnectionListener cl = (ConnectionListener) trackByTx
0494: .get(trackByTransaction);
0495: if (cl != null) {
0496: if (traceEnabled)
0497: dump("Previous connection tracked by transaction "
0498: + cl + " tx=" + trackByTransaction);
0499: return cl;
0500: }
0501: } finally {
0502: trackByTx.unlock(trackByTransaction);
0503: }
0504:
0505: // Need a new one for this transaction
0506: // This must be done outside the tx local lock, otherwise
0507: // the tx timeout won't work and get connection can do a lot of other work
0508: // with many opportunities for deadlocks.
0509: // Instead we do a double check after we got the transaction to see
0510: // whether another thread beat us to the punch.
0511: ConnectionListener cl = mcp.getConnection(subject, cri);
0512: if (traceEnabled)
0513: dump("Got connection from pool tracked by transaction "
0514: + cl + " tx=" + trackByTransaction);
0515:
0516: // Relock and check/set status
0517: try {
0518: trackByTx.lock(trackByTransaction);
0519: } catch (Throwable t) {
0520: mcp.returnConnection(cl, false);
0521: if (traceEnabled)
0522: dump("Had to return connection tracked by transaction "
0523: + cl
0524: + " tx="
0525: + trackByTransaction
0526: + " error=" + t.getMessage());
0527: JBossResourceException.rethrowAsResourceException(
0528: "Unable to get connection from the pool for tx="
0529: + trackByTransaction, t);
0530: }
0531: try {
0532: // Check we weren't racing with another transaction
0533: ConnectionListener other = (ConnectionListener) trackByTx
0534: .get(trackByTransaction);
0535: if (other != null) {
0536: mcp.returnConnection(cl, false);
0537: if (traceEnabled)
0538: dump("Another thread already got a connection tracked by transaction "
0539: + other + " tx=" + trackByTransaction);
0540: return other;
0541: }
0542:
0543: // This is the connection for this transaction
0544: cl.setTrackByTx(true);
0545: trackByTx.set(cl);
0546: if (traceEnabled)
0547: dump("Using connection from pool tracked by transaction "
0548: + cl + " tx=" + trackByTransaction);
0549: return cl;
0550: } finally {
0551: trackByTx.unlock(trackByTransaction);
0552: }
0553: }
0554:
0555: public boolean shouldPreFill() {
0556: return getPreFill();
0557: }
0558:
0559: public void prefill() {
0560:
0561: prefill(null, null, false);
0562:
0563: }
0564:
0565: public void prefill(boolean noTxSeperatePool) {
0566:
0567: prefill(null, null, noTxSeperatePool);
0568:
0569: }
0570:
0571: public void prefill(Subject subject, ConnectionRequestInfo cri,
0572: boolean noTxSeperatePool) {
0573: if (getPreFill()) {
0574:
0575: log
0576: .debug("Attempting to prefill pool for pool with jndi name"
0577: + poolName);
0578:
0579: try {
0580:
0581: getSubPool(getKey(subject, cri, noTxSeparatePools),
0582: subject, cri);
0583:
0584: } catch (Throwable t) {
0585: //No real need to throw here being that pool remains in the same state as before.
0586: log.error("Unable to prefill pool with jndi name"
0587: + getPoolName(), t);
0588:
0589: }
0590:
0591: }
0592:
0593: }
0594:
0595: public void returnConnection(ConnectionListener cl, boolean kill)
0596: throws ResourceException {
0597: cl.setTrackByTx(false);
0598: InternalManagedConnectionPool mcp = (InternalManagedConnectionPool) cl
0599: .getContext();
0600: mcp.returnConnection(cl, kill);
0601: if (traceEnabled)
0602: dump("Returning connection to pool " + cl);
0603: }
0604:
0605: /**
0606: * Return the inuse count
0607: *
0608: * @return the count
0609: */
0610: public int getInUseConnectionCount() {
0611: int count = 0;
0612: synchronized (subPools) {
0613: for (Iterator i = subPools.values().iterator(); i
0614: .hasNext();) {
0615: SubPoolContext subPool = (SubPoolContext) i.next();
0616: count += subPool.getSubPool()
0617: .getConnectionInUseCount();
0618: }
0619: }
0620: return count;
0621: }
0622:
0623: public int getConnectionCount() {
0624: int count = 0;
0625: synchronized (subPools) {
0626: for (Iterator i = subPools.values().iterator(); i
0627: .hasNext();) {
0628: SubPoolContext subPool = (SubPoolContext) i.next();
0629: count += subPool.getSubPool().getConnectionCount();
0630: }
0631: }
0632: return count;
0633: }
0634:
0635: public String getPoolName() {
0636: return poolName;
0637: }
0638:
0639: public boolean getPreFill() {
0640: return this .poolParams.prefill;
0641:
0642: }
0643:
0644: public int getConnectionCreatedCount() {
0645: int count = 0;
0646: synchronized (subPools) {
0647: for (Iterator i = subPools.values().iterator(); i
0648: .hasNext();) {
0649: SubPoolContext subPool = (SubPoolContext) i.next();
0650: count += subPool.getSubPool()
0651: .getConnectionCreatedCount();
0652: }
0653: }
0654: return count;
0655: }
0656:
0657: public int getConnectionDestroyedCount() {
0658: int count = 0;
0659: synchronized (subPools) {
0660: for (Iterator i = subPools.values().iterator(); i
0661: .hasNext();) {
0662: SubPoolContext subPool = (SubPoolContext) i.next();
0663: count += subPool.getSubPool()
0664: .getConnectionDestroyedCount();
0665: }
0666: }
0667: return count;
0668: }
0669:
0670: public long getAvailableConnectionCount() {
0671: long count = 0;
0672: synchronized (subPools) {
0673: if (subPools.size() == 0)
0674: return poolParams.maxSize;
0675: for (Iterator i = subPools.values().iterator(); i
0676: .hasNext();) {
0677: SubPoolContext subPool = (SubPoolContext) i.next();
0678: count += subPool.getSubPool()
0679: .getAvailableConnections();
0680: }
0681: }
0682: return count;
0683: }
0684:
0685: public int getMaxConnectionsInUseCount() {
0686: int count = 0;
0687: synchronized (subPools) {
0688: for (Iterator i = subPools.values().iterator(); i
0689: .hasNext();) {
0690: SubPoolContext subPool = (SubPoolContext) i.next();
0691: count += subPool.getSubPool()
0692: .getMaxConnectionsInUseCount();
0693: }
0694: }
0695: return count;
0696: }
0697:
0698: public void shutdown() {
0699: synchronized (subPools) {
0700: for (Iterator i = subPools.values().iterator(); i
0701: .hasNext();) {
0702: SubPoolContext subPool = (SubPoolContext) i.next();
0703: subPool.getSubPool().shutdown();
0704: }
0705: subPools.clear();
0706: }
0707: }
0708:
0709: public void flush() {
0710:
0711: for (Iterator i = subPools.values().iterator(); i.hasNext();) {
0712:
0713: SubPoolContext subPool = (SubPoolContext) i.next();
0714: subPool.getSubPool().shutdown();
0715: }
0716: subPools.clear();
0717:
0718: }
0719:
0720: /**
0721: * For testing
0722: */
0723: protected void shutdownWithoutClear() {
0724: synchronized (subPools) {
0725: for (Iterator i = subPools.values().iterator(); i
0726: .hasNext();) {
0727: SubPoolContext subPool = (SubPoolContext) i.next();
0728: subPool.getSubPool().shutdown();
0729: }
0730: }
0731: }
0732:
0733: /**
0734: * Get any transaction manager associated with the pool
0735: *
0736: * @return the transaction manager
0737: */
0738: protected TransactionManager getTransactionManager() {
0739: if (clf != null)
0740: return clf.getTransactionManagerInstance();
0741: else
0742: return null;
0743: }
0744:
0745: /**
0746: * Determine the correct pool for this request,
0747: * creates a new one when necessary
0748: *
0749: * @param key the key to the pool
0750: * @param subject the subject of the pool
0751: * @param cri the connection request info
0752: * @return the subpool context
0753: * @throws ResourceException for any error
0754: */
0755: protected SubPoolContext getSubPool(Object key,
0756: Subject subject, ConnectionRequestInfo cri)
0757: throws ResourceException {
0758: SubPoolContext subPool = (SubPoolContext) subPools.get(key);
0759: if (subPool == null) {
0760: TransactionManager tm = getTransactionManager();
0761: subPool = new SubPoolContext(tm, mcf, clf, subject,
0762: cri, poolParams, log);
0763: synchronized (subPools) {
0764: if (subPools.containsKey(key))
0765: subPool = (SubPoolContext) subPools.get(key);
0766: else {
0767: subPool.initialize();
0768: subPools.put(key, subPool);
0769: }
0770: }
0771: }
0772: return subPool;
0773: }
0774:
0775: protected SubPoolContext getSubPool(Object key) {
0776:
0777: return null;
0778: }
0779:
0780: /**
0781: * Dump the stats to the trace log
0782: *
0783: * @param info some context
0784: */
0785: private void dump(String info) {
0786: if (traceEnabled) {
0787: StringBuffer toLog = new StringBuffer(100);
0788: toLog.append(info).append(" [InUse/Available/Max]: [");
0789: toLog.append(this .getInUseConnectionCount())
0790: .append("/");
0791: toLog.append(this .getAvailableConnectionCount())
0792: .append("/");
0793: toLog.append(this .poolParams.maxSize);
0794: toLog.append("]");
0795: ;
0796: log.trace(toLog);
0797: }
0798: }
0799: }
0800:
0801: /**
0802: * Pooling by subject and connection request information
0803: */
0804: public static class PoolBySubjectAndCri extends BasePool {
0805:
0806: public PoolBySubjectAndCri(
0807: final ManagedConnectionFactory mcf,
0808: final InternalManagedConnectionPool.PoolParams poolParams,
0809: final boolean noTxSeparatePools, final Logger log) {
0810: this (mcf, null, poolParams, noTxSeparatePools, log);
0811:
0812: }
0813:
0814: public PoolBySubjectAndCri(
0815: final ManagedConnectionFactory mcf,
0816: final String poolName,
0817: final InternalManagedConnectionPool.PoolParams poolParams,
0818: final boolean noTxSeparatePools, final Logger log) {
0819: super (mcf, poolName, poolParams, noTxSeparatePools, log);
0820: }
0821:
0822: protected Object getKey(final Subject subject,
0823: final ConnectionRequestInfo cri,
0824: final boolean separateNoTx) throws ResourceException {
0825: return new SubjectCriKey(subject, cri, separateNoTx);
0826: }
0827:
0828: public void prefill() {
0829: prefill(null, null, false);
0830: }
0831:
0832: public void prefill(boolean noTxSeperatePool) {
0833: prefill(null, null, noTxSeperatePool);
0834: }
0835:
0836: public void prefill(Subject subject, ConnectionRequestInfo cri) {
0837: prefill(subject, cri, false);
0838:
0839: }
0840:
0841: public void prefill(Subject subject, ConnectionRequestInfo cri,
0842: boolean noTxSeperatePool) {
0843: if (getPreFill()) {
0844: log
0845: .warn("Prefill pool option was selected for pool with JNDI name "
0846: + getPoolName()
0847: + " that does not support this feature.");
0848: log
0849: .warn("Please verify your *-ds.xml file that corresponds with this resource and either remove the <prefill>true|false</prefill element or explicitly set this value to false.");
0850:
0851: }
0852: }
0853:
0854: }
0855:
0856: /**
0857: * Pool by subject and criteria
0858: */
0859: private static class SubjectCriKey {
0860: /** Identifies no subject */
0861: private static final Subject NOSUBJECT = new Subject();
0862:
0863: /** Identifies no connection request information */
0864: private static final Object NOCRI = new Object();
0865:
0866: /** The subject */
0867: private final Subject subject;
0868:
0869: /** The connection request information */
0870: private final Object cri;
0871:
0872: /** The cached hashCode */
0873: private int hashCode = Integer.MAX_VALUE;
0874:
0875: /** Separate no tx */
0876: private boolean separateNoTx;
0877:
0878: SubjectCriKey(Subject subject, ConnectionRequestInfo cri,
0879: boolean separateNoTx) {
0880: this .subject = (subject == null) ? NOSUBJECT : subject;
0881: this .cri = (cri == null) ? NOCRI : cri;
0882: this .separateNoTx = separateNoTx;
0883: }
0884:
0885: public int hashCode() {
0886: if (hashCode == Integer.MAX_VALUE)
0887: hashCode = SubjectActions.hashCode(subject)
0888: ^ cri.hashCode();
0889: return hashCode;
0890: }
0891:
0892: public boolean equals(Object obj) {
0893: if (this == obj)
0894: return true;
0895: if (obj == null || (obj instanceof SubjectCriKey) == false)
0896: return false;
0897: SubjectCriKey other = (SubjectCriKey) obj;
0898: return SubjectActions.equals(subject, other.subject)
0899: && cri.equals(other.cri)
0900: && separateNoTx == other.separateNoTx;
0901: }
0902: }
0903:
0904: /**
0905: * Pool by subject
0906: */
0907: public static class PoolBySubject extends BasePool {
0908: public PoolBySubject(
0909: final ManagedConnectionFactory mcf,
0910: final InternalManagedConnectionPool.PoolParams poolParams,
0911: final boolean noTxSeparatePools, final Logger log) {
0912: this (mcf, null, poolParams, noTxSeparatePools, log);
0913: }
0914:
0915: public PoolBySubject(
0916: final ManagedConnectionFactory mcf,
0917: final String poolJndiName,
0918: final InternalManagedConnectionPool.PoolParams poolParams,
0919: final boolean noTxSeparatePools, final Logger log) {
0920: super (mcf, poolJndiName, poolParams, noTxSeparatePools, log);
0921: }
0922:
0923: protected Object getKey(final Subject subject,
0924: final ConnectionRequestInfo cri, boolean separateNoTx) {
0925: return new SubjectKey(subject, separateNoTx);
0926: }
0927:
0928: public void prefill() {
0929: prefill(null, null, false);
0930: }
0931:
0932: public void prefill(boolean noTxSeperatePool) {
0933: prefill(null, null, noTxSeperatePool);
0934: }
0935:
0936: public void prefill(Subject subject, ConnectionRequestInfo cri) {
0937: prefill(subject, cri, false);
0938:
0939: }
0940:
0941: public void prefill(Subject subject, ConnectionRequestInfo cri,
0942: boolean noTxSeperatePool) {
0943: if (getPreFill()) {
0944: log
0945: .warn("Prefill pool option was selected for pool with JNDI name "
0946: + getPoolName()
0947: + " that does not support this feature.");
0948: log
0949: .warn("Please verify your *-ds.xml file that corresponds with this resource and either remove the <prefill>true|false</prefill element or explicitly set this value to false.");
0950:
0951: }
0952: }
0953: }
0954:
0955: /**
0956: * Pool by subject
0957: */
0958: private static class SubjectKey {
0959: /** Identifies no subject */
0960: private static final Subject NOSUBJECT = new Subject();
0961:
0962: /** The subject */
0963: private final Subject subject;
0964:
0965: /** Separate no tx */
0966: private boolean separateNoTx;
0967:
0968: /** The cached hashCode */
0969: private int hashCode = Integer.MAX_VALUE;
0970:
0971: SubjectKey(Subject subject, boolean separateNoTx) {
0972: this .subject = (subject == null) ? NOSUBJECT : subject;
0973: this .separateNoTx = separateNoTx;
0974: }
0975:
0976: public int hashCode() {
0977: if (hashCode == Integer.MAX_VALUE)
0978: hashCode = SubjectActions.hashCode(subject);
0979: return hashCode;
0980: }
0981:
0982: public boolean equals(Object obj) {
0983: if (this == obj)
0984: return true;
0985: if (obj == null || (obj instanceof SubjectKey) == false)
0986: return false;
0987: SubjectKey other = (SubjectKey) obj;
0988: return SubjectActions.equals(subject, other.subject)
0989: && separateNoTx == other.separateNoTx;
0990: }
0991:
0992: }
0993:
0994: /**
0995: * Pool by connection request information
0996: */
0997: public static class PoolByCri extends BasePool {
0998:
0999: public PoolByCri(
1000: final ManagedConnectionFactory mcf,
1001: final InternalManagedConnectionPool.PoolParams poolParams,
1002: final boolean noTxSeparatePools, final Logger log) {
1003: this (mcf, null, poolParams, noTxSeparatePools, log);
1004: }
1005:
1006: public PoolByCri(
1007: final ManagedConnectionFactory mcf,
1008: final String poolJndiName,
1009: final InternalManagedConnectionPool.PoolParams poolParams,
1010: final boolean noTxSeparatePools, final Logger log) {
1011: super (mcf, poolJndiName, poolParams, noTxSeparatePools, log);
1012: }
1013:
1014: protected Object getKey(final Subject subject,
1015: final ConnectionRequestInfo cri, boolean separateNoTx) {
1016: return new CriKey(cri, separateNoTx);
1017: }
1018:
1019: public void prefill() {
1020: prefill(null, null, false);
1021: }
1022:
1023: public void prefill(boolean noTxSeperatePool) {
1024: prefill(null, null, noTxSeperatePool);
1025: }
1026:
1027: public void prefill(Subject subject, ConnectionRequestInfo cri) {
1028: prefill(subject, cri, false);
1029:
1030: }
1031:
1032: public void prefill(Subject subject, ConnectionRequestInfo cri,
1033: boolean noTxSeperatePool) {
1034: if (getPreFill()) {
1035: log
1036: .warn("Prefill pool option was selected for pool with JNDI name "
1037: + getPoolName()
1038: + " that does not support this feature.");
1039: log
1040: .warn("Please verify your *-ds.xml file that corresponds with this resource and either remove the <prefill>true|false</prefill element or explicitly set this value to false.");
1041:
1042: }
1043: }
1044: }
1045:
1046: /**
1047: * Pool by subject and criteria
1048: */
1049: private static class CriKey {
1050: /** Identifies no connection request information */
1051: private static final Object NOCRI = new Object();
1052:
1053: /** The connection request information */
1054: private final Object cri;
1055:
1056: /** Separate no tx */
1057: private boolean separateNoTx;
1058:
1059: /** The cached hashCode */
1060: private int hashCode = Integer.MAX_VALUE;
1061:
1062: CriKey(ConnectionRequestInfo cri, boolean separateNoTx) {
1063: this .cri = (cri == null) ? NOCRI : cri;
1064: this .separateNoTx = separateNoTx;
1065: }
1066:
1067: public int hashCode() {
1068: if (hashCode == Integer.MAX_VALUE)
1069: hashCode = cri.hashCode();
1070: return hashCode;
1071: }
1072:
1073: public boolean equals(Object obj) {
1074: if (this == obj)
1075: return true;
1076: if (obj == null || (obj instanceof CriKey) == false)
1077: return false;
1078: CriKey other = (CriKey) obj;
1079: return cri.equals(other.cri)
1080: && separateNoTx == other.separateNoTx;
1081: }
1082: }
1083:
1084: /**
1085: * One pool
1086: */
1087: public static class OnePool extends BasePool {
1088:
1089: public OnePool(
1090: final ManagedConnectionFactory mcf,
1091: final InternalManagedConnectionPool.PoolParams poolParams,
1092: final boolean noTxSeparatePools, final Logger log) {
1093: this (mcf, null, poolParams, noTxSeparatePools, log);
1094: }
1095:
1096: public OnePool(
1097: final ManagedConnectionFactory mcf,
1098: final String poolName,
1099: final InternalManagedConnectionPool.PoolParams poolParams,
1100: final boolean noTxSeparatePools, final Logger log) {
1101: super (mcf, poolName, poolParams, noTxSeparatePools, log);
1102: }
1103:
1104: protected Object getKey(final Subject subject,
1105: final ConnectionRequestInfo cri, boolean separateNoTx) {
1106: if (separateNoTx)
1107: return Boolean.TRUE;
1108: else
1109: return Boolean.FALSE;
1110: }
1111:
1112: }
1113:
1114: private static class SubjectActions implements PrivilegedAction {
1115: Subject subject;
1116:
1117: Subject other;
1118:
1119: SubjectActions(Subject subject, Subject other) {
1120: this .subject = subject;
1121: this .other = other;
1122: }
1123:
1124: public Object run() {
1125: Object value = null;
1126: if (other == null)
1127: value = new Integer(subject.hashCode());
1128: else
1129: value = new Boolean(subject.equals(other));
1130: return value;
1131: }
1132:
1133: static int hashCode(Subject subject) {
1134: SubjectActions action = new SubjectActions(subject, null);
1135: Integer hash = (Integer) AccessController
1136: .doPrivileged(action);
1137: return hash.intValue();
1138: }
1139:
1140: static boolean equals(Subject subject, Subject other) {
1141: SubjectActions action = new SubjectActions(subject, other);
1142: Boolean equals = (Boolean) AccessController
1143: .doPrivileged(action);
1144: return equals.booleanValue();
1145: }
1146: }
1147: }
|