Closed eclipse-ocl-bot closed 1 month ago
By Ed Willink on Feb 02, 2009 02:48
In order to get an Ecore/EMOF-based OCL editor working on unnavigable opposites it is necessary to find a representation for a PropertyCallExp that can call a property opposite, and find a way to lookup such an opposite.
The OCL editor already uses a derived OCLAnalyzer and OCLEnvironment so using and providing a tryLookupOppositeProperty is easy. Re-using the OppositePropertyCallExp class introduced to solve the representation problem for QVTRelation, solves the problem for OCL as well.
However a QVTRelation class is not sensibly visible to an OCL editor, so I'm temporarily using an ExtendedOCL package that adds just the OppositePropertyCallExp class.
Possible alternative approaches using an annotation or an isOpposite property seem undesirable since an OppositePropertyCallExp has important semantic differences that the checkPropertyType validation must understand; easy for a derived class, clunky for a modified behaviour.
Are you happy to add OppositePropertyCallExp to ocl.ecore as a derivation of PropertyCallExp without any additional properties, or should I pursue the very heavyweight ExtendedOCL approach?
By Christian Damus on Feb 03, 2009 09:11
Would it be possible to refactor the editor a bit to make it extensible by QVT, for its context? I'm concerned about adding constructs to the OCL metamodel that the OCL parser will never be able to produce, and that it won't know how to consume when it is encounters them in a model.
What about the original problem of findNonNavigableAssociationEnds never being called? Can we refactor the abstract analyzer to improve that?
By Ed Willink on Feb 03, 2009 15:51
The editor already is extensible for QVT.
MDT-OCL is already extensible to support an OCL editor that edits constraints on Ecore models using unnavigable opposites. (This is not really a QVT issue; it's just that the QVT meta-models are my working example of Ecore meta-models that need such constraints.)
However the extension needs an OppositePropertyCallExp that I place in an ExtendedOCL meta-model and plug-in. This is a very heavyweight solution compared to a very simple addition to the Ecore OCL meta-model; hence the request for the class but not necessarily the associated analysis.
OppositePropertyCallExp is never produced by the CompleteOCL (UML) parser.
OppositePropertyCallExp is produced by an EssentialOCL (EMOF/Ecore) parser, if support for unnavigable opposites is considered to be appropriate for EssentialOCL - a very very grey area.
findNonNavigableAssociationEnds did not seem to be any help.
My derived Analyser just extends simplePropertyName to first lookup direct properties, and then lookup opposite properties and return an OppositePropertyCallExp rather than a PropertyCallExp.
[I haven't fixed implicitSource yet.]
By Christian Damus on Feb 06, 2009 09:10
(In reply to comment #3)\
findNonNavigableAssociationEnds did not seem to be any help.
Ah, I was rather hoping. That's OK.
My derived Analyser just extends simplePropertyName to first lookup direct properties, and then lookup opposite properties and return an OppositePropertyCallExp rather than a PropertyCallExp.
Well, we do have the "utilities" package that defines a number of non-standard types. Perhaps we can just add this opposite expression in there, then. That seems reasonable.
I suppose that the org.eclipse.ocl.ecore plug-in will need to provide an implementation of this construct, then, but not the org.eclipse.ocl.uml?
Can you supply a patch and re-assign the bug to me when it is ready? Thanks.
[I haven't fixed implicitSource yet.]
Ah. I'm not sure that you would want to. Would it not be a little surprising that the implicit source ends up resolving to a type that doesn't even have the property in the first place? It just seems a step too far ... I wouldn't even have wanted UML to have this feature. :-)
By Ed Willink on Mar 30, 2010 15:57
The following may be added to o.e.o.ecore.tests.AssociationTest:
\
/**
* Tests support for navigation of an opposite.\
*/\
public void test_navigateOpposite() {\
// navigate the association end. This end is multiplicity 1..1 by\
// definition\
parse(\
"package ocltest context Apple " +\
"inv: self.Fruit <> null" +\
" endpackage");\
}
It fails, reporting that Fruit is an undefined variable, after invoking the empty default AbstractEnvironment.findNonNavigableAssociationEnds() implementation.
The UML binding overrides findNonNavigableAssociationEnds to traverse all associations looking for an inverse.
The Ecore binding should also override, perhaps activating a CrossReferenceAdapter lazily.
By Axel Uhl on Apr 14, 2010 03:27
(In reply to comment #3)
However the extension needs an OppositePropertyCallExp that I place in an ExtendedOCL meta-model and plug-in. This is a very heavyweight solution compared to a very simple addition to the Ecore OCL meta-model; hence the request for the class but not necessarily the associated analysis.
OppositePropertyCallExp is never produced by the CompleteOCL (UML) parser.
OppositePropertyCallExp is produced by an EssentialOCL (EMOF/Ecore) parser, if support for unnavigable opposites is considered to be appropriate for EssentialOCL - a very very grey area.
As discussed before, I also think it's very helpful to optionally be able to add metadata to a Property/EReference in the EM(O)F case that would allow at least an OCL expression to navigate the reference in reverse direction. Scoping needs to be addressed just as it has to for allInstances(), so that's not a new issue.
I was wondering if maybe instead of annotating the forward EReference it would be possible to add an opposite EReference that is not owned by the class at the other end. This would be similar to the CMOF design then where the two properties of an association may either be owned by the association or by the class. This then decides whether the properties affect the respective class's contracts (generated Java interfaces and XMI serialization, in particular).
This way, no OppositePropertyCallExp would be necessary in the first place because a regular PropertyCallExp for the opposite EReference could be used. I'm just wondering where to compose the opposite property. Ideally it should be owned by the forward EReference so that when the forward reference is deleted, the opposite reference is deleted as well.
The locally-composed EReference would have the advantage that all multiplicity characteristics can be modeled in a straightforward and type-safe manner without any annotation encoding tricks.
I understand that this would require an extension to the EM(O)F M3/Ecore and can already hear what you're thinking. Still, it seems more straightforward to me than an annotation-based approach that subsequently requires a change in the OCL metamodel. At least, with the approach proposed we'd get away without introducing any new classes, only one new reference to optionally compose the opposite in an EReference.
Best,\ -- Axel
By Ed Willink on Apr 14, 2010 04:00
Hi Axel
I considered ways to abuse EReference, but there will inevitably be some EReference semantics that are violated and Ecore gets very upset when things are not right.
In order to resolve proxies it is mandatory that the containment path terminate via eResource on not null. In order to save a file it is manadatory that all EObjects are transitively contained. Validation will expect getEContainingClass consistency. eAllStructuralFeatures should return it ...
The problem all gets much harder in the context of OCL (Issue 12854) for which:
context MyClass\ def myProperty : MyClass = null\ def anotherProperty : MyClass = myProperty
requires an AST reference to a property that has no Ecore/EMOF counterpart. OCL 2.x has no solution to this.
I plan to resolve this with the Reflective Run-Time OCL Meta-Model so that the various forms of property (meta-model defined, meta-model implied opposites, user-defined, standard library defined) are all represented uniformly by an OclProperty whose URI is defined by the OCL standard.
With a family of OclXXX classes, the origin of the meta-model as EMOF, Ecore or UML should be invisible and homogeneity should not be necessary.
In principle PropertyCallExp must therefore reference an OclProperty which may be an opposite constructed in accordance with Ecore EAnnotations or EMOF Comments. [Don't need OppositePropertyCallExp after all, just a concrete syntax.] However the OclProperty is not necessarily persisted so the URI that persists the Property reference needs to encode the opposite access.
forward: referredProperty="http://my/model/Model.ecore#//MyClass/myProperty"
reverse: referredProperty="http://my/model/Model.ecore#//MyClass/myProperty?opposite"
[Need to do a bit of URI syntax study here.]
By Axel Uhl on Apr 15, 2010 04:16
(In reply to comment #5)
Hi Ed,
The UML binding overrides findNonNavigableAssociationEnds to traverse all associations looking for an inverse.
The Ecore binding should also override, perhaps activating a CrossReferenceAdapter lazily.
findNonNavigableAssociationEnds(C classifier, String name, List
ends) adds to the List
which for the Ecore case is a List
Best,\ -- Axel
By Axel Uhl on Apr 15, 2010 04:17
(In reply to comment #5)
Hi Ed,
The UML binding overrides findNonNavigableAssociationEnds to traverse all associations looking for an inverse.
The Ecore binding should also override, perhaps activating a CrossReferenceAdapter lazily.
findNonNavigableAssociationEnds(C classifier, String name, List
ends) adds\ to the List
which for the Ecore case is a List
Best,\ -- Axel
By Ed Willink on Apr 15, 2010 05:15
(In reply to comment #9)
findNonNavigableAssociationEnds(C classifier, String name, List
ends) adds to the List
which for the Ecore case is a List
, I assume. This suggests that it may not suffice to represent the non-navigable opposite in the Ecore model by just an annotation, but instead an EStructuralFeature element would be required. Or am I missing something?
Exactly. None of Ecore or EMOF or UML are suitable for internal OCL usage. A new OCL run-time meta-model is needed that from an MDT/OCL perspective has the major advantage of hiding the persistent representation of the meta-model.
In OCL the usage is of a Classifier and its associated information content. It does not matter whether it is an EClassifier or ... just so long as all the information to construct the OclClassifer is encoded in some way in the persistent Ecore/EMOF/UML/... representation. The OclClassifier can manage OclProperties as required.
By Axel Uhl on Jun 26, 2010 13:25
Created attachment 172839 (attachment deleted)\
Patch for OppositePropertyCallExp support
This patch adds OppositePropertyCallExp to the generic OCL metamodel and its two specializations (OCLEcore, OCL-UML). It uses the proposed annotation source and then "Property.oppositeRoleName" as details key.
"Hidden" opposites of this sort are found by the parser when resolving property names. Ecore lookup is performed using the Ecore package registry. An OppositePropertyCallExp is created then, referring to the forward property, meaning to traverse it backwards.
Backwards traversal by default is performed by looking for an ECrossReferenceAdapter. However, this behavior can also be adjusted by providing a more specific implementation of the new OppositeEndFinder interface to the EcoreEnvironmentFactory during its construction. For example, it is conceivable to perform lookup with the yet-in-incubation EMF Query2 component (we've prototyped this successfully).
By Axel Uhl on Jun 26, 2010 13:35
Oh, and BTW: the patch also contains a tiny fix towards improved extensibility of the delegate domain implementation: In the patch I changed the direct field access to delegateURI in AbstractOCLDelegateFactory.getDelegateDomain(...) to use getURI() so that specializations can redefine the otherwise final delegate URI.
By Ed Willink on Jun 27, 2010 12:41
This patch raises API compatibility challenges that are highlighted by setting 3.6 as an API baseline. (Windows->Preferences->Plugin Development->API baselines). 190-odd errors.
Adding a new class is no problem.
Adding a new method to an interface is, since anyone who implements that interface is broken until they also add the implementation. This kind of breakage can only occur at a major version change e.g. 3.0.0 to 4.0.0 which we plan to do this year, but we plan to have an interim 3.1.0 release to make the Xtext editors more useable, and that cannot change Environment.
Therefore, either this must wait until after 3.1.0 (perhaps November), or as a workaround you can create an additional Environment.WithOpposites interface that AbstractEnvironment implements and which you can cast to.
cf. BasicEnvironment2.
[It is often better to leave auto-generated Java out of patches, particularly when your workspace is not up-to-date. This keep the amount of code to review smaller and avoids spurious changes.]
I'm inclined to feel that this is a fair amount of work for you (and for me) and that the change will be rendered obsolete by the evolution to the pivot model. See http://wiki.eclipse.org/MDT/OCL/Pivot_Model.
By Axel Uhl on Jun 27, 2010 14:23
Ed,
thanks for the hints as to the compatibility rules that I wasn't aware of. I'll follow your recommendations and work on an improved version of the patch which does not add to existing interfaces.
We'd rather not wait for the Pivot approach since timelines are less clear than for such a patch, and adoption seems more difficult for us right now.
By Axel Uhl on Jun 27, 2010 17:58
Hi Ed,
I've managed to reproduce the error messages you mentioned. I notice that adding OppositePropertyCallExp in itself will add a field to EcorePackage and a method to EcoreFactory. Now, both are generated. Does the rule that nothing must be added to an interface between major releases also apply to generated code, particularly against the background of what you said about not including generated files in the patch?
Best,\ -- Axel
By Axel Uhl on Jun 27, 2010 18:04
What about missing @since tags in generated classes and interfaces, such as ExpressionsPackage? Do they have to go in there? And if so, where to best add them? In the OCLEcore.ecore?
By Axel Uhl on Jun 27, 2010 19:11
Created attachment 172863 (attachment deleted)\
Updated patch without additions to non-generated interfaces
Ed,
I've created an updated patch using your suggestions. I introduced EnvironmentWithHiddenOpposites and EvaluationEnvironmentWithHiddenOpposites and used casts where required. OCL Tests suites all pass. The key remaining issue as I understand it from your description of the backwards compatibility requirements is that introducing a new class to the OCL.ecore metamodel of course has that very effect on several generated intarfaces, including Visitor, Package and Factory.
Do the compatibility rules also apply to those generated interfaces? If so, I can hardly see how such a patch would generally be possible without a major release or by an extremely ugly metamodel extension in a separate EPackage which as its sole EClass owns OppositePropertyCallExp. Was that what you had in mind?
Otherwise, I'd opt for a clean extension with the next major release in November which would also save us the introduction of the auxiliary interfaces that this patch contains and instead would let us extend the standard interfaces Environment and EvaluationEnvironment as needed.
Your take?
Best,\ -- Axel
By Ed Willink on Jun 28, 2010 01:59
There are still 144 API problems.
API filters (quick fixes) can fix many of them, e.g. the constants for use rather than definition, buy while a new class in itself is not a problem, clearly its use in Ecore interfaces is.
The extra ExpressionsFactory.createOppositePropertyCallExp could perhaps be filtered since does anyone actually re-implement ExpressionsFactory? However the extra Visitor.visitOppositePropertyCallExp could break real users.
The solution to these as you observe is an ugly meta-model extension.
I think this has to be left for the povit model.
I'll leave the bug open, so that the pivot model gets JUnit tests, quite possibly based on your contribution.
By Axel Uhl on Jun 28, 2010 02:29
Hi Ed,
thanks for the comments. The Pivot model seems like a massive burden, and several questions seem still open (how/when to re-sync it after changes in an Ecore model; how does code generation which so far works off the Ecore have to change; when/how will the services available for Ecore models become available for Pivot models; ...), particularly from a life cycle management perspective, compared to an extension of the OCLEcore.ecore metamodel by one class which doesn't change anything about the life cycle. I advocate making the change in the November release, based on the first patch proposed which adds to Environment and EvaluationEnvironment, doesn't need to introduce additional auxiliary interfaces and comes with extension discussed to the Visitor interface. Compared to the changes required based on the Pivot approach this is still pretty manageable.
By Ed Willink on Jun 28, 2010 03:10
(In reply to comment #19)
The Pivot model seems like a massive burden,
It's hopefully proportionate; you only pay for what you use. It is extremely difficult (? impossible) to achieve OMG compliance on oclType() or getMetaClass() without providing a true OMG-compliant facade and without these it is very hard for MDT/OCL to progress along with the OCL specification.
and several questions seem still open (how/when to re-sync it after changes in an Ecore model;
Re-sync is automatic and 'instantaneous'.
how does code generation which so far works off the Ecore have to change;
No change; still works off Ecore.
when/how will the services available for Ecore models become available for Pivot models; ...), particularly from a life cycle management perspective, compared to an extension of the OCLEcore.ecore metamodel by one class which doesn't change anything about the life cycle. I advocate making the change in the November release, based on the first patch proposed which adds to Environment and EvaluationEnvironment, doesn't need to introduce additional auxiliary interfaces and comes with extension discussed to the Visitor interface. Compared to the changes required based on the Pivot approach this is still pretty manageable.
By Axel Uhl on Jun 28, 2010 05:56
Created attachment 172880 (attachment deleted)\
Patch that doesn't add method to Visitor interface
Ed,
after your proposal to tolerate additional factory methods and constants on the generated Factory and Package interfaces, I've created another version of the patch which gets along without adding a method to the Visitor interface. I subclassed Visitor by VisitorWithHiddenOpposite and added the corresponding visitOppositePropertyCallExp method there. Added downcasts to this interface where needed. Tests green.
If nobody objects because they provided an implementation for the ExpressionsFactory interface, that should be fine now, I hope.
Best,\ -- Axel
By Ed Willink on Jun 28, 2010 13:50
Sorry Axel, I wrote, "The extra ExpressionsFactory.createOppositePropertyCallExp could perhaps be filtered" using the stronger Visitor API breakage to give an easy decision.
My preferred direction, (does any other MDT/OCL committer have an opinion), is still to reject it.
It is an API violation, and it is surprising what our largely unknown customers do.
The benefit of the change is distinctly limited, and arguably not justified anyway since the OMG OCL specification fails to accommodate EMOF, defining opposites as an optional conformance point.
The change is not in accord with the planned evolution of the MDT/OCL project.
So this is WONTFIX until at least 3.1.0 when I hope the change will be resolved in other ways.
By Axel Uhl on Jun 29, 2010 02:10
Hi Ed,
this is pretty disappointing. You suggested the same direction with OppositePropertyCallExp a while ago. Very recently you suggested that if we provided a patch that implements it, you'd put it on the CVS trunk. Even after that you at least suggested that if API breakages should prohibit putting it on the trunk you could put it into the next major release around November which would be fine with us, as I indicated.
Now you imply that what you want to reject the patch because it's not in line with your intended direction of MDT/OCL. This has to come as an unpleasant surprise to those who spent time to work on such patches.
It would be interesting to hear other opinions on this.
Best,\ -- Axel
By Ed Willink on Jun 30, 2010 16:45
A comment by Anthony Hunter on cross-project-issues-dev:
"A few releases ago I thought it would be a great idea to fix a critical bug in a service release that required a new API in one of the modeling components. This incremented the minor version of one bundle (i.e. version 1.0.0 to version 1.1.0). This seemingly small change made one part of the community happy, but caused a large amount of grief from another part of the community whose translation fragments were broken and API binary compatibility questioned. I think we learnt our lesson and are sticking with the true and tested guidelines of only service revisions (bug fixes) in a service release (i.e. version 1.0.0 to version 1.0.1)."
By Axel Uhl on Jun 30, 2010 18:42
I'm happy with integrating the patch with the next major release. I fully understand the guidelines. Is 4.0.0 the release you mentioned is planned for November? I was just a bit irritated by your statement about rejecting the patch altogether. Could you please clarify what your plans are regarding the original issue and the patch I submitted in particular? Thanks.
By Axel Uhl on Jul 02, 2010 02:57
Created attachment 173270 (attachment deleted)\
Solution approach without modification to org.eclipse.* plugins
We've managed to come up with a solution to the problem without modifying any existing plugin. There are a few places where missing extensibility required some code copying, such as for HelperUtil and for OCLSyntaxHelper. Also, the ToStringVisitor creation can't be changed through a factory, so a little trick was required in OppositePropertyCallExp.accept.
With the approach displayed by the attached archive we can at least solve the problem for us while remaining on the standard EMF / MDT distribution. Of course we'd be happy if this mechanism became part of the MDT standard delivery.
Best,\ -- Axel
By Ed Willink on Jul 04, 2010 09:49
The new plugins use Java 6 and so give a bad class version error in a Java 5 environment. After correcting this and all the irritating @Override's that differ from 6 to 5...
At first sight the separate plugin demonstrates that you have not affected the API, however the need to change many of the tests raises questions. Running the new tests plugin variant gives 11 class cast failures in the Serialization tests. Restoring the SerializationTest.java to its original form cures the problems, so it seems that the problems affect only consumers of OCLWithHiddenOpposites, but there are problems.
If the problems are fixed, a new plugin is new functionality so it cannot go in 3.0.1. It could however go in 3.1.0. In 4.0.0 the functionality can be folded in, so the extra plugins would be deprecated but have to be maintained till at least 5.0.0.
I think it best that the availability of this enhancement is publicized so that those few users that care about opposites and can ensure adequate support throughout their tool chains can exploit it. See http://wiki.eclipse.org/MDT/OCL/FAQ#How_do_I_access_unnavigable_opposites_in_Ecore.
By Axel Uhl on Jul 04, 2010 15:53
(In reply to comment #27)
Hi Ed,
The new plugins use Java 6 and so give a bad class version error in a Java 5 environment. After correcting this and all the irritating @Override's that differ from 6 to 5...
what exactly are you referring to with "irritating @Override's?" Is that the issue with @Override in connection with interface methods getting implemented in classes and how that changed between 1.5 and 1.6?
At first sight the separate plugin demonstrates that you have not affected the API, however the need to change many of the tests raises questions. Running the new tests plugin variant gives 11 class cast failures in the Serialization tests. Restoring the SerializationTest.java to its original form cures the problems, so it seems that the problems affect only consumers of OCLWithHiddenOpposites, but there are problems.
You're of course right that the original tests should remain unchanged. However, I also wanted to ensure that using OCLWithHiddenOpposites passes the existing tests. This in particular meant that I had to clone the tests so that I could change calls to factory methods and explicit object creation such that they would instead refer to the OCLWithHiddenOpposites variants. I understand that cloning the tests (especially without renaming the packages) is not ideal. Suggestions?
If the problems are fixed, a new plugin is new functionality so it cannot go in 3.0.1. It could however go in 3.1.0. In 4.0.0 the functionality can be folded in, so the extra plugins would be deprecated but have to be maintained till at least 5.0.0.
I think it best that the availability of this enhancement is publicized so that those few users that care about opposites and can ensure adequate support throughout their tool chains can exploit it. See http://wiki.eclipse.org/MDT/OCL/FAQ#How_do_I_access_unnavigable_opposites_in_Ecore.
Thanks for referencing this thread there.
Best,\ -- Axel
By Ed Willink on Jul 04, 2010 16:44
(In reply to comment #28)
(In reply to comment #27)
what exactly are you referring to with "irritating @Override's?" Is that the issue with @Override in connection with interface methods getting implemented in classes and how that changed between 1.5 and 1.6?
Exactly. To ease consumption you need to specify J2SE1.5 like all the other Modeling plugins.
You're of course right that the original tests should remain unchanged. However, I also wanted to ensure that using OCLWithHiddenOpposites passes the existing tests. This in particular meant that I had to clone the tests so that I could change calls to factory methods and explicit object creation such that they would instead refer to the OCLWithHiddenOpposites variants. I understand that cloning the tests (especially without renaming the packages) is not ideal. Suggestions?
I see this as your contribution to anyone with similar concerns. It is up to you to achieve whatever quality you feel appropriate. Cloning the tests is probably very sensible for the limited lifetime of the contribution.
I would recommend splitting the contributions.
a) A tests patch much as you submitted but with all tests passing.
b) The add-on plugin that users actually use (as J2SE1.5).
By Axel Uhl on Jul 14, 2010 04:05
Created attachment 174263 (attachment deleted)\
Java-1.5 Solution without modifications to org.eclipse.*
Here's an updated version with Java-1.5 settings and the cloned tests. I've also removed the bin/ folders from the archive.
By Axel Uhl on Jul 14, 2010 04:05
Comment on attachment 173270 (attachment deleted)\
Solution approach without modification to org.eclipse.* plugins
obsoleted by the Java-1.5-specific attachment
By Ed Willink on Nov 09, 2010 01:54
See comments on Bug 323223.
I suggest a single plugin and related package paths:
org.eclipse.ocl.examples.ecore.opposites
including opposite finder as the package:
org.eclipse.ocl.examples.ecore.opposites.finder
Please trim the tests to the novel ones.
By Ed Willink on Nov 09, 2010 12:54
Following off-line consulation with Ed Merks, it appears that 'breaking' changes to the Factory API are acceptable so, let's see what this looks like as a patch that:
Adds OppositePropertyCallExp in OCLEcore.ecore only.\ Suppresses a 'breaking' API change in the Factory.\ Adds an additional derived Visitor2 interface that is instanceof checked in OppositePropertyCallExp.accept.\ Derived Visitor implementations such as ToStringVisitor should implement Visitor2 and so just add the extra visitOppositePropertyCallExp without extra classes.
Aargh! ToStringVisitor is not created by a factory method. I guess that you'll have to add an OppositePropertyCallExp<...> to o.e.o too. Enjoy editing OCL.uml and then reloading the genmodel to update OCL.ecore.
By Axel Uhl on Nov 10, 2010 09:02
(In reply to comment #33)
Following off-line consulation with Ed Merks, it appears that 'breaking' changes to the Factory API are acceptable so, let's see what this looks like as a patch that:
Adds OppositePropertyCallExp in OCLEcore.ecore only. Suppresses a 'breaking' API change in the Factory. Adds an additional derived Visitor2 interface that is instanceof checked in OppositePropertyCallExp.accept. Derived Visitor implementations such as ToStringVisitor should implement Visitor2 and so just add the extra visitOppositePropertyCallExp without extra classes.
Aargh! ToStringVisitor is not created by a factory method. I guess that you'll have to add an OppositePropertyCallExp<...> to o.e.o too. Enjoy editing OCL.uml and then reloading the genmodel to update OCL.ecore.
That was pretty much what was in the original patch, including the changes to the OCL.uml and the resulting .ecore. I'll update to the use of a refactored and renamed plugin for opposite end finding (proposed name: org.eclipse.emf.oppositeendfinder) which I'll submit together with a revised patch soon.
By Ed Willink on Nov 10, 2010 12:08
Sorry. It seems we should have got Ed's more enlightened interpretation of API compatibility earlier.
By Axel Uhl on Nov 10, 2010 16:54
Created attachment 182848 (attachment deleted)\
Additional bundle required by patch
Required by the updated patch submitted to be attached next. Offers an interface and default implementation to find the OMG-standardized Property.oppositeRoleName EReferences and allows for a pluggable and scopable allInstances() implementation
By Axel Uhl on Nov 10, 2010 16:57
Created attachment 182851 (attachment deleted)\
In-place patch for hidden opposites implementation
As an updated version of the original patch, this one adds compatibility filters as discussed with Ed Merks, leaving no incompatibilities while offering the hidden opposites feature. Depends on the oppositeendfinder bundle attached as 182848.
By Ed Willink on Nov 11, 2010 02:39
Mostly looks good. After a partial review you might care to act on/consider the following. No more time today.
org.eclipse.emf.oppositeendfinder: is there an EMF bugzilla for this contribution? (I don't like the plugin name at all - ?? org.eclipse.emf.ecore.opposites). The package is com.sap.emf.oppositeendfinder, not o.e...
o.e.o.ecore must reexport org.eclipse.emf.oppositeendfinder to avoid breaking the OCL console and other clients. Should also have a version bound.
OCL.genmodel was not reloaded dfrom OCL.uml.
EcoreEnvironment constructors. I'm not fond of the combinatorial explosion of constructors, mopst of which are never used. This may be where we should start using dependency injection. Perhaps we should see which are the favoured constructors and support only those. No setOpossiteFinder() during construction is awkward. Maybe we don't care since this may go deprecated with the Pivot. I think I prefer DI since it allows the existing API to be extended unchanged.
I don't think o.e.o.uml needs to have OppositePropertyCallExp.
OppositePropertyCallExp.gif seems to be invalid. I would suggest re-usuing PropertyCallExp and putting a right to left arrow underneath, or possibly rotating the internal property by 90 degrees.
OppositePropertyCallExpItemProvider.java has the neutral "Copyright (c) 2009 Eclipse Modeling Project and others" which you should change to 2010 and SAP. You can customize /org.eclipse.ocl/templates/Header.javajetinc.
OppositePropertyCallExpTest.java etc has a copied copyright.
OppositePropertyNavigator.java etc has no copyright.
AbstractOCLDelegateFactory.java independent (?unnecessary) change. Try to avoid overlapping patches; the merge tools really do bnot support it and reviews/commits get very hard.
OCLFactoryImpl - change does not preserve alphabetical ordering.
UMLReflectionImpl.getOCLCollectionType. This is internal API. I don't like expanding what Christian closed down, but the whole UMLReflectionImpl packaging is inconsistent, so maybe.
By Axel Uhl on Nov 11, 2010 11:22
(In reply to comment #38)
Mostly looks good. After a partial review you might care to act on/consider the following. No more time today.
org.eclipse.emf.oppositeendfinder: is there an EMF bugzilla for this contribution? (I don't like the plugin name at all - ??
No, no separate Bugzilla. It's just part of this contribution.
org.eclipse.emf.ecore.opposites). The package is com.sap.emf.oppositeendfinder, not o.e...
No problem with changing it accordingly.
o.e.o.ecore must reexport org.eclipse.emf.oppositeendfinder to avoid breaking the OCL console and other clients. Should also have a version bound.
I'll make o.e.emf.ecore.opposites version 3.1.0 and put a [3.1.0-4.0.0) version bound on the usage. Ok?
OCL.genmodel was not reloaded dfrom OCL.uml.
Sorry, my mistake. I accidentally reloaded it from the OCL.ecore model. I adjusted the OCL.uml accordingly and reloaded the OCL.genmodel, then re-generated and adjusted missing @since annotations again.
EcoreEnvironment constructors. I'm not fond of the combinatorial explosion of constructors, mopst of which are never used. This may be where we should start using dependency injection. Perhaps we should see which are the favoured constructors and support only those. No setOpossiteFinder() during construction is awkward. Maybe we don't care since this may go deprecated with the Pivot. I think I prefer DI since it allows the existing API to be extended unchanged.
I think this should be a separate issue. A constructor variant with OppositeEndFinder is required. The other constructors need to remain unchanged for backward compatibility. What exactly are you suggesting?
I don't think o.e.o.uml needs to have OppositePropertyCallExp.
I can remove it from the metamodel. I will then also split up OCLFactory into another OCLFactoryWithHiddenOpposite so that the o.e.o.uml bundle doesn't need to know at all about OppositePropertyCallExp.
OppositePropertyCallExp.gif seems to be invalid. I would suggest re-usuing PropertyCallExp and putting a right to left arrow underneath, or possibly rotating the internal property by 90 degrees.
Maybe a problem with patch creation. I got a warning about CVS having trouble with creation of binary file patches. I'll update the icon as suggested and attach separately.
OppositePropertyCallExpItemProvider.java has the neutral "Copyright (c) 2009 Eclipse Modeling Project and others" which you should change to 2010 and SAP. You can customize /org.eclipse.ocl/templates/Header.javajetinc.
OppositePropertyCallExpTest.java etc has a copied copyright.
OppositePropertyNavigator.java etc has no copyright.
Copyrights fixed.
AbstractOCLDelegateFactory.java independent (?unnecessary) change. Try to avoid overlapping patches; the merge tools really do bnot support it and reviews/commits get very hard.
Sorry, it was so minor that it slipped my attention. I've extracted it into a separate Bugzilla with a dedicated patch. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=329980. I've removed the change from the hiddenopposites patch for clarity.
OCLFactoryImpl - change does not preserve alphabetical ordering.
Fixed.
UMLReflectionImpl.getOCLCollectionType. This is internal API. I don't like expanding what Christian closed down, but the whole UMLReflectionImpl packaging is inconsistent, so maybe.
Sorry, I'm not sure I understand what you mean by this. Could you please clarify what you'd like me to change? I need the respective feature in EcoreEnvironment.getOppositePropertyType(...). What's a better way to get access to it compared to making UMLReflectionImpl.getOCLCollectionType public?
The updated patch and opposites bundle follow as attachment any moment.
By Axel Uhl on Nov 11, 2010 11:24
Created attachment 182910 Icon for OppositePropertyCallExp
In case CVS has difficulties with importing/exporting binaries
OppositePropertyCallExp.gif
By Axel Uhl on Nov 11, 2010 11:28
Created attachment 182911 (attachment deleted)\
Additional bundle required by patch (opposites)
Now renamed to org.eclipse.emf.ecore.opposites as proposed by Ed
By Axel Uhl on Nov 11, 2010 11:30
Created attachment 182913 (attachment deleted)\
In-place patch for hidden opposites implementation
Incorporating Ed's latest comments. Tests all green. OCL for UML no longer knows about OppositePropertyCallExp.
By Axel Uhl on Nov 11, 2010 11:49
Created attachment 182917 (attachment deleted)\
Additional bundle required by patch (opposites)
Now with proper copyrights
By Axel Uhl on Nov 11, 2010 12:07
Created attachment 182920 (attachment deleted)\
In-place patch for hidden opposites implementation
This time with Association between OppositePropertyCallExp and referred opposite property added to OCL.uml
By Ed Willink on Nov 11, 2010 12:59
(In reply to comment #39)
org.eclipse.emf.oppositeendfinder: is there an EMF bugzilla for this contribution? (I don't like the plugin name at all - ??
No, no separate Bugzilla. It's just part of this contribution.
I'm confused. An org.eclipse.emf... should be part of EMF not OCL. If Ed agreed that this would be incorporated into EMF then you will need a separate Bugzilla for the separate IP review. Alternatively if it not part of EMF, then we need an OCL package location.
EcoreEnvironment constructors. I'm not fond of the combinatorial explosion of constructors, mopst of which are never used. This may be where we should start using dependency injection. Perhaps we should see which are the favoured constructors and support only those. No setOpossiteFinder() during construction is awkward. Maybe we don't care since this may go deprecated with the Pivot. I think I prefer DI since it allows the existing API to be extended unchanged.
I think this should be a separate issue. A constructor variant with OppositeEndFinder is required. The other constructors need to remain unchanged for backward compatibility. What exactly are you suggesting?
The old way was to add new constructor/set methods for every interacting object. This is inflexible and doesn't scale.
The new way is to @Inject an interface and bind implementations externally. Much more flexible but requires com.google.guice from Orbit. Indeed a separate prerequisite Bugzilla to introduce the dependency/initialization modeule.
UMLReflectionImpl.getOCLCollectionType. This is internal API. I don't like expanding what Christian closed down, but the whole UMLReflectionImpl packaging is inconsistent, so maybe.
Sorry, I'm not sure I understand what you mean by this. Could you please clarify what you'd like me to change? I need the respective feature in EcoreEnvironment.getOppositePropertyType(...). What's a better way to get access to it compared to making UMLReflectionImpl.getOCLCollectionType public?
Christian left us with a high quality project maintained with high integrity, which I feel we should continue. If something was not public API we need to investigate carefully. I cannot really see any reason why this method has package restriction. I would do a quick rummage to see whether there are perhaps CollectionUtil or other methods that do the same.
By Axel Uhl on Nov 11, 2010 15:47
(In reply to comment #45)
(In reply to comment #39)
org.eclipse.emf.oppositeendfinder: is there an EMF bugzilla for this contribution? (I don't like the plugin name at all - ??
No, no separate Bugzilla. It's just part of this contribution.
I'm confused. An org.eclipse.emf... should be part of EMF not OCL. If Ed agreed that this would be incorporated into EMF then you will need a separate Bugzilla for the separate IP review. Alternatively if it not part of EMF, then we need an OCL package location.
Ah, now I see. If the package location is the issue then I'll rename it to org.eclipse.ocl.ecore.opposites. No, I hadn't talked to Ed Merks about this one. We only discussed the event manager part for which I created a Bugzilla and which doesn't need the opposites stuff. Logically, the opposites part could be useful to anyone dealing with Ecore/EMF. However, I think as it's required for the hiddenopposites OCL part and the impact analyzer, for now it's best homed in OCL. I'll rename it, post it as a separate Bugzilla and then maybe you can create a dependency of this bugzilla on the new one.
EcoreEnvironment constructors. I'm not fond of the combinatorial explosion of constructors, mopst of which are never used. This may be where we should start using dependency injection. Perhaps we should see which are the favoured constructors and support only those. No setOpossiteFinder() during construction is awkward. Maybe we don't care since this may go deprecated with the Pivot. I think I prefer DI since it allows the existing API to be extended unchanged.
I think this should be a separate issue. A constructor variant with OppositeEndFinder is required. The other constructors need to remain unchanged for backward compatibility. What exactly are you suggesting?
The old way was to add new constructor/set methods for every interacting object. This is inflexible and doesn't scale.
The new way is to @Inject an interface and bind implementations externally. Much more flexible but requires com.google.guice from Orbit. Indeed a separate prerequisite Bugzilla to introduce the dependency/initialization modeule.
So we agree that this is a separate issue. I suggest we first try to get this one resolved and then open a new bugzilla for general DI topics.
UMLReflectionImpl.getOCLCollectionType. This is internal API. I don't like expanding what Christian closed down, but the whole UMLReflectionImpl packaging is inconsistent, so maybe.
Sorry, I'm not sure I understand what you mean by this. Could you please clarify what you'd like me to change? I need the respective feature in EcoreEnvironment.getOppositePropertyType(...). What's a better way to get access to it compared to making UMLReflectionImpl.getOCLCollectionType public?
Christian left us with a high quality project maintained with high integrity, which I feel we should continue. If something was not public API we need to investigate carefully. I cannot really see any reason why this method has package restriction. I would do a quick rummage to see whether there are perhaps CollectionUtil or other methods that do the same.
CollectionUtil largely deals with the construction of java.util.Collection objects, not with the creation of OCLCollectionType instantiations. I have looked around quite a bit but was unable to find similar functionality. Alternatively, I'd have to clone this piece of code which seems less reasonable to me.
By Axel Uhl on Nov 11, 2010 16:30
Depends on 330045 (https://bugs.eclipse.org/bugs/show_bug.cgi?id=330045) which obsoletes attachment https://bugs.eclipse.org/bugs/attachment.cgi?id=182917
By Axel Uhl on Nov 11, 2010 16:32
Created attachment 182939 (attachment deleted)\
In-place patch for hidden opposites implementation
Now with dependency on separate bugzilla https://bugs.eclipse.org/bugs/show_bug.cgi?id=330045 with renamed bundle org.eclipse.ocl.ecore.opposites.
By Ed Willink on Nov 12, 2010 17:21
I've now reviewed most of the opposite code...
Reviewing your code also forces me to review some existing code and so we have a mix of issues to consider.
AbstractVisitor/EvaluationVisitorImpl.propertyCallExp
The AbstractVisitor comments describe how source may be null for implicit self. However EvaluationVisitorImpl would clearly NPE for a null self. I think the analyzer always reifies implicit self using an explicit self varaible. OCL 2.2 clearly defines source for PropertyCallExp [A], [B], [D] allowing null for [C] which is a static property. Bug 330090 raised. Clearly there can be no opposite static properties so source can never be null for OppositePropertyCallExp.
qualifiers
These seem to be ignored by the EcoreEvaluationEnvironment, although there is a UML-derived FeatureMap idiom that might activate them. Leave it for the pivot model.
autogenerated and @since
If you put the @since within the
*'WithHiddenOpposites'
This is rather clumsy and not very informative or accurate. It doesn't scale well. I think SWT gives us a better precedent. e.g ITextHover, then ITextHoverExtension then ITextHoverExtension2... I think we should consider new rather than extending interfaces; VisitorExtension, OCLFactoryExtension. Then, in MDT/OCL 4.0.0, we minimize the API change by just making Visitor extend VisitorExtension. If code steadily migrates to use the derived 'WithHiddenOpposites' we would have to change it all back to once the 'WithHiddenOpposites' is promoted. The SWT approach requires no change at promotion, just an option to delete redundant interfaces.
I think this makes EvaluationVisitorWithHiddenOpposite obsolete since EvaluationVisitorDecorator can just extend EvaluationVisitor and VisitorExtension.
OppositePropertyCallExpImpl.accept
This is implemented solely for OCL
When the instanceof test fails, this is surely an UnsupportedOperation. null happens to be ok for evaluation but not more generally.\ (Ditto EvaluationVisitorDecorator, OCLFactoryWithHistory).
OppositePropertyCallExpOperations.checkPropertyType
No implementation and no tests of the implementation.
OppositeEndFinder
This not what the class does; none of its methods return an opposite end, since the opposite cannot be reified as an EReference.\ It is a PropertyNavigator. (Also AssociationEnd was discontinued in UML 2.0).
navigateOppositePropertyWithForwardScope, navigateOppositePropertyWithBackwardScope
where is the definition of scope and see? Why is the actual implementation identical?\ should be EReference argument.
OppositePropertyNavigator
This no longer needs to be a separate class. Half of it is copied from EvaluationVisitorImpl and the other half belongs there.
There seem to be too many classes doing not a great deal in a 1:1 relationship.
Perhaps we want an ExtentMapFactory (default built-in, reconfigurable by DI) that creates a derived ExtentMap.
navigateOppositeProperty(EStructuralFeature
This should be navigateOppositeProperty(EReference so that the type check is done up front. This implies EReference in the Ecore file.
(EClass) property.eContainer() is confusing. Use property.getEContainingClass(). .isSuperTypeOf(resultCandidate.eClass() is confusing. Use .isInstance(resultCandidate).
if (propertyValue == target\
|| (propertyValue instanceof Collection<?> && ((Collection<?>) propertyValue).contains(target))) {
can this ever fail? containment is very strict in Ecore and MOF.
result = coerceValue(property, resultCandidate, /* copy */true);
surely this is coercing to the type at the wrong end?
} else if (oppositeEndFinder == null) {
can this ever sensibly happen? perhaps an assert in the constructor.
result = oppositeEndFinder.navigateOppositePropertyWithForwardScope(property, (EObject) target);
there is no coerceValue here. coerceValue should be redundant with the static analysis scheduling explicit conversions, but at present the code occasionally needs dynamic conversion.
There also seems to be significant logic duplication with navigateOppositePropertyWithSymmetricScope.
EnvironmentWithHiddenOpposites.getHiddenOppositeProperties(C classifier)
should be CLS cls.
DefaultOppositeEndFinder.subclasses
The comment is subclasses, but the implementation is proper subclasses.
DefaultOppositeEndFinder.cacheSubclassRelations
This is a confusing name because it works upwards rather than downwards. I would expect it to gather known derived classes rather than register with all superclasses. You don't seem to exploit transitivity. I think a lazy implementation in which a request for the subclasses of X computes the union of the subclasses of X would be better, but I guess you need the pivot meta-model to have the transient subClasses eOpposite of superClasses. In the meantime ESuperAdapter might help.
DefaultOppositeEndFinder.updateOppositeCache -> cachePackage -> cache, cacheSubclassRelations -> cacheSubclassForSuperclass*
These names are not obviously part of the same algorithm which is accumulate all caches rather than update opposite cache; there is no deletion of obsolete packages. I think that 'update' is a major functionality increment that requires a fix to Bug 315034. Until we support mutation by design, I see little point supporting partial meta-model mutation. So there seems no point incurring the repeated cost of the O(Classes*Depth) traversal with full filtered set insertion throughout.
DefaultOppositeEndFinder.getAllOppositeEnds(EClassifier
should take an EClass argument.\ oppositesOnEClass is unclear. Perhaps referringEClasses.
DefaultOppositeEndFinder.getAllSubclasses
is never used, so subclasses seems redundant. Odd since it should be used.
EcoreEvaluationEnvironment(OppositeEndFinder oppositeEndFinder)
I don't like this extra constructor. Currently we have zero OppositeEndFinder algorithms. You add one. If we want more then use dependency injection and/or a set method to allow external binding.
EcoreEvaluationEnvironment.createExtentMap
You have fundamentally changed the implementation class. How do you realize the old functionality. It appears that 'oppsiteEndFinder' must be an arbitrary end finder.
OCLMessages.properties
'Assembles a description of a' describes what happens rather than why it happens.\ (OCL is internationalized and the translators need to understand the context.)
tryLookupOppositeProperty
The tryLookup alternate API was introduced to allow multiple returns and failures for QVT that the\ original lookup didn't support. Since opposite is new API there is no need for both and the associated\ tests and casts. Perhaps eliminate tryLookup and give lookup the tryLookup signature.
TypeUtil
This is informally deprecated since it uses static methods. You should find that you don't need to extend it.
AbstractVisitor.visitOppositePropertyCallExp\ // source is null when the property call expression is an\ // association class navigation qualifier\ Is this comment true? Surely opposites apply only to property navigation?\ and do opposite properties have qualifiers ? (and even if they did is the\ OCL specification implementable here?)
AbstractVisitor.handleOppositePropertyCallExp
same qualifiers query. @param callExp is wrong.
ToStringVisitor
probably worth factoring out a handlePropertyQualifiers into AbstractVisitor so that EvaluationVisitor uses it too.
EvaluationVisitorImpl.visitOppositePropertyCallExp
Why no opposite counterpart of getPropertyBody(property)? A Complete OCL document could augment a hidden opposite! OK Complete OCL support is not complete. Another problem fixed by the pivot model.
Logger
You use a non-static instance of java.util.Logger. The messages are not internationalized and do not go via the plugin log. Xtext and so the examples plugins uses the com.apache.log4j logger, but I'm not sure that the integration with the error log is yet right.
OCLEcore.ecore
Why doesn't OppositePropertyCallExp extend OppositePropertyCallExp<...> in the same pattern as PropertyCallExp?
AbstractOCLAnalyzer.simpleNameCS
if (astNode == null) {\
astNode = simplePropertyName(simpleNameCS, env, source,\
sourceElementType, simpleName);\
}\
if (astNode == null) {\
astNode = simpleOppositePropertyName(simpleNameCS, env, source,\
sourceElementType, simpleName);\
}
is not right because for each implicit self you must consider property and opposite for the first\ self before moving on to the second. You will find the second self.property rather than the\ first self.opposite.
Javadoc
There are many missing @param clauses which gives warnings during build.
By Ed Willink on Nov 13, 2010 04:49
Bug 329959 has been marked as a duplicate of this bug.
| --- | --- | | Bugzilla Link | 251621 | | Status | CLOSED FIXED | | Importance | P3 enhancement | | Reported | Oct 21, 2008 17:08 EDT | | Modified | Sep 29, 2013 18:26 EDT | | Blocks | 318248 | | Reporter | Ed Willink |
Description
Bug #245586 started with a discussion of whether OCL should or should not assist QVT in using unnamed opposites in EMOF; the discussion was inconclusive and diverted to refactoring simpleNameCS to allow a derived simplePropertyNameCS which solves the problem within QVTr.
I have just started writing the missing validation constraints for QVTr using my IMP-based MDT OCL text editor. So I'm writing pure MDT OCL expressions referring to the QVT meta-model which is defined in Ecore/EMOF.
I find that I cannot use the implicit toLeadingLower name to navigate a default-named relationship, because AbstractEnvironment.findNonNavigableAssociationEnds is never called.
It is difficult to resolve this in a derived implementation because of a number of private methods.
I'll submit a patch that at least makes derivation possible once bug #242236 has settled. You can choose whether to accept a larger patch that performs the resolution as well.