Example of Using Java Hibernate Driver

Caveat Emptor Example

A Hibernate sample NuoDB application can be found in NUODB_HOME/samples/doc/hibernate. The application performs a few operations on a hibernate data model. The data model is a subset of the "Caveat Emptor" example used in the JBoss Hibernate Caveat Emptor Example. This subset only contains the User and AddressEntity entity objects and two styles of component objects. The application uses Hibernate configuration files. It could have been built just as easily using Java annotations. For more on Hibernate, see http://www.hibernate.org/docs, start with the “Getting Started Guide” for your version. Here are a few pieces of the application.

SampleMain.java

package com.nuodb.sample;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.Session;
import com.nuodb.sample.model.Address;
import com.nuodb.sample.model.AddressEntity;
import com.nuodb.sample.model.User;
/**
 * A sample application that performs a few operations on a hibernate data
 * model. The data model is a subset of "Caveat Emptor" example used in _Java
 * Persistence with Hibernate_ (http://caveatemptor.hibernate.org/). This subset
 * only contains the User and AddressEntiy entity objects and two styles of
 * component objects.
 *
 * This application performs these steps:
 *
 * 1. Drop and create the necessary tables. To change this behavior, change the
 * hbm2ddl.auto value in hibernate.cfg.xml. Allowed values are: "validate",
 * "update", "create", or "create-drop".
 *
 * 2. Create two User records with associated shippingAddresses.
 *
 * 3. Print the user records. Note that each record is printed to console and
 * the output shows the identity of the record along with its version number.
 * For example, "User (3/0)" is identity 3, version 0. The identity is a
 * surrogate key that is assigned when the record is created and does not
 * change. The version changes each time the record is modified.
 *
 * 4. Modify the User's name and billing address by converting fields to
 * upper-case. The home address is not changed.
 *
 * 5. Print the user records a second time to show the modifications. In
 * addition to the field changes, note that the identity has not changed but the
 * version is incremented (eg: "User (3/0)" becomes "User (3/1)".
 *
 * Each one of these steps is performed in a separate transaction.
 *
 * By default, the logging level prints warnings. To override, modify
 * log4j.properties or add "-DCONSOLE_LEVEL=DEBUG" to the command line.
 */
public class SampleMain
{
  private static Logger LOG = Logger.getLogger(SampleMain.class);
  public static void main(String[] args)
  {
    runit();
  }
  public static int runit()
  {
    Configuration configuration = new Configuration();
    configuration.configure();
    String chorus = System.getProperty("nuodb.url");
 
    if (chorus != null)
        {
        System.out.println("Using JDBC URL: " + chorus);
        configuration.setProperty("hibernate.connection.url", chorus);
        }
    SessionFactory factory = configuration.buildSessionFactory();
    Session session = factory.openSession();
    int users = 0;
    try {
      createUsers(session);
      printUsers(session);
      modifyUsers(session);
      users = printUsers(session);
    } finally {
      session.close();
      factory.close();
    }
    return users;
  }
  /**
   * Create new user records using the given hibernate session.
   */
  private static void createUsers(Session session)
  {
    Transaction txn = session.beginTransaction();
    try {
      // @formatter:off
      createUser(session,
                 "Fred", "Flintstone",
                 "fredf@example.com", "fred", true,
                 "301 Cobblestone Way", "Bedrock", "00001",
                 "1 Slate Drive", "Granitetown", "00002");
      createUser(session,
                 "Barney", "Rubble",
                 "barney@example.com", "barney", false,
                 "303 Cobblestone Way", "Bedrock", "00001",
                 "1 Slate Drive", "Granitetown", "00002");
      // @formatter:on
      txn.commit();
    } finally {
      if (txn.isActive())
        txn.rollback();
    }
  }
  /**
   * Instantiate a new User instance and save it to the given session.
   */
  // @formatter:off
  private static User createUser(Session session,
                                 String firstName, String lastName,
                                 String email, String userName, boolean admin,
                                 String homeStreet, String homeCity, String homeZip,
                                 String shipStreet, String shipCity, String shipZip)
  // @formatter:on
  {
    User user = new User(firstName, lastName, userName, "", email);
    user.setHomeAddress(new Address(homeStreet, homeZip, homeCity));
    user.setAdmin(admin);
    // always use home address for billing
    user.setBillingAddress(new Address(homeStreet, homeZip, homeCity));
    user.setShippingAddress(new AddressEntity(shipStreet, shipZip, shipCity));
    user.getShippingAddress().setUser(user);
    session.save(user);
    LOG.info("Created user " + user);
    return user;
  }
  /**
   * Modify all Users by converting the name and billing address fields to upper
   * case. Home and shipping address are not changed.
   */
  private static void modifyUsers(Session session)
  {
    Transaction txn = session.beginTransaction();
    try {
      Query query = session.createQuery("from " + User.class.getName());
      @SuppressWarnings("unchecked")
      List<User> users = query.list();
      System.out.println("Found " + users.size() + " user records:");
      for (User user : users) {
        LOG.info("Updating " + user);
        user.setFirstname(user.getFirstname().toUpperCase());
        user.setLastname(user.getLastname().toUpperCase());
        user.setAdmin(false);
        Address bill = user.getBillingAddress();
        bill.setStreet(bill.getStreet().toUpperCase());
        bill.setCity(bill.getCity().toUpperCase());
        bill.setZipcode(bill.getZipcode().toUpperCase());
      }
      txn.commit();
    } finally {
      if (txn.isActive())
        txn.rollback();
    }
  }
  /**
   * Iterate over all User records and print them.
   */
  private static int printUsers(Session session)
  {
    int count = 0;
    Transaction txn = session.beginTransaction();
    try {
      Query query = session.createQuery("from " + User.class.getName());
      @SuppressWarnings("unchecked")
      List<User> users = query.list();
      System.out.println("Found " + users.size() + " user records:");
      for (User user : users) {
        System.out.println(user);
        System.out.println("  home: " + user.getHomeAddress());
        System.out.println("  bill: " + user.getBillingAddress());
        System.out.println("  ship: " + user.getShippingAddress());
    count++;
      }
      txn.commit();
    } finally {
      if (txn.isActive())
        txn.rollback();
    }
    return count;
  }
}

User.java

package com.nuodb.sample.model;
import java.io.Serializable;
import java.util.Date;
/**
 * A user of the CaveatEmptor auction application.
 *
 * @author Christian Bauer
 */
public class User implements Serializable, Comparable<User>
{
  private static final long serialVersionUID = 1L;
  private Long id = null;
  private int version = 0;
  private String firstname;
  private String lastname;
  private String username; // Unique and immutable
  private String password;
  private String email;
  private int ranking = 0;
  private boolean admin = false;
  private Address homeAddress;
  private Address billingAddress;
  private AddressEntity shippingAddress;
  private Date created = new Date();
  public User()
  {
  }
  public User(String firstname, String lastname, String username, String password, String email,
      int ranking, boolean admin, Address homeAddress, Address billingAddress,
      AddressEntity shippingAddress)
  {
    this.firstname = firstname;
    this.lastname = lastname;
    this.username = username;
    this.password = password;
    this.email = email;
    this.ranking = ranking;
    this.admin = admin;
    this.homeAddress = homeAddress;
    this.billingAddress = billingAddress;
    this.shippingAddress = shippingAddress;
  }
  public User(String firstname, String lastname, String username, String password, String email)
  {
    this.firstname = firstname;
    this.lastname = lastname;
    this.username = username;
    this.password = password;
    this.email = email;
  }
  public Long getId()
  {
    return id;
  }
 
  public int getVersion()
  {
    return version;
  }
  public String getFirstname()
  {
    return firstname;
  }
  public void setFirstname(String firstname)
  {
    this.firstname = firstname;
  }
  public String getLastname()
  {
    return lastname;
  }
  public void setLastname(String lastname)
  {
    this.lastname = lastname;
  }
  public String getUsername()
  {
    return username;
  }
  public String getPassword()
  {
    return password;
  }
  public void setPassword(String password)
  {
    this.password = password;
  }
  public String getEmail()
  {
    return email;
  }
  public void setEmail(String email)
  {
    this.email = email;
  }
  public int getRanking()
  {
    return ranking;
  }
  public void setRanking(int ranking)
  {
    this.ranking = ranking;
  }
 
  public boolean isAdmin()
  {
    return admin;
  }
  public void setAdmin(boolean admin)
  {
    this.admin = admin;
  }
  public Address getHomeAddress()
  {
    return homeAddress;
  }
  public void setHomeAddress(Address homeAddress)
  {
    this.homeAddress = homeAddress;
  }
  public Address getBillingAddress()
  {
    return billingAddress;
  }
  public void setBillingAddress(Address billingAddress)
  {
    this.billingAddress = billingAddress;
  }
  public AddressEntity getShippingAddress()
  {
    return shippingAddress;
  }
  public void setShippingAddress(AddressEntity shippingAddress)
  {
    this.shippingAddress = shippingAddress;
  }
  public Date getCreated()
  {
    return created;
  }
  public boolean equals(Object o)
  {
    if (this == o)
      return true;
    if (!(o instanceof User))
      return false;
    final User user = (User) o;
    return getUsername().equals(user.getUsername());
  }
  public int hashCode()
  {
    return getUsername().hashCode();
  }
  public String toString()
  {
    return "User (" + getId() + "/" + version + "), " + "Username: " + getUsername() + ", Name: "
           + getFirstname() + " " + getLastname() + (admin ? ", admin" : ", member");
  }
 
  public int compareTo(User that)
  {
    long a = this.getCreated().getTime();
    long b = that.getCreated().getTime();
    return (a<b ? -1 : (a==b ? 0 : 1));
  }
}

User.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Mapping file for the User class of CaveatEmptor.
A User is a versioned entity, with some special properties.
One is the username, it is immutable and unique. The
defaultBillingDetails property points to one of the
BillingDetails in the collection of all BillingDetails.
We never load any BillingDetails when a User is retrieved.
SQL customization examples:
- custom SQL for loading a User
- custom SQL for loading a collection of item on sale for a User
- custom SQL for inserting a User
- Hibernate-generated SQL (default) for deleting a User
@author Christian Bauer
-->
<hibernate-mapping package="com.nuodb.sample.model" default-access="field">
<class name="User" table="USERS" batch-size="10">
    <!-- Common id property -->
    <id name="id" type="long" column="USER_ID">
        <generator class="identity"/>
    </id>
    <!-- A versioned entity -->
    <version name="version" column="OBJ_VERSION"/>
    <property   name="firstname"
                type="string"
                column="FIRSTNAME"
                length="255"
                not-null="true"/>
    <property   name="lastname"
                type="string"
                column="LASTNAME"
                length="255"
                not-null="true"/>
    <!-- We don't change the username, so map it with update="false".
         This is an immutable property, it is also unique.
         If your DBMS supports regex functions, add this:
         check="REGEXP_LIKE(ENAME,'^[[:alpha:]]+$')"
         -->
    <property   name="username"
                type="string"
                update="false">
        <column name="USERNAME"
                length="16"
                not-null="true"
                unique="true"/>
    </property>
 
    <!-- Password is a keyword in some databases, so we quote it. In practice, rename it. -->
    <property   name="password"
                type="string"
                column="`PASSWORD`"
                length="12"
                not-null="true"/>
    <property   name="email"
                type="string"
                column="EMAIL"
                length="255"
                not-null="true"/>
    <property   name="ranking"
                type="int"
                column="RANK"
                not-null="true"/>
    <property   name="admin"
                type="boolean"
                column="IS_ADMIN"
                not-null="true"/>
    <!-- Immutable property -->
    <property   name="created"
                column="CREATED"
                type="timestamp"
                length="60"
                update="false"
                not-null="true"/>
    <!-- Regular component mapping -->
    <component name="homeAddress" class="Address">
        <property   name="street"
                    type="string"
                    column="HOME_STREET"
                    length="255"/>
        <property   name="zipcode"
                    type="string"
                    column="HOME_ZIPCODE"
                    length="16"/>
        <property   name="city"
                    type="string"
                    column="HOME_CITY"
                    length="255"/>
    </component>
 
    <!-- A one-to-one shared primary key entity association -->
    <one-to-one name="shippingAddress"
                class="AddressEntity"
                cascade="save-update"/>
    <!-- Example legacy mapping of a component to a separate table. -->
    <join table="BILLING_ADDRESS" optional="true">
        <key column="USER_ID" foreign-key="FK_BILLING_ADDRESS"/>
        <component name="billingAddress" class="Address">
            <property   name="street"
                        type="string"
                        column="STREET"
                        length="255"/>
            <property   name="zipcode"
                        type="string"
                        column="ZIPCODE"
                        length="16"/>
            <property   name="city"
                        type="string"
                        column="CITY"
                        length="255"/>
        </component>
        <!-- Custom SQL! -->
        <sql-insert>
            insert into BILLING_ADDRESS
                            (STREET, ZIPCODE, CITY, USER_ID)
            values (?, ?, ?, ?)
        </sql-insert>
    </join>
    <!-- Custom SQL! -->
    <loader query-ref="loadUser"/>
    <!-- Custom SQL! -->
    <sql-insert>
        insert into USERS (OBJ_VERSION, FIRSTNAME, LASTNAME, USERNAME,
                           "PASSWORD", EMAIL, RANK, IS_ADMIN,
                           CREATED,
                           HOME_STREET, HOME_ZIPCODE, HOME_CITY,
                           USER_ID)
        values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    </sql-insert>
</class>
 
<!-- This query could also be in a separate file, names are global... -->
<sql-query name="loadUser">
    <return alias="u" class="User"/>
    select
        us.USER_ID      as {u.id},
        us.OBJ_VERSION  as {u.version},
        us.FIRSTNAME    as {u.firstname},
        us.LASTNAME     as {u.lastname},
        us.USERNAME     as {u.username},
        us."PASSWORD"   as {u.password},
        us.EMAIL        as {u.email},
        us.RANK         as {u.ranking},
        us.IS_ADMIN     as {u.admin},
        us.CREATED      as {u.created},
        us.HOME_STREET  as {u.homeAddress.street},
        us.HOME_ZIPCODE as {u.homeAddress.zipcode},
        us.HOME_CITY    as {u.homeAddress.city},
        ba.STREET       as {u.billingAddress.street},
        ba.ZIPCODE      as {u.billingAddress.zipcode},
        ba.CITY         as {u.billingAddress.city}
    from
        USERS us
    left outer join
        BILLING_ADDRESS ba
            on us.USER_ID = ba.USER_ID
    where
        us.USER_ID = :id
</sql-query>
</hibernate-mapping>