Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » OCL » Ignoring OCL during Ecore validation possible ?
Ignoring OCL during Ecore validation possible ? [message #1826389] Fri, 24 April 2020 09:11 Go to next message
Andrzej Wąsowski is currently offline Andrzej WąsowskiFriend
Messages: 21
Registered: November 2019
Junior Member
I have an Ecore model with Pivot OCL constraints embedded (using OCLInEcore). I am validating instances loaded from ecore using

      Diagnostician.INSTANCE.validate (eObject)


where eObject is the root element in the instance. Validation fails (rightly so!) because some of my constraints are violated. My question is, is it possible to somehow deactivate validation of OCL constraints in such case? (for education reasons I would like to be able to run validation with and without OCL, using the same meta-model).
Re: Ignoring OCL during Ecore validation possible ? [message #1826394 is a reply to message #1826389] Fri, 24 April 2020 10:22 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7665
Registered: July 2009
Senior Member
Hi

It's only software .... of course it's possible.

Since your validation call is pure EMF, you just need to stop EMF delegating to OCL at all, or redirect the delegation to a DummyOCL that always validates successfully.

I suggest as a first point of attack replacing the EValidator.Registry entry. That should be pretty easy.

If that doesn't work you may need to replace the Invocation/Setting/ValidationDelegate registrations - much harder.

Alternatively, all OCL constraints have a severity so you could look to set the severity of them all to IGNORE. Not that easy but some JUnit tests conform that null-safe navigation validation can be switched on and off.

Regards

Ed Willink
Re: Ignoring OCL during Ecore validation possible ? [message #1826399 is a reply to message #1826394] Fri, 24 April 2020 11:51 Go to previous messageGo to next message
Andrzej Wąsowski is currently offline Andrzej WąsowskiFriend
Messages: 21
Registered: November 2019
Junior Member
Intersting. Would it be something like:

     org.eclipse.emf.ecore.EValidator.ValidationDelegate.Registry.INSTANCE.remove(
        org.eclipse.ocl.pivot.utilities.PivotConstants.OCL_DELEGATE_URI_PIVOT)


Actually this (almost) works. Obviously, It brings me back to the point were I was struggling with OCL not being validated :). An error that a delegate is missing. So apparently a dummy OCL is needed. I understand that I need to implement it myself, right? What is the type that it should extend?

[Updated on: Fri, 24 April 2020 12:10]

Report message to a moderator

Re: Ignoring OCL during Ecore validation possible ? [message #1826403 is a reply to message #1826399] Fri, 24 April 2020 12:26 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7665
Registered: July 2009
Senior Member
Hi

No. The EValidator..Registry.INSTANCE is the first point of attack. remove() may not work since you need to do so after it has been added and avoid a further lazy addition. A dummy is better since you can fill it with UnsupportedOperationException for debugging. org.eclipse.ocl.pivot.util.PivotValidator is the class you are replacing. A validate(int classifierID, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) override might intercept all calls.

EValidator.ValidationDelegate.Registry is part of the much harder fall back attack.

Regards

Ed Willink
Re: Ignoring OCL during Ecore validation possible ? [message #1826466 is a reply to message #1826403] Sat, 25 April 2020 10:59 Go to previous messageGo to next message
Andrzej Wąsowski is currently offline Andrzej WąsowskiFriend
Messages: 21
Registered: November 2019
Junior Member
This lazy loading and reloading seems to be chasing me. I had no success with EValidator.Registry.INSTANCE. Whether I put a dummy there, or simply removed, it seemed to have no effect. I suspect that things got reloaded before I managed to see the difference. So I tried EValidator.ValidationDelegate.Registry. I created (apologies for Scala syntax):

private class DummyDelegate extends EValidator.ValidationDelegate {

    override def validate (
      eClass: EClass, 
      eObject: EObject, 
      context: java.util.Map[java.lang.Object, java.lang.Object], 
      invariant: EOperation, 
      expression: java.lang.String): Boolean = true

    override def validate(
      eClass: EClass, 
      eObject: EObject, 
      context: java.util.Map[java.lang.Object, java.lang.Object], 
      constraint: java.lang.String, 
      expression: java.lang.String): Boolean = true

    override def validate(
      eDataType: EDataType, 
      value: java.lang.Object, 
      context: java.util.Map[java.lang.Object, java.lang.Object], 
      constraint: java.lang.String, 
      expression: java.lang.String): Boolean = true
}


and then registered it as follows:

  private val dummyDelegate = new DummyDelegate
  EValidator.ValidationDelegate.Registry.INSTANCE .put (OCL_DELEGATE_URI_PIVOT, dummyDelegate)


I am doing this dynamically (registering a dummy delegate, or whatever was there before) depending whether I need a test-case to check OCL or not. This does seem to work. To an extent. If I run few test cases, OCL seems to deactivate nicely, and I see behavior as I want (as if the constraints were not in the Ecore file).

When I run many tests, I am starting to see some Heisenbugs. Once in a while one of the tests fails due to lack of delegate for OCL. So magically OCL managed to activate. I get various errors, for example "org.eclipse.ocl.pivot.internal.utilities.IllegalLibraryException: No OCL Standard Library content available" or some classes missing. It is a different test that fails and often a different runtime error each time. It seems that OCL somehow manages to activate partially once in a while, even if I do not want it to. Something in the background (the lazy initialization?) must be kicking in.

I also tried do a dummy substitution in EValidator.Registry.INSTANCE. Even though, it did not prevent OCL validation in the first place, Perhaps it will improve stability. My present validation code looks roughly like this:

val oclDelegate = 
  EValidator.ValidationDelegate.Registry.INSTANCE.get (OCL_DELEGATE_URI_PIVOT)
val oclValidator = 
  EValidator.Registry.INSTANCE.get (org.eclipse.ocl.pivot.PivotPackage.eINSTANCE)
val essentialValidator = 
  EValidator.Registry.INSTANCE.get (org.eclipse.ocl.xtext.essentialoclcs.EssentialOCLCSPackage.eINSTANCE)
val baseValidator = 
  EValidator.Registry.INSTANCE.get (org.eclipse.ocl.xtext.basecs.BaseCSPackage.eINSTANCE)

EValidator.ValidationDelegate.Registry.INSTANCE
  .put (OCL_DELEGATE_URI_PIVOT, dummyDelegate)
EValidator.Registry.INSTANCE
  .put (org.eclipse.ocl.pivot.PivotPackage.eINSTANCE, dummyValidator)
EValidator.Registry.INSTANCE
  .put (org.eclipse.ocl.xtext.essentialoclcs.EssentialOCLCSPackage.eINSTANCE, dummyValidator)
EValidator.Registry.INSTANCE
  .put (org.eclipse.ocl.xtext.basecs.BaseCSPackage.eINSTANCE, dummyValidator)

val diagnostic = Diagnostician.INSTANCE.validate (root)

EValidator.ValidationDelegate.Registry.INSTANCE
  .put (OCL_DELEGATE_URI_PIVOT, oclDelegate)
EValidator.Registry.INSTANCE
  .put (org.eclipse.ocl.pivot.PivotPackage.eINSTANCE, oclValidator)
EValidator.Registry.INSTANCE
  .put (org.eclipse.ocl.xtext.essentialoclcs.EssentialOCLCSPackage.eINSTANCE, essentialValidator)
EValidator.Registry.INSTANCE
  .put (org.eclipse.ocl.xtext.basecs.BaseCSPackage.eINSTANCE, baseValidator)


DummyValidator is an instance of a class very similar to the DummyDelegate above. Unfortunately, this does not work either. The OCL validator would activate for a random check with the above procedure once in a while. Usually just 1 per probably 2-3 dozens of tests I have, but different one each time. What does seem to help (still testing), is to remove the put commands after the check of diagnostics, but I thought I need that (in case, I wanted to validate OCL later in the code).

Frankly, I do not know what I am doing. Any further hint, or thought would be invaluable.


[Updated on: Sat, 25 April 2020 11:44]

Report message to a moderator

Re: Ignoring OCL during Ecore validation possible ? [message #1826469 is a reply to message #1826466] Sat, 25 April 2020 12:17 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7665
Registered: July 2009
Senior Member
Hi

I strongly recommend you that you come up with a better explanation of why EValidator.Registry.INSTANCE doesn't work than 'it doesn't work' before you embark on delegates.

Regards

Ed Willink
Re: Ignoring OCL during Ecore validation possible ? [message #1826472 is a reply to message #1826469] Sat, 25 April 2020 14:09 Go to previous messageGo to next message
Andrzej Wąsowski is currently offline Andrzej WąsowskiFriend
Messages: 21
Registered: November 2019
Junior Member
I dug a bit deeper. The only explanation why it does not work that I could sniff on the Internet, is that I am running in Standalone mode outside Eclipse. I do not understand what delegators do, but they seem to be crucial in such setup. So my solution still uses delegators.

I found the error somewhere else in my setup. Basically, this idea of switching delegators/validators around as per validation call (depending whether I need OCL or not) is not thread safe. I realized that my testing framework (scalatest) was running my two test suites in parallel, and the two threads competed for switching validators. This is why I was seeing the validation activated and at random moments of time. So this way does not work, unless we synchronize for the time of validation. I chose to switch off parallel testing instead. It is good enough for me.

This is my final simples solution I could figure out (for anybody that would like to control whether OCL is validated or not):

private class DummyDelegate extends EValidator.ValidationDelegate {

  override def validate (
    eClass: EClass, 
    eObject: EObject, 
    context: java.util.Map[java.lang.Object, java.lang.Object], 
    invariant: EOperation, 
    expression: java.lang.String): Boolean = true

  override def validate(
    eClass: EClass, 
    eObject: EObject, 
    context: java.util.Map[java.lang.Object, java.lang.Object], 
    constraint: java.lang.String, 
    expression: java.lang.String): Boolean = true

  override def validate(
    eDataType: EDataType, 
    value: java.lang.Object, 
    context: java.util.Map[java.lang.Object, java.lang.Object], 
    constraint: java.lang.String, 
    expression: java.lang.String): Boolean = true
}

private val dummyDelegate = new DummyDelegate

//  OCL de-activated for a single validation run:

val oclDelegate = 
  EValidator.ValidationDelegate.Registry.INSTANCE.get (OCL_DELEGATE_URI_PIVOT)

EValidator.ValidationDelegate.Registry.INSTANCE
  .put (OCL_DELEGATE_URI_PIVOT, dummyDelegate)

val diagnostic = Diagnostician.INSTANCE.validate (root)

EValidator.ValidationDelegate.Registry.INSTANCE
  .put (OCL_DELEGATE_URI_PIVOT, oclDelegate)


The code is in Scala, but easy to translate to anything JVM-ish.

Thanks for helping!

[Updated on: Sat, 25 April 2020 14:10]

Report message to a moderator

Re: Ignoring OCL during Ecore validation possible ? [message #1826489 is a reply to message #1826472] Sat, 25 April 2020 18:49 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7665
Registered: July 2009
Senior Member
HI

EMF is not thread safe so OCL is not thread safe.

However if you ensure that you warm everything up on a single thread before allowing further threads, there is a fair chance that it might work. Don't be deceived by the number of "synchronized" declarations in the OCL code; they are an attempt at support, but until I have auto-generated synchronized code I am not going to make any claims for thread safety.

Regards

Ed Willink
Re: Ignoring OCL during Ecore validation possible ? [message #1826504 is a reply to message #1826489] Sun, 26 April 2020 05:02 Go to previous message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7665
Registered: July 2009
Senior Member
Quote:
The EValidator..Registry.INSTANCE is the first point of attack.


Correction.

The EValidator.Registry.INSTANCE is the correct point of attack to interfere with validation of OCL EObjects such as ExpressionInOCL, IfExp.

The EValidator..ValidationDelegate.Registry.INSTANCE is the correct point of attack to interfere with validation of OCL embedded within Ecore EObjects.

InvocationDelegate/InvocationDelegeate will only be relevant if your primary Ecore models have operations/derived properties with OCL implementations. You probably ould want this OCL to continue.

Whether the EValidator suppression is needed may be a side effect of whether you have previously executed the OCL and so caused its AST to be cached under the Ecore EObject. If your model is freshly loaded, the OCL should be solely in String form.

Regards

Ed Willink
Previous Topic:CompleteOCL - Import URI
Next Topic:OCL jars from Maven
Goto Forum:
  


Current Time: Sat Jul 20 14:09:17 GMT 2024

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

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

Back to the top