Commit 21d250bf authored by Martti Käärik's avatar Martti Käärik
Browse files

Constraints compiled into the metamodel, enabled via...

Constraints compiled into the metamodel, enabled via -Dtdl.validation.constraints=interpreted|compiled
parent 65f1ded7
Loading
Loading
Loading
Loading
+23 −1
Changes for plugins/org.etsi.mts.tdl.model/model/configurations.ecore: 23 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -5,6 +5,11 @@
  <eAnnotations source="http://www.eclipse.org/OCL/Import">
    <details key="tdl" value="tdl.ecore#/"/>
  </eAnnotations>
  <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
    <details key="validationDelegates" value="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot"/>
    <details key="invocationDelegates" value="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot"/>
    <details key="settingDelegates" value="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot"/>
  </eAnnotations>
  <eClassifiers xsi:type="ecore:EClass" name="ExtendedTestConfiguration" eSuperTypes="tdl.ecore#//TestConfiguration">
    <eStructuralFeatures xsi:type="ecore:EReference" name="configurations" ordered="false"
        upperBound="-1" eType="#//TestConfigurationInstance" containment="true"/>
@@ -27,6 +32,15 @@
        eType="#//TestConfigurationInstance"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="ComponentMerge" eSuperTypes="#//TestConfigurationOperation">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="NoSelfMerge ComponentMergeType"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="NoSelfMerge" value="not (self.component.component = self.target.component and&#xA;self.component.configuration = self.target.configuration)"/>
      <details key="NoSelfMerge$message" value="'A \'ComponentInstance\' shall not be merged with itself, i.e. the source and target \'ComponentInstance\'s specified by means of the \'ComponentReference\'s shall be different. ' + self.toString()"/>
      <details key="ComponentMergeType" value="self.target.component.type.conformsTo(self.component.component.type)"/>
      <details key="ComponentMergeType$message" value="'The \'ComponentInstance\' specified by means of the target \'ComponentReference\'s shall have a \'ComponentType\' which conforms to the \'ComponentType\' of the source \'ComponentReference\'. ' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="target" lowerBound="1"
        eType="#//ComponentReference" containment="true"/>
  </eClassifiers>
@@ -34,7 +48,15 @@
  <eClassifiers xsi:type="ecore:EClass" name="ReassignRole" eSuperTypes="#//TestConfigurationOperation">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="role" lowerBound="1" eType="ecore:EEnum tdl.ecore#//ComponentInstanceRole"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="ComponentAlias" eSuperTypes="#//TestConfigurationOperation"/>
  <eClassifiers xsi:type="ecore:EClass" name="ComponentAlias" eSuperTypes="#//TestConfigurationOperation">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="AliasMandatoryName"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="AliasMandatoryName" value="not self.name.oclIsUndefined() and self.name.size() > 0"/>
      <details key="AliasMandatoryName$message" value="'The \'name\' property of the \'ComponentAlias\' shall be set and it shall not be an empty String.' + self.toString()"/>
    </eAnnotations>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="ExtendedGateReference" eSuperTypes="tdl.ecore#//GateReference">
    <eStructuralFeatures xsi:type="ecore:EReference" name="configuration" lowerBound="1"
        eType="#//TestConfigurationInstance"/>
+78 −0
Changes for plugins/org.etsi.mts.tdl.model/model/structured.ecore: 78 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -77,6 +77,13 @@
        eType="#//EventSequence" containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="PICSReference" eSuperTypes="#//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="MultiplePICS"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="MultiplePICS" value="self.getTestObjective().picsReference->size() &lt; 2&#xA;or self.getTestObjective().picsReference->forAll(p |&#xA;self.getTestObjective().picsReference->at(1) = p&#xA;or (not p.comment->isEmpty()&#xA;and (p.comment->first()._'body' = 'and'&#xA;or p.comment->first()._'body' = 'or')))"/>
      <details key="MultiplePICS$message" value="'A \'Comment\' with body containing an \'and\' or \'or\' shall be attached to the \'PICSReference\' as a Boolean operand if there are two or more \'PICSReference\'s and it is not the first \'PICSReference\'.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="pics" lowerBound="1" eType="#//PICS"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="PICS" eSuperTypes="tdl.ecore#//PackageableElement #//Element"/>
@@ -93,6 +100,13 @@
        containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="EntityReference" eSuperTypes="#//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="EntityOrComponentInstance"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="EntityOrComponentInstance" value="(not self.entity.oclIsUndefined() and self.component.oclIsUndefined())&#xA;or (self.entity.oclIsUndefined() and not self.component.oclIsUndefined())"/>
      <details key="EntityOrComponentInstance$message" value="'There shall be a reference to an \'Entity\' or a \'ComponentInstance\' but not both.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="entity" eType="#//Entity"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="component" eType="ecore:EClass tdl.ecore#//ComponentInstance"/>
  </eClassifiers>
@@ -101,10 +115,28 @@
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Value" abstract="true" eSuperTypes="#//Element"/>
  <eClassifiers xsi:type="ecore:EClass" name="DataReference" eSuperTypes="#//Value #//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="DataReferenceContents CompatibleDataTypeInDataReference"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="DataReferenceContents" value="self.content.isEffectivelyStatic()&#xA;and self.content.argument->forAll(a | a.dataUse.isEffectivelyStatic())&#xA;and self.content.argument->closure(a |&#xA;a.dataUse.argument)->forAll(a|a.dataUse.isEffectivelyStatic())"/>
      <details key="DataReferenceContents$message" value="'Only effectively static \'DataUse\'s may be used directly or indirectly in \'ParameterBinding\'s of the \'DataUse\' within a \'DataReference\'.' + self.toString()"/>
      <details key="CompatibleDataTypeInDataReference" value="self.container().oclIsTypeOf(EventOccurrenceSpecification) implies (&#xA;self.container().oclAsType(EventOccurrenceSpecification).oppositeEntityReference&#xA;->including(self.container().oclAsType(EventOccurrenceSpecification).entityReference)&#xA;->collect(e | e.component)->excluding(null)->isEmpty()&#xA;or&#xA;self.container().oclAsType(EventOccurrenceSpecification).oppositeEntityReference&#xA;->including(self.container().oclAsType(EventOccurrenceSpecification).entityReference)&#xA;->collect(e | e.component)->excluding(null)&#xA;->collect(c | c.type.allGates())&#xA;->collect(g | g.type.allDataTypes())&#xA;->exists(d | self.content.resolveDataType().conformsTo(d))&#xA;)"/>
      <details key="CompatibleDataTypeInDataReference$message" value="'Only compatible \'DataType\'s may be used directly when \'ComponentInstance\'s are referenced within a top-level \'DataReference\'.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="content" lowerBound="1"
        eType="ecore:EClass tdl.ecore#//DataUse" containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Content" eSuperTypes="#//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="ContentOrValue CollectionLikeContent"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="ContentOrValue" value="self.content->isEmpty() or self.value.oclIsUndefined()"/>
      <details key="ContentOrValue$message" value="'Either nested \'Content\'s or \'Value\' may be specified within \'Content\', but not both.' + self.toString()"/>
      <details key="CollectionLikeContent" value="(not self.comment->isEmpty() and self.comment->last()._body = 'including') implies&#xA;(self.content->isEmpty() or self.content->forAll(c | c.value.oclIsUndefined()))"/>
      <details key="CollectionLikeContent$message" value="'If the \'including\' qualifier is used, directly contained \'Content\'s shall not contain a \'Value\'.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="value" eType="#//Value"
        containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="content" ordered="false"
@@ -112,25 +144,64 @@
    <eStructuralFeatures xsi:type="ecore:EReference" name="member" eType="ecore:EClass tdl.ecore#//Member"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="LiteralValue" eSuperTypes="#//Value #//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="CollectionLikeContentLiteralValue"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="CollectionLikeContentLiteralValue" value="(not self.comment->isEmpty() and self.comment->last()._body = 'including') implies&#xA;(self.content->isEmpty() or self.content->forAll(c | c.value.oclIsUndefined()))"/>
      <details key="CollectionLikeContentLiteralValue$message" value="'If the \'including\' qualifier is used, directly contained \'Content\'s shall not contain a \'Value\'.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="content" ordered="false"
        upperBound="-1" eType="#//Content" containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="dataType" eType="ecore:EClass tdl.ecore#//DataType"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="ContentReference" eSuperTypes="#//Value #//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="VisibleContent"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="VisibleContent" value="self.getTestObjective().contains(self.content)&#xA;and self.getTestObjective().indexOf(self.content) &lt; self.getTestObjective().indexOf(self)"/>
      <details key="VisibleContent$message" value="'Only \'Content\' defined within previous \'EventOccurrence\'s of the containing \'StructuredTestObjective\' may be referenced.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="content" lowerBound="1"
        eType="#//Content"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="LiteralValueReference" eSuperTypes="#//Value #//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="VisibleValue"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="VisibleValue" value="self.getTestObjective().contains(self.content)&#xA;and self.getTestObjective().indexOf(self.content) &lt; self.getTestObjective().indexOf(self)"/>
      <details key="VisibleValue$message" value="'Only \'LiteralValue\'s defined within previous \'EventOccurrence\'s of the containing \'StructuredTestObjective\' may be referenced.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="content" lowerBound="1"
        eType="#//LiteralValue"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="RepeatedEventSequence" eSuperTypes="#//EventSequence #//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="RepetitionOrInterval RepetitionCount RepetitionInterval"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="RepetitionOrInterval" value="self.repetitions.oclIsUndefined() or self.interval.oclIsUndefined()"/>
      <details key="RepetitionOrInterval$message" value="'At most one of the optional properties \'repetitions\' or \'interval\' shall be defined.' + self.toString()"/>
      <details key="RepetitionCount" value="true --This constraint cannot be expressed in OCL"/>
      <details key="RepetitionCount$message" value="'The expression assigned to the \'repetitions\' property shall evaluate to a positive and countable \'Value\'.' + self.toString()"/>
      <details key="RepetitionInterval" value="true --This constraint cannot be expressed in OCL"/>
      <details key="RepetitionInterval$message" value="'The expression assigned to the \'repetitions\' property shall evaluate to a positive and countable \'Value\'' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="repetitions" eType="#//Value"
        containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="interval" eType="#//Value"
        containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="EventTemplateOccurrence" eSuperTypes="#//EventOccurrence #//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="EntityTemplateOccurrenceConsistency"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="EntityTemplateOccurrenceConsistency" value="self.entityBinding->forAll(b |&#xA;(not b.templateEntity.entity.oclIsUndefined()&#xA;and (b.templateEntity.entity =&#xA;self.eventTemplate.eventSpecification.entityReference.entity))&#xA;or (not b.templateEntity.component.oclIsUndefined()&#xA;and (b.templateEntity.component =&#xA;self.eventTemplate.eventSpecification.entityReference.component)&#xA;or self.eventTemplate.eventSpecification.oppositeEntityReference->exists(e |&#xA;(not b.templateEntity.entity.oclIsUndefined()&#xA;and (e.entity = b.templateEntity.entity))&#xA;or (not b.templateEntity.component.oclIsUndefined()&#xA;and (e.component = b.templateEntity.component)))))"/>
      <details key="EntityTemplateOccurrenceConsistency$message" value="'If \'EntityBinding\'s are provided, the \'Entity\'s or \'ComponentInstance\'s referenced in the \'templateEntity\' properties shall also be referenced by one of the \'EntityReferences\' in the \'EventOccurrenceSpecification\' of the \'EventSpecificationTemplate\' referenced in the \'EventTemplateOccurrence\'.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="eventTemplate" lowerBound="1"
        eType="#//EventSpecificationTemplate"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="entityBinding" ordered="false"
@@ -163,6 +234,13 @@
    </eStructuralFeatures>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="VariantBinding" eSuperTypes="#//Element">
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
      <details key="constraints" value="VariantBindingValues"/>
    </eAnnotations>
    <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot">
      <details key="VariantBindingValues" value="(self.value.oclIsTypeOf(LiteralValueReference) implies&#xA;self.value.oclAsType(LiteralValueReference).content.getTestObjective() = self.getTestObjective())&#xA;and&#xA;(self.value.oclIsTypeOf(ContentReference) implies&#xA;self.value.oclAsType(ContentReference).content.getTestObjective() = self.getTestObjective())"/>
      <details key="VariantBindingValues$message" value="'If the \'value\' property references a \'LiteralValue\' or \'Content\' element, the referenced element shall be contained in the \'StructuredTestObjective\' containing the \'VariantBinding\'.' + self.toString()"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EReference" name="value" lowerBound="1" eType="#//Value"
        containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="boundTo" lowerBound="1"
+616 −5

File changed.

Preview size limit exceeded, changes collapsed.

+5 −5
Changes for plugins/org.etsi.mts.tdl.model/src/org/etsi/mts/tdl/Activator.java: 5 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -9,20 +9,20 @@ public class Activator implements BundleActivator {

	@Override
	public void start(BundleContext context) throws Exception {

//		registerValidator("model/tdl-structured-constraints.ocl", StructuredObjectivesPackage.eINSTANCE, context);
//		registerValidator("model/tdl-configurations-constraints.ocl", ExtendedConfigurationsPackage.eINSTANCE, context);
		// See class comment at ConstraintImplementation
		if (ConstraintImplementation.isInterpreted()) {
			Validator.registerValidator("model/tdl-constraints.ocl", tdlPackage.eINSTANCE, context);
			Validator.registerValidator("model/tdl-structured-constraints.ocl", StructuredObjectivesPackage.eINSTANCE, context);
			Validator.registerValidator("model/tdl-configurations-constraints.ocl", ExtendedConfigurationsPackage.eINSTANCE, context);

		}
	}

	@Override
	public void stop(BundleContext context) throws Exception {
		if (ConstraintImplementation.isInterpreted()) {
			Validator.removeValidator(tdlPackage.eINSTANCE);
			Validator.removeValidator(StructuredObjectivesPackage.eINSTANCE);
			Validator.removeValidator(ExtendedConfigurationsPackage.eINSTANCE);
		}

	}
}
+56 −0
Changes for plugins/org.etsi.mts.tdl.model/src/org/etsi/mts/tdl/ConstraintImplementation.java: 56 added lines, 0 removed lines.
Original line number Diff line number Diff line
package org.etsi.mts.tdl;

/**
 * Arbiter of constraint implementation to use.
 * <ul>
 * <li>{@link #INTERPRETED} - the Complete OCL documents in {@code model/*.ocl}, evaluated at run time
 * by the Eclipse OCL interpreter ({@link Validator}). This is the 
 * default.</li>
 * <li>{@link #COMPILED} - the same invariants (embedded) converted to Java from {@code model/*.ecore}
 * ({@code tdlValidator}, {@code StructuredObjectivesValidator},
 * {@code ExtendedConfigurationsValidator}).</li>
 * </ul>
 * Only one of them is active, so a constraint is never reported twice. The choice is made once per
 * process with the system property {@value #PROPERTY} ({@code interpreted} or {@code compiled}): the
 * validators live in the global {@code EValidator} registry, so switching while models are being
 * validated would mix the two. In the IDE set it in {@code eclipse.ini} or the launch configuration
 * ({@code -Dtdl.validation.constraints=compiled}); for a Maven test run pass
 * {@code -DsystemProperties=-Dtdl.validation.constraints=compiled}.
 */
public enum ConstraintImplementation {

	INTERPRETED, COMPILED;

	public static final String PROPERTY = "tdl.validation.constraints";

	private static final ConstraintImplementation CURRENT = resolve(System.getProperty(PROPERTY));

	/** The implementation active in this process. */
	public static ConstraintImplementation current() {
		return CURRENT;
	}

	public static boolean isCompiled() {
		return CURRENT == COMPILED;
	}

	public static boolean isInterpreted() {
		return CURRENT == INTERPRETED;
	}

	static ConstraintImplementation resolve(String value) {
		if (value == null || value.isBlank()) {
			return INTERPRETED;
		}
		switch (value.trim().toLowerCase()) {
		case "compiled":
		case "java":
			return COMPILED;
		case "interpreted":
		case "ocl":
			return INTERPRETED;
		default:
			throw new IllegalArgumentException("-D" + PROPERTY + "=" + value + ": expected 'interpreted' or 'compiled'");
		}
	}
}
Loading