Skip to content

#683 Add activity constraints - #684

Open
AndreaPuffo wants to merge 26 commits into
mainfrom
683-add-activity-constraints
Open

#683 Add activity constraints#684
AndreaPuffo wants to merge 26 commits into
mainfrom
683-add-activity-constraints

Conversation

@AndreaPuffo

Copy link
Copy Markdown
Collaborator

Closes #683.

I will add a regression test once the changes are approved.

@AndreaPuffo AndreaPuffo linked an issue Feb 11, 2026 that may be closed by this pull request
@AndreaPuffo

Copy link
Copy Markdown
Collaborator Author

Documentation to be updated as well.

}

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

Copy link
Copy Markdown
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
Copy Markdown
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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Did we ever discuss this? Was there a conclusion?

return constraint.getContext() instanceof PrimitiveType;
}

public static boolean isActivityRequirement(Constraint constraint) {

Copy link
Copy Markdown
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.

return constraint.getContext() instanceof PrimitiveType;
}

public static boolean isActivityRequirement(Constraint constraint) {

Copy link
Copy Markdown
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?


public static boolean isActivityRequirement(Constraint constraint) {
return constraint.getContext() instanceof Activity activity
// It is the correct type of constraint.

Copy link
Copy Markdown
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
Copy Markdown
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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Rename to isClassRequirementConstraint?

.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
Copy Markdown
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
Copy Markdown
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.

checkValidActivityPrePostconditionConstraint(constraint);
} else if (CifContext.isClassConstraint(constraint)) {
checkValidClassConstraint(constraint);
} else if (CifContext.isClassConstraint(constraint) || (CifContext.isActivityRequirement(constraint))) {

Copy link
Copy Markdown
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
Copy Markdown
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.

}

private void checkValidClassConstraint(Constraint constraint) {
private void checkValidClassOrActivityConstraint(Constraint constraint) {

Copy link
Copy Markdown
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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why check this with a global scope? Why not in the scope of the activity, if it is in an activity?

@dhendriks

Copy link
Copy Markdown
Collaborator

Does editing these new constraints with the SynthML tab work?

@AndreaPuffo

AndreaPuffo commented Feb 25, 2026

Copy link
Copy Markdown
Collaborator Author

Does editing these new constraints with the SynthML tab work?

A quick example of how this works. This is the model: 2 class requirements and 2 activities, each with its own activity requirements.
Screenshot 2026-02-25 093817

Editing one activity constraint looks like this:
Screenshot 2026-02-25 100309

And finally the CIF translation of the activities (Activity1 top, Activity 2 bottom):
Screenshot 2026-02-25 093838
Screenshot 2026-02-25 093856

@@ -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
Copy Markdown
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?

AndreaPuffo and others added 9 commits March 9, 2026 14:13
Co-authored-by: Dennis Hendriks <dh_tue@hotmail.com>
UmlToCifTranslator, FlattenUmlActivity: rename methods
- make methods public
- add occurrence constraint and primitive type constraint methods
PokaYokeProfileValidator: use the new methods
UmlToCameoTransformer, Uml2GalTranslator, PokaYokeProfileValidator: use
the PokaYokeUmlProfileUtil method
AbstractActivityDependencyOrderer: use the PokaYokeUmlProfileUtil method
constraint
PokaYokeProfileValidator: use the PokaYokeUmlProfileUtil methods
@AndreaPuffo

Copy link
Copy Markdown
Collaborator Author

Ready for review, best commit-by-commit.

*/
private boolean isBlockingOccurrenceConstraint(Constraint constraint) {
if (CifContext.isOccurrenceConstraint(constraint)) {
if (PokaYokeUmlProfileUtil.isContainedAsActivityOccurrenceConstraint(constraint)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'd have expected here isOccurrenceConstraint, not the containment variant. (see also other comment)


private static boolean isPreconditionConstraint(Constraint constraint) {
public static boolean isContainedAsActivityPrecondition(Constraint constraint) {
return (constraint.eContainer() instanceof Activity activity)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Remove unnecessary parentheses like in isContainedAsClassOrActivityOwnedRule.


public static boolean isSynthesisPrecondition(Constraint constraint) {
public static boolean isContainedAsActivityPostcondition(Constraint constraint) {
return (constraint.eContainer() instanceof Activity activity)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Remove unnecessary parentheses like in isContainedAsClassOrActivityOwnedRule.


public static boolean isContainedAsClassOrActivityOwnedRule(Constraint constraint) {
// Activity is a sub-type of Classifier.
return constraint.eContainer() instanceof Classifier clazz && clazz.getOwnedRules().contains(constraint);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we check for Classifier and not Class? Not saying it is wrong. Just wondering which is better?

}

public static boolean isContainedAsClassOrActivityOwnedRule(Constraint constraint) {
// Activity is a sub-type of Classifier.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

// Activity is a sub-type of Classifier. -> // 'Activity' is a sub-type of 'Class'. (if we go check for being a class) or // 'Activity' is a sub-type of 'Class', which is a sub-type of 'Classifier'. (if we keep the code as is).

return (constraint.eContainer() instanceof Activity activity)
&& activity.getPostconditions().contains(constraint);
}
public static boolean isRequirementConstraint(Constraint constraint) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I miss here isOccurrenceConstraint that checks the stereotype, like this and similar methods. We seem to only have the containment one for occurrence constraints.

.flatMap(Set::stream).collect(Collectors.toSet());

if (!members.equals(allowedMembers)) {
error("Activity should contain only precondition, postcondition, constraints and interval constraint members.",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
error("Activity should contain only precondition, postcondition, constraints and interval constraint members.",
error("Activity should contain only precondition, postcondition, requirement and interval constraints as members.",

} else if (PokaYokeUmlProfileUtil.isContainedAsActivityOccurrenceConstraint(constraint)) {
checkValidOccurrenceConstraint((IntervalConstraint)constraint);
} else if (PokaYokeUmlProfileUtil.isRequirementConstraint(constraint)) {
// Check the class and activity requirements.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// Check the class and activity requirements.
// Check the class or activity requirement.

It is either one of them, not both. It is also only one requirement, I think.

@dhendriks

Copy link
Copy Markdown
Collaborator

Documentation to be updated as well.

Should still be done then.

@dhendriks

Copy link
Copy Markdown
Collaborator

I will add a regression test once the changes are approved.

Should not forget this.

@AndreaPuffo

Copy link
Copy Markdown
Collaborator Author

Thanks for the review. I would prefer to finish vertical scaling and then finish this PR. just to avoid confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add activity constraints

2 participants