/**
   * Gets Hibernate session.
   *
   * @param tx Cache transaction.
   * @return Session.
   */
  Session session(@Nullable GridCacheTx tx) {
    Session ses;

    if (tx != null) {
      ses = tx.meta(ATTR_SES);

      if (ses == null) {
        ses = sesFactory.openSession();

        ses.beginTransaction();

        // Store session in transaction metadata, so it can be accessed
        // for other operations on the same transaction.
        tx.addMeta(ATTR_SES, ses);

        if (log.isDebugEnabled())
          log.debug("Hibernate session open [ses=" + ses + ", tx=" + tx.xid() + "]");
      }
    } else {
      ses = sesFactory.openSession();

      ses.beginTransaction();
    }

    return ses;
  }
  /** {@inheritDoc} */
  @Override
  public void txEnd(GridCacheTx tx, boolean commit) throws GridException {
    init();

    Session ses = tx.removeMeta(ATTR_SES);

    if (ses != null) {
      Transaction hTx = ses.getTransaction();

      if (hTx != null) {
        try {
          if (commit) {
            ses.flush();

            hTx.commit();
          } else hTx.rollback();

          if (log.isDebugEnabled())
            log.debug("Transaction ended [xid=" + tx.xid() + ", commit=" + commit + ']');
        } catch (HibernateException e) {
          throw new GridException(
              "Failed to end transaction [xid=" + tx.xid() + ", commit=" + commit + ']', e);
        } finally {
          ses.close();
        }
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public void rollback() throws GridException {
    enter();

    try {
      tx.rollback();
    } finally {
      leave();
    }
  }
  /** {@inheritDoc} */
  @Override
  public GridFuture<GridCacheTx> commitAsync() {
    enter();

    try {
      return tx.commitAsync();
    } finally {
      leave();
    }
  }
  /** {@inheritDoc} */
  @Override
  public void end() throws GridException {
    enter();

    try {
      tx.end();
    } finally {
      leave();
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean isRollbackOnly() {
    enter();

    try {
      return tx.isRollbackOnly();
    } finally {
      leave();
    }
  }
 /** {@inheritDoc} */
 @Override
 public long timeout() {
   return tx.timeout();
 }
 /** {@inheritDoc} */
 @Override
 public GridCacheTxConcurrency concurrency() {
   return tx.concurrency();
 }
 /** {@inheritDoc} */
 @Override
 public long startTime() {
   return tx.startTime();
 }
 /** {@inheritDoc} */
 @Override
 public UUID nodeId() {
   return tx.nodeId();
 }
 /** {@inheritDoc} */
 @Override
 public <V> boolean replaceMeta(String name, V curVal, V newVal) {
   return tx.replaceMeta(name, curVal, newVal);
 }
 /** {@inheritDoc} */
 @Override
 public boolean hasMeta(String name) {
   return tx.hasMeta(name);
 }
 /** {@inheritDoc} */
 @Override
 public void copyMeta(GridMetadataAware from) {
   tx.copyMeta(from);
 }
 /** {@inheritDoc} */
 @Override
 public long timeout(long timeout) {
   return tx.timeout(timeout);
 }
 /** {@inheritDoc} */
 @Override
 public GridCacheTxState state() {
   return tx.state();
 }
 /** {@inheritDoc} */
 @Override
 public <V> boolean removeMeta(String name, V val) {
   return tx.removeMeta(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public <V> Map<String, V> allMeta() {
   return tx.allMeta();
 }
 /** {@inheritDoc} */
 @Override
 public void copyMeta(Map<String, ?> data) {
   tx.copyMeta(data);
 }
 /** {@inheritDoc} */
 @Override
 public <V> boolean hasMeta(String name, V val) {
   return tx.hasMeta(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public <V> V addMeta(String name, V val) {
   return tx.addMeta(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public UUID xid() {
   return tx.xid();
 }
 /** {@inheritDoc} */
 @Override
 public <V> V putMetaIfAbsent(String name, V val) {
   return tx.putMetaIfAbsent(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public long threadId() {
   return tx.threadId();
 }
 /** {@inheritDoc} */
 @Override
 public <V> V putMetaIfAbsent(String name, Callable<V> c) {
   return tx.putMetaIfAbsent(name, c);
 }
 /** {@inheritDoc} */
 @Override
 public GridCacheTxIsolation isolation() {
   return tx.isolation();
 }
 /** {@inheritDoc} */
 @Nullable
 @Override
 public <V> V addMetaIfAbsent(String name, V val) {
   return tx.addMeta(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public boolean isInvalidate() {
   return tx.isInvalidate();
 }
 /** {@inheritDoc} */
 @Override
 public <V> V addMetaIfAbsent(String name, @Nullable Callable<V> c) {
   return tx.addMetaIfAbsent(name, c);
 }
 /** {@inheritDoc} */
 @SuppressWarnings({"RedundantTypeArguments"})
 @Override
 public <V> V removeMeta(String name) {
   return tx.<V>removeMeta(name);
 }
 /** {@inheritDoc} */
 @Override
 public boolean implicit() {
   return tx.implicit();
 }