Home » Modeling » OCL » Variable definitions
Variable definitions [message #21024] |
Sat, 28 April 2007 08:23  |
Eclipse User |
|
|
|
Originally posted by: mike.aol.com
I am adapting my EMF model for OCL and am trying to get variable
definitions to work. In my EMF model, I have an operation that returns
multiple instances of a model element (PropertyBinding), e.g.:
PropertyBinding X.getProperties(String specName)
where the multiplicity of the return type is 0..*
When I try to define variables to correspond to various values of
specName and bind them to the result of the getProperties() operation, I
don't understand the results.
For example, here is how I am defining the variable:
vbl = ExpressionsFactory.eINSTANCE.createVariable();
vbl.setName(spec.getName());
vbl.setType(TypesPackage.eINSTANCE.getOrderedSetType());
oclEnv.addElement(spec.getName(), vbl, false);
evalEnv.add(spec.getName(), ruleBinding.getProperties(spec));
The result of ruleBinding.getProperties('isGrowable'), for example, is a
n EList of two elements. But when I evaluate this related expression:
isGrowable->size()
The result is 1.
When I evaluate the expression:
ruleBinding.getProperties('isGrowable')->size()
The result is 2.
How should I define the variables to correctly reflect their type?
I am puzzled by a related issue. I can't find a way to define a Let
expression to reflect the evaluation of the getProperties() operation.
For example:
let x : Sequence(PropertyBinding) =
ruleBinding.getProperties('isGrowable')->iterate(foobar :
PropertyBinding;
result : Sequence(PropertyBinding) = Sequence{} |
result->including(foobar))
in
x
throws an IllegalArgumentException: Init expression type does not
conform to type of variable (result).
I am using version plugin version 1.0.1 on a 3.2.2 platform.
Any help would be welcome.
Thanks,
Mike Gering
|
|
|
Re: Variable definitions [message #21072 is a reply to message #21024] |
Mon, 30 April 2007 12:15   |
Eclipse User |
|
|
|
Originally posted by: cdamus.ca.ibm.com
Hi, Mike,
See some replies in-line, below.
HTH,
Christian
Mike Gering wrote:
> I am adapting my EMF model for OCL and am trying to get variable
> definitions to work. In my EMF model, I have an operation that returns
> multiple instances of a model element (PropertyBinding), e.g.:
> PropertyBinding X.getProperties(String specName)
> where the multiplicity of the return type is 0..*
>
> When I try to define variables to correspond to various values of
> specName and bind them to the result of the getProperties() operation, I
> don't understand the results.
>
> For example, here is how I am defining the variable:
> vbl = ExpressionsFactory.eINSTANCE.createVariable();
> vbl.setName(spec.getName());
> vbl.setType(TypesPackage.eINSTANCE.getOrderedSetType());
> oclEnv.addElement(spec.getName(), vbl, false);
> evalEnv.add(spec.getName(), ruleBinding.getProperties(spec));
You are setting the type of the variable to be the OrderedSet *metaclass*
from the OCL abstract syntax metamodel. What you really want is an
OrderedSet(PropertyBinding). Try this:
vbl.setType(TypesFactory.eINSTANCE.createOrderedSetType(
MyPackage.Literals.PROPERTY_BINDING);
(assuming that your EMF model is named 'My').
> The result of ruleBinding.getProperties('isGrowable'), for example, is a
> n EList of two elements. But when I evaluate this related expression:
> isGrowable->size()
> The result is 1.
Because the type is the OrderedSetType metaclass, which isn't itself a
collection type, the value is interpreted as a scalar (despite being, in
fact, an EList).
> When I evaluate the expression:
> ruleBinding.getProperties('isGrowable')->size()
>
> The result is 2.
>
> How should I define the variables to correctly reflect their type?
>
> I am puzzled by a related issue. I can't find a way to define a Let
> expression to reflect the evaluation of the getProperties() operation.
>
> For example:
> let x : Sequence(PropertyBinding) =
> ruleBinding.getProperties('isGrowable')->iterate(foobar :
> PropertyBinding;
> result : Sequence(PropertyBinding) = Sequence{} |
> result->including(foobar))
> in
> x
>
> throws an IllegalArgumentException: Init expression type does not
> conform to type of variable (result).
This looks like bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=164614
that was resolved in MDT OCL 1.1 (no help to you). To work around it in
for your particular case, try:
let x : Sequence(PropertyBinding) =
ruleBinding.getProperties('isGrowable')->asSequence()
in
x
using the standard collection-type coercion operation.
> I am using version plugin version 1.0.1 on a 3.2.2 platform.
>
> Any help would be welcome.
>
> Thanks,
> Mike Gering
|
|
| | | |
Re: Variable definitions [message #21150 is a reply to message #21133] |
Mon, 30 April 2007 14:59   |
Eclipse User |
|
|
|
Originally posted by: cdamus.ca.ibm.com
Hi, Mike,
Are you working with MDT OCL 1.1 or 1.0? What is the run-time type of
isGrowable? I suppose it's an EList, but I wonder why it, too, isn't an
OrderedSet? (Java Linked HashSet)
This sounds like a bug: the OCL collection needs to be coerced to an EList
when passed into the EOperation. Raise a bug and we'll see about fixing
it:
https://bugs.eclipse.org/bugs/enter_bug.cgi?product=MDT& version=1.1.0&component=OCL
Thanks,
Christian
Mike Gering wrote:
> Christian W. Damus wrote:
>> That's odd. Since the result type of the select iterator in this case is
>> OrderedSet, I can only suppose that some run-time exception is happening
>> (probably in the evaluation of the select?). Try debugging from a
>> breakpoint in EvaluationVisitorImpl.evaluateSelectIterator(...) to see
>> what kind of exception you are getting.
>
> Sure enough, there is an exception: IllegalArgumentException is being
> thrown by the java.lang.reflect.Method.invoke() which is called from
> visitOperationCallExp(), and here's why. The OCL evaluation result of
> the select is a LinkedHashSet, but the EMF generated operation parameter
> is an EList.
>
> ruleBinding.addPropLoci(isGrowable) -- works
> ruleBinding.addPropLoci(isGrowable->select(value = 'false')) -- throws
> exception.
>
> Is this a bug? If so, is there a workaround?
>
> Thanks,
> Mike
|
|
| |
Re: Variable definitions [message #21176 is a reply to message #21161] |
Mon, 30 April 2007 17:45   |
Eclipse User |
|
|
|
Originally posted by: cdamus.ca.ibm.com
Hi, Mike,
EMF wouldn't generate anything other than EList (or List in the case of
suppression of EMF types) anyway, so that wouldn't help.
Unfortunately, there isn't a plan for any more maintenance releases of the
MDT components (at least, not OCL).
You can work around this problem by overriding the
org.eclipse.emf.ocl.expressions.util.EvalEnvironment class's
canEvaluate(EOperation, int)
evaluate(EOperation, int, Object, Object[])
methods to replace the broken implementation of delegation to the Java
reflection API that the bottom of the
EvaluationVisitorImpl.visitOperationCall() class. Basically, implement
evaluate() to do what visitOperationCall() does, except with the OCL-to-EMF
collection conversion. Be careful to return true from canEvaluate() only
for operation codes <= zero (meaning that it is not an OCL-defined
operation, but an EOperation in your model).
Configure your org.eclipse.emf.ocl.query.Query instance with your custom
EvalEnvironment (Query.setEvaluationEnvironment method) before you use it
to evaluate your expression.
In the mean-time, we'll see about fixing this in the 1.1 stream.
HTH,
Christian
Mike Gering wrote:
> Christian,
>
> I'm working with 1.0.2 because I'm constrained by the 3.2.2
> platform/emf/gmf combination.
>
> The runtime type is isGrowable is an EList -- it's generated from my
> ecore model as a multi-valued parameter. OCL queries the EParameter and
> maps it to an OrderedSet (because there's an EMF bug that forces the
> EParameter to appear as an ordered, unique typed element). I don't know
> that the EMF code generator produces anything other than an EList for
> multi-value parameters. It doesn't honor isUnique = false at all.
>
> I opened a bug report:
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=184789
>
> Mike
|
|
|
Re: Variable definitions [message #21190 is a reply to message #21176] |
Mon, 30 April 2007 20:52   |
Eclipse User |
|
|
|
Originally posted by: mike.aol.com
Christian,
Very good! Following your advice, here's my workaround. It hacks any arg
which is an AbstractSet to an EList:
static class VceEvalEnvironment extends EvalEnvironment {
/* (non-Javadoc)
* @see
org.eclipse.emf.ocl.expressions.util.EvalEnvironment#canEval uate(org.eclipse.emf.ecore.EOperation,
int)
*/
public boolean canEvaluate(EOperation operation, int opcode) {
if(opcode <= 0) {
return true;
}
return super.canEvaluate(operation, opcode);
}
/* (non-Javadoc)
* @see
org.eclipse.emf.ocl.expressions.util.EvalEnvironment#evaluat e(org.eclipse.emf.ecore.EOperation,
int, java.lang.Object, java.lang.Object[])
*/
public Object evaluate(EOperation operation, int opcode, Object
target, Object[] args) throws UnsupportedOperationException {
//NOTE: Due to a bug in the mapping of OCL types to EMF, Any
AbstractSet type must be coerced into
// an EList
Object[] hackedArgs = new Object[args.length];
for(int i = 0; i < args.length; i++) {
if(args[i] instanceof AbstractSet) {
hackedArgs[i] = new BasicEList((AbstractSet) args[i]);
} else {
hackedArgs[i] = args[i];
}
}
// get java method for operation
Method method = EvaluationVisitorImpl.getJavaMethodFor(operation);
if (method == null) {
return Types.OCL_INVALID;
}
// invoke method on evaluated args
try {
Object result = method.invoke(target, hackedArgs);
return result;
} catch (Exception e) {
return Types.OCL_INVALID;
}
}
}
It seems to work. If you see a problem with this implementation, please
let me know.
Thanks again!
Mike
|
|
|
Re: Variable definitions [message #21205 is a reply to message #21190] |
Tue, 01 May 2007 08:26  |
Eclipse User |
|
|
|
Originally posted by: cdamus.ca.ibm.com
Hi, Mike,
Good news! I'm glad it works for you.
The only comment that I would make is to check for Collection, more
generally than for AbstractSet. The reason is that you may encounter Bags
resulting from some set operations, and the Java implementation of these is
distinct from the Set hierarchy.
Cheers,
Christian
Mike Gering wrote:
> Christian,
>
> Very good! Following your advice, here's my workaround. It hacks any arg
> which is an AbstractSet to an EList:
>
> static class VceEvalEnvironment extends EvalEnvironment {
>
> /* (non-Javadoc)
> * @see
>
org.eclipse.emf.ocl.expressions.util.EvalEnvironment#canEval uate(org.eclipse.emf.ecore.EOperation,
> int)
> */
> public boolean canEvaluate(EOperation operation, int opcode) {
> if(opcode <= 0) {
> return true;
> }
> return super.canEvaluate(operation, opcode);
> }
>
> /* (non-Javadoc)
> * @see
>
org.eclipse.emf.ocl.expressions.util.EvalEnvironment#evaluat e(org.eclipse.emf.ecore.EOperation,
> int, java.lang.Object, java.lang.Object[])
> */
> public Object evaluate(EOperation operation, int opcode, Object
> target, Object[] args) throws UnsupportedOperationException {
> //NOTE: Due to a bug in the mapping of OCL types to EMF, Any
> AbstractSet type must be coerced into
> // an EList
> Object[] hackedArgs = new Object[args.length];
> for(int i = 0; i < args.length; i++) {
> if(args[i] instanceof AbstractSet) {
> hackedArgs[i] = new BasicEList((AbstractSet) args[i]);
> } else {
> hackedArgs[i] = args[i];
> }
> }
> // get java method for operation
> Method method = EvaluationVisitorImpl.getJavaMethodFor(operation);
>
> if (method == null) {
> return Types.OCL_INVALID;
> }
>
> // invoke method on evaluated args
> try {
> Object result = method.invoke(target, hackedArgs);
> return result;
> } catch (Exception e) {
> return Types.OCL_INVALID;
> }
> }
> }
> It seems to work. If you see a problem with this implementation, please
> let me know.
>
> Thanks again!
> Mike
|
|
|
Goto Forum:
Current Time: Tue Jul 22 12:07:07 EDT 2025
Powered by FUDForum. Page generated in 0.05064 seconds
|