Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 352577 - Provide custom CrossReferencer delegation
Summary: Provide custom CrossReferencer delegation
Status: NEW
Alias: None
Product: EMF
Classification: Modeling
Component: Core (show other bugs)
Version: 2.7.0   Edit
Hardware: PC Windows 7
: P3 enhancement with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: Ed Merks CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-07-20 09:31 EDT by Victor Roldan Betancort CLA
Modified: 2014-01-03 12:37 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Victor Roldan Betancort CLA 2011-07-20 09:31:48 EDT
org.eclipse.emf.ecore.util.EcoreUtil provides the CrossReferencer, an utility class that, as years passed by, its use become very much widespread among other EMF-based frameworks.

CrossReferencing a Resource or even just an EObject is a fairly lightweight operation when models are completely loaded in memory. However, it depends pretty much on the size of the model: as models grow, the operation becomes more intensive. Haven't calculated it, but it shouldn't be difficult to write a O() complexity formula for it.

With the appearance of CDO in the modeling scene, EMF models could grow further than the JVM Heap. CDO comes into play as the favourite "memory-virtualization" framework for EMF.

However, CrossReferencer current implementation doesn't go along very well with huge models stored in CDO. It implies loading the whole model in memory, and also implies a lot of round-tripping overhead.

It doesn't mean CrossReferencer implementation is wrong. It means that there probably should be a CrossReferencer for each persistence scenario. At that implies that it is desirable to contribute custom CrossReferencer implementations to the EMF core.

My proposal here is to provide some delegation or extensibility mechanism for the CrossReferencer class. So, pretty much the same way EMF does with other things, a CrossReferencer implementation should be selected in favor of another one, for example, depending of the type of Resource or EObject this class is actually CrossReferencing.

The requirement is that this should be transparent to CrossReferencer consumers. Other frameworks should be affected by this change (so, this means, no API breakage).

So, for instance, if a EMF-based framework uses CrossReferencer, it may, behind the scenes, be delegated to some custom implementation more suitable for their model (CDO, Teneo, and other scenarios...)
Comment 1 Victor Roldan Betancort CLA 2011-07-20 09:32:41 EDT
Please Ed, if you find any other requirements as the framework provider, feel free to add them here!
Comment 2 Ed Merks CLA 2012-01-18 09:56:12 EST
So this is mostly about the UsageCrossReferencer?  The only place the EMF framework itself uses this in the DeleteCommand.  Is that your primary concern?  

We might make the static finalAll methods (the resource and resource set ones) look for an adapter (on the resource or resource set)...

Or is ECrossReferenceAdapter also a concern?  It's not used in the framework...  We might support some type of adapter lookup mechanism there as well, but
Comment 3 Victor Roldan Betancort CLA 2012-02-01 10:01:15 EST
Ed, 

some comments below,

(In reply to comment #2)
> So this is mostly about the UsageCrossReferencer?  The only place the EMF
> framework itself uses this in the DeleteCommand.  Is that your primary concern? 

DeleteCommand is a concern, yes, but not the only one. The EMF framework, as you say, does not make any extensive use of the CrossReferncing utilities provided in EcoreUtils.

However, frameworks depending on EMF do make use of these utilities. Just some examples:

org.eclipse.gmf.runtime.emf.core.util.CrossReferenceAdapter (extends ECrossReferenceAdapter)

org.eclipse.m2m.internal.qvt.oml.ast.env.ModelParameterExtent.delete(List<EObject>, EObject)

calls:

org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer.findAll(Collection<?>, Collection<?>)

org.eclipse.emf.compare.diff.engine.GenericDiffEngine.doDiff(MatchModel, boolean)

calls:

org.eclipse.emf.ecore.util.EcoreUtil.CrossReferencer.CrossReferencer(EObject)

and I'm sure I could find more, but I dont have all EMF based frameworks in my target platform ;)

So CrossReferencing is something offered in the EMF framework that ended up being a basic operation for many frameworks. This is fine, but when dealing with models persisted in a CDO repository, that implies an important performance overhead, specially with large models. The assumption of "my models are on memory" are no longer valid with CDO fine-grained and lazy-load basics.

> We might make the static finalAll methods (the resource and resource set ones)
> look for an adapter (on the resource or resource set)...
> 

That sounds like a nice solution, I had doubts on how could those adapters be automatically installed (specially when those frameworks control a great deal of the execution flow), but that could be done in the Resource.Factory (right?)

> Or is ECrossReferenceAdapter also a concern?  It's not used in the framework...
>  We might support some type of adapter lookup mechanism there as well, but

Yes, ECrossReferenceAdapter is a concern (as shown above) and it's also a whole different story. I had to sub-class it and substitute with specialized logic. So it looks like there should be ECrossReferenceAdapter delegation mechanism too (I guess it's late to add factories...).
Comment 4 Ed Merks CLA 2012-04-06 09:14:16 EDT
So if we changed DeleteCommand.findReferences to the following then it would reuse a cross reference adapter, if there is one on the resource set

  protected Map<EObject, Collection<EStructuralFeature.Setting>> findReferences(Collection<EObject> eObjects)
  {
    ResourceSet resourceSet = domain.getResourceSet();
    ECrossReferenceAdapter crossReferenceAdapter = ECrossReferenceAdapter.getCrossReferenceAdapter(resourceSet);
    if (crossReferenceAdapter != null)
    {
      Map<EObject, Collection<EStructuralFeature.Setting>> result = new HashMap<EObject, Collection<EStructuralFeature.Setting>>();
      for (EObject eObject : eObjects)
      {
        result.put(eObject, crossReferenceAdapter.getInverseReferences(eObject, true));
      }
      return result;
    }
    else
    {
      return EcoreUtil.UsageCrossReferencer.findAll(eObjects, resourceSet);
    }
  }

That appears to be sufficient to address the issue in the core framework, but it's not clear that solves the downstream problems. But those are in other frameworks, so I'm not sure what to do about those.  As long as they make sure they install an adapter on the resource set that derives from ECrossReferenceAdapter, it's perhaps sufficient.

Does this help?
Comment 5 Victor Roldan Betancort CLA 2014-01-03 12:35:53 EST
Hi Ed,

sorry for not giving any feedback on this. 2013 is been a weird year :P

As you said, your suggestion may help for the core framework, but it wont to any other frameworks using EcoreUtil. CrossReferencer and subclasses are API and may be used anywhere. I haven't made an analysis of how much is it used, and sure your proposal would help.

Here's a simple and apparently innocuous proposal. Modification of org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer.find(EObject, EObject)

    public static Collection<EStructuralFeature.Setting> find(EObject eObjectOfInterest, EObject eObject)
    {
      CrossReferencerFactory factory = CrossReferencerFactory.Registry.INSTANCE.getFactoryFor(eObject);
      if (factory != null) {
        return factory.createUsageCrossReferencer(eObject).findUsage(eObjectOfInterest);  
      }   
      return new UsageCrossReferencer(eObject).findUsage(eObjectOfInterest);
    }
Comment 6 Victor Roldan Betancort CLA 2014-01-03 12:37:19 EST
If it looks good to you, I have a working prototype ready for review.