| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You 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. |
| */ |
| package org.apache.geode.internal.datasource; |
| |
| import java.util.Map; |
| |
| import javax.resource.ResourceException; |
| import javax.resource.spi.ConnectionEvent; |
| import javax.resource.spi.ConnectionEventListener; |
| import javax.resource.spi.ConnectionManager; |
| import javax.resource.spi.ConnectionRequestInfo; |
| import javax.resource.spi.ManagedConnection; |
| import javax.resource.spi.ManagedConnectionFactory; |
| import javax.security.auth.Subject; |
| import javax.transaction.RollbackException; |
| import javax.transaction.SystemException; |
| import javax.transaction.Transaction; |
| import javax.transaction.TransactionManager; |
| import javax.transaction.xa.XAResource; |
| |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.internal.jndi.JNDIInvoker; |
| import org.apache.geode.internal.jta.TransactionManagerImpl; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| |
| /** |
| * This class implements a connection pool manager for managed connections (JCA) for transactional |
| * and non-transactional resource connection. Implements ConnectionManager interface. QoS |
| * (Transaction, Security etc is taken into account while allocating a connection). Security related |
| * features are remaining. |
| * |
| */ |
| public class JCAConnectionManagerImpl implements ConnectionManager, ConnectionEventListener { |
| |
| private static final Logger logger = LogService.getLogger(); |
| |
| private static final long serialVersionUID = 5281512854051120661L; |
| protected transient TransactionManager transManager; |
| protected ConnectionPoolCache mannPoolCache; |
| protected ConnectionRequestInfo conReqInfo = null; |
| protected Subject subject = null; |
| protected Map xaResourcesMap = new java.util.HashMap(); |
| protected boolean isActive = true; |
| |
| /* |
| * Constructor. |
| * |
| */ |
| public JCAConnectionManagerImpl(ManagedConnectionFactory mcf, |
| ConfiguredDataSourceProperties configs) { |
| // Get the security info and form the Subject |
| // Initialize the Pool. |
| try { |
| isActive = true; |
| mannPoolCache = new ManagedPoolCacheImpl(mcf, null, null, this, configs); |
| } catch (Exception ex) { |
| logger.fatal(String.format( |
| "JCAConnectionManagerImpl::Constructor: An exception was caught while initialising due to %s", |
| ex.getLocalizedMessage()), |
| ex); |
| } |
| } |
| |
| /* |
| * allocates a ManagedConnection from the ConnectionPool or creates a new |
| * ManagedConnection. @param javax.resource.spi.ManagedConnectionFactory |
| * |
| * @param javax.resource.spi.ConnectionRequestInfo |
| * |
| */ |
| @Override |
| public Object allocateConnection(ManagedConnectionFactory mcf, ConnectionRequestInfo reqInfo) |
| throws ResourceException { |
| if (!isActive) { |
| throw new ResourceException( |
| "JCAConnectionManagerImpl::allocateConnection::No valid Connection available"); |
| } |
| ManagedConnection conn = null; |
| try { |
| conn = (ManagedConnection) mannPoolCache.getPooledConnectionFromPool(); |
| } catch (PoolException ex) { |
| // ex.printStackTrace(); |
| throw new ResourceException( |
| String.format( |
| "JCAConnectionManagerImpl:: allocateConnection : in getting connection from pool due to %s", |
| ex.getMessage()), |
| ex); |
| } |
| // Check if a connection is having a transactional context |
| // if a transactional context is used, get the XA Resource |
| // from the ManagedConnection and register it with the |
| // Transaction Manager. |
| try { |
| synchronized (this) { |
| if (transManager == null) { |
| transManager = JNDIInvoker.getTransactionManager(); |
| } |
| } |
| Transaction txn = transManager.getTransaction(); |
| if (txn != null) { |
| // Check if Data Source provides XATransaction |
| // if(configs.getTransactionType = "XATransaction") |
| XAResource xar = conn.getXAResource(); |
| txn.enlistResource(xar); |
| // Asif :Add in the Map after successful registration of XAResource |
| xaResourcesMap.put(conn, xar); |
| // else throw a resource exception |
| } |
| } catch (RollbackException ex) { |
| throw new ResourceException( |
| String.format("JCAConnectionManagerImpl:: allocateConnection : in transaction due to %s", |
| ex.getMessage()), |
| ex); |
| } catch (SystemException ex) { |
| throw new ResourceException( |
| String.format( |
| "JCAConnectionManagerImpl:: allocateConnection :system exception due to %s", |
| ex.getMessage()), |
| ex); |
| } |
| return conn.getConnection(subject, reqInfo); |
| } |
| |
| /** |
| * CallBack for Connection Error. |
| * |
| * @param event ConnectionEvent |
| */ |
| @Override |
| public void connectionErrorOccurred(ConnectionEvent event) { |
| if (isActive) { |
| // If its an XAConnection |
| ManagedConnection conn = (ManagedConnection) event.getSource(); |
| XAResource xar = (XAResource) xaResourcesMap.get(conn); |
| xaResourcesMap.remove(conn); |
| TransactionManagerImpl transManager = TransactionManagerImpl.getTransactionManager(); |
| try { |
| Transaction txn = transManager.getTransaction(); |
| if (txn != null && xar != null) |
| txn.delistResource(xar, XAResource.TMSUCCESS); |
| } catch (SystemException se) { |
| se.printStackTrace(); |
| } |
| try { |
| mannPoolCache.expirePooledConnection(conn); |
| // mannPoolCache.destroyPooledConnection(conn); |
| } catch (Exception ex) { |
| String exception = |
| "JCAConnectionManagerImpl::connectionErrorOccurred: Exception occurred due to " + ex; |
| if (logger.isDebugEnabled()) { |
| logger.debug(exception, ex); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Callback for Connection Closed. |
| * |
| * @param event ConnectionEvent Object. |
| */ |
| @Override |
| public void connectionClosed(ConnectionEvent event) { |
| if (isActive) { |
| ManagedConnection conn = (ManagedConnection) event.getSource(); |
| XAResource xar = null; |
| if (xaResourcesMap.get(conn) != null) |
| xar = (XAResource) xaResourcesMap.get(conn); |
| xaResourcesMap.remove(conn); |
| try { |
| Transaction txn = transManager.getTransaction(); |
| if (txn != null && xar != null) { |
| txn.delistResource(xar, XAResource.TMSUCCESS); |
| } |
| } catch (Exception se) { |
| String exception = |
| "JCAConnectionManagerImpl::connectionClosed: Exception occurred due to " + se; |
| if (logger.isDebugEnabled()) { |
| logger.debug(exception, se); |
| } |
| } |
| mannPoolCache.returnPooledConnectionToPool(conn); |
| } |
| } |
| |
| /* |
| * Local Transactions are not supported by Gemfire cache. |
| */ |
| @Override |
| public void localTransactionCommitted(ConnectionEvent arg0) { |
| // do nothing. |
| } |
| |
| /* |
| * Local Transactions are not supported by Gemfire cache. |
| */ |
| @Override |
| public void localTransactionRolledback(ConnectionEvent arg0) { |
| // do nothing. |
| } |
| |
| /* |
| * Local Transactions are not supported by Gemfire cache. |
| */ |
| @Override |
| public void localTransactionStarted(ConnectionEvent arg0) { |
| // do nothing |
| } |
| |
| public void clearUp() { |
| isActive = false; |
| mannPoolCache.clearUp(); |
| } |
| } |