Integrating with EMF and Other Frameworks

 

Author: Eike Stepper

CDO is an EMF persistence and collaboration layer. CDO model objects are still EMF EObjects, and CDO resources still participate in EMF resource sets. The CDO-specific part is the context around those objects: a session connects to a repository, a view defines the branch and repository time that is visible, and a transaction supplies the writable view.

This chapter concentrates on integration mechanisms: resource sets, CDO URIs, view providers, EMF adapters and commands, and supported extension points. Session configuration, view semantics, transactions and notification details belong to Working with Sessions, Working with Views, Working with Transactions, and Notifications and Event Handling.

Table of Contents

1 CDO in the EMF Programming Model
2 ResourceSet Integration
3 CDO URIs
4 View Providers
5 View-Provider Extension Point
6 Standard EMF Tools and Editing
7 Adapters and Remote Changes
8 UI and Other Frameworks
9 Lifecycle and Choosing an Integration

1  CDO in the EMF Programming Model

Use generated EMF interfaces, EObject, Resource, ResourceSet, and EcoreUtil with CDO objects where their contracts apply. A CDO object is not a second, unrelated model type. It is an EMF object whose state is managed by a CDO view and backed by repository revisions.

The important difference is context. A read-only view rejects mutations, a transaction records mutations until commit or rollback, and a historical view exposes a different revision from a floating view. Objects can be loaded lazily and can be invalidated by repository changes. Code that needs CDO-specific state can use CDOUtil.getCDOObject(EObject) or CDOUtil.getView(Notifier); code that only needs EMF behavior should remain expressed in EMF terms.

2  ResourceSet Integration

A view owns a CDO view set, and the view set owns exactly one ResourceSet. Obtain that resource set from CDOView.getResourceSet() or pass an application-created resource set when opening the view. The same set can contain ordinary EMF resources as well as CDO resources when the application has configured the corresponding resource factories.

Loading through ResourceSet.getResource(URI, boolean) is the normal EMF integration point. For a resource already associated with a view, CDOView.getResource(String) is also convenient. Do not mistake a resource factory registration for opening a session: a connection, view, and repository context must still be supplied by a directly opened view or by a matching view provider.

The resource set is an ownership boundary. Keep it alive while its CDO resources and objects are in use, and close the associated view or transaction before disposing the application component that owns the set. A resource that remains referenced after its view is closed is not a substitute for a live CDO view.

LoadResourceFromView.java      
ResourceSet resourceSet = view.getResourceSet();
URI uri = view.createResourceURI(path);
Resource resource = resourceSet.getResource(uri, true);
return (CDOResource)resource;

shows the direct pattern.

3  CDO URIs

CDO has a canonical cdo://repositoryUUID/resource/path form and connection-aware forms such as cdo.net4j.tcp://host:2036/repository/resource/path. The canonical form identifies a repository by UUID and requires the resource set to be associated with a view that can resolve that repository. A connection-aware URI contains transport information and a repository name, so a matching built-in provider can open the session and view.

Connection-aware URIs can carry branch, time, transactional, and prefetch query parameters. A branch path is relative to the branch tree; time=HEAD denotes the floating current state; transactional=true requests a transaction and is not valid with a historical time. The current Net4j providers use the cdo.net4j.jvm, cdo.net4j.tcp, cdo.net4j.ssl, cdo.net4j.ws, and cdo.net4j.wss schemes.

Use CDOView.createResourceURI(String) when a view already exists. Use CDOURIData to inspect a connection-aware URI and CDOURIUtil.extractResourcePath(URI) or CDOURIUtil.analyzePath(URI) to normalize its resource path. Avoid hand-parsing authority and query strings, and do not introduce the deprecated CDOURIUtil.createResourceURI(String, String) helpers into new code.

InspectURI.java      
CDOURIData data = new CDOURIData(uri);
return data.getScheme() + ":" + data.getRepositoryName() + CDOURIUtil.SEGMENT_SEPARATOR + data.getResourcePath().toPortableString();

illustrates the public parser.

4  View Providers

A CDOViewProvider adapts URI-driven EMF loading to CDO. When ResourceSet.getResource(URI, boolean) encounters a URI, the CDOViewProviderRegistry selects matching providers by regular expression and priority. The same selection can be requested explicitly with CDOViewProviderRegistry.provideView(URI, ResourceSet). The selected provider returns a view associated with that resource set; the CDO resource factory then serves the resource transparently to the EMF caller.

Built-in Net4j providers are contributed by the org.eclipse.emf.cdo.net4j plug-in. Applications should use them for the standard transport schemes and use a custom provider only when an application-specific URI scheme or repository selection policy is needed. A provider is an SPI implementation of a public interface, not a replacement for ordinary direct session and view APIs.

The registry reuses a view already present in the resource set's view set when possible. Otherwise the provider opens a view and the view set associates it with the resource set; the registry does not provide a general provider cache or transfer ownership of the session. The component that owns the view and session must close them, and must not keep using CDO resources after that lifecycle has ended.

CreateProvider.java      
return new AbstractCDOViewProvider("cdo\\.local://.*", 1000)
{
  @Override
  public CDOView getView(URI uri, ResourceSet resourceSet)
  {
    if (!repositoryName.equals(uri.authority()))
    {
      return null;
    }

    return session.openTransaction(resourceSet);
  }

  @Override
  public URI getResourceURI(CDOView view, String path)
  {
    URI uri = URI.createHierarchicalURI("cdo.local", repositoryName, null, null, null);
    return CDOURIUtil.appendResourcePath(uri, path);
  }
};

uses an injected session so that the provider does not hide connector and session configuration. The repository name is read from URI.authority(), without retaining the leading colon. This corrects the former legacy provider pattern without reactivating that excluded material.

5  View-Provider Extension Point

Plug-in applications can contribute providers with the org.eclipse.emf.cdo.viewProviders extension point. Each viewProvider specifies a public implementation class, a URI regular expression, and an optional integer priority (default 500); higher priorities win when several providers match. The implementation must have a usable no-argument construction path for the extension mechanism. Programmatic registration is more suitable when the provider needs application-owned state such as an already configured session.

The extension point is declared by the CDO plug-in and its schema is schema/viewProviders.exsd. Keep the regular expression narrow enough not to capture another provider's URI space. Remove programmatically registered providers when the contributing component is disposed. Provider registration does not transfer ownership of a session, connector, view, or resource set.

6  Standard EMF Tools and Editing

Generated model APIs, EMF traversal, adapters, and utilities such as EcoreUtil remain useful with CDO-backed objects. EMF Edit item-provider and command infrastructure can be used when the relevant edit plug-ins and adapter factories are present. A command that mutates a CDO object must execute against a writable CDO transaction, and the command stack's undo/redo history must not outlive the transaction context it records.

CDO transactions are not EMF Transaction framework transactions. CDO does not require a special EditingDomain for normal client access, and an application must not assume that an EMF transactional editing domain supplies CDO commit, locking, conflict, or branch semantics. If an application uses a transactional editing framework, treat it as an additional coordination layer and verify its command and notification assumptions.

Serialization is also contextual: saving a CDO resource through its CDO resource implementation is not the same as serializing a detached object graph to an ordinary file. Use a CDO resource URI and its owning view when the intent is repository access; use ordinary EMF resources when the intent is a standalone interchange file.

7  Adapters and Remote Changes

Ordinary EMF adapters can be attached to CDO objects. CDO-specific adapters and CDOAdapterPolicy change-subscription policies are available when an application needs selected remote changes delivered to adapters. A policy controls subscription and delivery; it does not replace passive updates or view invalidation.

Remove adapters and policies when the observing component is disposed. Do not infer that the repository is unchanged merely because an adapter did not receive a notification: objects may not be loaded or subscribed. For invalidation, subscription, and event ordering details, see Notifications and Event Handling.

8  UI and Other Frameworks

An Eclipse editor or viewer can consume a CDO resource through the same EMF resource and adapter-factory contracts as other EMF resources. UI plug-ins may add selection, navigation, and editor integrations, but those facilities remain UI concerns and should not be confused with the core URI/provider mechanism described here.

CDO currently has no general-purpose adapter layer for arbitrary third-party frameworks. Integrate such a framework through its documented EMF APIs, provide the required adapter factories, and make its lifecycle follow the CDO view and resource-set lifecycle. Do not assume that a framework that accepts EMF objects also understands lazy loading, read-only views, invalidation, or CDO transactions without an integration-specific adapter.

9  Lifecycle and Choosing an Integration

Direct session/view APIs are the clearest choice when the application owns connection setup, view reuse, commits, and shutdown. Use a view's resource set when an EMF-based component needs CDO resources while the application still controls the view. Use URI and view-provider integration when a component naturally calls ResourceSet.getResource(URI, boolean) and cannot be taught CDO session APIs; make the provider's session and view ownership explicit.

Use adapters and listeners for observation, with the cleanup rules in Notifications and Event Handling. Use the extension point for plug-in-discoverable provider implementations and programmatic registration for application-scoped providers. In every case, close the views and sessions owned by the integration component, remove providers owned by that component, and keep resource sets and command stacks within the lifetime of their CDO view or transaction.