| Summary: | [ast] Allow for selection of hidden opposite-supporting factory in delegate domain | ||
|---|---|---|---|
| Product: | [Modeling] OCL | Reporter: | Axel Uhl <eclipse> |
| Component: | Core | Assignee: | OCL Inbox <mdt-ocl-inbox> |
| Status: | CLOSED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | ed |
| Version: | 3.1.0 | ||
| Target Milestone: | 3.1.0 | ||
| Hardware: | PC | ||
| OS: | Windows 7 | ||
| Whiteboard: | |||
| Attachments: | |||
|
Description
Axel Uhl
(In reply to comment #0) > Proposed solution: look for a detail on the delegate annotation that turns > "hidden opposites" on. Presuming you mean an EPackage annotation detail. > For a holistic solution, this should also be settable by the OCLinEcore > editors. There already is default capability for any EAnnotation. However OCL annotations deserve a first class syntax. Possibly package xxx { options { environmentFactory = '...'; } The options should perhaps support any Parsing/Evaluation option. It is probably worth considering how options are communicated to the CDO server as part of this activity. The same solution may suit both requirements. We need to be clear that there are three levels of options resolution. a) the default built-in settings b) the overrides embedded within EPackage EAnnotations c) the overrides programmatically inserted in an Environment Created attachment 193957 [details]
Introduces hiddenOpposites detail on OCL package annotation
Allows the use of hiddenOpposites=true annotation detail in the OCL package annotation. This is now evaluated by the OCLDelegateDomain constructor, and the EcoreEnvironmentFactoryWithHiddenOpposites is used if it's set.
Contains corresponding test case, required extension of the HiddenOpposites test model as well as a bit of documentation.
It currently only supports the use of the DefaultOppositeEndFinder as the opposite end finder can't be configured. The issue is that even if we'd allow for the specification of a fully-qualified class name, class path issues could thwart the easy creation of the opposite end finder class if outside of the OCL bundle (which it usually would be if it isn't the DefaultOppositeEndFinder). I'll open a bugzilla for that, depending on this one.
(In reply to comment #2) > It currently only supports the use of the DefaultOppositeEndFinder as the > opposite end finder can't be configured. The issue is that even if we'd allow > for the specification of a fully-qualified class name, class path issues could > thwart the easy creation of the opposite end finder class if outside of the OCL > bundle (which it usually would be if it isn't the DefaultOppositeEndFinder). > I'll open a bugzilla for that, depending on this one. grep the EMF code, particularly the validation delegate dispatcher for ClassLoader. There's some strange code that makes sure that the user's class loader is in use. This may be what's needed to use the plugin of the Ecore. (Not a separate Bugzilla; a necessary part of this one.) Do you mean ./org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/XMLHandler.java:2502: Class<?> javaClass = Class.forName(className, true, Thread.currentThread().getContextClassLoader()); ? This looks as if it depended on the thread currently invoking some piece of code. How can we know that the desired OppositeEndFinder is in scope for any of the class loaders "accidentally" triggering the delegate domain constructor? No. I was thinking of EObjectValidator line 334
return
new DynamicEClassValidator()
{
// Ensure that the class loader for this class will be used downstream.
//
}.validate(eClass, eObject, diagnostics, context);
Both snippets may help solve the following:
The annotation will reference a class from an Ecore file, that, in an Eclipse environment, forms part of a plugin that has a class path. That class path can be required to include the target path, so it is just necessary to access the class from a class loader for the plugin.
For standalone usage, the standalone application must provide access to the class on its own class path.
(In reply to comment #5) We may be able to determine the class loader that loads classes for an Ecore model. It is certainly ok that an Ecore model that makes use of hidden opposites specifies so in its OCL annotation. However, it feels wrong to fix the OppositeEndFinder class by an annotation in the package. This choice should be "injected" by the using environment. Ideally, the client of the Ecore that uses hidden opposites would be able to specify the OppositeEndFinder to use. However, other than by a heavy-weight and global extension point (which would also cleanly solve the class loading issue) I'm not aware of a good, reliable way for performing such an injection. Having the client explicitly invoke some setter for the OppositeEndFinder raises the question of synchronization and the right point in time for calling such a setter. Ideas? My initial instinct was to allow the user environment to influence the use of a model, but for different reasons I observed a very similar problem with the pivot model. EMF delegates are a service required by and declared by an Ecore model. Using an editing domain, the Ecore model may be shared by many applications, therefore the shared service should be independent of each application, else one application can disrupt the behaviour of another. So since the Ecore model declares the service, only the Ecore model can parameterize that declaration and the Ecore model provides the context for resolution of that parameterization. (In reply to comment #7) > So since the Ecore model declares the service, only the Ecore model can > parameterize that declaration and the Ecore model provides the context for > resolution of that parameterization. Another way to view it is this: an Ecore model provides the structural declarations. It depends on a specific application how these declarations are rendered in a persistence service (CDO, file system storage as XMI, ...), and the Ecore model/plugin doesn't and shouldn't know. The Ecore model does not specify from where its instance models can be loaded. Also, query2 scope definitions are independent of what the Ecore model specifies. I see the opposite end finder as a related mechanism that should be independent of the Ecore model's definitions. The Ecore model should only have to specify that it *does* use hidden opposites, not how they have to be resolved scope-wise. Yes. Every interesting problem in software engineeering can be solved by an extra level of indirection. But exactly what is the intermediate? Call it a "key" that identifies a "handler" for now. Keys are defined: - primarily by OCL with default priority handlers - extensibly by extension points with default handlers Handlers are requested by an Ecore model by listing required keys. Applications may specifically override the key response by programmatically specifying a higher priority handler. Tool suites may generically override the key response by specifying an extension point with a higher priority handler. So what is a key? Do we need this new terminology or is an extension point id directly reusable as a key? Prioritised extension points seem the solution. So the Ecore model just specifies to activate the highest priority registration for a facility identified by an extension point, that can have a facility-specific schema to define whatever is appropriate. This is now nothing to do with OCL; just an ability for an Ecore model to trigger extension points during loading. Check the existing EMF load capabilities; there are a lot of facilities already that few users are aware of. Perhaps there's something similar. (In reply to comment #9) Extension points are one way. They are global in the sense that they require the participating bundles to be singletons. A pretty heavy-weight approach and not really context-sensitive. How about using DefaultOppositeEndFinder by default unless a specific ThreadLocal has been set by the thread calling the delegate? Not completely thought through. One problem seems to be that currently the OppositeEndFinder is fixed by a triple of EcoreEnvironmentFactory/EcoreEvaluationEnvironment/EcoreEnvironment. And this in turn is attached to one OCL which is attached to one OCLDelegateDomain which for one delegate URI is probably unique for the EMF/Ecore bundle and hence presumably even unique for the VM (singleton). If a ThreadLocal is only used for *initializing* the OCLDelegateDomain, this could again cause trouble due to unclear timing and multiple clients. With this, there currently doesn't seem any better way than setting an opposite end finder for the OCLDelegateDomain for all clients of the respective Ecore. Not nice, but I currently don't see a better way. I sure could add an extension point for this, but I'm scared by - the long-term compatibility obligations emerging from this - the question whether such a change can happen before Indigo - the fact that this would make the org.eclipse.ocl.ecore bundle into a singleton If we attach the OppositeEndFinder implementation class to use to the Ecore model then I think it's just fair to demand a bundle dependency from the this Ecore bundle to the bundle holding the OppositeEndFinder implementation specified. So it should suffice using the Ecore model bundle's class loader for loading the OppositeEndFinder class. I'll look at this option tomorrow. Created attachment 194473 [details]
Allows clients to choose opposite end finder class
As discussed, choosing an opposite end finder implementation is necessary. With this patch, any opposite end finder class in scope for the using Ecore package can be loaded by providing an additional key in the annotation.
abstractSyntax.html ------------------- Since you're 'editing' this can you prepare a 'test' for DocumentationExamples to validate the Java source text. Your extra paragraph would look better with a Sample Ecore Editor snapshot showing the result, with text that provides clarifying detail, probably in 'bullet' form: source: http://www.eclipse.org/emf/2002/Ecore/OCL detail key: hiddenOpposites detail value: true EcoreEnvironmentFactoryWithHiddenOpposites ------------------------------------------ I see no need for yet another constructor, particularly one that should be deprecated. 3 was already too many. OCLDelegateDomain ----------------- I think a custom EnvironmentFactory class is much more useful than a custom OppositeEndFinder class. Seems to me the algorithm should be Choose either EPackage.Registry.INSTANCE or resourceSet.getPackageRegistry() as the package registry. Then call createEnvironmentFactory(ePackage, packageRegistry) where if there is a custom environment factory annotation use it to create a custom environment factory (which can process standard and/or custom annotations) otherwise if there is a hidden opposites annotation create a EcoreEnvironmentFactoryWithHiddenOpposites otherwise create a EcoreEnvironmentFactory I think EMF has a WrappedException that is slightly better than RuntimeException. Created attachment 194650 [details]
Configurable environment factory, too
Better?
Created attachment 194930 [details]
Simplified patch without opposite finder class
I've simplified the logic.
It seems enough to have three cases:
a) environmentFactoryClass - user gets substantial conrtrol to change all sorts of things including opposites
b) hiddenOpposites - declarative behaviour change
c) traditional default
the extra opposite class is unnecessary. If opposites need customisation then use the factory.
I've also fixed an NPE on a null resource that I'm sure I'd fixed, but maybe only on the pivot.
I've tweaked the docunmentation, and deleted an obsolete test; you might want to check it.
Created attachment 194932 [details]
additional binary file for 194930
put this in same directory as abstractSyntax.html
Created attachment 195238 [details]
Removed commented test case
Remove the commented test case; use a LocalDefaultOppositeEndFinder to ensure and document that / how it is possible to use a specific OppositeEndFinder implementation by providing an own factory. Tweaked existing test case to ensure that this opposite end finder is actually used.
+1 Committed to CVS HEAD for RC1 Closing all bugs resolved in Indigo. |