Bug 529564 - Support resolving uml::Packages from an EPackage definition
Summary: Support resolving uml::Packages from an EPackage definition
Status: CLOSED FIXED
Alias: None
Product: MDT.UML2
Classification: Modeling
Component: Core (show other bugs)
Version: 5.0.0   Edit
Hardware: All All
: P2 enhancement (vote)
Target Milestone: 5.4.0   Edit
Assignee: Camille Letavernier CLA
QA Contact:
URL:
Whiteboard:
Keywords: helpwanted
Depends on:
Blocks:
 
Reported: 2018-01-09 04:47 EST by Camille Letavernier CLA
Modified: 2018-06-28 11:39 EDT (History)
2 users (show)

See Also:
Kenn.Hussey: iplog+


Attachments
Proposed patch (3.55 KB, patch)
2018-01-09 04:50 EST, Camille Letavernier CLA
no flags Details | Diff
Two plug-ins (Example Profile/Library + Test case) (86.02 KB, application/octet-stream)
2018-01-10 12:32 EST, Camille Letavernier CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Camille Letavernier CLA 2018-01-09 04:47:03 EST
The method org.eclipse.uml2.uml.util.UMLUtil.getNamedElement(ENamedElement, EObject) doesn't support ENamedElements that should resolve to a uml::Package. The method assumes that all EPackage correspond to a uml::Profile

This isn't true in at least two cases:

- Since UML 2.4, a profile hierarchy may contain packages (IIRC, Profiles could only contain Profiles before that)
- Packages may be statically generated (Without any relationship to a profile)

The lack of support for Packages in this method makes it difficult to identify datatype instances in Profiles (Where Classes are converted to EClasses, and stereotypes applications can own instances of these - these datatype instances are not stereotype applications, they are not UML Instances, but they are still related to the UML Profile; however, we can't really distinguish them from standard EObjects unrelated to UML).

In the past, this also (indirectly) caused performance issues when manipulating stereotypes located in such packages, but this is now mitigated by the cache added in Bug 501740 (Although I suspect the initial lookup would still be slow, but I've not verified that)

Note: the real performance issue is caused by the LOOP code in getProfile(org.eclipse.uml2.uml.util.UMLUtil.getProfile(EPackage, EObject)) that iterates over the entire resource set, but IIRC, this was required for some specific applications (Was it CDO?) and couldn't simply be removed. So this ticket is about making best effort to avoid ever entering that LOOP when a matching Package can be found.
Comment 1 Camille Letavernier CLA 2018-01-09 04:50:22 EST
Created attachment 272185 [details]
Proposed patch

Proposed patch (Excluding tests)
Comment 2 Kenn Hussey CLA 2018-01-09 08:13:11 EST
This is an "internal" method that was originally designed to be used (only) to look up profile definitions. At the risk of endorsing the notion that this method is "API", I'll take a look at the proposed patch to see if it can be enhanced without any adverse side-effects.
Comment 3 Kenn Hussey CLA 2018-01-10 09:42:10 EST
Camille, I looked at the patch and have some feedback.

From what I can tell, the methods that were designed to look up profiles have been re-purposed for use with packages and then referenced by lookup method. Unfortunately, what those methods do for profiles doesn't apply to packages. Specifically, Ecore definitions for packages don't get nested in annotations the way those for (dynamic) profiles do and packages don't get registered in the ePackageNsURIToProfileLocationMap registry the way profiles do.

The main lookup method already falls back to looking for packages in the event that a matching profile (either nested in an annotation in the case of a dynamically defined profile or in the registry if a statically defined profile) isn't found, so I'm wondering what else it needs to do in order to fully support resolution of packages...
Comment 4 Ed Willink CLA 2018-01-10 10:04:17 EST
For OCL, where I try to use just the UML model, I find the EPackages something of a distraction. They are an implementation artefact that 'corrupts' some of the original UML model relationships.

It is probably better if a bidirectional UML2Ecore and Ecore2UML map is maintained (it's probably there already), then the Ecore lookup arguments can be mapped to UML where the relationships can be accurately traversed by a more rational lookup method before converting the result back to Ecore.
Comment 5 Camille Letavernier CLA 2018-01-10 10:11:54 EST
Hi Kenn,

To give a little bit more context: in Papyrus, we use this method to determine whether an EObject is a Stereotype Application, an instance of a DataType (From a Profile or Library), or is unrelated to the UML Model (e.g. a Diagram, ...)

Typically, our profiles also come with a standard library that is located outside of the profile, but contains UML Types that can be instantiated in Stereotype applications (e.g. DataTypes or Classes)

So, we register the Package via the org.eclipse.uml2.uml.generated_package extension point, then for an EObject that we find in the model, we use UMLUtil.getNamedElement(EClass, EObject) to find whether it is an instance of Stereotype, Class, DataType, or nothing related to UML.

Unfortunately, UMLUtil.getNamedElement() is unable to resolve Packages registered via the generated_package extension point (If it finds an EPackage, it will always try to resolve it to a Profile). Note: the Package is not located in a Profile, we're not looking for a Root profile owning the Package. It is a standalone Package (That may be imported by a Profile); I don't think this case is supported at all at the moment.

An alternative to my patch would be to provide optimized (performance-wide) utility methods to identify the nature of an EObject:

- UML Element (That's easy)
- Stereotype Application
- DataType (Or Class) instance (Typically owned by a Stereotype Application; I don't think such instances could live anywhere else. But more generally: any instance of an EClass that can be mapped to a UML Classifier other than a Stereotype)
- Unrelated to UML
Comment 6 Ed Willink CLA 2018-01-10 11:08:13 EST
(In reply to Camille Letavernier from comment #5)

An Ecore2UML lookup should solve all this:

> - UML Element (That's easy)
> - DataType (Or Class) instance

similarly easy - it's a UML element

> - Unrelated to UML

easy - the lookup returns null

> - Stereotype Application

This is the nightmare. OMG neglected to specify a StereotypeApplication class forcing everyone into the world of XMI magic.

For OCL's Pivot normalization of UML, there is a StereotypeApplication class called ElementExtension.

The UML2 project could make the use of the UML model very much easier by ensuring that the magic DynamicEObject is converted to a StereotypeApplication in memory and converted back to a DynamicEObject when saved. With this in place, the OCL support might never have to look at the embedded Ecore ever again.
Comment 7 Camille Letavernier CLA 2018-01-10 11:26:57 EST
> similarly easy – it's a UML element

No, it's not, that's the trick: DataType instances have 0 relationship to the UML Metamodel.

You define a uml::DataType in a UML Package/Model, convert it to an EClass via the UML2Ecore generator, then instantiate this EClass: the resulting EObject is not a UML instance

DataType instances are really similar to Stereotype Applications, except that they are not related to a Profile, but to a Package.

Such DataType instances exist when you define a Composition Association between a uml::Stereotype and uml::DataType (Or Class), then apply a stereotype: the Stereotype Application may own instances of the DataType (Or Class), via this custom Composite Association (Or simple Property). Neither the Stereotype Application nor the DataType instance can be related to UML without a valid Ecore-to-UML mapping (And although UMLUtil contains the API to do this mapping, it currently fails in the case of the DataType, and succeeds in the case of the StereotypeApplication - assuming the profile was properly generated, and extension points properly populated)
Comment 8 Ed Willink CLA 2018-01-10 11:48:39 EST
(In reply to Camille Letavernier from comment #7)
> No, it's not, that's the trick: DataType instances have 0 relationship to
> the UML Metamodel.

Ah! OK yet another omission from the OMG UML metamodel that Eclipse OCL evaluation over UML Instances supports using a UMLElementExtension.

The org.eclipse.ocl.pivot.uml.internal.library.UMLElementExtension object is not dependent on the OCL Pivot model; only a few helper methods are. UMLElementExtension could usefully be promoted to the UML2 project. 

UMLElementExtension extends DynamicEObjectImpl and adds:
	protected final org.eclipse.uml2.uml.@NonNull Element umlElement;
	protected final org.eclipse.uml2.uml.@NonNull Stereotype umlDynamicStereotype;
	protected final org.eclipse.uml2.uml.@NonNull Stereotype umlStaticStereotype;
Comment 9 Kenn Hussey CLA 2018-01-10 12:03:59 EST
(In reply to comment #5)
> So, we register the Package via the org.eclipse.uml2.uml.generated_package
> extension point, then for an EObject that we find in the model, we use
> UMLUtil.getNamedElement(EClass, EObject) to find whether it is an instance of
> Stereotype, Class, DataType, or nothing related to UML.

This is a mis-use of the extention point and lookup method as they are currently defined; both were designed to work with profiles (and indeed, the extension element you use to register a UML element is called "profile"). I could imagine an enhancement to the extension point that adds optional 'library' and 'metamodel' elements which could be used to register the correlation between library or metamodel and its generated Ecore counterpart; such an enhancement could then be leveraged to do some of the additional lookups you're asking for (see below).

> - Stereotype Application

The UML2 project itself uses either UMLUtil#getStereotype(EObject) or UMLUtil#getBaseElement(EObject) for this purpose.

> - DataType (Or Class) instance (Typically owned by a Stereotype Application; I
> don't think such instances could live anywhere else. But more generally: any
> instance of an EClass that can be mapped to a UML Classifier other than a
> Stereotype)

In order to achieve this, a more appropriate registration mechanism (like the enhancement I suggested above) should be implemented. Then, we could rework the current lookup method(s) to find any UML elements in profiles, metamodels, or libraries that have been registered via the extension point. It would, however, probably need to still be optimized for the profile use cases, in the interest of performance (since that's what they were designed to do in the first place).
Comment 10 Camille Letavernier CLA 2018-01-10 12:32:40 EST
Created attachment 272219 [details]
Two plug-ins (Example Profile/Library + Test case)
Comment 11 Camille Letavernier CLA 2018-01-10 12:32:47 EST
Sounds good to me

To clarify the use case, I attach two projects (One with a Profile + Library as we define them today in Papyrus, and a JUnit Plug-in Test case showing what I expect - two of them are failing without my patch, and working with it; but we can consider a different approach. The test is mostly there to highlight the various cases)
Comment 12 Kenn Hussey CLA 2018-01-10 13:03:19 EST
(In reply to comment #11)
> To clarify the use case, I attach two projects (One with a Profile + Library as
> we define them today in Papyrus, and a JUnit Plug-in Test case showing what I
> expect - two of them are failing without my patch, and working with it; but we
> can consider a different approach. The test is mostly there to highlight the
> various cases)

Thanks, it's great to have the use cases more clearly identified. Contributions towards implementing the alternative approach (since I don't think it's appropriate to pursue an approach that reinforces improper use of the existing extension point and look-up mechanisms) are most welcome!
Comment 13 Camille Letavernier CLA 2018-01-18 06:51:43 EST
Ok, I'll have a look at this.

Would it make sense to add a "package" element to the existing (org.eclipse.uml2.uml.generated_package / dynamic_package) extension points? Or should I go for a completely different one?

The extension point itself doesn't seem specific to profile (Except for the fact that it currently only accepts a "Profile" element)
Comment 14 Eclipse Genie CLA 2018-01-18 07:13:31 EST
New Gerrit change created: https://git.eclipse.org/r/115612
Comment 15 Camille Letavernier CLA 2018-01-18 07:19:37 EST
> New Gerrit change created: https://git.eclipse.org/r/115612

This gerrit adds a 'package' choice to the generatedPackage/dynamicPackage extension points, and populates a distinct repository.

In that scenario, when trying to resolve a Package from an Ecore URI, we will check both repositories (As a Package may be either a Package or a Profile - or even a Model, but I don't think it would make sense to add a third choice there)

I've only slightly changed my previous patch to account for the new extension point, so it may still find a Profile which has been registered as a Package, or a Package registered as a Profile (i.e. both extension points are interchangeable). I may add proper checks if needed. Another potential change would be to define the new (Package) registry as a super-set of the existing (Profile) one, since all Profiles are also Packages. Currently, profiles are stored in the profile registry, and Packages/Model are stored in the package registry (Assuming the extension points were correctly used; since we never load the URI to check if we're actually registering Profiles or Packages)
Comment 16 Kenn Hussey CLA 2018-01-18 09:31:57 EST
(In reply to comment #15)
> > New Gerrit change created: https://git.eclipse.org/r/115612

Thanks, Camille, I'll take a look as soon as I am able.

> Another potential change
> would be to define the new (Package) registry as a super-set of the existing
> (Profile) one, since all Profiles are also Packages. Currently, profiles are
> stored in the profile registry, and Packages/Model are stored in the package
> registry (Assuming the extension points were correctly used; since we never load
> the URI to check if we're actually registering Profiles or Packages)

The need to retain a separate, dedicated repository may depend on the performance implications. The two repositories should probably be treated conceptually as superset and subset; as such, it probably makes sense during plug-in initialization to dump all of the registered profiles (via the 'profile' extension element) into both repositories so that the lookup code only needs to iterate through one of them (the superset) when looking for packages.
Comment 17 Kenn Hussey CLA 2018-01-18 15:56:08 EST
(In reply to comment #16)
> (In reply to comment #15)
> > > New Gerrit change created: https://git.eclipse.org/r/115612
> 
> Thanks, Camille, I'll take a look as soon as I am able.

I added some comment and requested that the contribution be re-based against the 'master' branch.
Comment 18 Eclipse Genie CLA 2018-01-19 02:56:52 EST
New Gerrit change created: https://git.eclipse.org/r/115671
Comment 19 Camille Letavernier CLA 2018-01-19 03:03:54 EST
> I added some comment and requested that the contribution be re-based against the 'master' branch.

Were there actual comments, in addition to rebasing? If so, they don't appear on Gerrit. So for now, I've just rebased the commit
Comment 20 Kenn Hussey CLA 2018-01-19 13:53:13 EST
(In reply to comment #19)
> Were there actual comments, in addition to rebasing? If so, they don't appear on
> Gerrit. So for now, I've just rebased the commit

Yes, at least I tried to add them (I'm new to Gerrit so I may have done something wrong). I'll take a second look and include my comments here in case they don't show up in Gerrit.
Comment 21 Kenn Hussey CLA 2018-01-19 14:20:48 EST
(In reply to comment #20)
> I'll take a second look and include my comments here in case
> they don't show up in Gerrit.

Here are the comments I just posted:

plugins/org.eclipse.uml2.uml/schema/dynamic_package.exsd

Line 21:
I don’t think the dynamic registry needs to be expanded to handle packages, does it?


plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/UMLPlugin.java

Line 65:
I think it might be better to keep the original constructor and add the new one with the extra agrument.

Line 79:
I think this would be better done as two cases, 1) if profile, add it to both registries and 2) if package, add it to just the package registry.


plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java

Line 11575:
This doesn’t apply to generic packages, as they don’t have annotations as containers the same way (dynamic) profiles do.

Line 11601:
Per my comment on the plugin class, if profile registrations are also added to the package registry, we only need to check one of them (the general one) here.

Line 11627:
This doesn’t apply generally to packages as they don’t get annotated with this annotation the way profiles do.
Comment 23 Kenn Hussey CLA 2018-01-23 07:52:28 EST
The changes have been committed/pushed tothe 'master' branch in git and will be available in the next integration build.
Comment 24 Kenn Hussey CLA 2018-01-23 08:18:41 EST
An integration build containing the changes is now available.
Comment 25 Kenn Hussey CLA 2018-06-28 11:39:27 EDT
The changes are available in UML2 5.4.0 (as part of the simultaneous Eclipse Photon release).