Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » OCL » Define custom operations on primitive types
Define custom operations on primitive types [message #60171] Mon, 04 August 2008 05:10 Go to next message
Laurent Goubet is currently offline Laurent Goubet
Messages: 1625
Registered: July 2009
Senior Member
This is a multi-part message in MIME format.
--------------040802090600080603040304
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hi Christian,

For the purpose of implementing the MTL specification, we need to
provide custom operations on OCL primitive types. An example of this
would be the "substritute(String, String)" operation on the primitive
type "String" (which is no more than a "replaceAll").

I wanted to provide these operations by defining them in a model
(inventively called mtlstdlib.ecore). I then used a "load resource" with
the URI "http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore" in order to
be able to simply reference the primitive types in the ecore editor.

Then I created a java Class MTLStandardLibrary which is in charge of
loading this model and returning all the operations of a given
classifier (String for this example) as well as a custom implementation
of an EcoreEnvironment which calls :
addHelperOperations(getOCLStandardLibrary().getString(),
getMTLStandardLibrary().getExistingOperations(getOCLStandard Library().getString()));
in order to let the parser know of these operations.

This seems to go fine and the parser sees my operation in the list of
candidates when it tries to find it through
TypeUtil#findOperationMatching() ... yet it does not accept it as the
matching operations since TypeUtil#matchArgs() fails. The OCL standard
library's "String" primitive type and the one in the oclstdlib.ecore
instance that was loaded in the resourceset of my custom lib are distinct!

I was then wondering ... is it intended to be possible to provide custom
operations without building the model "by hand" to provide them? I
managed to have the parser recognize my operation by loading
mtlstdlib.ecore as such :

ResourceSet resourceSet = new ResourceSetImpl();
Resource oclStdLibResource =
environment.getOCLStandardLibrary().getString().eResource();
resourceSet.getResources().add(oclStdLibResource);

try {
stdLibPackage = (EPackage)ModelUtils.load(URI.createURI(NS_URI),
resourceSet);
// This ensures we have all links to the OCL standard lib resolved
EcoreUtil.resolveAll(stdLibPackage);
[...]

which means I needed to put the oclstdlib instance of my environment
within the resourceSet of the model providing my own standard lib and
resolve all links to it so that EMF resolves its link toward it via that
particular instance. I cannot remove it from the resourceSet afterwards,
else links toward it would be proxified and a new instance (distinct
from the environment's!) loaded when resolving them.

How would be the "accurate" way of providing such EOperations while
still allowing the user to easily see them (hence the .ecore file)?

Regards

Laurent Goubet
Obeo

--------------040802090600080603040304
Content-Type: text/x-vcard; charset=utf-8;
name="laurent_goubet.vcf"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="laurent_goubet.vcf"

begin:vcard
fn:Laurent Goubet
n:Goubet;Laurent
org:<a href="http://www.obeo.fr/">Obeo</a>
email;internet:laurent.goubet@obeo.fr
url:http://www.obeo.fr
version:2.1
end:vcard


--------------040802090600080603040304--
Re: Define custom operations on primitive types [message #60199 is a reply to message #60171] Mon, 04 August 2008 09:22 Go to previous messageGo to next message
Eclipse User
Originally posted by: cdamus.zeligsoft.com

Hi, Laurent,

See some replies in-line, below.

HTH,

Christian


laurent Goubet wrote:
> Hi Christian,
>
> For the purpose of implementing the MTL specification, we need to
> provide custom operations on OCL primitive types. An example of this
> would be the "substritute(String, String)" operation on the primitive
> type "String" (which is no more than a "replaceAll").

It seems that you are heading down a similar route as our colleagues in
the QVT implementations in the M2M project. The OCL parser was not
designed for extensibility of the standard library in this way, but
together we are working on improving that.


> I wanted to provide these operations by defining them in a model
> (inventively called mtlstdlib.ecore). I then used a "load resource" with
> the URI "http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore" in order to
> be able to simply reference the primitive types in the ecore editor.

The benefit, of course, of modeling the operations in this way is that
serialized OCL expressions can reference unique definitions of the
operations. However, as you have noticed, this is difficult in
practice, given how the OCL stdlib resource is managed.

If you aren't much concerned with serializing the AST, then an approach
that does work well is to simply re-define the operations as "additional
operations" in each root MTLEnvironment that you create. Every
serialization of this environment would repeat the operations, but maybe
this isn't cause for concern in MTL.


> Then I created a java Class MTLStandardLibrary which is in charge of
> loading this model and returning all the operations of a given
> classifier (String for this example) as well as a custom implementation
> of an EcoreEnvironment which calls :
> addHelperOperations(getOCLStandardLibrary().getString(),
> getMTLStandardLibrary().getExistingOperations(getOCLStandard Library().getString()));
>
> in order to let the parser know of these operations.
>
> This seems to go fine and the parser sees my operation in the list of
> candidates when it tries to find it through
> TypeUtil#findOperationMatching() ... yet it does not accept it as the
> matching operations since TypeUtil#matchArgs() fails. The OCL standard
> library's "String" primitive type and the one in the oclstdlib.ecore
> instance that was loaded in the resourceset of my custom lib are distinct!

Right. The problem is, that the EcoreEnvironment defines the standard
library statically. It's like trying to use an EPackage loaded in your
resource set when the static EPackage.Registry already knows the same
EPackage. They are two different instances of the same EPackage, but
their types are incompatible (Java class-loaders behave likewise).

This is the main reason why the OCL stdlib design isn't extensible. A
more extensible design would have the EcoreEnvironment load the stdlib
resource separately in every resource set.


> I was then wondering ... is it intended to be possible to provide custom
> operations without building the model "by hand" to provide them? I

No, as I mentioned, the parser was not initially designed for this kind
of extensibility. But, with similar requirements from QVT and now MTL,
I expect that we'll be able to do a better job of it in the 2.0 release
of MDT OCL (whenever that should be).


> managed to have the parser recognize my operation by loading
> mtlstdlib.ecore as such :
>
> ResourceSet resourceSet = new ResourceSetImpl();
> Resource oclStdLibResource =
> environment.getOCLStandardLibrary().getString().eResource();
> resourceSet.getResources().add(oclStdLibResource);

Oo. Now you're hijacking a shared resource into your applications
resource set. That may have ill effects for other applications in the
same workbench (e.g., GMF). I'm not sure ...


> try {
> stdLibPackage = (EPackage)ModelUtils.load(URI.createURI(NS_URI),
> resourceSet);
> // This ensures we have all links to the OCL standard lib resolved
> EcoreUtil.resolveAll(stdLibPackage);
> [...]
>
> which means I needed to put the oclstdlib instance of my environment
> within the resourceSet of the model providing my own standard lib and
> resolve all links to it so that EMF resolves its link toward it via that
> particular instance. I cannot remove it from the resourceSet afterwards,
> else links toward it would be proxified and a new instance (distinct
> from the environment's!) loaded when resolving them.

Yeah. I'm inclined to suspect that this is unsafe.


> How would be the "accurate" way of providing such EOperations while
> still allowing the user to easily see them (hence the .ecore file)?

One approach that comes to mind is to use the TypeResolver API's ability
to serialize an Environment. Instead of defining an mtlstdlib.ecore
after the fashion of oclstdlib.ecore, try this instead:

1. Create a new (empty) file:/tmp/mtlenv.ecore resource.
2. Load an environment instance from it (the EcoreEnvironmentFactory
has a loadEnvironment(Resource) method; your MTLEnvironmentFactory
will have inherited it). "Loading" an empty environment simply
ensures that the environment will persist its definitions in your
resource.
3. Use the AbstractEnvironment::addHelper{Operation,Property} methods
to add your definitions to the environment.
4. Save the file:/tmp/mtlenv.ecore resource.

Now, you have a ready-to-go environment that you can load every time you
need to create a root-level MTL environment. It's not as pretty,
perhaps, as your stdlib resource currently is, but it should do the job.
If necessary, you can customize the structure that the
AbstractTypeResolver imposes on the resource in a sub-class.


>
> Regards
>
> Laurent Goubet
> Obeo
Re: Define custom operations on primitive types [message #60223 is a reply to message #60199] Mon, 04 August 2008 10:46 Go to previous message
Laurent Goubet is currently offline Laurent Goubet
Messages: 1625
Registered: July 2009
Senior Member
This is a multi-part message in MIME format.
--------------020004080205030505030103
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit

Christian,

Thanks for those clarifications. I'll try and find a way to manage and
provide these EOperations (if worst comes to worst, I'll simply
reflectively create them through code).

Serializing the environment might be a way to do what I intend to. I'll
come back to you if I manage (or fail :p).

Regards

Laurent Goubet
Obeo

Christian W. Damus a
Previous Topic:String operation - trim function
Next Topic:Additional Operations collision
Goto Forum:
  


Current Time: Fri Aug 22 19:49:40 EDT 2014

Powered by FUDForum. Page generated in 0.01516 seconds