Sphinx' ResourceSetListener, Notification Processing and URI change detection

The Sphinx framework adds functionality for model management to the base EMF tooling. Since it was developed within the Artop/AUTOSAR activities, it also includes code to make sure that the name-based references of AUTOSAR models are always correct. This includes some post processing after model changes by working on the notifications that are generated within a transaction.

Detecting changes in reference URIs and dirty state of resources

Assume that we have two resources SR.arxml (source) and target (TR.arxml) in the same ResourceSet (and on disk). TR contains an element TE with a qualified name /AUTOSAR/P/P2/Target which is referenced from a source element SE that is contained in SR. That means that the string "/AUTOSAR/P/P2/Target" is to be found somewhere in SR.arxml.

Now what happens if some code changes TE's name to NewName and saves the resource TR.arxml? If only TR.arxml would be saved, that means that we now would have an inconsistent model on disk, since the SR.arxml would still contain "/AUTOSAR/P/P2/Target" as a reference, which could not be resolved the next time the model is loaded.

We see that there are some model modifications that affect not only the resource of the modified elements, but also referencing resources. Sphinx determines the "affected" other resources and marks them as "dirty", so that they are serialized the next time the model is written to make sure that name based references are still correct.

But obviously, only changes that affect the URIs of referencing elements should cause other resources to be set to dirty. Features that are not involved should not have that effect. Sphinx offers the possibility to specify specific strategies per meta-model. The interface is IURIChangeDetectorDelegate.

The default implementation for XMI based resources is:

@Override
public ListdetectChangedURIs(Notification notification)
{
List uriChangeNotifications = new ArrayList();

Object notifier = notification.getNotifier();
if (notifier instanceof EObject) {
EObject eObject = (EObject) notifier;
uriChangeNotifications.add(new URIChangeNotification(eObject,
EcoreResourceUtil.getURI(eObject))); } return
uriChangeNotifications;
}

This will cause a change notification to be generated for any EObject that is modified, of course we do not want that. In contrast, the beginning of the Artop implementation of AutosarURIChangeDetectorDelegate looks like this:

    public List detectChangedURIs(Notification notification) {
List notifications = new ArrayList();
if (notification.getNotifier() instanceof EObject) {
EObject eObject = (EObject) notification.getNotifier();
if (IdentifiableUtil.isIdentifiable(eObject)) {
Object feature = notification.getFeature();
if (feature instanceof EAttribute) {
EAttribute attribute = (EAttribute) feature;
// we check that modified feature correspond to the
shortname of the identifiable
if ("shortName".equals(attribute.getName())) { //$NON-NLS-1$

A notification on a feature is only processed if the modified object is an Identifiable and the modified feature is the one used for URI calculation (shortName in AUTOSAR). There is additional code in this fragment to detect changes in containment hierarchy, which is not shown here.

So if you use Sphinx for your own metamodel with name based referencing, have a look at AutosarURIChangeDetectorDelegate and create your own custom implementation for efficiency.

LocalProxyChangeListener

In addition, Sphinx detects objects that have been removed from the containment tree and updates references by turning the removed object into proxies! That might be unexpected if you then work with the removed object later on. The rationale is well-explained in the Javadoc of LocalProxyChangeListener:

Detects {@link EObject model object}s that have been removed from their {@link org.eclipse.emf.ecore.EObject#eResource() containing resource} and/or their {@link EObject#eContainer containing object} and turns them as well as all their directly and indirectly contained objects into proxies. This offers the following benefits:

  • After removal of an {@link EObject model object} from its container, all other {@link EObject model object}s that are still referencing the removed {@link EObject model object} will know that the latter is no longer available but can still figure out its type and {@link URI}.
  • If a new {@link EObject model object} with the same type as the removed one is added to the same container again later on, the proxies which the other {@link EObject model object}s are still referencing will be resolved as usual and therefore get automatically replaced by the newly added {@link EObject model object}.
  • In big models, this approach can yield significant advantages in terms of performance because it helps avoiding full deletions of {@link EObject model object}s involving expensive searches for their cross-references and those of all their directly and indirectly contained objects. It does all the same not lead to references pointing at "floating" {@link EObject model object}s, i.e., {@link EObject model object}s that are not directly or indirectly contained in a resource.
About The Author

I am working at itemis as a project manager and business development manager (automotive) supporting and promoting the use of Eclipse and Open Source tooling for the implementation of integrated tool chains and the support of model driven (software) engineering.