Jump to: navigation, search

Difference between revisions of "CDO/Hibernate Store/Tutorial"

Line 221: Line 221:
== Change the mapping ==
The mapping is generated by [[Teneo|Teneo]]. Teneo preserves and uses any manual JPA annotations you place in the model or in a separate xml file. In the example project there is a separate mapping file which will be updated. The idea is to change the table name used to store addresses:
# Stop the CDO Server
# Open the file META-INF/company_model_teneo_annotations.xml and change the value theAddressTable to MyAddressTable.
# Drop and create the database manually.
# start the CDO server and run one of the testcases
The address is now stored in a different table. This was just a first example. The full range of JPA annotations is supported. Check out the [[CDO_Hibernate_Store_Model_Relational_Mapping|Model Relational Mapping]] page for much more information on all the mapping possibilities.
Wikis: [[CDO]] | [[Net4j]] | [[EMF]] | [[Eclipse]]
Wikis: [[CDO]] | [[Net4j]] | [[EMF]] | [[Eclipse]]

Revision as of 18:28, 21 January 2010

This tutorial assumes that the required dependencies are installed.

Download the example projects from CVS

As a first step download the example projects from CVS, see here for the CVS location information.

After downloading it is possible that you need to clean all the projects, goto Project > Clean (and clean all projects). The projects should not show any error messages.

After performing the above steps the Project Explorer should look like this:

Org.eclipse.emf.cdo.hibernate.project explorer.png

Details of the example projects

Before continuing take some time to study the projects.

The org.eclipse.emf.cdo.examples.company project contains the model. Instances of this model will be persisted. The model has been prepared for CDO. The interfaces inherit from CDOObject and the impl classes from CDOObjectImpl.

The org.eclipse.emf.cdo.examples.hibernate.server project contains the server side configuration files. This plugin is used on the server, it has been added to the launch configuration of the server. The org.eclipse.emf.cdo.examples.hibernate.server project contains a number of important files:

  • config/cdo-server.xml: the CDO server config file, for more information see the configuration page
  • META-INF/company_model_teneo_annotations.xml: contains JPA annotations which control how the model is mapped to the database. In this case there is only a simple annotation which controls the table name of the Address EClas.
  • META-INF/MANIFEST.MF: the plugin has been set to depend on org.eclipse.emf.cdo.server.hibernate.teneo, using the Eclipse buddy loading policy this makes the annotations xml file visible for the Hibernate/Teneo plugins

The org.eclipse.emf.cdo.examples.hibernate.client project contains the client side code. The actual runnable code consists of 2 test cases. Both test cases extend from BaseTest which contains the client-server connection code. The test cases are discussed in more detail below.

Start the CDO Server

As a next step, start the CDO server. To do this open the org.eclipse.emf.cdo.examples.hibernate.server project and right click on the CDOHibernateServer.launch and do: Run As > CDOHibernateServer. This launch configuration loads all plugins in the Eclipse installation and workspace so it takes some time to start the CDO server (around 10 seconds).


Note: Check in the console if you don't see an exception like this: java.net.BindException: Address already in use. If so stop the CDO server (in the console view, small red button), check the Debug view if you see any running CDO server processes, if so terminate them. Then also check on operating system level if you don't see CDO server processes (sometimes they are not shown in the Debug view) and kill/stop them.

At this point there is a running CDO Server using Hibernate and Teneo. The server uses hsqldb so it is not directly possible to see the database. It is quite easy to change this to mysql or another database (check the cdo-server.xml in the config folder, if you change it you need to restart the cdo server).

Run client code: QuickStartTest

The CDO server runs so now it is time to start running some client code. The client code can be found in the org.eclipse.emf.cdo.examples.hibernate.client project. Go to the src folder and navigate to the test cases. You will find three classes, one base parent class (BaseTest) and 2 junit test cases. Let's look at them in some detail.

The BaseTest class contains client-server connection code.

The initialize method builds the connection code and creates a CDOSessionConfiguration. The test cases use the TCP connector and CONNECTION_ADDRESS constant (which is localhost:2036). TCP and the portnumber are also specified in the cdo-server.xml, so the client and server use the same settings.

    // Prepare container
    final IManagedContainer container = ContainerUtil.createContainer();
    Net4jUtil.prepareContainer(container); // Register Net4j factories
    TCPUtil.prepareContainer(container); // Register TCP factories
    CDONet4jUtil.prepareContainer(container); // Register CDO factories
    // Create connector
    final IConnector connector = TCPUtil.getConnector(container, CONNECTION_ADDRESS);
    // Create configuration
    sessionConfiguration = CDONet4jUtil.createSessionConfiguration();

The sessionConfiguration is used in the openSession method to create a session and register the EPackage:

  protected CDOSession openSession()
    if (sessionConfiguration == null)
    final CDOSession cdoSession = sessionConfiguration.openSession();
    return cdoSession;

The EPackage is defined/generated in the org.eclipse.emf.cdo.examples.company project. The openSession method is called by the two subclasses.

As the BaseTest class has been discussed let's move to the first simple test case, the QuickStartTest contains a single test method. The first part:

    // first create an address and persist it
    final String addressName = "name " + System.currentTimeMillis(); //$NON-NLS-1$
      final CDOSession session = openSession();
      final CDOTransaction transaction = session.openTransaction();
      // get/create a resource
      CDOResource resource = transaction.getOrCreateResource("/res1"); //$NON-NLS-1$
      // clear any previous data
      final Address address = CompanyFactory.eINSTANCE.createAddress();
      address.setCity("test"); //$NON-NLS-1$
      address.setStreet("test"); //$NON-NLS-1$

The above code does the following:

  1. open a session and transaction
  2. create or get a resource, all data access takes place with an active resource
  3. create an address with some simple data, and add it to the resource
  4. commit (saves the resource) and close

Now the test case needs to check if the address actually got saved:

      final CDOSession session = openSession();
      final CDOTransaction transaction = session.openTransaction();
      CDOResource resource = transaction.getResource("/res1"); //$NON-NLS-1$
      assertTrue(resource.getContents().get(0) instanceof Address);
      assertEquals(1, resource.getContents().size());
      final Address address = (Address)resource.getContents().get(0);
      assertEquals(addressName, address.getName());

This reads the resource back and checks the content. We should find only one object and that should have the same information as persisted in the beginning.

Now run the test case, right click on it and then: Run As > Junit testcase. You should see a green bar after a few seconds. Also check out the console. Depending on which version of CDO/Teneo you are running you should see log statements showing actual activities and mappings taking place.

Run client code: HibernateQueryTest

The next test case shows some more advanced behavior, mainly the many different types of HQL queries which can be used on the client. See this page for a detailed description of the queries in this testcase. In this tutorial we will only do a quick review.

The HibernateQueryTest consists of 2 distinct parts: 1) creation of a test set, 2) query and check query results. The test data generation can be controlled with a number of static members in the top of the class:

private static final int NUM_OF_PRODUCTS = 20;
private static final int NUM_OF_CUSTOMERS = 5;
private static final int NUM_OF_SALES_ORDERS = 5;

You can change these values to increase the test volume. But before doing that first run the test case as it is, to be sure that it passes fine in its current form.

A number of methods are involved in generating the test data: fillResource, createSalesOrder, etc.

Now let's move to a first query test case (truncated a bit for this page):

  public void testSimpleQueries() throws Exception
    CDOSession session = openSession();
    CDOTransaction transaction = session.openTransaction();
      CDOQuery cdoQuery = transaction.createQuery("hql", "from Product"); //$NON-NLS-1$  //$NON-NLS-2$
      final List<Product> products = cdoQuery.getResult(Product.class);
      assertEquals(NUM_OF_PRODUCTS, products.size());
      CDOQuery cdoQuery = transaction.createQuery("hql", "from Product where name=:name"); //$NON-NLS-1$  //$NON-NLS-2$
      cdoQuery.setParameter("name", "" + 1); //$NON-NLS-1$  //$NON-NLS-2$
      final List<Product> products = cdoQuery.getResult(Product.class);
      assertEquals(1, products.size());
      CDOQuery cdoQuery = transaction.createQuery("hql", "from Product where vat=:vat"); //$NON-NLS-1$  //$NON-NLS-2$
      cdoQuery.setParameter("vat", VAT.VAT15); //$NON-NLS-1$ 
      final List<Product> products = cdoQuery.getResult(Product.class);
      assertEquals(10, products.size());
      for (Product p : products)
        assertEquals(p.getVat(), VAT.VAT15);

This test case shows a number of things:

  • queries are created by a transaction, the main api is formed by the CDOQuery object
  • the query language ("hql") is explicitly passed in as a first parameter
  • queries use the standard HQL syntax
  • the entity names used in the query are the names of the EClasses (Teneo can support many different naming strategies). So you use model elements naming in your queries.
  • you can pass in parameters, and use the actual object (enum, Date, CDOObject, etc.) as a parameter value

The other queries in the test case show other functionality of HQL in combination with CDO. For a more complete description check out the CDO Hibernate Store HQL page.

Change to Mysql (or another database...)

Hsqldb is fast but can be difficult to see at runtime what happens in the database. Therefore it can make sense to change the database being used. First stop the CDO server. Then open the config/cdo-server.xml file in the org.eclipse.emf.cdo.examples.hibernate.server project and look at the part which defines the database:

<!-- Setting for hsqldb -->
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:cdohibernate"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.autocommit" value="true"/>

and below that you can see the settings for mysql (commented out):

<!-- Setting for mysql
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/cdohibernate"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="root"/>

To see more of the database action and result we will change this to use mysql:

  1. comment out the hsqldb part and uncomment the mysql part.
  2. check the hibernate.connection.url for mysql, ensure that the host and port are correct, for now we will use the name cdohibernate for the database (you can take another name also, change the connection url also then)
  3. ensure that the username and password are correct for mysql
  4. create the cdohibernate database in mysql, without tables (this is not done by Hibernate)

Now save the cdo-server.xml and start the cdo server. Rerun the QuickStartTest and check the database, you should see the tables being created and the address table (called theaddresstable) contains an address.

Note: if you want to use another database then you can adapt the hibernate.connection settings accordingly. Also check the following:

  • determine what the correct hibernate dialect is to use for your database
  • as part of the install jdbc drivers have been installed for: mysql, hsqldb, h2, postgresql and derby. If you want to use another database then you need to find the osgi plugin for the jdbc driver for that database and install it (and then restart Eclipse).

Change the mapping

The mapping is generated by Teneo. Teneo preserves and uses any manual JPA annotations you place in the model or in a separate xml file. In the example project there is a separate mapping file which will be updated. The idea is to change the table name used to store addresses:

  1. Stop the CDO Server
  2. Open the file META-INF/company_model_teneo_annotations.xml and change the value theAddressTable to MyAddressTable.
  3. Drop and create the database manually.
  4. start the CDO server and run one of the testcases

The address is now stored in a different table. This was just a first example. The full range of JPA annotations is supported. Check out the Model Relational Mapping page for much more information on all the mapping possibilities.

Wikis: CDO | Net4j | EMF | Eclipse