CDO – Connected Data Objects

An introduction to CDO

This framework, which is a component of the EMF project, allows the sharing of an EMF model.
Whereas with Teneo we can make each client access a database (implementing a two-tier client/server solution), with CDO we make each client access a server which shares them the same model instance.
In this tutorial we will see how to:

  • install CDO
  • create a CDO server
  • create a CDO client

You can find a detailed documentation about CDO at the following link http://www.eclipse.org/cdo/documentation/
While you can download the various versions here  http://www.eclipse.org/cdo/downloads/

Installing CDO

Let’s see now how to install CDO starting from version Eclipse 4.3 (Kepler) Modeling. CDO can use several Store implementations; here we will prepare to use the DBStore.

Furthermore, since we will use a MySQL database, we have to make sure that the correspondent JDBC plug-in is installed (please note that if you followed the tutorial Teneo Setup for Eclipse 4.2 – Juno you can skip this step).
(Note: for a straightforward following of this tutorial it is advisable to use a MySQL version not beyond the 5.5)

Update Site => http://www.elver.org/eclipse/2.0.0/update/

  • MySQL Connector/J

Now let’s install  Net4j DB Adapter for MySQL
Update Site =>
http://download.eclipse.org/modeling/emf/cdo/updates/releases

Let’s expland the more recent category and select the following:

CDO R
> Net4j DB Framework
>> Net4j DB Framework MYSQL Adapter

Creating a CDO server

In this section we will see how to create a feature-based Eclipse product that will handle the launch of a CDO server defined by an XML configuration file.
In Eclipse a feature is a set of plug-ins which collaborate in order to provide a software functionality.
So let’s create a Feature Project with   File -> New -> Project… -> Plug-in Development -> Feature Project

press Next and at the next step give a name to our project, for example it.rcpvision.rcptutorial.cdo.server

then Finish.

What we just obtained is an empty feature; let’s go to tab Plug-ins and add the following plug-ins using button  Add…

Note: if you don’t want to add them one by one, here is the content of file feature.xml, which you can modify with tab “feature.xml

<?xml version="1.0" encoding="UTF-8"?>
<feature
      id="it.rcpvision.rcptutorial.cdo.server"
      label="Server"
      version="1.0.0.qualifier">
 
   <description url="http://www.example.com/description">
      [Enter Feature Description here.]
   </description>
 
   <copyright url="http://www.example.com/copyright">
      [Enter Copyright Description here.]
   </copyright>
 
   <license url="http://www.example.com/license">
      [Enter License Description here.]
   </license>
 
	<plugin id="com.mysql.jdbc" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.core.contenttype" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.core.jobs" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.core.runtime" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.core.runtime.compatibility.registry" download-size="0" install-size="0" version="0.0.0" fragment="true"/>
	<plugin id="org.eclipse.emf.cdo" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.emf.cdo.common" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.emf.cdo.server" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.emf.cdo.server.db" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.emf.cdo.server.net4j" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.emf.common" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.emf.ecore" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.emf.ecore.change" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.emf.ecore.xmi" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.equinox.app" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.equinox.common" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.equinox.preferences" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.equinox.registry" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.net4j" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.net4j.db" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.net4j.db.mysql" download-size="0" install-size="0" version="0.0.0" unpack="false"/> 
	<plugin id="org.eclipse.net4j.tcp" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.net4j.util" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.osgi" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.net4j.db.h2" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.h2" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
	<plugin id="org.eclipse.emf.cdo.server.product" download-size="0" install-size="0" version="0.0.0" unpack="false"/>
</feature>

Now let’s create a product based on this feature; just right-click on this project and select New -> Other… -> Plug-in Development -> Product Configuration

press Next.
At the next step give a name to our product, for instance  CDO-Server.product,

select “Use an existing product” radio-button and in the combo next to the selected radio-button set the value “org.eclipse.emf.cdo.server.product.tcp_h2“, then Finish.
What we just obtained is a product, but it is now plug-ins based.

in order to have it feature-based we need to select the correspondent radio-button

now, to list the features that make part of that product, select tab Dependencies

press button Add…

and select the just created feature (it.rcpvision.rcptutorial.cdo.server)

and save the product (Ctrl-S).

Now it’s time to define the XML configuration file for CDO. Let’s select the project and create a folder named “rootfiles” (right click, New -> Folder)
and then add another subfolder named “configuration

inside this folder let’s create a file (right click, New -> File) named cdo-server.xml and copy the following content inside

<?xml version="1.0" encoding="UTF-8"?>
<cdoServer>
 
    <acceptor type="tcp" listenAddr="0.0.0.0" port="2036">
    </acceptor>
 
    <repository name="demo">
 
        <store type="db">
            <mappingStrategy type="horizontal"/>
            <dbAdapter name="mysql"/>
            <dataSource
                class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
                url="jdbc:mysql://localhost/cdotest?createDatabaseIfNotExist=true"
                user="root"
                password="admin"
                />
        </store>
    </repository>
 
</cdoServer>

This configuration file indicates that a CDO server will be active on TCP port 2036 and it will make available a CDO repository named “demo“. Just after we find the database coordinates. Please note that at first startup or after a model change, it is advisable to drop the database; it will be created automatically at startup. Before launching the server we need yet to pass the location of the configuration file . In order to do so just select the product, go to Launching tab and in the VM Arguments section provide the following parameter value

-Dnet4j.config=${resource_loc:/it.rcpvision.rcptutorial.cdo.server/rootfiles/configuration}

save the product, get back to Overview tab and launch, with
Launch An Eclipse Application

The console should end with a message like this

!MESSAGE CDO server started

Verify that the database is successfully created.
(Note: if you get error messages please ensure that your firewall is not blocking ports 2036 and 3306)

Well, now at the network address of this computer, at the configured Net4j port (2036), the CDO repository named “demo” is available.

Just one note: in order to be prepared when we will need to deploy the product, it is advisable to make the product include also the configuration file (otherwise it would not be exported). To do this let’s open the build.properties file, go to Build tab and in the “Binary Build” section just select the folder “rootfiles“.

Creating a CDO client

Here we will use the same EMF model (the plug-in it.rcpvision.rcptutorial.model) used in previous tutorials (see ). In case you are going to do that tutorial again, consider that now, when creating the EMF Generator Model (.genmodel), at step “Select a Model Importer” you should select “Ecore model (CDO Native)“.
Otherwise, if you have the previous model plugin available (which was created without the CDO compatibility option) you can convert it by right-clicking file .genmodel and clicking on CDO -> Migrate EMF Generator Model (dynamic feature delegation)

and obviously re-generating model sources

further, in plug-in it.rcpvision.rcptutorial.model, we need to add a dependence on CDO

In the end we are ready to really create our client. Create an RCP application the usual way (see How to create an RCP application) and add the following dependences:

  • it.rcpvision.rcptutorial.model
  • org.eclipse.emf.cdo.net4j
  • org.eclipse.net4j.tcp
  • org.junit

Let’s create now a class named “TestCdoClient” in the main package, with the following content

package it.rcpvision.rcptutorial.application;

import library.Author;
import library.Book;
import library.Library;
import library.LibraryFactory;

import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.net4j.CDONet4jSession;
import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration;
import org.eclipse.emf.cdo.net4j.CDONet4jUtil;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.net4j.Net4jUtil;
import org.eclipse.net4j.connector.IConnector;
import org.eclipse.net4j.tcp.TCPUtil;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.lifecycle.ILifecycle;
import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
import org.junit.BeforeClass;
import org.junit.Test;

public class TestCdoClient {

    private static CDONet4jSession cdoSession;

    @BeforeClass
    public static void init() {
        //The following lines are not needed if the extension 
        //registry (OSGi/Equinox) is running
        Net4jUtil.prepareContainer(IPluginContainer.INSTANCE);
        TCPUtil.prepareContainer(IPluginContainer.INSTANCE);

        cdoSession = openSession("demo");
    }

    @Test
    public void popola() {
        try {
            CDOTransaction transaction = cdoSession.openTransaction();
            CDOResource resource = transaction.getOrCreateResource("/myResource");
            Library library = LibraryFactory.eINSTANCE.createLibrary();

            Book book = LibraryFactory.eINSTANCE.createBook();
            book.setTitle("Eclipse Modeling Framework (2nd edition)");
            library.getListBook().add(book);

            Author author = LibraryFactory.eINSTANCE.createAuthor();
            author.setName("Ed");
            author.setSurname("Merks");
            library.getListAuthor().add(author);
            book.getAuthor().add(author);

            author = LibraryFactory.eINSTANCE.createAuthor();
            author.setName("Marcelo");
            author.setSurname("Paternostro");
            library.getListAuthor().add(author);
            book.getAuthor().add(author);

            author = LibraryFactory.eINSTANCE.createAuthor();
            author.setName("Frank");
            author.setSurname("Budinsky");
            library.getListAuthor().add(author);
            book.getAuthor().add(author);

            author = LibraryFactory.eINSTANCE.createAuthor();
            author.setName("David");
            author.setSurname("Steinberg");
            library.getListAuthor().add(author);
            book.getAuthor().add(author);

            resource.getContents().add(library);
            transaction.commit();
            cdoSession.close();

        } catch (CommitException e) {
            e.printStackTrace();
        } finally {
            cdoSession.close();
        }
    }

    public static CDONet4jSession openSession(String repoName) {
        final IConnector connector = (IConnector) IPluginContainer.INSTANCE
                .getElement( //
                        "org.eclipse.net4j.connectors", // Product group
                        "tcp", // Type
                        "localhost"); // Description

        CDONet4jSessionConfiguration config = CDONet4jUtil
                .createNet4jSessionConfiguration();
        config.setConnector(connector);
        config.setRepositoryName(repoName);

        CDONet4jSession session = config.openNet4jSession();

        session.addListener(new LifecycleEventAdapter() {
            @Override
            protected void onDeactivated(ILifecycle lifecycle) {
                connector.close();
            }
        });

        return session;
    }

}

As you can see it is a JUnit test that connects to the “demo” CDO repository which is available at address “localhost” (should the client be executed on a different computer you should obviously change this address with the one from the CDO server). Then some model instance are created and persisted inside a CDO transaction.

Let’s launch it with right-click  Run As -> JUnit Test