/**
   * 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();
        }
      }
    }
  }