| /* |
| * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.enterprise.resource.pool; |
| |
| import com.sun.appserv.connectors.internal.api.ConnectorConstants.PoolType; |
| import com.sun.appserv.connectors.internal.api.ConnectorRuntime; |
| import com.sun.appserv.connectors.internal.api.PoolingException; |
| import com.sun.appserv.connectors.internal.spi.MCFLifecycleListener; |
| import com.sun.enterprise.connectors.ConnectorConnectionPool; |
| import com.sun.enterprise.connectors.ConnectorRegistry; |
| import com.sun.enterprise.deployment.ResourceReferenceDescriptor; |
| import com.sun.enterprise.resource.ClientSecurityInfo; |
| import com.sun.enterprise.resource.ResourceHandle; |
| import com.sun.enterprise.resource.ResourceSpec; |
| import com.sun.enterprise.resource.allocator.ResourceAllocator; |
| import com.sun.enterprise.resource.listener.PoolLifeCycle; |
| import com.sun.enterprise.resource.rm.*; |
| import com.sun.enterprise.transaction.api.JavaEETransaction; |
| import com.sun.enterprise.transaction.api.JavaEETransactionManager; |
| import com.sun.enterprise.util.i18n.StringManager; |
| import com.sun.logging.LogDomains; |
| import org.glassfish.api.invocation.ComponentInvocation; |
| import org.glassfish.api.invocation.ComponentInvocationHandler; |
| import org.glassfish.api.invocation.InvocationException; |
| import org.glassfish.resourcebase.resources.api.PoolInfo; |
| import org.jvnet.hk2.annotations.Service; |
| |
| import jakarta.inject.Inject; |
| import jakarta.inject.Provider; |
| import jakarta.resource.ResourceException; |
| import jakarta.resource.spi.ManagedConnection; |
| import jakarta.resource.spi.ManagedConnectionFactory; |
| import jakarta.resource.spi.RetryableUnavailableException; |
| import jakarta.transaction.Synchronization; |
| import jakarta.transaction.Transaction; |
| import javax.transaction.xa.XAResource; |
| import java.util.*; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * @author Tony Ng, Aditya Gore |
| */ |
| @Service |
| public class PoolManagerImpl extends AbstractPoolManager implements ComponentInvocationHandler { |
| |
| private final ConcurrentHashMap<PoolInfo, ResourcePool> poolTable; |
| protected final static StringManager localStrings = |
| StringManager.getManager(PoolManagerImpl.class); |
| |
| private ResourceManager resourceManager; |
| private ResourceManager sysResourceManager; |
| private ResourceManager noTxResourceManager; |
| private LazyEnlistableResourceManagerImpl lazyEnlistableResourceManager; |
| |
| private static Logger _logger = null; |
| |
| @Inject |
| private Provider<ConnectorRuntime> connectorRuntimeProvider; |
| |
| private ConnectorRuntime runtime; |
| |
| static { |
| _logger = LogDomains.getLogger(PoolManagerImpl.class, LogDomains.RSR_LOGGER); |
| } |
| private PoolLifeCycle listener; |
| |
| public PoolManagerImpl() { |
| this.poolTable = new ConcurrentHashMap<PoolInfo, ResourcePool>(); |
| resourceManager = new ResourceManagerImpl(); |
| sysResourceManager = new SystemResourceManagerImpl(); |
| noTxResourceManager = new NoTxResourceManagerImpl(); |
| lazyEnlistableResourceManager = new LazyEnlistableResourceManagerImpl(); |
| } |
| |
| public void createEmptyConnectionPool(PoolInfo poolInfo, |
| PoolType pt, Hashtable env) throws PoolingException { |
| //Create and initialise the connection pool |
| createAndInitPool(poolInfo, pt, env); |
| if (listener != null) { |
| try { |
| listener.poolCreated(poolInfo); |
| } catch (Exception ex) { |
| if(_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Exception thrown on pool listener"); |
| } |
| } |
| } |
| //notify mcf-create |
| ManagedConnectionFactory mcf = ConnectorRegistry.getInstance().getManagedConnectionFactory(poolInfo); |
| if(mcf != null){ |
| if(mcf instanceof MCFLifecycleListener){ |
| ((MCFLifecycleListener)mcf).mcfCreated(); |
| } |
| } |
| } |
| |
| /** |
| * Create and initialize pool if not created already. |
| * |
| * @param poolInfo Name of the pool to be created |
| * @param pt - PoolType |
| * @return ResourcePool - newly created pool |
| * @throws PoolingException when unable to create/initialize pool |
| */ |
| private ResourcePool createAndInitPool(final PoolInfo poolInfo, PoolType pt, Hashtable env) |
| throws PoolingException { |
| ResourcePool pool = getPool(poolInfo); |
| if (pool == null) { |
| pool = ResourcePoolFactoryImpl.newInstance(poolInfo, pt, env); |
| addPool(pool); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, "Created connection pool and added it to PoolManager :" + pool); |
| } |
| } |
| return pool; |
| } |
| |
| |
| // invoked by DataSource objects to obtain a connection |
| public Object getResource(ResourceSpec spec, ResourceAllocator alloc, ClientSecurityInfo info) |
| throws PoolingException, RetryableUnavailableException { |
| |
| Transaction tran = null; |
| boolean transactional = alloc.isTransactional(); |
| |
| if (transactional) { |
| tran = getResourceManager(spec).getTransaction(); |
| } |
| |
| ResourceHandle handle = |
| getResourceFromPool(spec, alloc, info, tran); |
| |
| if (!handle.supportsLazyAssociation()) { |
| spec.setLazyAssociatable(false); |
| } |
| |
| if (spec.isLazyAssociatable() && |
| spec.getConnectionToAssociate() != null) { |
| //If getConnectionToAssociate returns a connection that means |
| //we need to associate a new connection with it |
| try { |
| Object connection = spec.getConnectionToAssociate(); |
| ManagedConnection dmc |
| = (ManagedConnection) handle.getResource(); |
| dmc.associateConnection(connection); |
| } catch (ResourceException e) { |
| putbackDirectToPool(handle, spec.getPoolInfo()); |
| PoolingException pe = new PoolingException( |
| e.getMessage()); |
| pe.initCause(e); |
| throw pe; |
| } |
| } |
| |
| //If the ResourceAdapter does not support lazy enlistment |
| //we cannot either |
| if (!handle.supportsLazyEnlistment()) { |
| spec.setLazyEnlistable(false); |
| } |
| |
| handle.setResourceSpec(spec); |
| |
| try { |
| if (handle.getResourceState().isUnenlisted()) { |
| //The spec being used here is the spec with the updated |
| //lazy enlistment info |
| //Here's the real place where we care about the correct |
| //resource manager (which in turn depends upon the ResourceSpec) |
| //and that's because if lazy enlistment needs to be done |
| //we need to get the LazyEnlistableResourceManager |
| getResourceManager(spec).enlistResource(handle); |
| } |
| } catch (Exception e) { |
| //In the rare cases where enlistResource throws exception, we |
| //should return the resource to the pool |
| putbackDirectToPool(handle, spec.getPoolInfo()); |
| _logger.log(Level.WARNING, "poolmgr.err_enlisting_res_in_getconn", |
| spec.getPoolInfo()); |
| logFine("rm.enlistResource threw Exception. Returning resource to pool"); |
| //and rethrow the exception |
| throw new PoolingException(e); |
| |
| } |
| |
| return handle.getUserConnection(); |
| } |
| |
| public void putbackDirectToPool(ResourceHandle h, PoolInfo poolInfo) { |
| // notify pool |
| if (poolInfo != null) { |
| ResourcePool pool = poolTable.get(poolInfo); |
| if (pool != null) { |
| pool.resourceClosed(h); |
| } |
| } |
| } |
| |
| public ResourceHandle getResourceFromPool(ResourceSpec spec, ResourceAllocator alloc, ClientSecurityInfo info, |
| Transaction tran) throws PoolingException, RetryableUnavailableException { |
| ResourcePool pool = getPool(spec.getPoolInfo()); |
| // pool.getResource() has been modified to: |
| // - be able to create new resource if needed |
| // - block the caller until a resource is acquired or |
| // the max-wait-time expires |
| return pool.getResource(spec, alloc, tran); |
| } |
| |
| /** |
| * Switch on matching in the pool. |
| * |
| * @param poolInfo Name of the pool |
| */ |
| public boolean switchOnMatching(PoolInfo poolInfo) { |
| ResourcePool pool = getPool(poolInfo); |
| |
| if (pool != null) { |
| pool.switchOnMatching(); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| |
| /* private ConcurrentHashMap<PoolInfo, ResourcePool> getPoolTable() { |
| return poolTable; |
| } |
| */ |
| |
| private void addPool(ResourcePool pool) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.fine("Adding pool " + pool.getPoolInfo() + "to pooltable"); |
| } |
| poolTable.put(pool.getPoolStatus().getPoolInfo(), pool); |
| } |
| |
| |
| private ResourceManager getResourceManager(ResourceSpec spec) { |
| if (spec.isNonTx()) { |
| logFine("Returning noTxResourceManager"); |
| return noTxResourceManager; |
| } else if (spec.isPM()) { |
| logFine("Returning sysResourceManager"); |
| return sysResourceManager; |
| } else if (spec.isLazyEnlistable()) { |
| logFine("Returning LazyEnlistableResourceManager"); |
| return lazyEnlistableResourceManager; |
| } else { |
| logFine("Returning resourceManager"); |
| return resourceManager; |
| } |
| } |
| |
| private void addSyncListener(Transaction tran) { |
| Synchronization sync = new SynchronizationListener(tran); |
| try { |
| tran.registerSynchronization(sync); |
| } catch (Exception ex) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.fine("Error adding syncListener : " |
| + (ex.getMessage() != null ? ex.getMessage() : " ")); |
| } |
| } |
| } |
| |
| // called by EJB Transaction Manager |
| public void transactionCompleted(Transaction tran, int status) |
| throws IllegalStateException { |
| |
| Iterator iter = ((JavaEETransaction) tran).getAllParticipatingPools().iterator(); |
| while (iter.hasNext()) { |
| ResourcePool pool = getPool((PoolInfo) iter.next()); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.fine("calling transactionCompleted on " + pool.getPoolInfo()); |
| } |
| pool.transactionCompleted(tran, status); |
| } |
| } |
| |
| public void resourceEnlisted(Transaction tran, com.sun.appserv.connectors.internal.api.ResourceHandle h) |
| throws IllegalStateException { |
| ResourceHandle res = (ResourceHandle) h; |
| |
| PoolInfo poolInfo = res.getResourceSpec().getPoolInfo(); |
| try { |
| JavaEETransaction j2eeTran = (JavaEETransaction) tran; |
| if (poolInfo != null && j2eeTran.getResources(poolInfo) == null) { |
| addSyncListener(tran); |
| } |
| } catch (ClassCastException e) { |
| addSyncListener(tran); |
| } |
| if (poolInfo != null) { |
| ResourcePool pool = getPool(poolInfo); |
| if (pool != null) { |
| pool.resourceEnlisted(tran, res); |
| } |
| } |
| } |
| |
| /** |
| * This method gets called by the LazyEnlistableConnectionManagerImpl when |
| * a connection needs enlistment, i.e on use of a Statement etc. |
| */ |
| public void lazyEnlist(ManagedConnection mc) throws ResourceException { |
| lazyEnlistableResourceManager.lazyEnlist(mc); |
| } |
| |
| |
| private ConnectorRuntime getConnectorRuntime() { |
| if(runtime == null){ |
| runtime = connectorRuntimeProvider.get(); |
| } |
| return runtime; |
| } |
| |
| public void registerResource(com.sun.appserv.connectors.internal.api.ResourceHandle handle) throws PoolingException { |
| ResourceHandle h = (ResourceHandle)handle; |
| ResourceManager rm = getResourceManager(h.getResourceSpec()); |
| rm.registerResource(h); |
| } |
| |
| public void registerPoolLifeCycleListener(PoolLifeCycle poolListener) { |
| listener = poolListener; |
| } |
| |
| public void unregisterPoolLifeCycleListener() { |
| listener = null; |
| } |
| |
| public void unregisterResource(com.sun.appserv.connectors.internal.api.ResourceHandle resource, int xaresFlag) { |
| ResourceHandle h = (ResourceHandle)resource; |
| ResourceManager rm = getResourceManager(h.getResourceSpec()); |
| rm.unregisterResource(h, xaresFlag); |
| } |
| |
| public void resourceClosed(ResourceHandle resource) { |
| ResourceManager rm = getResourceManager(resource.getResourceSpec()); |
| rm.delistResource(resource, XAResource.TMSUCCESS); |
| putbackResourceToPool(resource, false); |
| } |
| |
| public void badResourceClosed(ResourceHandle resource) { |
| ResourceManager rm = getResourceManager(resource.getResourceSpec()); |
| rm.delistResource(resource, XAResource.TMSUCCESS); |
| putbackBadResourceToPool(resource); |
| } |
| |
| public void resourceErrorOccurred(ResourceHandle resource) { |
| putbackResourceToPool(resource, true); |
| } |
| |
| public void resourceAbortOccurred(ResourceHandle resource) { |
| ResourceManager rm = getResourceManager(resource.getResourceSpec()); |
| rm.delistResource(resource, XAResource.TMSUCCESS); |
| putbackResourceToPool(resource, true); |
| } |
| |
| public void putbackBadResourceToPool(ResourceHandle h) { |
| |
| // notify pool |
| PoolInfo poolInfo = h.getResourceSpec().getPoolInfo(); |
| if (poolInfo != null) { |
| ResourcePool pool = poolTable.get(poolInfo); |
| if (pool != null) { |
| synchronized (pool) { |
| pool.resourceClosed(h); |
| h.setConnectionErrorOccurred(); |
| pool.resourceErrorOccurred(h); |
| } |
| } |
| } |
| } |
| |
| public void putbackResourceToPool(ResourceHandle h, |
| boolean errorOccurred) { |
| |
| // notify pool |
| PoolInfo poolInfo = h.getResourceSpec().getPoolInfo(); |
| if (poolInfo != null) { |
| ResourcePool pool = poolTable.get(poolInfo); |
| if (pool != null) { |
| if (errorOccurred) { |
| pool.resourceErrorOccurred(h); |
| } else { |
| pool.resourceClosed(h); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Use this method if the string being passed does not <br> |
| * involve multiple concatenations<br> |
| * Avoid using this method in exception-catch blocks as they |
| * are not frequently executed <br> |
| * |
| * @param msg String |
| */ |
| private void logFine(String msg) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.fine(msg); |
| } |
| } |
| |
| public ResourcePool getPool(PoolInfo poolInfo) { |
| if (poolInfo == null) { |
| return null; |
| } |
| return poolTable.get(poolInfo); |
| } |
| |
| /** |
| * Kill the pool with the specified pool name |
| * |
| * @param poolInfo - The name of the pool to kill |
| */ |
| public void killPool(PoolInfo poolInfo) { |
| |
| //empty the pool |
| //and remove from poolTable |
| ResourcePool pool = poolTable.get(poolInfo); |
| if (pool != null) { |
| pool.cancelResizerTask(); |
| pool.emptyPool(); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.fine("Removing pool " + pool + " from pooltable"); |
| } |
| poolTable.remove(poolInfo); |
| if (listener != null){ |
| listener.poolDestroyed(poolInfo); |
| } |
| |
| //notify mcf-destroy |
| ManagedConnectionFactory mcf = ConnectorRegistry.getInstance().getManagedConnectionFactory(poolInfo); |
| if(mcf != null){ |
| if(mcf instanceof MCFLifecycleListener){ |
| ((MCFLifecycleListener)mcf).mcfDestroyed(); |
| } |
| } |
| } |
| } |
| |
| public void killFreeConnectionsInPools() { |
| Iterator pools = poolTable.values().iterator(); |
| logFine("Killing all free connections in pools"); |
| while (pools.hasNext()) { |
| ResourcePool pool = (ResourcePool) pools.next(); |
| if (pool != null) { |
| PoolInfo poolInfo = pool.getPoolStatus().getPoolInfo(); |
| try { |
| if (poolInfo != null) { |
| ResourcePool poolToKill = poolTable.get(poolInfo); |
| if (poolToKill != null) { |
| pool.emptyFreeConnectionsInPool(); |
| } |
| if (_logger.isLoggable(Level.FINE)){ |
| _logger.fine("Now killing free connections in pool : " + poolInfo); |
| } |
| } |
| } catch (Exception e) { |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.fine("Error killing pool : " + poolInfo + " :: " |
| + (e.getMessage() != null ? e.getMessage() : " ")); |
| } |
| } |
| } |
| } |
| } |
| |
| public ResourceReferenceDescriptor getResourceReference(String jndiName, String logicalName) { |
| Set descriptors = getConnectorRuntime().getResourceReferenceDescriptor(); |
| List matchingRefs = new ArrayList(); |
| |
| if (descriptors != null) { |
| for (Object descriptor : descriptors) { |
| ResourceReferenceDescriptor ref = |
| (ResourceReferenceDescriptor) descriptor; |
| String name = ref.getJndiName(); |
| if (jndiName.equals(name)) { |
| matchingRefs.add(ref); |
| } |
| } |
| } |
| if(matchingRefs.size()==1){ |
| return (ResourceReferenceDescriptor)matchingRefs.get(0); |
| }else if(matchingRefs.size() > 1){ |
| Iterator it = matchingRefs.iterator(); |
| while(it.hasNext()){ |
| ResourceReferenceDescriptor rrd = (ResourceReferenceDescriptor)it.next(); |
| String refName = rrd.getName(); |
| if(refName != null && logicalName != null){ |
| refName = getJavaName(refName); |
| if(refName.equals(getJavaName(logicalName))){ |
| return rrd; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static String getJavaName(String name){ |
| if(name == null || name.startsWith("java:")){ |
| return name; |
| }else { |
| //by default, scope is "comp" |
| return "java:comp/env/" + name; |
| } |
| } |
| |
| public void beforePreInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, |
| ComponentInvocation newInv) throws InvocationException { |
| //no-op |
| } |
| |
| public void afterPreInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, |
| ComponentInvocation curInv) throws InvocationException { |
| //no-op |
| } |
| |
| public void beforePostInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, |
| ComponentInvocation curInv) throws InvocationException { |
| //no-op |
| } |
| |
| /* |
| * Called by the InvocationManager at methodEnd. This method |
| * will disassociate ManagedConnection instances from Connection |
| * handles if the ResourceAdapter supports that. |
| */ |
| public void afterPostInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, |
| ComponentInvocation curInv) throws InvocationException { |
| postInvoke(curInv); |
| } |
| |
| private void postInvoke(ComponentInvocation curInv){ |
| |
| ComponentInvocation invToUse = curInv; |
| /* |
| if(invToUse == null){ |
| invToUse = getConnectorRuntime().getInvocationManager().getCurrentInvocation(); |
| } |
| */ |
| if (invToUse == null) { |
| return; |
| } |
| |
| Object comp = invToUse.getInstance(); |
| |
| if (comp == null) { |
| return; |
| } |
| |
| handleLazilyAssociatedConnectionPools(comp, invToUse); |
| } |
| |
| /** |
| * If the connections associated with the component are lazily-associatable, dissociate them. |
| * @param comp Component that acquired connections |
| * @param invToUse component invocation |
| */ |
| private void handleLazilyAssociatedConnectionPools(Object comp, ComponentInvocation invToUse) { |
| JavaEETransactionManager tm = getConnectorRuntime().getTransactionManager(); |
| List list = tm.getExistingResourceList(comp, invToUse); |
| if (list == null) { |
| //For invocations of asadmin the ComponentInvocation does not |
| //have any resources and hence the existingResourcesList is null |
| return; |
| } |
| |
| if (list.size() == 0) return; |
| |
| ResourceHandle[] handles = new ResourceHandle[list.size()]; |
| handles = (ResourceHandle[]) list.toArray(handles); |
| for (ResourceHandle h : handles) { |
| |
| if(h==null) { |
| _logger.log(Level.WARNING, "lazy_association.lazy_association_resource_handle"); |
| } |
| else { |
| ResourceSpec spec = h.getResourceSpec(); |
| if(spec == null) { |
| _logger.log(Level.WARNING, "lazy_association.lazy_association_resource_spec"); |
| } else { |
| if (spec.isLazyAssociatable()) { |
| //In this case we are assured that the managedConnection is |
| //of type DissociatableManagedConnection |
| if(h.getResource()!=null) { |
| jakarta.resource.spi.DissociatableManagedConnection mc = |
| (jakarta.resource.spi.DissociatableManagedConnection) h.getResource(); |
| if (h.isEnlisted()) { |
| getResourceManager(spec).delistResource( |
| h, XAResource.TMSUCCESS); |
| } |
| try { |
| mc.dissociateConnections(); |
| } catch (ResourceException re) { |
| InvocationException ie = new InvocationException( |
| re.getMessage()); |
| ie.initCause(re); |
| throw ie; |
| } finally { |
| if (h.getResourceState().isBusy()) { |
| putbackDirectToPool(h, spec.getPoolInfo()); |
| } |
| } |
| } else { |
| _logger.log(Level.WARNING, "lazy_association.lazy_association_resource"); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| class SynchronizationListener implements Synchronization { |
| |
| private Transaction tran; |
| |
| SynchronizationListener(Transaction tran) { |
| this.tran = tran; |
| } |
| |
| public void afterCompletion(int status) { |
| try { |
| transactionCompleted(tran, status); |
| } catch (Exception ex) { |
| if(_logger.isLoggable(Level.FINE)) { |
| _logger.fine("Exception in afterCompletion : " + |
| (ex.getMessage() != null ? ex.getMessage() : " ")); |
| } |
| } |
| } |
| |
| public void beforeCompletion() { |
| // do nothing |
| } |
| } |
| |
| public void reconfigPoolProperties(ConnectorConnectionPool ccp) throws PoolingException { |
| PoolInfo poolInfo = ccp.getPoolInfo(); |
| ResourcePool pool = getPool( poolInfo ); |
| if (pool != null ) { |
| pool.reconfigurePool( ccp ); |
| } |
| } |
| |
| /** |
| * Flush Connection pool by reinitializing the connections |
| * established in the pool. |
| * @param poolInfo |
| * @throws com.sun.appserv.connectors.internal.api.PoolingException |
| */ |
| public boolean flushConnectionPool(PoolInfo poolInfo) throws PoolingException { |
| boolean result = false; |
| ResourcePool pool = getPool( poolInfo ); |
| if(pool != null) { |
| result = pool.flushConnectionPool(); |
| } else { |
| _logger.log(Level.WARNING, "poolmgr.flush_noop_pool_not_initialized", poolInfo); |
| String exString = localStrings.getString("poolmgr.flush_noop_pool_not_initialized", |
| poolInfo.toString()); |
| throw new PoolingException(exString); |
| } |
| return result; |
| } |
| |
| /** |
| * Get connection pool status. |
| * @param poolInfo |
| * @return |
| */ |
| public PoolStatus getPoolStatus(PoolInfo poolInfo) { |
| ResourcePool pool = poolTable.get(poolInfo); |
| if(pool != null) { |
| return pool.getPoolStatus(); |
| } else { |
| //TODO log exception |
| return null; |
| } |
| } |
| } |