Home » Modeling » OCL » limit OCL validation of an invariant
limit OCL validation of an invariant [message #1758761] |
Sun, 02 April 2017 07:48  |
Eclipse User |
|
|
|
Hi all,
Let's consider this simple metamodel (inspired by my real dsl)
package test : test = 'http://test/2.0'
{
class Model
{
property containers : Container[*|1] { ordered composes };
}
class Container
{
property as : A[*|1] { ordered composes };
property bs : B[*|1] { ordered composes };
}
class A
{
attribute name : String[1];
property refersToB : B[1];
invariant containedB: Tuple {
status: Boolean= self.oclContainer().oclAsType(Container).bs->includes(self.refersToB),
message: String ='The refersToB instance '+ refersToB.name + ' in '+ name + ' instance must be declared in the Container of '+ name,
severity :Integer = -1
}.status;
}
class B
{
attribute name : String[1];
}
}
In the generated genmodel, I add this annotation (for other reasons)
<genAnnotations source="http://www.eclipse.org/OCL/GenModel">
<details key="Use Delegates" value="false"/>
</genAnnotations>
When refersToB reference is null, the OCL validator shows two validation problems (as shown in the image below):
- (error) The required feature 'refersToB' of 'A a1' must be set, because of refersToB : B[1] property
- (warning) The 'A::containedB' constraint is violated for 'A a1', because self.refersToB is null
My question is that how can I limit the validation of containedB to be done ONLY when self.refersToB is not null?
I tried to edit my constraint containedB by adding an if then else
I tried two possibilities
status: Boolean= if (not self.refersToB.oclIsUndefined()) then self.oclContainer().oclAsType(Container).bs->includes(self.refersToB) else true endif,
and
status: Boolean= if (self.refersToB <> null) then self.oclContainer().oclAsType(Container).bs->includes(self.refersToB) else true endif,
However, there is no change. I have always two OCL validation problems
In addition, as shown below, the containeB generated java method doesn't contain a generated java code related to my if then else.
public boolean containedB(final DiagnosticChain diagnostics, final Map<Object, Object> context) {
/**
*
* inv containedB:
* let severity : Integer[1] = 'A::containedB'.getSeverity()
* in
* if severity <= 0
* then true
* else
* let
* result : OclAny[1] = let
* status : Boolean[1] = if self.refersToB <> null
* then
* self.oclContainer()
* .oclAsType(Container)
* .bs->includes(self.refersToB)
* else true
* endif
* in
* if status = true
* then true
* else
* Tuple{status = status, message = 'The refersToB instance ' + refersToB.name + ' in ' + name + ' instance must be declared in the Container of ' + name, severity = -1
* }
* endif
* in
* 'A::containedB'.logDiagnostic(self, null, diagnostics, context, null, severity, result, 0)
* endif
*/
final /*@NonInvalid*/ Executor executor = PivotUtilInternal.getExecutor(this);
final /*@NonInvalid*/ IdResolver idResolver = executor.getIdResolver();
final /*@NonInvalid*/ IntegerValue severity_0 = CGStringGetSeverityOperation.INSTANCE.evaluate(executor, TestTables.STR_A_c_c_containedB);
final /*@NonInvalid*/ boolean le = OclComparableLessThanEqualOperation.INSTANCE.evaluate(executor, severity_0, TestTables.INT_0).booleanValue();
/*@NonInvalid*/ Object symbol_2;
if (le) {
symbol_2 = ValueUtil.TRUE_VALUE;
}
else {
/*@Caught*/ /*@NonNull*/ Object CAUGHT_symbol_1;
try {
final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_test_c_c_Container = idResolver.getClass(TestTables.CLSSid_Container, null);
final /*@NonInvalid*/ B refersToB = this.getRefersToB();
final /*@NonInvalid*/ Object oclContainer = ClassifierOclContainerOperation.INSTANCE.evaluate(executor, this);
final /*@Thrown*/ test.Container oclAsType = ClassUtil.nonNullState((test.Container)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, oclContainer, TYP_test_c_c_Container));
final /*@Thrown*/ List<B> bs = oclAsType.getBs();
final /*@Thrown*/ OrderedSetValue BOXED_bs = idResolver.createOrderedSetOfAll(TestTables.ORD_CLSSid_B, bs);
final /*@Thrown*/ boolean includes = CollectionIncludesOperation.INSTANCE.evaluate(BOXED_bs, refersToB).booleanValue();
/*@Thrown*/ Object symbol_1;
if (includes) {
symbol_1 = ValueUtil.TRUE_VALUE;
}
else {
final /*@NonInvalid*/ String name_1 = this.getName();
final /*@NonInvalid*/ String name = refersToB.getName();
final /*@NonInvalid*/ String sum = StringConcatOperation.INSTANCE.evaluate(TestTables.STR_The_32_refersToB_32_instance_32, name);
final /*@NonInvalid*/ String sum_0 = StringConcatOperation.INSTANCE.evaluate(sum, TestTables.STR__32_in_32);
final /*@NonInvalid*/ String sum_1 = StringConcatOperation.INSTANCE.evaluate(sum_0, name_1);
final /*@NonInvalid*/ String sum_2 = StringConcatOperation.INSTANCE.evaluate(sum_1, TestTables.STR__32_instance_32_32_must_32_be_32_declared_32_in_32_the_32_Container_32_of_32);
final /*@NonInvalid*/ String sum_3 = StringConcatOperation.INSTANCE.evaluate(sum_2, name_1);
final /*@NonInvalid*/ IntegerValue diff = (IntegerValue)NumericNegateOperation.INSTANCE.evaluate(TestTables.INT_1);
final /*@Thrown*/ TupleValue symbol_0 = ValueUtil.createTupleOfEach(TestTables.TUPLid_, sum_3, diff, includes);
symbol_1 = symbol_0;
}
CAUGHT_symbol_1 = symbol_1;
}
catch (Exception e) {
CAUGHT_symbol_1 = ValueUtil.createInvalidValue(e);
}
final /*@NonInvalid*/ boolean logDiagnostic = CGStringLogDiagnosticOperation.INSTANCE.evaluate(executor, TypeId.BOOLEAN, TestTables.STR_A_c_c_containedB, this, (Object)null, diagnostics, context, (Object)null, severity_0, CAUGHT_symbol_1, TestTables.INT_0).booleanValue();
symbol_2 = logDiagnostic;
}
return Boolean.TRUE == symbol_2;
}
Is it normal that the generated code doesn't contain my OCL if then else?
Does exist another way to limit the validation of an OCL invariant?
Any suggestions ?
best regards
Attachment: ocl.png
(Size: 196.52KB, Downloaded 900 times)
[Updated on: Sun, 02 April 2017 07:49] by Moderator
|
|
| | | | |
Re: limit OCL validation of an invariant [message #1758770 is a reply to message #1758768] |
Sun, 02 April 2017 10:47  |
Eclipse User |
|
|
|
Hi
Not sure without the two contrasting repros, but I suspect the error was because you actually navigated from a null value whereas the warning is the 'correct' behavior.
You can now (perhaps since M2) push the Tuple inside the if and so avoid duplicating logic on message/status. Particularly useful if you want to display a partial computation from a let variable in the error message.
Probably something like "if refersToB <> null implies Tuple{...}.status
Regards
Ed Willink
|
|
|
Goto Forum:
Current Time: Wed Apr 30 20:43:51 EDT 2025
Powered by FUDForum. Page generated in 0.07054 seconds
|