public static CoreSession wrap(CoreSession session) {
   try {
     TransactionHelper.lookupTransactionManager();
   } catch (NamingException e) {
     // no transactions, do not wrap
     return session;
   }
   ClassLoader cl = session.getClass().getClassLoader();
   return (CoreSession)
       Proxy.newProxyInstance(cl, INTERFACES, new TransactionalCoreSessionWrapper(session));
 }
 @Override
 public void afterCompletion(int status) {
   Transaction current = null;
   try {
     current = TransactionHelper.lookupTransactionManager().getTransaction();
   } catch (Exception e) {
     throw new Error("no tx", e);
   }
   Transaction main = threadBound.get();
   if (main.equals(current)) {
     threadBound.remove();
   }
   boolean committed;
   if (status == Status.STATUS_COMMITTED) {
     committed = true;
   } else if (status == Status.STATUS_ROLLEDBACK) {
     committed = false;
   } else {
     log.error("Unexpected status after completion: " + status);
     return;
   }
   session.afterCompletion(committed);
 }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Transaction main = threadBound.get();
    if (main == null) {
      // first call in thread
      try {
        main = TransactionHelper.lookupTransactionManager().getTransaction();

        if (main != null) {
          if (main.getStatus() != Status.STATUS_MARKED_ROLLBACK) {
            main.registerSynchronization(this);
            session.afterBegin();
            threadBound.set(main);
          }
        }
      } catch (NamingException e) {
        // no transaction manager, ignore
      } catch (Exception e) {
        log.error("Error on transaction synchronizer registration", e);
      }
      checkTxActiveRequired(method);
    }
    try {
      return method.invoke(session, args);
    } catch (Throwable t) {
      if (TransactionHelper.isTransactionActive() && needsRollback(method, t)) {
        TransactionHelper.setTransactionRollbackOnly();
      }
      if (t instanceof InvocationTargetException) {
        Throwable tt = ((InvocationTargetException) t).getTargetException();
        if (tt != null) {
          throw tt;
        }
      }
      throw t;
    }
  }