@Override
  protected Object doGetTransaction() {
    JpaTransactionObject txObject = new JpaTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed());

    EntityManagerHolder emHolder =
        (EntityManagerHolder)
            TransactionSynchronizationManager.getResource(getEntityManagerFactory());
    if (emHolder != null) {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Found thread-bound EntityManager ["
                + emHolder.getEntityManager()
                + "] for JPA transaction");
      }
      txObject.setEntityManagerHolder(emHolder, false);
    }

    if (getDataSource() != null) {
      ConnectionHolder conHolder =
          (ConnectionHolder) TransactionSynchronizationManager.getResource(getDataSource());
      txObject.setConnectionHolder(conHolder);
    }

    return txObject;
  }
  public void testLoggingAutoActivate() throws Throwable {
    assertFalse(
        "Auto-logging of misuse of the wrapper should be off",
        BorrowedConnectionProxy.isCallStackTraced());

    UserTransaction txn = transactionService.getUserTransaction();
    Connection connection;
    try {
      txn.begin();
      // Dig the proxy out of ... somewhere
      ConnectionHolder conHolder =
          (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
      connection = conHolder.getConnection();
      txn.commit();
    } catch (Throwable e) {
      try {
        txn.rollback();
      } catch (Throwable ee) {
      }
      throw e;
    }
    // Now mess with the connection, which is protected by the Hibernate wrapper
    try {
      connection.commit();
      fail("Use case should have generated a HibernateException");
    } catch (HibernateException e) {
      // Expected
    }
    assertTrue(
        "Auto-logging of misuse of the wrapper should now be on",
        BorrowedConnectionProxy.isCallStackTraced());

    // Now start a new transaction and we should see logging
    txn = transactionService.getUserTransaction();
    try {
      txn.begin();
      // Dig the proxy out of ... somewhere
      ConnectionHolder conHolder =
          (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
      connection = conHolder.getConnection();
      txn.commit();
    } catch (Throwable e) {
      try {
        txn.rollback();
      } catch (Throwable ee) {
      }
      throw e;
    }
    // Now mess with the connection, which is protected by the Hibernate wrapper
    try {
      connection.commit();
      fail("Use case should have generated a HibernateException");
    } catch (HibernateException e) {
      // Expected
    }
    // Check for error logs
  }
 /** Retrieve the Spring-managed Session for the current thread, if any. */
 public Session currentSession() throws HibernateException {
   Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
   if (value instanceof Session) {
     return (Session) value;
   } else if (value instanceof SessionHolder) {
     SessionHolder sessionHolder = (SessionHolder) value;
     Session session = sessionHolder.getSession();
     if (TransactionSynchronizationManager.isSynchronizationActive()
         && !sessionHolder.isSynchronizedWithTransaction()) {
       TransactionSynchronizationManager.registerSynchronization(
           new SpringSessionSynchronization(sessionHolder, this.sessionFactory));
       sessionHolder.setSynchronizedWithTransaction(true);
       // Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
       // with FlushMode.MANUAL, which needs to allow flushing within the transaction.
       FlushMode flushMode = session.getFlushMode();
       if (FlushMode.isManualFlushMode(flushMode)
           && !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
         session.setFlushMode(FlushMode.AUTO);
         sessionHolder.setPreviousFlushMode(flushMode);
       }
     }
     return session;
   } else if (this.jtaSessionContext != null) {
     Session session = this.jtaSessionContext.currentSession();
     if (TransactionSynchronizationManager.isSynchronizationActive()) {
       TransactionSynchronizationManager.registerSynchronization(
           new SpringFlushSynchronization(session));
     }
     return session;
   } else {
     throw new HibernateException("No Session found for current thread");
   }
 }
Beispiel #4
0
  /**
   * Get a TopLink Session for the given SessionFactory. Is aware of and will return any existing
   * corresponding Session bound to the current thread, for example when using
   * TopLinkTransactionManager. Will create a new Session otherwise, if allowCreate is true.
   *
   * <p>Same as <code>getSession</code>, but throwing the original TopLinkException.
   *
   * @param sessionFactory TopLink SessionFactory to create the session with
   * @param allowCreate if a non-transactional Session should be created when no transactional
   *     Session can be found for the current thread
   * @return the TopLink Session
   * @throws TopLinkException if the Session couldn't be created
   * @throws IllegalStateException if no thread-bound Session found and allowCreate false
   * @see #releaseSession
   * @see TopLinkTemplate
   */
  public static Session doGetSession(SessionFactory sessionFactory, boolean allowCreate)
      throws TopLinkException, IllegalStateException {

    Assert.notNull(sessionFactory, "No SessionFactory specified");

    SessionHolder sessionHolder =
        (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
    if (sessionHolder != null) {
      return sessionHolder.getSession();
    }

    if (!allowCreate && !TransactionSynchronizationManager.isSynchronizationActive()) {
      throw new IllegalStateException(
          "No TopLink Session bound to thread, "
              + "and configuration does not allow creation of non-transactional one here");
    }

    logger.debug("Creating TopLink Session");
    Session session = sessionFactory.createSession();

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
      logger.debug("Registering new Spring transaction synchronization for new TopLink Session");
      // Use same Session for further TopLink actions within the transaction.
      // Thread object will get removed by synchronization at transaction completion.
      sessionHolder = new SessionHolder(session);
      sessionHolder.setSynchronizedWithTransaction(true);
      TransactionSynchronizationManager.registerSynchronization(
          new SessionSynchronization(sessionHolder, sessionFactory));
      TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
    }

    return session;
  }
  @Override
  protected Object doGetTransaction() {
    EntityManagerHolder holder =
        (EntityManagerHolder)
            TransactionSynchronizationManager.getResource(getEntityManagerFactory());

    boolean isNew = false;

    if (holder == null) {
      EntityManager em = _jpaContext.getEm(getEntityManagerFactory());
      holder = new EntityManagerHolder(em);
      TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), holder);
      isNew = true;
    }

    JdbcTransactionObjectSupport transactionObj =
        (JdbcTransactionObjectSupport) super.doGetTransaction();

    if (isNew) {
      _newTransactionObjects.put(transactionObj, holder.getEntityManager());
      LOGGER.debug(
          "doGetTransaction() bound EntityManagerHolder [{}] and saved transactionObj [{}]",
          holder,
          transactionObj);
    } else {
      LOGGER.debug(
          "doGetTransaction() existing EntityManagerHolder, ignoring transactionObj: {}",
          holder,
          transactionObj);
    }

    return transactionObj;
  }
 /**
  * Determine whether the given JDBC Connection is transactional, that is, bound to the current
  * thread by Spring's transaction facilities.
  *
  * @param con the Connection to check
  * @param dataSource the DataSource that the Connection was obtained from (may be <code>null
  *     </code>)
  * @return whether the Connection is transactional
  */
 public static boolean isConnectionTransactional(Connection con, DataSource dataSource) {
   if (dataSource == null) {
     return false;
   }
   ConnectionHolder conHolder =
       (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
   return (conHolder != null && connectionEquals(conHolder, con));
 }
Beispiel #7
0
 /**
  * Return whether the given TopLink Session is transactional, that is, bound to the current thread
  * by Spring's transaction facilities.
  *
  * @param session the TopLink Session to check
  * @param sessionFactory TopLink SessionFactory that the Session was created with (can be <code>
  *     null</code>)
  * @return whether the Session is transactional
  */
 public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) {
   if (sessionFactory == null) {
     return false;
   }
   SessionHolder sessionHolder =
       (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
   return (sessionHolder != null && session == sessionHolder.getSession());
 }
 /**
  * Determine whether the given JMS Session is transactional, that is, bound to the current thread
  * by Spring's transaction facilities.
  *
  * @param session the JMS Session to check
  * @param cf the JMS ConnectionFactory that the Session originated from
  * @return whether the Session is transactional
  */
 public static boolean isSessionTransactional(Session session, ConnectionFactory cf) {
   if (session == null || cf == null) {
     return false;
   }
   JmsResourceHolder resourceHolder =
       (JmsResourceHolder) TransactionSynchronizationManager.getResource(cf);
   return (resourceHolder != null && resourceHolder.containsSession(session));
 }
 public static List<String> bindAndGetEventLog(EventLogSender eventLogSender) {
   if (!TransactionSynchronizationManager.hasResource(EVENT_LOG_KEY)) {
     TransactionSynchronizationManager.bindResource(EVENT_LOG_KEY, new ArrayList<String>());
     TransactionSynchronizationManager.registerSynchronization(
         new EventLogSynchronization(eventLogSender));
   }
   return (List<String>) TransactionSynchronizationManager.getResource(EVENT_LOG_KEY);
 }
  /**
   * Return whether the given DB instance is transactional, that is, bound to the current thread by
   * Spring's transaction facilities.
   *
   * @param db the DB to check
   * @param mongo the Mongo instance that the DB was created with (may be <code>null</code>)
   * @return whether the DB is transactional
   */
  public static boolean isDBTransactional(DB db, Mongo mongo) {

    if (mongo == null) {
      return false;
    }
    DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
    return dbHolder != null && dbHolder.containsDB(db);
  }
 /**
  * Apply the current transaction timeout, if any, to the given JPA Query object.
  *
  * <p>This method sets the JPA 2.0 query hints "javax.persistence.lock.timeout" and
  * "javax.persistence.query.timeout" accordingly.
  *
  * @param query the JPA Query object
  * @param emf JPA EntityManagerFactory that the Query was created for
  */
 public static void applyTransactionTimeout(Query query, EntityManagerFactory emf) {
   EntityManagerHolder emHolder =
       (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
   if (emHolder != null && emHolder.hasTimeout()) {
     int timeoutValue = emHolder.getTimeToLiveInSeconds();
     query.setHint("javax.persistence.lock.timeout", timeoutValue);
     query.setHint("javax.persistence.query.timeout", timeoutValue);
   }
 }
  public Connection getConnection(DataSource dataSource) {
    ConnectionHolder connectionHolder =
        (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

    if (connectionHolder == null) {
      return null;
    } else {
      return connectionHolder.getConnection();
    }
  }
  /**
   * Return whether the given Redis connection is transactional, that is, bound to the current
   * thread by Spring's transaction facilities.
   *
   * @param conn Redis connection to check
   * @param connFactory Redis connection factory that the connection was created with
   * @return whether the connection is transactional or not
   */
  public static boolean isConnectionTransactional(
      RedisConnection conn, RedisConnectionFactory connFactory) {
    if (connFactory == null) {
      return false;
    }
    RedisConnectionHolder connHolder =
        (RedisConnectionHolder) TransactionSynchronizationManager.getResource(connFactory);

    return (connHolder != null && conn == connHolder.getConnection());
  }
 private void endSession(PhaseEvent event) {
   if (event.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
     final SessionHolder sessionHolder =
         (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
     if (sessionHolder != null
         && !FlushMode.MANUAL.equals(sessionHolder.getSession().getFlushMode())) {
       sessionHolder.getSession().flush();
     }
     if (boundByMe.get()) unbindSession();
   }
 }
 /**
  * Apply the current transaction timeout, if any, to the given JPA Query object.
  *
  * <p>This method sets the JPA 2.0 query hint "javax.persistence.query.timeout" accordingly.
  *
  * @param query the JPA Query object
  * @param emf JPA EntityManagerFactory that the Query was created for
  */
 public static void applyTransactionTimeout(Query query, EntityManagerFactory emf) {
   EntityManagerHolder emHolder =
       (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
   if (emHolder != null && emHolder.hasTimeout()) {
     int timeoutValue = (int) emHolder.getTimeToLiveInMillis();
     try {
       query.setHint("javax.persistence.query.timeout", timeoutValue);
     } catch (IllegalArgumentException ex) {
       // oh well, at least we tried...
     }
   }
 }
 @Override
 protected Session getSession() {
   SessionHolder sessionHolder =
       (SessionHolder) TransactionSynchronizationManager.getResource(jpaDatastore);
   if (sessionHolder == null) {
     Session session = jpaDatastore.connect();
     sessionHolder = new SessionHolder(session);
     TransactionSynchronizationManager.bindResource(jpaDatastore, sessionHolder);
     return session;
   }
   return sessionHolder.getSession();
 }
  /**
   * Obtain a JPA EntityManager from the given factory. Is aware of a corresponding EntityManager
   * bound to the current thread, for example when using JpaTransactionManager.
   *
   * <p>Same as <code>getEntityManager</code>, but throwing the original PersistenceException.
   *
   * @param emf EntityManagerFactory to create the EntityManager with
   * @param properties the properties to be passed into the <code>createEntityManager</code> call
   *     (may be <code>null</code>)
   * @return the EntityManager, or <code>null</code> if none found
   * @throws javax.persistence.PersistenceException if the EntityManager couldn't be created
   * @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
   * @see JpaTransactionManager
   */
  public static EntityManager doGetTransactionalEntityManager(
      EntityManagerFactory emf, Map properties) throws PersistenceException {

    Assert.notNull(emf, "No EntityManagerFactory specified");

    EntityManagerHolder emHolder =
        (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
    if (emHolder != null) {
      if (!emHolder.isSynchronizedWithTransaction()
          && TransactionSynchronizationManager.isSynchronizationActive()) {
        // Try to explicitly synchronize the EntityManager itself
        // with an ongoing JTA transaction, if any.
        try {
          emHolder.getEntityManager().joinTransaction();
        } catch (TransactionRequiredException ex) {
          logger.debug("Could not join JTA transaction because none was active", ex);
        }
        Object transactionData = prepareTransaction(emHolder.getEntityManager(), emf);
        TransactionSynchronizationManager.registerSynchronization(
            new EntityManagerSynchronization(emHolder, emf, transactionData, false));
        emHolder.setSynchronizedWithTransaction(true);
      }
      return emHolder.getEntityManager();
    }

    if (!TransactionSynchronizationManager.isSynchronizationActive()) {
      // Indicate that we can't obtain a transactional EntityManager.
      return null;
    }

    // Create a new EntityManager for use within the current transaction.
    logger.debug("Opening JPA EntityManager");
    EntityManager em =
        (!CollectionUtils.isEmpty(properties)
            ? emf.createEntityManager(properties)
            : emf.createEntityManager());

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
      logger.debug("Registering transaction synchronization for JPA EntityManager");
      // Use same EntityManager for further JPA actions within the transaction.
      // Thread object will get removed by synchronization at transaction completion.
      emHolder = new EntityManagerHolder(em);
      Object transactionData = prepareTransaction(em, emf);
      TransactionSynchronizationManager.registerSynchronization(
          new EntityManagerSynchronization(emHolder, emf, transactionData, true));
      emHolder.setSynchronizedWithTransaction(true);
      TransactionSynchronizationManager.bindResource(emf, emHolder);
    }

    return em;
  }
 /**
  * Apply the specified timeout - overridden by the current transaction timeout, if any - to the
  * given JDBC Statement object.
  *
  * @param stmt the JDBC Statement object
  * @param dataSource the DataSource that the Connection was obtained from
  * @param timeout the timeout to apply (or 0 for no timeout outside of a transaction)
  * @throws SQLException if thrown by JDBC methods
  * @see java.sql.Statement#setQueryTimeout
  */
 public static void applyTimeout(Statement stmt, DataSource dataSource, int timeout)
     throws SQLException {
   Assert.notNull(stmt, "No Statement specified");
   Assert.notNull(dataSource, "No DataSource specified");
   ConnectionHolder holder =
       (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
   if (holder != null && holder.hasTimeout()) {
     // Remaining transaction timeout overrides specified value.
     stmt.setQueryTimeout(holder.getTimeToLiveInSeconds());
   } else if (timeout > 0) {
     // No current transaction timeout -> apply specified value.
     stmt.setQueryTimeout(timeout);
   }
 }
 private boolean bindSession() {
   if (sessionFactory == null) {
     throw new IllegalStateException("No sessionFactory property provided");
   }
   final Object inStorage = TransactionSynchronizationManager.getResource(sessionFactory);
   if (inStorage != null) {
     ((SessionHolder) inStorage).getSession().flush();
     return false;
   } else {
     Session session = SessionFactoryUtils.getSession(sessionFactory, true);
     session.setFlushMode(FlushMode.AUTO);
     TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
     return true;
   }
 }
  /**
   * Gets a Redis connection. Is aware of and will return any existing corresponding connections
   * bound to the current thread, for example when using a transaction manager. Will create a new
   * Connection otherwise, if {@code allowCreate} is <tt>true</tt>.
   *
   * @param factory connection factory for creating the connection
   * @param allowCreate whether a new (unbound) connection should be created when no connection can
   *     be found for the current thread
   * @param bind binds the connection to the thread, in case one was created
   * @param enableTransactionSupport
   * @return an active Redis connection
   */
  public static RedisConnection doGetConnection(
      RedisConnectionFactory factory,
      boolean allowCreate,
      boolean bind,
      boolean enableTransactionSupport) {

    Assert.notNull(factory, "No RedisConnectionFactory specified");

    RedisConnectionHolder connHolder =
        (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);

    if (connHolder != null) {
      if (enableTransactionSupport) {
        potentiallyRegisterTransactionSynchronisation(connHolder, factory);
      }
      return connHolder.getConnection();
    }

    if (!allowCreate) {
      throw new IllegalArgumentException("No connection found and allowCreate = false");
    }

    if (log.isDebugEnabled()) {
      log.debug("Opening RedisConnection");
    }

    RedisConnection conn = factory.getConnection();

    if (bind) {

      RedisConnection connectionToBind = conn;
      if (enableTransactionSupport && isActualNonReadonlyTransactionActive()) {
        connectionToBind = createConnectionProxy(conn, factory);
      }

      connHolder = new RedisConnectionHolder(connectionToBind);

      TransactionSynchronizationManager.bindResource(factory, connHolder);
      if (enableTransactionSupport) {
        potentiallyRegisterTransactionSynchronisation(connHolder, factory);
      }

      return connHolder.getConnection();
    }

    return conn;
  }
 private void unbindSession() {
   if (sessionFactory == null) {
     throw new IllegalStateException("No sessionFactory property provided");
   }
   SessionHolder sessionHolder =
       (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
   try {
     if (!FlushMode.MANUAL.equals(sessionHolder.getSession().getFlushMode())) {
       sessionHolder.getSession().flush();
     }
   } catch (Exception e) {
     e.printStackTrace();
   } finally {
     TransactionSynchronizationManager.unbindResource(sessionFactory);
     SessionFactoryUtils.closeSession(sessionHolder.getSession());
   }
 }
  @Override
  protected void createCriteriaInstance() {
    {
      if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
        participate = true;
        hibernateSession =
            ((SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory))
                .getSession();
      } else {
        hibernateSession = sessionFactory.openSession();
      }

      criteria = hibernateSession.createCriteria(targetClass);
      cacheCriteriaMapping();
      criteriaMetaClass = GroovySystem.getMetaClassRegistry().getMetaClass(criteria.getClass());
    }
  }
 @Override
 public void afterCompletion(int status) {
   RestPostProcessorDelegate.LOG.info("Transaction completed");
   try {
     if (status == STATUS_COMMITTED) {
       RestPostProcessorDelegate.LOG.info("Transaction was committed, sending events.");
       List<String> eventLog =
           (List<String>) TransactionSynchronizationManager.getResource(EVENT_LOG_KEY);
       eventLogSender.send(eventLog);
     } else {
       RestPostProcessorDelegate.LOG.info(
           "Transaction was not committed, status was " + status + ", not sending events.");
     }
   } catch (IOException e) {
     throw new RuntimeException("Failed to send the event log.", e);
   } finally {
     TransactionSynchronizationManager.unbindResource(EVENT_LOG_KEY);
   }
 }
  /**
   * Actually obtain a JDBC Connection from the given DataSource. Same as {@link #getConnection},
   * but throwing the original SQLException.
   *
   * <p>Is aware of a corresponding Connection bound to the current thread, for example when using
   * {@link DataSourceTransactionManager}. Will bind a Connection to the thread if transaction
   * synchronization is active (e.g. if in a JTA transaction).
   *
   * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
   *
   * @param dataSource the DataSource to obtain Connections from
   * @return a JDBC Connection from the given DataSource
   * @throws SQLException if thrown by JDBC methods
   * @see #doReleaseConnection
   */
  public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    Assert.notNull(dataSource, "No DataSource specified");

    ConnectionHolder conHolder =
        (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    if (conHolder != null
        && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
      conHolder.requested();
      if (!conHolder.hasConnection()) {
        logger.debug("Fetching resumed JDBC Connection from DataSource");
        conHolder.setConnection(dataSource.getConnection());
      }
      return conHolder.getConnection();
    }
    // Else we either got no holder or an empty thread-bound holder here.

    logger.debug("Fetching JDBC Connection from DataSource");
    Connection con = dataSource.getConnection();

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
      logger.debug("Registering transaction synchronization for JDBC Connection");
      // Use same Connection for further JDBC actions within the transaction.
      // Thread-bound object will get removed by synchronization at transaction completion.
      ConnectionHolder holderToUse = conHolder;
      if (holderToUse == null) {
        holderToUse = new ConnectionHolder(con);
      } else {
        holderToUse.setConnection(con);
      }
      holderToUse.requested();
      TransactionSynchronizationManager.registerSynchronization(
          new ConnectionSynchronization(holderToUse, dataSource));
      holderToUse.setSynchronizedWithTransaction(true);
      if (holderToUse != conHolder) {
        TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
      }
    }

    return con;
  }
  /**
   * Closes the given connection, created via the given factory if not managed externally (i.e. not
   * bound to the thread).
   *
   * @param conn the Redis connection to close
   * @param factory the Redis factory that the connection was created with
   */
  public static void releaseConnection(RedisConnection conn, RedisConnectionFactory factory) {

    if (conn == null) {
      return;
    }

    RedisConnectionHolder connHolder =
        (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);

    if (connHolder != null && connHolder.isTransactionSyncronisationActive()) {
      if (log.isDebugEnabled()) {
        log.debug("Redis Connection will be closed when transaction finished.");
      }
      return;
    }

    // Only release non-transactional/non-bound connections.
    if (!isConnectionTransactional(conn, factory)) {
      if (log.isDebugEnabled()) {
        log.debug("Closing Redis Connection");
      }
      conn.close();
    }
  }
  /**
   * Actually close the given Connection, obtained from the given DataSource. Same as {@link
   * #releaseConnection}, but throwing the original SQLException.
   *
   * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
   *
   * @param con the Connection to close if necessary (if this is <code>null</code>, the call will be
   *     ignored)
   * @param dataSource the DataSource that the Connection was obtained from (may be <code>null
   *     </code>)
   * @throws SQLException if thrown by JDBC methods
   * @see #doGetConnection
   */
  public static void doReleaseConnection(Connection con, DataSource dataSource)
      throws SQLException {
    if (con == null) {
      return;
    }

    if (dataSource != null) {
      ConnectionHolder conHolder =
          (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
      if (conHolder != null && connectionEquals(conHolder, con)) {
        // It's the transactional Connection: Don't close it.
        conHolder.released();
        return;
      }
    }

    // Leave the Connection open only if the DataSource is our
    // special SmartDataSoruce and it wants the Connection left open.
    if (!(dataSource instanceof SmartDataSource)
        || ((SmartDataSource) dataSource).shouldClose(con)) {
      logger.debug("Returning JDBC Connection to DataSource");
      con.close();
    }
  }
  /**
   * Obtain a JMS Session that is synchronized with the current transaction, if any.
   *
   * @param connectionFactory the JMS ConnectionFactory to bind for (used as
   *     TransactionSynchronizationManager key)
   * @param resourceFactory the ResourceFactory to use for extracting or creating JMS resources
   * @param startConnection whether the underlying JMS Connection approach should be started in
   *     order to allow for receiving messages. Note that a reused Connection may already have been
   *     started before, even if this flag is {@code false}.
   * @return the transactional Session, or {@code null} if none found
   * @throws JMSException in case of JMS failure
   */
  public static Session doGetTransactionalSession(
      ConnectionFactory connectionFactory, ResourceFactory resourceFactory, boolean startConnection)
      throws JMSException {

    Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
    Assert.notNull(resourceFactory, "ResourceFactory must not be null");

    JmsResourceHolder resourceHolder =
        (JmsResourceHolder) TransactionSynchronizationManager.getResource(connectionFactory);
    if (resourceHolder != null) {
      Session session = resourceFactory.getSession(resourceHolder);
      if (session != null) {
        if (startConnection) {
          Connection con = resourceFactory.getConnection(resourceHolder);
          if (con != null) {
            con.start();
          }
        }
        return session;
      }
      if (resourceHolder.isFrozen()) {
        return null;
      }
    }
    if (!TransactionSynchronizationManager.isSynchronizationActive()) {
      return null;
    }
    JmsResourceHolder resourceHolderToUse = resourceHolder;
    if (resourceHolderToUse == null) {
      resourceHolderToUse = new JmsResourceHolder(connectionFactory);
    }
    Connection con = resourceFactory.getConnection(resourceHolderToUse);
    Session session = null;
    try {
      boolean isExistingCon = (con != null);
      if (!isExistingCon) {
        con = resourceFactory.createConnection();
        resourceHolderToUse.addConnection(con);
      }
      session = resourceFactory.createSession(con);
      resourceHolderToUse.addSession(session, con);
      if (startConnection) {
        con.start();
      }
    } catch (JMSException ex) {
      if (session != null) {
        try {
          session.close();
        } catch (Throwable ex2) {
          // ignore
        }
      }
      if (con != null) {
        try {
          con.close();
        } catch (Throwable ex2) {
          // ignore
        }
      }
      throw ex;
    }
    if (resourceHolderToUse != resourceHolder) {
      TransactionSynchronizationManager.registerSynchronization(
          new JmsResourceSynchronization(
              resourceHolderToUse,
              connectionFactory,
              resourceFactory.isSynchedLocalTransactionAllowed()));
      resourceHolderToUse.setSynchronizedWithTransaction(true);
      TransactionSynchronizationManager.bindResource(connectionFactory, resourceHolderToUse);
    }
    return session;
  }
  private static DB doGetDB(
      Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate) {

    DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);

    // Do we have a populated holder and TX sync active?
    if (dbHolder != null
        && !dbHolder.isEmpty()
        && TransactionSynchronizationManager.isSynchronizationActive()) {

      DB db = dbHolder.getDB(databaseName);

      // DB found but not yet synchronized
      if (db != null && !dbHolder.isSynchronizedWithTransaction()) {

        LOGGER.debug(
            "Registering Spring transaction synchronization for existing MongoDB {}.",
            databaseName);

        TransactionSynchronizationManager.registerSynchronization(
            new MongoSynchronization(dbHolder, mongo));
        dbHolder.setSynchronizedWithTransaction(true);
      }

      if (db != null) {
        return db;
      }
    }

    // Lookup fresh database instance
    LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);

    DB db = mongo.getDB(databaseName);
    boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();

    synchronized (db) {
      if (credentialsGiven && !db.isAuthenticated()) {

        String username = credentials.getUsername();
        String password = credentials.hasPassword() ? credentials.getPassword() : null;

        if (!db.authenticate(username, password == null ? null : password.toCharArray())) {
          throw new CannotGetMongoDbConnectionException(
              "Failed to authenticate to database ["
                  + databaseName
                  + "], username = ["
                  + username
                  + "], password = ["
                  + password
                  + "]",
              databaseName,
              credentials);
        }
      }
    }

    // TX sync active, bind new database to thread
    if (TransactionSynchronizationManager.isSynchronizationActive()) {

      LOGGER.debug(
          "Registering Spring transaction synchronization for MongoDB instance {}.", databaseName);

      DbHolder holderToUse = dbHolder;

      if (holderToUse == null) {
        holderToUse = new DbHolder(databaseName, db);
      } else {
        holderToUse.addDB(databaseName, db);
      }

      TransactionSynchronizationManager.registerSynchronization(
          new MongoSynchronization(holderToUse, mongo));
      holderToUse.setSynchronizedWithTransaction(true);

      if (holderToUse != dbHolder) {
        TransactionSynchronizationManager.bindResource(mongo, holderToUse);
      }
    }

    // Check whether we are allowed to return the DB.
    if (!allowCreate && !isDBTransactional(db, mongo)) {
      throw new IllegalStateException(
          "No Mongo DB bound to thread, "
              + "and configuration does not allow creation of non-transactional one here");
    }

    return db;
  }
 /*
  * @seeorg.springframework.jdbc.datasource.DataSourceTransactionManager#
  * doGetTransaction()
  */
 public Object doGetTransaction() throws TransactionException {
   CompensatingTransactionHolderSupport holder =
       (CompensatingTransactionHolderSupport)
           TransactionSynchronizationManager.getResource(getTransactionSynchronizationKey());
   return new CompensatingTransactionObject(holder);
 }