/**
   * Init lock
   *
   * @return The lock
   */
  private synchronized Lock initLock() {
    TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry();
    if (tsr != null && tsr.getTransactionKey() != null) {
      if (tsr.getResource(LockKey.INSTANCE) == null) {
        Lock lock = new ReentrantLock(true);
        tsr.putResource(LockKey.INSTANCE, lock);
        return lock;
      } else {
        return (Lock) tsr.getResource(LockKey.INSTANCE);
      }
    }

    return null;
  }
 /**
  * Returns an unmodifiable view of timers in the current transaction that are waiting for the
  * transaction to finish
  */
 private Map<String, TimerImpl> getWaitingOnTxCompletionTimers() {
   Map<String, TimerImpl> timers = null;
   if (getTransaction() != null) {
     timers = (Map<String, TimerImpl>) tsr.getResource(waitingOnTxCompletionKey);
   }
   return timers == null ? Collections.<String, TimerImpl>emptyMap() : timers;
 }
  /**
   * Gets connection listener instance associated with transaction. This method is package protected
   * beacause it is intended only for test case use. Please don't use it in your production code.
   *
   * @param trackByTransaction transaction instance
   * @param mcp the managed connection pool associated with the desired connection listener
   * @return connection listener instance
   * @throws ResourceException Thrown if an error occurs
   */
  ConnectionListener getTransactionOldConnection(
      Transaction trackByTransaction, ManagedConnectionPool mcp) throws ResourceException {
    TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry();
    Lock lock = getLock();

    try {
      lock.lockInterruptibly();
    } catch (InterruptedException ie) {
      Thread.interrupted();

      throw new ResourceException(bundle.unableObtainLock(), ie);
    }
    try {
      // Already got one
      ConnectionListener cl = (ConnectionListener) tsr.getResource(mcp);
      if (cl != null) {
        if (trace)
          log.tracef("Previous connection tracked by transaction=%s tx=%s", cl, trackByTransaction);
        return cl;
      }

      return null;
    } finally {
      lock.unlock();
    }
  }
 private void addWaitingOnTxCompletionTimer(final TimerImpl timer) {
   Map<String, TimerImpl> timers =
       (Map<String, TimerImpl>) tsr.getResource(waitingOnTxCompletionKey);
   if (timers == null) {
     tsr.putResource(waitingOnTxCompletionKey, timers = new HashMap<String, TimerImpl>());
   }
   timers.put(timer.getId(), timer);
 }
  /**
   * Gets new connection listener if necessary instance with transaction. This method is package
   * protected beacause it is intended only for test case use. Please don't use it in your
   * production code.
   *
   * @param trackByTransaction transaction instance
   * @param mcp pool instance
   * @param subject subject instance
   * @param cri connection request info
   * @return connection listener instance
   * @throws ResourceException ResourceException
   */
  ConnectionListener getTransactionNewConnection(
      Transaction trackByTransaction,
      ManagedConnectionPool mcp,
      Subject subject,
      ConnectionRequestInfo cri)
      throws ResourceException {
    // Need a new one for this transaction
    // This must be done outside the tx local lock, otherwise
    // the tx timeout won't work and get connection can do a lot of other work
    // with many opportunities for deadlocks.
    // Instead we do a double check after we got the transaction to see
    // whether another thread beat us to the punch.
    ConnectionListener cl = mcp.getConnection(subject, cri);
    if (trace)
      log.tracef(
          "Got connection from pool tracked by transaction=%s tx=%s", cl, trackByTransaction);

    TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry();
    Lock lock = getLock();
    try {
      lock.lockInterruptibly();
    } catch (InterruptedException ie) {
      Thread.interrupted();

      throw new ResourceException(bundle.unableObtainLock(), ie);
    }
    try {
      // Check we weren't racing with another transaction
      ConnectionListener other = (ConnectionListener) tsr.getResource(mcp);

      if (other != null) {
        mcp.returnConnection(cl, false);

        if (trace)
          log.tracef(
              "Another thread already got a connection tracked by transaction=%s tx=%s",
              other, trackByTransaction);

        cl = other;
      }

      // This is the connection for this transaction
      cl.setTrackByTx(true);
      tsr.putResource(mcp, cl);

      if (trace)
        log.tracef(
            "Using connection from pool tracked by transaction=%s tx=%s", cl, trackByTransaction);

      return cl;
    } finally {
      lock.unlock();
    }
  }
  /**
   * Get lock
   *
   * @return The lock
   */
  private Lock getLock() {
    Lock result = null;
    TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry();

    if (tsr != null && tsr.getTransactionKey() != null) {
      result = (Lock) tsr.getResource(LockKey.INSTANCE);
      if (result == null) {
        result = initLock();
      }
    }

    return result;
  }
Exemple #7
0
  private void ejbLoad(final EntityBean entityBean) {
    if (entityBean == null) {
      throw new NullPointerException("entityBean is null");
    }

    final ThreadContext callContext = createThreadContext(entityBean);
    callContext.setCurrentOperation(Operation.LOAD);

    final ThreadContext oldCallContext = ThreadContext.enter(callContext);
    try {
      entityBean.ejbLoad();
    } catch (final RemoteException e) {
      throw new EJBException(e);
    } finally {
      ThreadContext.exit(oldCallContext);
    }

    // if we call load we must call store
    try {
      //noinspection unchecked
      Set<EntityBean> registeredEntities =
          (LinkedHashSet<EntityBean>) synchronizationRegistry.getResource(ENTITIES_TO_STORE);
      if (registeredEntities == null) {
        registeredEntities = new LinkedHashSet<EntityBean>();
        synchronizationRegistry.putResource(ENTITIES_TO_STORE, registeredEntities);
        synchronizationRegistry.registerInterposedSynchronization(
            new Synchronization() {
              @Override
              public void beforeCompletion() {
                //noinspection unchecked
                final Set<EntityBean> registeredEntities =
                    (LinkedHashSet<EntityBean>)
                        synchronizationRegistry.getResource(ENTITIES_TO_STORE);
                if (registeredEntities == null) {
                  return;
                }
                for (final EntityBean entityBean : registeredEntities) {
                  ejbStore(entityBean);
                }
              }

              @Override
              public void afterCompletion(final int i) {}
            });
      }
      registeredEntities.add(entityBean);
    } catch (final Exception e) {
      // no-op
    }
  }
  /**
   * Looks for a current Spring managed transaction and wraps/returns that as a Ebean transaction.
   *
   * <p>Returns null if there is no current spring transaction (lazy loading outside a spring txn
   * etc).
   */
  public Object getCurrentTransaction() {

    TransactionSynchronizationRegistry syncRegistry = getSyncRegistry();

    SpiTransaction t = (SpiTransaction) syncRegistry.getResource(EBEAN_TXN_RESOURCE);
    if (t != null) {
      // we have already seen this transaction
      return t;
    }

    // check current Ebean transaction
    SpiTransaction currentEbeanTransaction = DefaultTransactionThreadLocal.get(serverName);
    if (currentEbeanTransaction != null) {
      // NOT expecting this so log WARNING
      String msg =
          "JTA Transaction - no current txn BUT using current Ebean one "
              + currentEbeanTransaction.getId();
      logger.warn(msg);
      return currentEbeanTransaction;
    }

    UserTransaction ut = getUserTransaction();
    if (ut == null) {
      // no current JTA transaction
      if (logger.isDebugEnabled()) {
        logger.debug("JTA Transaction - no current txn");
      }
      return null;
    }

    // This is a transaction that Ebean has not seen before.

    // "wrap" it in a Ebean specific JtaTransaction
    String txnId = String.valueOf(System.currentTimeMillis());
    JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource, transactionManager);

    // create and register transaction listener
    JtaTxnListener txnListener = createJtaTxnListener(newTrans);

    syncRegistry.putResource(EBEAN_TXN_RESOURCE, newTrans);
    syncRegistry.registerInterposedSynchronization(txnListener);

    // also put in Ebean ThreadLocal
    DefaultTransactionThreadLocal.set(serverName, newTrans);
    return newTrans;
  }
    private Map<Contextual<?>, BeanInstanceBag<?>> findMap() {
      final Object resource;
      try { // we can't call registry.getResource(KEY) in afterCompletion
        resource =
            context.geronimoTxMgr
                ? TransactionImpl.class
                    .cast(context.transactionManager.getTransaction())
                    .getResource(KEY)
                : registry.getResource(KEY);
      } catch (final SystemException e) {
        throw new IllegalStateException(e);
      }

      if (resource == null) {
        final Map<Contextual<?>, BeanInstanceBag<?>> map = new HashMap<>();
        registry.putResource(KEY, map);
        registry.registerInterposedSynchronization(context);
        return map;
      }
      return Map.class.cast(resource);
    }