Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
12cb8f6
#683 CifContext: add `isActivityRequirement` method
AndreaPuffo Feb 10, 2026
58705a8
#683 PokaYokeProfileValidator: allow activity requirement constraints
AndreaPuffo Feb 10, 2026
6fe4ef6
#683 PokaYokeProfileValidator: rename method
AndreaPuffo Feb 10, 2026
212a07b
#683 PokaYokeUmlProfileUtil, PokaYokeProfileValidator: rename stereotype
AndreaPuffo Feb 11, 2026
3bb41f9
#683 UmlToCifTranslator: update JavaDoc.
AndreaPuffo Feb 25, 2026
0fa177a
#683 CifContext: move method `isActivityRequirement`.
AndreaPuffo Feb 25, 2026
a468205
#683 CifContext, UmlToCifTranslator, PYProfileValidator: rename method
AndreaPuffo Feb 25, 2026
19fa69f
#683 CifContext: remove `isActivityRequirementConstraint`
AndreaPuffo Feb 25, 2026
6b5dc4d
#683 PokaYokeUmlProfileUtil: add `isRequirementConstraint` method
AndreaPuffo Feb 25, 2026
8a1f8c1
#683 PokaYokeProfileValidator, UmlToCifTranslator: use new method
AndreaPuffo Feb 25, 2026
ee430c6
#683 PokaYokeUmlProfileUtil: rename method.
AndreaPuffo Feb 25, 2026
3127da1
#683 PokaYokeProfileValidator: create set union before check.
AndreaPuffo Feb 25, 2026
5aa521f
#683 PokaYokeProfileValidator: rename method.
AndreaPuffo Feb 25, 2026
ab173a0
#683 PokaYokeProfileValidator: use scoped context.
AndreaPuffo Feb 25, 2026
549e163
#683 Apply suggestions from code review
AndreaPuffo Mar 9, 2026
8cd8aac
#683 PokaYokeProfileValidator: change variable name after review
AndreaPuffo Mar 9, 2026
f689a77
#683 PokaYokeUmlProfileUtil: move methods.
AndreaPuffo Mar 9, 2026
686be24
#683 PokaYokeUmlProfileUtil: rename methods.
AndreaPuffo Mar 9, 2026
281f185
#683 PokaYokeUmlProfileUtil: rename methods
AndreaPuffo Mar 9, 2026
1c52cc8
#683 PokaYokeUmlProfileUtil:
AndreaPuffo Mar 9, 2026
49a6a8e
#683 CifContext: remove `isPrimitiveTypeConstraint`
AndreaPuffo Mar 9, 2026
3312f5d
#683 CifContext: remove `isOccurrenceConstraint`
AndreaPuffo Mar 9, 2026
e623614
#683 CifContext: remove method to check activity pre/post condition
AndreaPuffo Mar 9, 2026
0487e95
#638 PokaYokeProfileValidator: update if-clause with new methods
AndreaPuffo Mar 10, 2026
2f63429
#638 PokaYokeUmlProfileUtil: add comment
AndreaPuffo Mar 10, 2026
f0ba3f0
#638 UmlToCifTranslator: reformat file
AndreaPuffo Mar 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1656,10 +1656,18 @@ private List<Invariant> createDisableEventsWhenDoneRequirements() {
private List<Invariant> translateRequirements() {
List<Invariant> cifInvariants = new ArrayList<>();

// Translate class requirements.
for (Constraint umlConstraint: activity.getContext().getOwnedRules()) {
cifInvariants.addAll(translateRequirement(umlConstraint));
}

// Translate activity requirements.
for (Constraint umlConstraint: activity.getOwnedRules()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it sufficient to translate the requirements like this? Should we also include all requirements of other activities that we call, etc? (all other 'relevant' activities)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this to be consistent with the occurrence constraints: these are considered only during the activity synthesis, not when an activity is called. Better to have a conversation offline about this.

if (CifContext.isActivityRequirement(umlConstraint)) {
cifInvariants.addAll(translateRequirement(umlConstraint));
}
}

return cifInvariants;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.ControlFlow;
import org.eclipse.uml2.uml.DataType;
import org.eclipse.uml2.uml.DurationConstraint;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.EnumerationLiteral;
import org.eclipse.uml2.uml.InteractionConstraint;
import org.eclipse.uml2.uml.IntervalConstraint;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.OpaqueBehavior;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.TimeConstraint;

import com.github.tno.synthml.uml.profile.util.PokaYokeTypeUtil;

Expand Down Expand Up @@ -276,6 +279,16 @@ public static boolean isPrimitiveTypeConstraint(Constraint constraint) {
return constraint.getContext() instanceof PrimitiveType;
}

public static boolean isActivityRequirement(Constraint constraint) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move isActivityRequirement to just after isActivityPostconditionConstraint.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename isActivityRequirement to isActivityRequirementConstraint, to match other methods?

return constraint.getContext() instanceof Activity activity
// It is the correct type of constraint.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we check that it is a FormalConstraint?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was my first choice, but I then wrote it this way to be consistent with the rest of the class and structure that we have e.g., in the validator. To be honest, if I write a isRequirementConstraint method in PokaYokeUmlProfileUtil, this method in CifContext is not needed at all. But it will not be consistent with the rest of validation, for instance.
I will remove this method and add a new one in PokaYokeUmlProfileUtil, and let's see how it looks. I think it looks better; but if consistency with the rest is more important we can revert back to this.

&& !(constraint instanceof DurationConstraint) && !(constraint instanceof InteractionConstraint)
&& !(constraint instanceof IntervalConstraint) && !(constraint instanceof TimeConstraint)
// It is neither a precondition nor a postcondition.
&& !activity.getPreconditions().contains(constraint)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I like the negative conditions. Can't we check something more definitive?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved now with new method (see previous comment).

&& !activity.getPostconditions().contains(constraint);
}

default boolean hasAbstractActivities() {
return getDeclaredElements().stream().anyMatch(e -> e instanceof Activity a && a.isAbstract());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public class PokaYokeUmlProfileUtil {

private static final String ST_FORMAL_CONSTRAINT = SynthMLPackage.Literals.FORMAL_CONSTRAINT.getName();

public static final String ST_CLASS_REQUIREMENT = SynthMLPackage.Literals.REQUIREMENT.getName();
public static final String ST_REQUIREMENT = SynthMLPackage.Literals.REQUIREMENT.getName();

public static final String ST_SYNTHESIS_PRECONDITION = SynthMLPackage.Literals.SYNTHESIS_PRECONDITION.getName();

Expand Down Expand Up @@ -112,8 +112,7 @@ public class PokaYokeUmlProfileUtil {
+ ST_FORMAL_CONSTRAINT;

/** Qualified name for the {@link Requirement} stereotype. */
public static final String REQUIREMENT_STEREOTYPE = POKA_YOKE_PROFILE + NamedElement.SEPARATOR
+ ST_CLASS_REQUIREMENT;
public static final String REQUIREMENT_STEREOTYPE = POKA_YOKE_PROFILE + NamedElement.SEPARATOR + ST_REQUIREMENT;

/** Qualified name for the {@link SynthesisPrecondition} stereotype. */
public static final String SYNTHESIS_PRECONDITION_STEREOTYPE = POKA_YOKE_PROFILE + NamedElement.SEPARATOR
Expand Down Expand Up @@ -529,7 +528,7 @@ public static List<Stereotype> getSupportedConstraintStereotypes(Constraint cons
} else if (isPostconditionConstraint(constraint)) {
return List.of(getStereotype(constraint, ST_POSTCONDITION));
} else if (isClassRequirement(constraint)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also check for isActivityRequirementConstraint?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isClassRequirement checks whether the constraint belongs to the container classifier. This works also for activities, since activities are a subtype of classifiers. To clarify we can split this into two methods, one exclusively for UML activities and one for UML Classes (not Classifiers, as it is now). Let me know if you'd prefer this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I always forget that Activity inherits from Class. Super non-intuitive. I'd maybe rename the method to isClassOrActivityRequirementConstraint, and there add a comment in the body like // Note that 'Activity' inherits from 'Class'. or so?

return List.of(getStereotype(constraint, ST_CLASS_REQUIREMENT));
return List.of(getStereotype(constraint, ST_REQUIREMENT));
} else {
return List.of();
}
Expand Down Expand Up @@ -592,7 +591,7 @@ public static void setConstraintStereotype(Constraint constraint, Stereotype ste
}

private static String getQualifiedStereotypeName(String stereotypeName) {
if (ST_CLASS_REQUIREMENT.equals(stereotypeName)) {
if (ST_REQUIREMENT.equals(stereotypeName)) {
return REQUIREMENT_STEREOTYPE;
} else if (ST_SYNTHESIS_PRECONDITION.equals(stereotypeName)) {
return SYNTHESIS_PRECONDITION_STEREOTYPE;
Expand All @@ -616,7 +615,7 @@ public static void setConstraintExpression(Constraint constraint, String newValu

public static String getStereotypeName(Stereotype st) {
// Returns a slightly better formatted name for the preconditions.
if (st.getName().equals(ST_CLASS_REQUIREMENT)) {
if (st.getName().equals(ST_REQUIREMENT)) {
return "Requirement";
} else if (st.getName().equals(ST_SYNTHESIS_PRECONDITION)) {
return "Synthesis precondition";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,12 @@ private void checkValidActivity(Activity activity) {
.filter(IntervalConstraint.class::isInstance).map(IntervalConstraint.class::cast)
.collect(Collectors.toCollection(LinkedHashSet::new));

if (!members.equals(Sets.union(preAndPostconditions, intervalConstraints))) {
error("Activity should contain only precondition, postcondition, and interval constraint members.",
Set<Constraint> activityRequirements = activity.getOwnedRules().stream()
.filter(r -> CifContext.isActivityRequirement(r)).map(Constraint.class::cast)
.collect(Collectors.toCollection(LinkedHashSet::new));

if (!members.equals(Sets.union(Sets.union(preAndPostconditions, intervalConstraints), activityRequirements))) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Sets.union supports also giving 3 sets instead of 2, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how to make it work, so I created a set union with stream.

error("Activity should contain only precondition, postcondition, constraints and interval constraint members.",
UMLPackage.Literals.NAMESPACE__MEMBER);
}

Expand Down Expand Up @@ -1003,8 +1007,8 @@ private void checkValidConstraint(Constraint constraint) {

if (CifContext.isActivityPrePostconditionConstraint(constraint)) {
checkValidActivityPrePostconditionConstraint(constraint);
} else if (CifContext.isClassConstraint(constraint)) {
checkValidClassConstraint(constraint);
} else if (CifContext.isClassConstraint(constraint) || (CifContext.isActivityRequirement(constraint))) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it still make sense to have CifContext.isClassConstraint? Should we rename it to CifContext.isClassRequirementConstraint?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comments.

checkValidClassOrActivityConstraint(constraint);
} else if (CifContext.isOccurrenceConstraint(constraint)) {
checkValidOccurrenceConstraint((IntervalConstraint)constraint);
} else if (CifContext.isPrimitiveTypeConstraint(constraint)) {
Expand Down Expand Up @@ -1058,7 +1062,7 @@ private void checkValidActivityPrePostconditionConstraint(Constraint constraint)
}
}

private void checkValidClassConstraint(Constraint constraint) {
private void checkValidClassOrActivityConstraint(Constraint constraint) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only requirements, from classes and activities, right? So, maybe rename to checkValidRequirementConstraint?

// Check that the constraint has the right stereotype applied.
List<Stereotype> stereotypes = constraint.getAppliedStereotypes();

Expand All @@ -1068,7 +1072,7 @@ private void checkValidClassConstraint(Constraint constraint) {
return;
}

if (!stereotypes.get(0).getName().equals(PokaYokeUmlProfileUtil.ST_CLASS_REQUIREMENT)) {
if (!stereotypes.get(0).getName().equals(PokaYokeUmlProfileUtil.ST_REQUIREMENT)) {
error(String.format("Constraint '%s' must have a requirement stereotype applied.", constraint.getName()),
UMLPackage.Literals.CONSTRAINT__SPECIFICATION);
return;
Expand Down