Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » OCL » limit OCL validation of an invariant
limit OCL validation of an invariant [message #1758761] Sun, 02 April 2017 11:48 Go to next message
Faiez Zalila is currently offline Faiez ZalilaFriend
Messages: 235
Registered: March 2010
Senior Member
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

index.php/fa/28957/0/
  • Attachment: ocl.png
    (Size: 196.52KB, Downloaded 118 times)

[Updated on: Sun, 02 April 2017 11:49]

Report message to a moderator

Re: limit OCL validation of an invariant [message #1758764 is a reply to message #1758761] Sun, 02 April 2017 12:08 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 5585
Registered: July 2009
Senior Member
Hi

property refersToB : B[1];

asserts that refersToB cannot be null, so one of the code generator optimizations throws away the dead code path.

IMHO "X <> null" is better style than "not X.oclIsUndefined()".

You may find "implies" helpful for guards.

One day there might be an optimization that orders all constraints applicable to a particular object so that the simplest execute first and avoid degenerate repeated failures.

So for your case, the failure of the refersToB non-null constraint could inhibit further constraints that navigate from refersToB.

Regards

Ed Willink
Re: limit OCL validation of an invariant [message #1758766 is a reply to message #1758764] Sun, 02 April 2017 12:33 Go to previous messageGo to next message
Faiez Zalila is currently offline Faiez ZalilaFriend
Messages: 235
Registered: March 2010
Senior Member
I expriment the implies operator but no changes
(self.refersToB <> null) implies (self.oclContainer().oclAsType(Container).bs->includes(self.refersToB))


So, ACTUALLY, the only solution is to edit the generated java code?

by adding
			if(this.getRefersToB() == null){
				return true;
			}


best regards
Re: limit OCL validation of an invariant [message #1758767 is a reply to message #1758766] Sun, 02 April 2017 13:31 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 5585
Registered: July 2009
Senior Member
Hi

No. If refersToB can be non null, do not declare it as non-null. e.g. try:

property refersToB : B[?];

Regards

Ed Willink
Re: limit OCL validation of an invariant [message #1758768 is a reply to message #1758767] Sun, 02 April 2017 14:07 Go to previous messageGo to next message
Faiez Zalila is currently offline Faiez ZalilaFriend
Messages: 235
Registered: March 2010
Senior Member
Thanks Ed,

It works perfectly

	class A
	{
		attribute name : String[1];
		property refersToB : B[?];
		invariant containedB: Tuple {
				status: Boolean=if (refersToB <> null) 
									then self.oclContainer().oclAsType(Container).bs->includes(self.refersToB) 
								else 
									false 
								endif,
				message: String = if (refersToB <> null) 
								 	 then 'The refersToB instance '+ refersToB.name + ' in '+ name + ' instance  must be declared in the Container of '+ name
								 else
								 	'refersToB of '+ name+ ' A instance must be a set'
								 endif,
				severity :Integer = -1
				}.status;
	}


Just a remark:

When I customize the message by adding if then else in message body (to deal with refersToB is null), the validation problem is shown as an error (when refersToB is null).
Before this customization, the validation problem is shown as an warning (when refersToB is null).

what is the interpretation of that?

best regards,

Faiez

Re: limit OCL validation of an invariant [message #1758770 is a reply to message #1758768] Sun, 02 April 2017 14:47 Go to previous message
Ed Willink is currently offline Ed WillinkFriend
Messages: 5585
Registered: July 2009
Senior Member
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
Previous Topic:OCL Codegenerator
Next Topic:How to derive a collection of objects
Goto Forum:
  


Current Time: Tue Jan 23 08:25:45 GMT 2018

Powered by FUDForum. Page generated in 0.02102 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software