Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 321630

Summary: NPE in GenOperationImpl.isInvariant() called from GenOperationImpl.getName()
Product: [Modeling] EMF Reporter: Fabien Giquel <fabien.giquel>
Component: ToolsAssignee: Dave Steinberg <davidms>
Status: RESOLVED WONTFIX QA Contact:
Severity: normal    
Priority: P3 CC: Ed.Merks, Kenn.Hussey
Version: 2.6.0   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Bug Depends on:    
Bug Blocks: 318391    
Attachments:
Description Flags
Related code
none
related stack trace none

Description Fabien Giquel CLA 2010-08-03 12:37:19 EDT
Hi,

i encounter some NPE with GenOperationImpl.isInvariant() method when unloading UML.genmodel resource from my ResourceSet. 
I tried to isolate in some simple code a way to reproduce the problem : see attached action code which loads the files UML.ecore & UML.genmodel in a ResourceSet and then unload them.

The attached code does not give exactly the NullPointerException we got in our context (not at the same line of isInvariant() : line 1062, see bug 318391), but the cause is the same : related UML.ecore EObjects have been proxified.

Of course, unloading UML.genmodel before UML.ecore avoids the issue in related attached code. But is it a wrong path to use the opposite order ?

Thanks,
Fabien.
Comment 1 Fabien Giquel CLA 2010-08-03 12:37:49 EDT
Created attachment 175796 [details]
Related code
Comment 2 Fabien Giquel CLA 2010-08-03 12:38:11 EDT
Created attachment 175797 [details]
related stack trace
Comment 3 Nicolas Rouquette CLA 2010-08-03 17:06:35 EDT
The stack trace seeems to implicate a broken promise in the Ecore API somewhere.

The documentation for org.eclipse.emf.ecore.resource.Resource.getURIFragment(EObject) says:

   * Returns the URI {@link URI#fragment fragment} that,
   * when passed to {@link #getEObject getEObject} will return the given object.
   * <p>
   * In other words,
   * the following is <code>true</code> for any object contained by a resource:
   *<pre>
   *   Resource resource = eObject.eResource();
   *   eObject == resource.getEObject(resource.getURIFragment(eObject))
   *</pre>

In this case, the eobject argument is a proxy for an eobject defined in a resource that is no longer there.
What possible value other than null could Resource.getURIFragment() return?

At minimum, the answer should be clearly spelled out in the javadoc API. 

Although EMF itself is robust w.r.t. proxies, other EMF-based frameworks like EMF's genmodel/codegen may not be with downstream implications for other derivative frameworks like UML2's codegen.

The stack trace clearly corroborates this point, see: org.eclipse.emf.codegen.ecore.genmodel.impl.GenTypedElementImpl.isEObjectType()

    EClassifier type = getEcoreTypedElement().getEType();
    return type instanceof EClass && findGenClass((EClass)type).isEObject(); // GenTypeElementImpl, line 450

GenTypedElementImpl.getECoreTypedElement() is defined to return an ETypedElement; clearly this precludes returning InternalEObject proxies.

It seems unreasonable to me to ask the EMF folks to make the genmodel/codegen frameworks robust for the case where a *.genmodel resource is in memory but its *.ecore resource is unloaded.

It would be nice if the EMF Resource API supported the notion of resource dependencies, particularly w.r.t. respecting the order in which they have to be unloaded or at least clearly indicated in the API that this must be done in client frameworks/applications that use EMF.
Comment 4 Kenn Hussey CLA 2010-08-17 17:17:46 EDT
(In reply to comment #3)
> It seems unreasonable to me to ask the EMF folks to make the genmodel/codegen
> frameworks robust for the case where a *.genmodel resource is in memory but its
> *.ecore resource is unloaded.

I'm not sure how unreasonable it is; adding a guard to avoid this case wouldn't be a bad idea... In any case, if this issue is to be fixed, EMF is the place to do it.
Comment 5 Ed Merks CLA 2010-08-18 19:57:08 EDT
If if the name this produces really depends on things that can't be known anymore because the Ecore model is unloaded, adding a guard will just produce a wrong result for isInvariant in some cases and hence produce a wrong proxy, won't it?
Comment 6 Kenn Hussey CLA 2010-08-19 08:58:10 EDT
(In reply to comment #5)
> If if the name this produces really depends on things that can't be known
> anymore because the Ecore model is unloaded, adding a guard will just produce a
> wrong result for isInvariant in some cases and hence produce a wrong proxy,
> won't it?

Hmm, good point. In hindsight, I suppose the URI fragment for operations should not be based on information from another model (an unintended side-effect of the override in UML2). Unfortunately, I can't think of a way to work around this in UML2 without potentially breaking references from other UML2 generator models...
Comment 7 Ed Merks CLA 2010-08-19 09:38:59 EDT
The GenModel doesn't contain useful identifying information that could be used for improved (less fragile) fragments.  Relying on the Ecore model isn't a big problem even when unloading it first because the names in the Ecore model will still be available.  The bottom line though is there's not much I can do for this bugzilla, other than to have another version of getName that UML2 doesn't override to rely on more complex navigation...
Comment 8 Ed Merks CLA 2010-09-07 22:04:57 EDT
Given that a change in the base code would just mask the problem (return the wrong value which would produce the wrong name in UML) it seems better to fail and then to ensure that the genmodel itself is unloaded before the Ecore model it references.
Comment 9 Fabien Giquel CLA 2010-09-09 04:00:55 EDT
Ok, we will take it in account in related 318391.