Commit 7e0d88b3 authored by Martti Käärik's avatar Martti Käärik
Browse files

Export OCL constraints in the newer Tuple format

parent a48c455e
Loading
Loading
Loading
Loading
+16 −0
Changes for plugins/org.etsi.mts.tdl.constraints.helper/src/org/etsi/mts/tdl/constraints/helper/ConstraintRecord.java: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@ public final class ConstraintRecord {
	public final String title;
	public final String description;
	public final String expression;
	/** Severity of a violation in the OCL runtime's terms (negative: error, zero: info, positive: warning); null for the default. */
	public final Integer severity;

	public ConstraintRecord(String className, String name, String title, String description, String expression) {
		this.className = className;
@@ -24,6 +26,20 @@ public final class ConstraintRecord {
		return "'" + description.replace("'", "\\'") + "' + self.toString()";
	}

	/**
	 * The invariant in the tuple form:
	 * {@code Tuple { message : String = …, severity : Integer = …, status : Boolean = … }.status}, parts in
	 * alphabetical order as {@code PivotUtil.createTupleValuedConstraint} writes them. The expression is kept as
	 * is, a line break added before the closing brace to account for comment at the end of an expression.
	 */
	public String invariantExpression() {
		StringBuilder s = new StringBuilder("Tuple { message : String = ").append(messageExpression()).append(", ");
		if (severity != null) {
			s.append("severity : Integer = ").append(severity).append(", ");
		}
		return s.append("status : Boolean = ").append(expression).append("\n}.status").toString();
	}

	@Override
	public String toString() {
		return className + "::" + name;
+11 −12
Changes for plugins/org.etsi.mts.tdl.constraints.helper/src/org/etsi/mts/tdl/constraints/helper/EcoreConstraintEmitter.java: 11 added lines, 12 removed lines.
Original line number Diff line number Diff line
@@ -24,11 +24,12 @@ import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;

/**
 * Writes constraints as OCLinEcore invariants into an {@code .ecore} file: per
 * {@link EClass}, the details {@code <Name>} (expression) and
 * {@code <Name>$message} (message expression) of the Pivot OCL annotation and
 * the standard EMF {@code constraints} list. This is exactly the form the OCL
 * code generator reads (see {@code OCLinEcoreGenModelGeneratorAdapter}) and the
 * form the OCLinEcore editor saves.
 * {@link EClass}, one detail {@code <Name>} of the Pivot OCL annotation with value being the
 * tuple invariant ({@link ConstraintRecord#invariantExpression()}: message, severity
 * if configured, status), and the standard EMF {@code constraints} list. The OCL code
 * generator ({@code OCLinEcoreGenModelGeneratorAdapter}) and the Ecore loader
 * ({@code Ecore2ASDeclarationSwitch}) take the value as the invariant body. The older
 * {@code <Name>$message} detail is deprecated in Eclipse OCL and removed here when found.
 * <p>
 * For every class that has constraints in the input, invariants that are no
 * longer in the input are removed. Classes absent from the input are left as
@@ -37,6 +38,7 @@ import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
public final class EcoreConstraintEmitter {

	public static final String PIVOT_SOURCE = "http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot";
	/** Suffix of the deprecated message detail that is removed. */
	public static final String MESSAGE_SUFFIX = "$message";

	/** What changed, for the console report. */
@@ -162,16 +164,15 @@ public final class EcoreConstraintEmitter {
			names.remove(r.name);
			names.add(r.name);
			String old = pivot.getDetails().get(r.name);
			String oldMessage = pivot.getDetails().get(r.name + MESSAGE_SUFFIX);
			String invariant = r.invariantExpression();
			if (old == null) {
				report.added.add(qualified);
			} else if (!old.equals(r.expression) || !r.messageExpression().equals(oldMessage)) {
			} else if (!old.equals(invariant) || pivot.getDetails().containsKey(r.name + MESSAGE_SUFFIX)) {
				report.updated.add(qualified);
			} else {
				report.unchanged.add(qualified);
			}
			pivot.getDetails().put(r.name, r.expression);
			pivot.getDetails().put(r.name + MESSAGE_SUFFIX, r.messageExpression());
			pivot.getDetails().put(r.name, invariant);
			if (r.expression.contains("allInstances()")) {
				report.warnings.computeIfAbsent(qualified, k -> new ArrayList<>()).add("uses allInstances()");
			}
@@ -179,15 +180,13 @@ public final class EcoreConstraintEmitter {
		for (String stale : existing) {
			if (!names.contains(stale)) {
				pivot.getDetails().removeKey(stale);
				pivot.getDetails().removeKey(stale + MESSAGE_SUFFIX);
				report.removed.add(eClass.getName() + "::" + stale);
			}
		}
		// keep the details in a stable order: name, name$message, ...
		// keep the details in the order of the input, drop legacy <Name>$message details
		Map<String, String> ordered = new LinkedHashMap<>();
		for (String n : names) {
			ordered.put(n, pivot.getDetails().get(n));
			ordered.put(n + MESSAGE_SUFFIX, pivot.getDetails().get(n + MESSAGE_SUFFIX));
		}
		pivot.getDetails().clear();
		for (Map.Entry<String, String> e : ordered.entrySet()) {