private void registerSessionSynchronization(Instance instance, ThreadContext callContext) {
    TransactionPolicy txPolicy = callContext.getTransactionPolicy();
    if (txPolicy == null) {
      throw new IllegalStateException("ThreadContext does not contain a TransactionEnvironment");
    }

    SessionSynchronizationCoordinator coordinator =
        (SessionSynchronizationCoordinator)
            txPolicy.getResource(SessionSynchronizationCoordinator.class);
    if (coordinator == null) {
      coordinator = new SessionSynchronizationCoordinator(txPolicy);
      txPolicy.registerSynchronization(coordinator);
      txPolicy.putResource(SessionSynchronizationCoordinator.class, coordinator);
    }

    // SessionSynchronization are only enabled for beans after CREATE that are not bean-managed and
    // implement the SessionSynchronization interface
    boolean synchronize =
        callContext.getCurrentOperation() != Operation.CREATE
            && callContext.getBeanContext().isSessionSynchronized()
            && txPolicy.isTransactionActive();

    coordinator.registerSessionSynchronization(
        instance, callContext.getBeanContext(), callContext.getPrimaryKey(), synchronize);
  }
    public void beforeCompletion() {
      for (Synchronization synchronization : registry.values()) {

        Instance instance = synchronization.instance;

        // don't call beforeCompletion when transaction is marked rollback only
        if (txPolicy.isRollbackOnly()) return;

        // only call beforeCompletion on beans with session synchronization
        if (!synchronization.isCallSessionSynchronization()) continue;

        // Invoke beforeCompletion
        ThreadContext callContext =
            new ThreadContext(
                instance.beanContext, instance.primaryKey, Operation.BEFORE_COMPLETION);
        callContext.setCurrentAllowedStates(null);
        ThreadContext oldCallContext = ThreadContext.enter(callContext);
        try {
          instance.setInUse(true);

          BeanContext beanContext = instance.beanContext;
          List<InterceptorData> interceptors = beanContext.getCallbackInterceptors();
          InterceptorStack interceptorStack =
              new InterceptorStack(
                  instance.bean,
                  null,
                  Operation.BEFORE_COMPLETION,
                  interceptors,
                  instance.interceptors);
          interceptorStack.invoke();

          instance.setInUse(false);
        } catch (InvalidateReferenceException e) {
          // exception has alredy been handled
        } catch (Exception e) {
          String message =
              "An unexpected system exception occured while invoking the beforeCompletion method on the SessionSynchronization object";

          // [1] Log the exception or error
          logger.error(message, e);

          // [2] Mark the transaction for rollback.
          txPolicy.setRollbackOnly(e);

          // [3] Discard the instance
          discardInstance(callContext);

          // [4] throw the java.rmi.RemoteException to the client
          throw new RuntimeException(message, e);
        } finally {
          ThreadContext.exit(oldCallContext);
        }
      }
    }