Release Notes CDO 3.0

This document elaborates on the new and noteworthy enhancements in CDO 3.0.

  1. Release Notes CDO 3.0
    1. User Interface
      1. CDO Explorer Perspective has been added
      2. CDO Remote Sessions View has been added
      3. Common Navigator Framework Integration
      4. Legacy Mode Support
      5. Branching Support
      6. Dawn - Rise of the collaborative UI
    2. Core Framework
      1. Branching and merging is now supported
      2. Offline clones are now supported
      3. Increased server reliability though backup repositories
      4. Legacy models are now supported
      5. EMaps are now supported for DynamicCDOObject
      6. The transient modifier of an EStructuralFeature can now be overridden by annotation
      7. The session API to determine or wait for remote updates
      8. New session option for receiving more detailed commit infos
      9. Reattached objects now keep their original identity
      10. Push transactions have been introduced
      11. Changes in a local transaction can be exported and imported
      12. Successful commits can now be queried
      13. Better type support for queries
      14. New call-back hook after object state changes
      15. New call-back hook after branch point changes of a view
      16. New call-back hook after adapter notification
      17. New call-back hook after successful commits
      18. New call-back hook after repository state change
      19. New call-back hook after repository type change
      20. New API to distinguish local commits from remote commits
    3. DB Store
      1. New alternative mapping strategy for increased performance for particular list operations
      2. New model annotations are available to override mapping defaults
      3. External references are now supported
      4. Feature maps are now supported
      5. Unsettable Features are now supported properly
      6. SQL is now supported as a query language
    4. Hibernate Store
      1. Documentation has been completed
      2. Example projects added
      3. HQL is supported as a query language
      4. Teneo extension mechanism support added
      5. External references are supported
      6. Feature Map support has been added
    5. Objectivity Store
      1. Databases from Objectivity Inc. are now supported

Alternatively you can query Bugzilla directly to list

To get a complete overview about all API changes since version 2.0, breaking or compatible, you can

User Interface

CDO Explorer Perspective has been added

A new perspective has been added to let the user have a overall picture of the UI features the framework provides. It serves as an entry point to experiment with the main concepts of the framework.

CDO Remote Sessions View has been added

This view allows browsing active sessions in an specific repository and even perform communication with those.

Common Navigator Framework Integration

Now you may use a CDO model repository through a workspace project, allowing you to explore the repository:

Legacy Mode Support

You enable the new legacy model support through the CDO Sessions view, by enabling it in an opened session. Any view/transaction opened thereafter will be able to deal with EPackages that do not extend CDOObject.

Branching Support

CDO Sessions view now allows the user to switch the target branch of a CDOView. This way you can explore the state of a repository in certain branch.

Dawn - Rise of the collaborative UI

CDO now provides collaborative support for GMF editors over a CDO model repository with a new sub-component called Dawn. Dawn allows the storage of a GMF editor�s model data using CDO. It enables GMF editors to be used in a real-time shared editing scenario.

With a generated OSGi fragment an existing GMF editor can be connected to the Dawn runtime which provides the automatic synchronization of the editor as well as conflict detection and conflict handling mechanisms. More information about Dawn is provided on website.

See bugzilla 308232.

Core Framework

Branching and merging is now supported

Branches form an explicit, navigable tree in CDO. It is managed by a session's CDOBranchManager, which also emits CDOBranchCreatedEvent for local and remote branch creation.

    CDOBranch mainBranch = session.getBranchManager().getMainBranch();
    CDOBranch team1Branch = mainBranch.createBranch("team1", timeStamp);

    CDOTransaction transaction = session.openTransaction(team1Branch);
    CDOView view = session.openView(team1Branch, team1Branch.getBase().getTimeStamp());
    view.setBranchPoint(mainBranch.getHead());


Merging is also supported through the new merge(CDOBranchPoint source, CDOMerger merger) method in CDOTransaction. There are several default implementations of the CDOMerger interface provided. An interactive merger will be provided soon.

See bugzilla 270716.

Offline clones are now supported

You need to setup a normal repository as the master. Then you setup a second one via CDOServerUtil.createOfflineClone(String, IStore, Map<String, String>, IRepositorySynchronizer). Depending on the configuration of the synchronizer that you have to pass in there are certain restrictions on the store type of the clone repo. The clone is a repository by itself and can be embedded it into a client or made available via TCP transport to many clients. So, it can also be used the clone like a "group server" to serve a subset of the overall clients. That speeds up reads but slows down writes a little bit, as commits are "write-through".

For the clone creation you need a repository synchronizer. Use CDOServerUtil.createRepositorySynchronizer(CDOSessionConfigurationFactory). The synchronizer maintains a session to the master and tries to re-establish that session if the connection breaks down. See: IRepositorySynchronizer.setRetryInterval(int)

A clone repository has a state, one of OFFLINE, SYNCING, ONLINE. Reads are always served from the clone. commits are write-through if the clone is ONLINE. If the clone is not ONLINE, a commit from a client will create a new "local" branch (or offline branch) on the fly. Your client app will always have to check the CDOCommitInfo that is returned from tx.commit(). The branch in the info can be different from the branch of the local tx. In that case it usually makes sense to switch the local tx to the newly created offline branch and adjust the UI accordingly. You will also have to persist that branch info locally, so that you can use that branch after client restarts.

After an OFFLINE phase of the clone repo the synchronizer enters an intermediary SYNCING state and fetches new changesets. After syncing everything the clone transitions back to ONLINE. now your app can merge up from the offline branch and commit the result to the master (write-through).

There are 2 different replication mechanisms in the synchronizer:

See bugzilla 256936.

Increased server reliability though backup repositories

Reusing the basic mechanism of clone repositories there is now support for operating several backup repositories. In this scenario both master server and backup server(s) must be started as FailoverParticipants.

See bugzilla 203167.

Legacy models are now supported

Legacy models from a CDO perspective are those that have not been regenerated to support all CDO features natively. These models are now supported by CDO, although they do not support lazy loading and unloading of their instances. The legacy mode has to be enabled explicitely for new transactions/views:

    // Enable legacy support from now on for all views that will be opened by this thread
    CDOUtil.setLegacyModeDefault(true);

    CDOView view = session.openView();
    System.out.println("Legacy model support: " + view.isLegacyModeEnabled());


See bugzilla 247226.

EMaps are now supported for DynamicCDOObject

Using EMaps on DynamicCDOObjects is now supported.

See bugzilla 305723.

The transient modifier of an EStructuralFeature can now be overridden by annotation

Sometimes you want to use transient/persistent modifiers for particular structural features in CDO repositories that differ from the normal (XML) behaviour. The following annotation constants have been added to EMFUtil:

      public static final String CDO_ANNOTATION_SOURCE = "http://www.eclipse.org/emf/CDO";
      public static final String CDO_ANNOTATION_KEY_PERSISTENT = "persistent";


Their literals can be used in an Ecore model definition as follows:

      <eClassifiers xsi:type="ecore:EClass" name="Product1">
        <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="..." transient="true">
          <eAnnotations source="http://www.eclipse.org/emf/CDO">
            <details key="persistent" value="true"/>
          </eAnnotations>
        </eStructuralFeatures>
      </eClassifiers>


See bugzilla 290990.

The session API to determine or wait for remote updates

A getLastUpdateTime() method has been added to CDOSession. With the new waitForUpdate() methods in CDOSession you can, e.g., synchronize local views and transactions.

    final CDOCommitInfo commitInfo = transaction.commit();

    new Thread()
    {
      @Override
      public void run()
      {
        session.waitForUpdate(commitInfo.getTimeStamp());
      }
    }.start();


See bugzilla 283947.

New session option for receiving more detailed commit infos

A session can now be configured to receive full revision deltas instead of just invalidation keys.

    session.options().setPassiveUpdateMode(PassiveUpdateMode.CHANGES);
    session.addListener(new IListener()
    {
      public void notifyEvent(IEvent event)
      {
        if (event instanceof CDOSessionInvalidationEvent)
        {
          CDOSessionInvalidationEvent e = (CDOSessionInvalidationEvent)event;
          for (CDORevisionKey key : e.getChangedObjects())
          {
            CDORevisionDelta revisionDelta = (CDORevisionDelta)key;
            System.out.println("Feature deltas: " + revisionDelta.getFeatureDeltas());
          }
        }
      }
    });


A session can now be configured to receive full new revisions instead of only keys.

    session.options().setPassiveUpdateMode(PassiveUpdateMode.ADDITIONS);
    session.addListener(new IListener()
    {
      public void notifyEvent(IEvent event)
      {
        if (event instanceof CDOSessionInvalidationEvent)
        {
          CDOSessionInvalidationEvent e = (CDOSessionInvalidationEvent)event;
          for (CDOIDAndVersion key : e.getNewObjects())
          {
            CDORevision revision = (CDORevision)key;
            System.out.println("Container of new object: " + revision.data().getContainerID());
          }
        }
      }
    });


PassiveUpdateMode.ADDITIONS includes PassiveUpdateMode.CHANGES.
The default option is PassiveUpdateMode.INVALIDATIONS.
Note that the CDOSessionInvalidationEvent interface extends CDOCommitInfo.

See bugzilla 294528.

Reattached objects now keep their original identity

Formerly objects that were first being detached from a transaction and then being reattached to the same transaction were assigned a new identitiy. That was annoying in use cases like drag and drop in a user interface. Now the transaction remembers identities of detached objects and reassigns them if needed.

See bugzilla 294528.

Push transactions have been introduced

The new push transactions support commits to local files. Later the changes can be read from this local file and pushed to a repository.

    File file = new File("changes.bin");
    file.delete();

    // Open a new transaction and wrap it in a push transaction
    CDOPushTransaction transaction1 = new CDOPushTransaction(session.openTransaction(), file);

    // Commit to local file
    transaction1.commit();
    transaction1.close();

    // Open a new push transaction and load changes from local file
    CDOPushTransaction transaction2 = new CDOPushTransaction(session.openTransaction(), file);

    // Push changes to the repository
    transaction2.push();
    transaction2.close();


See bugzilla 297967.

Changes in a local transaction can be exported and imported

The method exportChanges() has been added to CDOTransaction.

    OutputStream fos = new FileOutputStream("changes.bin");

    try
    {
      CDOSavepoint[] savepoints = transaction1.exportChanges(fos);
    }
    finally
    {
      IOUtil.close(fos);
    }


The method importChanges() has been added to CDOTransaction.

    InputStream fis = new FileInputStream("changes.bin");

    try
    {
      CDOSavepoint[] savepoints = transaction2.importChanges(fis, true);
    }
    finally
    {
      IOUtil.close(fis);
    }


See bugzilla 298334.

Successful commits can now be queried

The concept of successful commits has been made explicit and queriable through CDOCommitInfoManager.

    CDOBranchManager branchManager = session.getBranchManager();
    CDOBranch mainBranch = branchManager.getMainBranch();

    CDOCommitInfoManager commitInfoManager = session.getCommitInfoManager();
    commitInfoManager.getCommitInfos(
        mainBranch,
        CDOBranchPoint.UNSPECIFIED_DATE,
        CDOBranchPoint.UNSPECIFIED_DATE,
        new CDOCommitInfoHandler()
        {
          public void handleCommitInfo(CDOCommitInfo commitInfo)
          {
            System.out.println("Commit comment: " + commitInfo.getComment());
          }
        });


See bugzilla 256649.

Better type support for queries

Several small enhancements have been applied to query and query result transport:

New call-back hook after object state changes

Provides a way of being notified about state changes of objects.

    CDOView view = session.openView();
    view.addObjectHandler(new CDOObjectHandler()
    {
      public void objectStateChanged(CDOView view, CDOObject object, CDOState oldState, CDOState newState)
      {
        System.out.println("Object transitioned to " + newState);
      }
    });


See bugzilla 292733.

New call-back hook after branch point changes of a view

Provides a way of being notified about target changes of views.

    CDOView view = session.openView();
    view.addListener(new IListener()
    {
      public void notifyEvent(IEvent event)
      {
        if (event instanceof CDOViewTargetChangedEvent)
        {
          CDOViewTargetChangedEvent e = (CDOViewTargetChangedEvent)event;
          System.out.println("A new view target has been set: " + e.getBranchPoint());
        }
      }
    });

    view.setBranch(view.getSession().getBranchManager().getMainBranch());
    view.setTimeStamp(CDOBranchPoint.UNSPECIFIED_DATE);
    view.setBranchPoint(anotherView);


See bugzilla 289880.

New call-back hook after adapter notification

Since adapter notification can cause side effects and the order of the notifications is unpredictable a new event is emitted by views to indicate the end of a notification series.

    CDOView view = session.openView();
    view.addListener(new IListener()
    {
      public void notifyEvent(IEvent event)
      {
        if (event instanceof CDOViewAdaptersNotifiedEvent)
        {
          CDOViewAdaptersNotifiedEvent e = (CDOViewAdaptersNotifiedEvent)event;
          System.out.println("All adapters have been notified about commit " + e.getTimeStamp());
        }
      }
    });


See bugzilla 289880.

New call-back hook after successful commits

Provides a way to handle transactions after they have been committed to the backend store.

    IRepository repository = CDOServerUtil.createRepository("myrepo", store, props);

    repository.addHandler(new IRepository.WriteAccessHandler()
    {
      public void handleTransactionBeforeCommitting(ITransaction transaction,
          IStoreAccessor.CommitContext commitContext, OMMonitor monitor) throws RuntimeException
      {
        System.out.println("About to commit " + transaction);
      }

      public void handleTransactionAfterCommitted(ITransaction transaction,
          IStoreAccessor.CommitContext commitContext, OMMonitor monitor)
      {
        System.out.println("Committed " + transaction);
      }
    });


See bugzilla 304959.

New call-back hook after repository state change

The repository state can change in an offline clone or in the backup repository of a fail-over scenario. The possible states are: INITIAL, OFFLINE, SYNCING and ONLINE.

See bugzilla 256936.

New call-back hook after repository type change

The repository type can change in the master and the backup repository of a fail-over scenario. The possible states are: INITIAL, OFFLINE, SYNCING and ONLINE.

See bugzilla 203167.

New API to distinguish local commits from remote commits

An isRemote() method has been added to CDOSessionInvalidationEvent.

    session.addListener(new IListener()
    {
      public void notifyEvent(IEvent event)
      {
        if (event instanceof CDOSessionInvalidationEvent)
        {
          CDOSessionInvalidationEvent e = (CDOSessionInvalidationEvent)event;
          if (e.isRemote())
          {
            System.out.println("A remote session has committed a transaction: " + e.getUserID());
          }
        }
      }
    });


See bugzilla 281566.

DB Store

New alternative mapping strategy for increased performance for particular list operations

The default mapping strategy for the audit-aware DBStore usually writes value lists (for many-valued features) completely for each revision. The new mapping strategy type horizontalAuditWithRanges uses a different approch: each list value is associated with a start and end revision indicating its lifetime. For applications in which lists are mostly extended by adding elements to the end of the lists, using this mapping strategy can lead to increased performance.

However, in cases where lists are rearranged, of if list entries in the middle of the list are removed regularly, the default mapping should still be the better choice. Also, as of now, this strategy can not be used together with the new branching feature.

To activate the alternative mapping strategy, use the following configuration setting in the server's configuration.xml:

<store type="db">
  <mappingStrategy type="horizontalAuditWithRanges">
    <property name="qualifiedNames" value="false"/>
  </mappingStrategy>
  ...
</store>


See bugzilla 296440.

New model annotations are available to override mapping defaults

The following new annotations are now recognized by the DBStore:

    public enum DBAnnotation
    {
      TABLE_MAPPING("tableMapping"),
      TABLE_NAME("tableName"),
      COLUMN_NAME("columnName"),
      COLUMN_TYPE("columnType"),
      COLUMN_LENGTH("columnLength");

      public final static String SOURCE_URI = "http://www.eclipse.org/CDO/DBStore";
    }


In CDO a structural feature can have multiple annotation with the same source, like:

    <eStructuralFeatures xsi:type="ecore:EAttribute" name="value"
                eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
      <eAnnotations source="http://www.eclipse.org/CDO/DBStore">
        <details key="columnName" value="HOLY"/>
      </eAnnotations>
      <eAnnotations source="http://www.eclipse.org/CDO/DBStore">
        <details key="columnType" value="CLOB"/>
      </eAnnotations>
    </eStructuralFeatures>


See bugzillas 284701, 282976, 284680.

External references are now supported

External references are created if an object managed by a transaction refers to an object that is either not managed by a view or is managed by a view to a different repository. Internally such references are represented by instances of CDOIDExternal and their CDOID.isExternal() method always returns true. In the database they appear as negative long values, indicating that the URI of the target object can be looked up in a separate table.

See bugzilla 249610.

Feature maps are now supported

If your model contains feature maps you can now use the DBStore to persist them.

See bugzilla 254455.

Unsettable Features are now supported properly

For EStructuralFeatures which have the unsettable property set to true, an additional boolean column is created in the corresponding database table which indicates if the feature is set. If an unset feature is stored, false is stored in the additional column and the feature's default value is stored in the feature's value field.

See bugzilla 284110.

SQL is now supported as a query language

If you are aware of the structure and meaning of a DBStore created mapping schema you can now use SQL to query the backend efficiently. Note that might need to consider version and/or branch information to prevent duplicate results from being returned.

    CDOQuery query = view.createQuery("sql", "SELECT CDO_ID FROM CUSTOMER ORDER BY NAME");
    List<Customer> customers = query.getResult(Customer.class);


See bugzilla 248933.

Hibernate Store

Documentation has been completed

The documentation of the Hibernate store has been completed and is available on the CDO wiki. The documentation includes a quick start and tutorial, an overview article on the architecture, download and install, model relational mapping specifics and details on the HQL support.

Example projects added

To ease the learning curve and facilitate starting with the Hibernate store 2 example development projects have been created and are downloadable from cvs. The example projects show how to setup the server side and shows examples of querying and updating on the client using the CDO-Hibernate store.

HQL is supported as a query language

The Hibernate store now supports HQL on the client. Practically the complete HQL syntax is supported:

In addition asynchronous queries are supported.

For more information on the HQL support see this wiki page.

Teneo extension mechanism support added

The CDO Hibernate store supports the Teneo extension mechanism. This allows you to replace core parts of Teneo's mapping logic with your own implementation. See here for more information.

External references are supported

By using special the special @External annotation it is now possible to persist references to objects which are not persisted directly in the CDO Hibernate store. See this Teneo documentation for more information.

Feature Map support has been added

Feature maps are now supported out-of-the-box. See this Teneo documentation for a general discussion on featuremap support, the CDO Hibernate store supports a similar mechanism.

Objectivity Store

Databases from Objectivity Inc. are now supported

See bugzilla 277420.