Home » Modeling » VIATRA » Matches not send to change listener
Matches not send to change listener [message #1826168] |
Mon, 20 April 2020 15:10 |
Hans van der Laan Messages: 34 Registered: February 2020 |
Member |
|
|
Hey,
I've just finished my proposal, which means I can finally return to experimenting with Viatra! :)
I'm observing some behavior I'm not sure how to explain. It seems as a specific match update listener is blocking something unless I interact with the engine.
Consider the following model:
and some basic patterns:
pattern policy(policy: Policy) {
Policy(policy);
}
pattern roleName(role: Role, name : java String) {
Role.name(role,name);
}
pattern userShouldHaveARole(user: User) {
neg User.UR(user, _);
}
pattern accessRelation(user: User, permission: Permission) {
User.UR(user,role);
Role.RD(role, demarcation);
Demarcation.DP(demarcation, permission);
}
Weirdly after I've added a match update listener for the "accessRelation" query, for all other match update listeners I add afterwards the existing matches are only given to the listeners after I interact with the engine.
For example: When I first add a match change listener for "userShouldHaveARole", then for "accessRelation" and lastly for "roleName", the match listener for "roleName" will only be invoked after I interact with the engine (e.g. calling getAllMatches()/applying a model transformation).
Why is this happening?
Aditionally, in the documentation of "addMatchUpdateListener()", a function "addCallbackAfterUpdates(Runnable)" is mentioned. Where can we find this function? The link is not working and I can not find it the ViatraQueryEngine nor the AdvancedViatraQueryEngine.
Kind regards,
Hans
PS:
A program which shows this behaviour:
package validator;
import java.util.function.Consumer;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
import org.eclipse.viatra.query.runtime.emf.EMFScope;
import org.eclipse.viatra.transformation.runtime.emf.modelmanipulation.IModelManipulations;
import org.eclipse.viatra.transformation.runtime.emf.modelmanipulation.SimpleModelManipulations;
import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRuleFactory;
import org.eclipse.viatra.transformation.runtime.emf.transformation.batch.BatchTransformation;
import org.eclipse.viatra.transformation.runtime.emf.transformation.batch.BatchTransformationStatements;
import org.eclipse.xtext.xbase.lib.Extension;
import com.google.common.base.Objects;
import queries.AccessRelation;
import queries.Policy;
import queries.RoleName;
//import queries.SameRoleName;
import queries.TestQueries;
import queries.UserShouldHaveARole;
public class Validator implements IApplication {
@Extension
private BatchTransformation transformation;
@Extension
private BatchTransformationStatements statements;
@Extension
private BatchTransformationRuleFactory factory = new BatchTransformationRuleFactory();
@Extension
private IModelManipulations manipulation;
@Override
public Object start(IApplicationContext context) throws Exception {
System.out.println("Validator Called!");
System.out.print("Initialize model scope and preparing engine... ");
EMFScope scope = initializeModelScope();
AdvancedViatraQueryEngine engine = prepareAdvancedQueryEngine(scope);
System.out.println(" Done!");
Thread.sleep(5000);
System.out.println("\nAdding Change Listeners... ");
addChangeListeners(engine);
System.out.println("Done!");
Thread.sleep(5000);
System.out.println("\nSearching for Access Relation Matches... ");
//printAllAccessRelationMatches(engine);
System.out.println("Done!");
System.out.println("\nSearching for Users without a role... ");
printAllUserShouldHaveARoleMatches(engine);
System.out.println("Done!");
Thread.sleep(5000);
System.out.println("\nCreate and Execute Model Transformation");
//createTransformation(engine);
//execute();
System.out.println("Done!");
return 0;
}
@Override
public void stop() {
// Headless applications do not require specific stop steps
}
private EMFScope initializeModelScope() {
ResourceSet rs = new ResourceSetImpl();
rs.getResource(URI.createPlatformPluginURI("rbacviatratest/trebla.rbac", true), true);
return new EMFScope(rs);
}
private AdvancedViatraQueryEngine prepareAdvancedQueryEngine(EMFScope scope) {
AdvancedViatraQueryEngine engine = AdvancedViatraQueryEngine.createUnmanagedEngine(scope);
// Initialize all queries on engine
TestQueries.instance().prepare(engine);
return engine;
}
private void addChangeListeners(AdvancedViatraQueryEngine engine) {
// fireNow = true parameter means all current matches are sent to the listener
engine.addMatchUpdateListener(UserShouldHaveARole.Matcher.on(engine), ListenerFactory.getUserShouldHaveARoleUpdateListener(), true);
engine.addMatchUpdateListener(AccessRelation.Matcher.on(engine), ListenerFactory.getAccessRelationUpdateListener(), true);
engine.addMatchUpdateListener(RoleName.Matcher.on(engine), ListenerFactory.getRoleNameMatchUpdateListener(), true);
}
private void printAllAccessRelationMatches(ViatraQueryEngine engine) {
AccessRelation.Matcher matcher = AccessRelation.Matcher.on(engine);
for (AccessRelation.Match match : matcher.getAllMatches()) {
System.out.println("Found Access Relation:" + match.prettyPrint());
}
}
private void printAllUserShouldHaveARoleMatches(ViatraQueryEngine engine) {
UserShouldHaveARole.Matcher matcher = UserShouldHaveARole.Matcher.on(engine);
for (UserShouldHaveARole.Match match : matcher.getAllMatches()) {
System.out.println("Found user without role:" + match.prettyPrint());
}
}
public void execute() {
System.out.println("Execute Called!");
this.statements.<Policy.Match>fireOne(this.getExampleRule());
}
private BatchTransformationStatements createTransformation(AdvancedViatraQueryEngine engine) {
BatchTransformationStatements _xblockexpression = null;
{
SimpleModelManipulations _simpleModelManipulations = new SimpleModelManipulations(engine);
this.manipulation = _simpleModelManipulations;
this.transformation = BatchTransformation.forEngine(engine).build();
_xblockexpression = this.statements = this.transformation.getTransformationStatements();
}
return _xblockexpression;
}
private BatchTransformationRule<Policy.Match, Policy.Matcher> getExampleRule() {
final Consumer<Policy.Match> _function = (Policy.Match it) -> {
it.getPolicy().getRoles().get(0).setName("R2");
};
final BatchTransformationRule<Policy.Match, Policy.Matcher> exampleRule = this.factory.<Policy.Match, Policy.Matcher>createRule(Policy.instance()).action(_function).build();
return exampleRule;
}
public void dispose() {
boolean _notEquals = (!Objects.equal(this.transformation, null));
if (_notEquals) {
this.transformation.getRuleEngine().dispose();
}
this.transformation = null;
return;
}
}
With the listeners defined as:
public static IMatchUpdateListener<RoleName.Match> getRoleNameMatchUpdateListener() {
return new IMatchUpdateListener<RoleName.Match>() {
@Override
public void notifyAppearance(RoleName.Match match) {
System.out.printf("[ADD RoleName Match] %s %n", match.prettyPrint());
}
@Override
public void notifyDisappearance(RoleName.Match match) {
System.out.printf("[REM RoleName Match] %s %n", match.prettyPrint());
}
};
}
public static IMatchUpdateListener<UserShouldHaveARole.Match> getUserShouldHaveARoleUpdateListener() {
return new IMatchUpdateListener<UserShouldHaveARole.Match>() {
@Override
public void notifyAppearance(UserShouldHaveARole.Match match) {
System.out.printf("[ADD UserShouldHaveARole Match] %s %n", match.prettyPrint());
}
@Override
public void notifyDisappearance(UserShouldHaveARole.Match match) {
System.out.printf("[REM UserShouldHaveARole Match] %s %n", match.prettyPrint());
}
};
}
public static IMatchUpdateListener<AccessRelation.Match> getAccessRelationUpdateListener() {
return new IMatchUpdateListener<AccessRelation.Match>() {
@Override
public void notifyAppearance(AccessRelation.Match match) {
System.out.printf("[ADD AccessRelation Match] %s %n", match.prettyPrint());
}
@Override
public void notifyDisappearance(AccessRelation.Match match) {
System.out.printf("[REM AccessRelation Match] %s %n", match.prettyPrint());
}
};
}
Debug output:
Validator Called!
Initialize model scope and preparing engine... Done!
Adding Change Listeners...
[ADD UserShouldHaveARole Match] "user"=Kevin Alberts
[ADD AccessRelation Match] "user"=Isaac, "permission"=Workshop
[...]
[ADD AccessRelation Match] "user"=Isaac, "permission"=Office2
Done!
Searching for Users without a role...
[ADD RoleName Match] "role"=Director, "name"=Director
[...]
[ADD RoleName Match] "role"=Guard, "name"=Guard
Found user without role:"user"=Kevin Alberts
Done!
[Updated on: Mon, 20 April 2020 15:12] Report message to a moderator
|
|
| | |
Re: Matches not send to change listener [message #1826242 is a reply to message #1826210] |
Tue, 21 April 2020 18:00 |
Zoltan Ujhelyi Messages: 392 Registered: July 2015 |
Senior Member |
|
|
Hi Hans,
thanks for the reproduction, it worked for me and I have managed to create a minimal reproduction and a corresponding bug report in https://bugs.eclipse.org/bugs/show_bug.cgi?id=562369 We will have a look at what the issue might be.
To be honest, for logging the output (if you are fine with some occasional temporary inconsistencies, such as a match getting removed and added if multiple elements are changed once), relying on match update listeners should work. However, I'd recommend skipping EVM and working with the transformation API (already mentioned in the tutorial) for this case, as there you can ensure that logging only happens in stable states (e.g. after a transaction was processed) and also you have control over the order of logging (e.g. you can make sure some type of events will get logged before others).
About the paper recommendation, I will ask one of my colleagues, as he has worked with similar things recently, and maybe he has some better recommendations I can get from the top of my head.
Best regards,
Zoltán
|
|
|
Re: Matches not send to change listener [message #1826383 is a reply to message #1826210] |
Fri, 24 April 2020 08:43 |
Gabor Bergmann Messages: 36 Registered: July 2009 |
Member |
|
|
Hi Hans,
Hans van der Laan wrote on Tue, 21 April 2020 10:22
On a small side note. I'm also reading up on some of the papers published on VIATRA. I've read: "Road to a reactive and incremental model transformation platform: three generations of the VIATRA framework" and
"Viatra 3: A Reactive Model Transformation Platform" thus far. I'm now reading "EMF-IncQuery: An integrated development environment for live model queries". As you can probably guess from the project on GitHub,
I'm doing research about incremental verification of physical access control systems. Are there any other papers you recommend reading about VIATRA / incremental consistency checking?
Zoltán alerted me to your request on further Viatra-related papers, specifically relating to incremental verification and to access control.
I have the following two pointers to give.
1. We were involved in a line of research that applied Viatra to (non-physical) access control. Here is the main MODELS 2016 paper, and here is a workshop paper on making the computation live/incremental. There are new developments on incrementalizing these kinds of problems based on Differential Dataflow (an alternative technique for handling recursion), but they are not fully implemented or published yet.
2. As for complex incremental verification outside the domain of access control... we can implement static analysis of program code in Viatra, and use it to provide incremental feedback in an IDE! Here is the main paper at OOPSLA 2018. (The language frontend here is different from the usual VQL syntax, it is specifically geared for program verification, but it compiles to the same kind of Viatra queries.) Again, there are significant improvements in the works using Differential Dataflow; again, they are unfortunately not published yet.
3. I would really love to hear about what you are doing with Viatra and access control. :) Can you give me some pointers? Starting mid May, I will perhaps have enough time to read stuff again.
Cheers,
Gábor
|
|
|
Re: Matches not send to change listener [message #1826663 is a reply to message #1826383] |
Tue, 28 April 2020 13:16 |
Hans van der Laan Messages: 34 Registered: February 2020 |
Member |
|
|
Hello Gábor,
Thank you very much for these pointers! Interesting to see you've also been working on access control.
I'm currently working on efficient authorization constraint verification (e.g. prerequisite, cardinality and separation of duty constraints). I'm doing this research in the R&D department of Nedap. They make soft- and hardware for physical access control systems.
Most tools recheck all constraints whenever the authorization policy changes. This is not very efficient. Through reasoning about the changes I hope reduce the amount of recalculations required. This is especially necessary when reasoning about temporal role-based access control.
... And that's when I came across Viatra... :)
The physical aspect of the problem is that this domain introduces new constraints. For example, the implicit assumption is (almost) always made that whenever you have access to an object, you can invoke this access. This assumption does hold in physical access control. Having the permission to access a door does not mean you can actually reach this door. Thus we want to check that the user can always invoke all granted permissions. Another example constraint is that a user should never get "stuck" inside the building: at all times, the user should be able to reach the exit.
When you have the time to read again, I can recommend checking out [2] and [3]. I've found them very insightful.
[2] is an extensive overview paper. They show which methods and tools have been used for access control / network policy analyses and provide a good conceptual model on what actually is policy analysis and what kind of analyses one might want to perform.
When I started writing my research proposal, Nedap had a lot of ideas/wishes. This paper helped put all the disconnected ideas/wishes into one framework and also showed us new possibilities. I've found this paper so good that I actually shared this paper with the manager of the department, which in turn shared it with the business team.
[3] presents an ecore-based access control model which (mostly) subsumes many popular RBAC extensions. They also present an exhaustive list of constraints found in the literature, and show how they can be expressed in OCL.
Kind regards,
Hans
[1] https://www.nedapsecurity.com/
[2] Methods and Tools for Policy Analysis (https://dl.acm.org/doi/pdf/10.1145/3295749)
[3] A Comprehensive Modeling Framework for Role-based Access Control Policies (https://people.svv.lu/bianculli/pubs/bbb-jss2015.pdf)
[Updated on: Tue, 28 April 2020 13:19] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Wed Dec 11 23:24:18 GMT 2024
Powered by FUDForum. Page generated in 0.03501 seconds
|