How to model a bi-directional relationship and make it mandatory? - alloy

I'm developing a simple role-based authorization model, using https://profsandhu.com/journals/tissec/p207-ahn.pdf as an inspiration. The code so far is:
abstract sig Object {}
abstract sig Operation {}
sig User, Transaction extends Object {
by: some Permission
} {
by.on = this
}
one sig View, Update, Add, Delete extends Operation {}
sig Permission {
to: one Operation,
on: one Object
}
pred show {
#Permission > 0
}
run show
The first instance generated already shows two issues with my model:
When a permission has an "on" relationship to a user, the reverse relationship "by" must be there as well;
Two permissions on the same user can delete it, which doesn't make sense. There should be always zero or one permission for a particular operation on a user.
Any ideas on how to solve?

You can add these constraints as "facts":
fact {
all p: Permission, u: User | p.on = u implies p in u.by
all u: User | all disj p1,p2 : u.by | p1.to != p2.to
}
Now to verify the last fact, you might also want to check that two permission to the same operation are never owned by the same user:
assert sameOperationImpliesDifferentUser {
all disj p1, p2: Permission | p1.to = p2.to implies no (p1.on & p2.on & User)
}
check sameOperationImpliesDifferentUser

The first instance generated already shows two issues with my model:
When a permission has an "on" relationship to a user, the reverse relationship "by" must be there as well;
It is generally bad idea to have bidirectional links in Alloy since it is so easy to traverse in both directions. Models are significantly easier when you just make them in the most convenient direction. You can always use a function or macro to traverse them backwards. #wmeyer shows you correctly how to constrain the reverse link but your model gets a lot more complex and therefore harder to debug.
Two permissions on the same user can delete it, which doesn't make sense. There should be always zero or one permission for a particular operation on a user.
Why doesn't that make sense? These kind of constraints are hard to enforce and provide as far as I can see very little value. If you get roles in this model, I could see you could end up with multiple identical permissions for an Object. Constraining the model might then cause the model to have no solutions. Daniel Jackson also indicates that the best way to work is to minimize the constraints.
If you still want to enforce no duplicate permissions, I would introduce a Role object that holds the permissions.
I understand (I think) why you want a User to extend Object but it does make the model's solutions awkward to browse. A Role can also help here.
So my 2cts model would be:
abstract sig Object {}
enum Operation { View, Update, Add, Delete }
sig Transaction extends Object {}
sig User extends Object {
role : set Role
}
sig Role {
permit : Operation lone -> Object
}
With a solution:
┌─────────┬─────┐
│this/User│role │
├─────────┼─────┤
│User⁰ │Role²│
│ ├─────┤
│ │Role³│
├─────────┼─────┤
│User¹ │Role⁰│
│ ├─────┤
│ │Role¹│
│ ├─────┤
│ │Role³│
└─────────┴─────┘
┌─────────┬─────────────┐
│this/Role│permit │
├─────────┼───────┬─────┤
│Role⁰ │Delete⁰│User¹│
├─────────┼───────┼─────┤
│Role¹ │Update⁰│User⁰│
│ ├───────┼─────┤
│ │View⁰ │User¹│
├─────────┼────┬──┴─────┤
│Role² │Add⁰│User¹ │
├─────────┼────┴──┬─────┤
│Role³ │Add⁰ │User⁰│
│ ├───────┼─────┤
│ │Update⁰│User¹│
└─────────┴───────┴─────┘

Related

DDD Entity and EntityType reference

I'm learning DDD and here is a problem I faced. I have two Aggregates (simplified):
class NoteType : AggregateRoot {
int noteTypeId
string name
string fields[]
... code omitted ...
}
class Note : AggregateRoot {
int noteId
int noteTypeId
map<str, str> fieldValues
setFieldValue(fieldName, fieldValue) {
// I want to check that fieldName is present in Notes.fields
// and later fieldValues[field.name] = fieldValue
}
... code omitted ...
}
I've heard that aggregates should reference to each other by ID's only. It this case I can't access NoteType.fields. I found several ways to do so, but not sure which one is better:
Pass NoteType instance into the Note model via constructor (do not reference by ID)
Use repository in setFieldValue to load NoteType
Use service which will do the check (this may cause all the Note logic to be implemented in this service, since Note highly dependent on NoteType)
What do you suggest?
What do you suggest?
Pass the information that the aggregate needs to the aggregate when it needs it.
setFieldValue(fieldName, fieldValue, noteType) {
// Now you have the data that you need to verify the noteType.fields
}
Sometimes, if you can't tell from outside the aggregate what information you need, then you instead pass the capability to look up that information
setFieldValue(fieldName, fieldValue, notes) {
// Use the provided capability to get what you need
noteType = notes.get(this.noteTypeId)
// the do the useful work
this.setFieldValue(fieldName, fieldValue, noteType)
}
Of course, if the only thing you need is the fields, then you might prefer to work only with that property:
setFieldValue(fieldName, fieldValue, fields)
Design is what we do, when we want to get more of what we want than we'd get by just doing it. -- Ruth Malan
In Domain Driven Design, a common "what we want" is to have the "business logic", meaning our implementation of the policies of information change that are important to our business, separated from the "plumbing" that describes how to read and store that information.

Assign variable from hiera as username (with uid and gid) inside puppet class

Hello Community members,
We have a puppet file which has a main class like below:
class profile::Profname::application::classname {
$appname_homedir = hiera('appname::appname_homedir')
$appname_installdir = hiera('appname::appname_installdir')
$java_optional_args = "${java_keystore_args} ${java_proxy_args} ${java_timezone_args}"
..
..
$user = hiera('appname::appname_user')
$gid = hiera('appname::appname_user_gid')
$uid = hiera('appname::appname_user_uid')
exec { "Many blocks":
command => "commands",
..
}
exec { "Many blocks":
command => "commands",
..
}
# Install and configure app
class { 'app':
user => hiera('classname::appname_user'),
jvm_opts => $java_optional_args,
download_url => "s3://${s3_bucket}/${APPDIR}/appname",
dbserver => hiera('appname::db-endpoint'),
notify => Exec["Change appname gid and uid"],
require => [ Class['java'], Exec['Create Homedir'], Exec['Create Appdir']],
}
#other exec blocks
exec { "blocks"
..
..
}
}
Now I have two more variables in hiera those are: uid and gid for the appname_user.
How can I create the user "appname_user" in the inner class 'app'?
I was trying to refer https://puppet.com/docs/puppet/4.10/quick_start_user_group.html but not sure how can I do this inside the inner class. Any help would be greatly appreciated.
I did another exec block of changing the uid and gid for the user later when user is created but that way does not seem to be working for some files already present. Though puppet execution is successful. Hence I want to create the user with uid, and gid at the time of creation.
Thanks and Regards,
Saha
How can I create the user "appname_user" in the inner class 'app'?
My best guess is that you mean within this construct:
class { 'app':
user => hiera('classname::appname_user'),
jvm_opts => $java_optional_args,
download_url => "s3://${s3_bucket}/${APPDIR}/appname",
dbserver => hiera('appname::db-endpoint'),
notify => Exec["Change appname gid and uid"],
require => [ Class['java'], Exec['Create Homedir'], Exec['Create Appdir']],
}
The answer to that is simple: you can't. But there is a variety of related things you could do.
First things first: "inner class" is not a term used in Puppet. There can be nested classes, but
that's not what you have presented, and
nesting classes is widely regarded as poor style.
What you have shown is a declaration of class app inside the definition of class profile::Profname::application::classname. A class declaration, when evaluated, tells Puppet to include the designated class in the catalog then under construction, and it optionally binds values to some that class's parameters. There must be a definition of the class elsewhere to tell Puppet what that means. If you want it to declare a resource that it does not already declare, then it is the definition that must be modified.
You would typically manage a user by declaring a User resource (inside one class definition or another). In your case, you could find the definition of class app and put it there, but you could also put it in your profile class, alongside the existing declaration of class app. Which one would serve you best depends on what you're trying to accomplish.

Using captured types to type a class's attributes

I've followed the directions from the answers to the SO question
How can classes be made parametric in Perl 6?. However, I've hit some soft roadblock; I'm trying to type an internal class's attribute using the type capture and getting the following error:
Died with X::TypeCheck::Assignment
in submethod BUILDALL at ...
in method insert at ...
in block <unit> at ...
In the following example, I've typed the class BinaryNode's $.item attribute (with T) but doing so causes the above error:
class BinarySearchTree {
my role BTSImpl[::T] {
my class BinaryNode is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode.new(item => $x)
}
}
method ^parameterize(Mu:U \this, Mu \T) {
my $type := this.^mixin: BTSImpl[T];
$type.^set_name: this.^name ~ '[' ~ T.^name ~ ']';
$type
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
First off, there's almost no need to perform the class + ^parameterize + role trick. It appears in some of the internals because it helps deal with some bootstrapping problems (the kind of fun one has when defining a language in terms of itself). However, in normal Raku code, just write a parametric role instead of a class. From the point of view of the consumer, there's usually no difference; one can:
Call .new on it to make an instance (which actually creates a class, known as a "pun", behind the scenes and makes the instance of that)
In fact, call any method on the type object with the same result; new isn't special
Inherit from it (again, it works on the automatically produced class)
With the added bonus that somebody can also compose it instead of inheriting.
Secondly, there's no relationship between a class defined inside of a role and the enclosing role (this is a general principle: nesting of one package inside of another doesn't imply any relationship between them at an object model level). Thus we need to make that separately generic and instantiate it.
These two get us to:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[T].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
Which really should work, but the compiler seems to get the timing wrong on the BinaryNode[T]. We can work around that by just forcing it to delay the paramerterization until runtime; there's many ways we may do that, but writing BinaryNode[$(T)] compact and cheap (optimizes into pretty much no extra cost). Thus giving a working solution:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[$(T)].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);

How to add restrictions to fields of a signature when there are two instances in the model

I have the following Alloy model which describes a group of people. to simplify the problem. Here is a sample code snip.
sig groupofpeople {
member: set person,
country: Country
}{
#person=2
}
sig people {
teamleader: Bool,
position: String
}
So now we have two peoples in a group. Next I want to add some restrictions to the people in the group. For example, I want the two people in a group to always have one team leader and one team member. I use the following fact to do this:
fact {
all n: people , m: people - n {
n.teamleader not in m.teamleader
}
}
Now I encounter a problem which keep me from moving forward. The desired model I'm looking for is that if a group's country is "US", then the position of the teamleader is "US_TL" and position of the team member is "US_TM". If the country is "UK" then the position of teamleader is "UK_TL" and position of the team member is "UK_TM", and so on.
I tried to add something like:
all n: groupofpeople {
(n.country in US => (
n.member.position="US_TL" or
n.member.position= "US_TM")) or
(n.country in UK => (
n.member.position ="UK_TL" or
n.member.position = "UK_TM"))
}
But there are obviously something wrong with the prediction and the model can't generate correct solutions for me. Could you help me to identify the problem in my model?
The model you posted here doesn't compile, so I can't really pinpoint the problem (since there are many, so of which might be just typos). What seems to be incorrect for sure is the or between the two implications in the last all quantifiers: based on your description of the task, it should be and instead.
If I understood the desired properties of your model, here's how I would rewrite it (and if that's not what you intended to achieve, please clarify your question and post a model that is syntactically correct):
open util/boolean
abstract sig Country {}
one sig US extends Country {}
one sig UK extends Country {}
sig GroupOfPeople {
member: set Person,
country: one Country
}{
#member=2
}
sig Person {
teamleader: Bool,
position: String
}
fact {
all g: GroupOfPeople {
all n: g.member, m: g.member - n {
n.teamleader not in m.teamleader
}
}
}
run {
all n: GroupOfPeople {
(n.country in US => (
n.member.position="US_TL" or
n.member.position= "US_TM"))
(n.country in UK => (
n.member.position ="UK_TL" or
n.member.position = "UK_TM"))
}
} for 5
Would it not be nicer to replace the defn of sig Person above by
abstract sig Person{position : String}
sig Leader, Follower extends Person
fact one_leader {
all g : GroupOfPeople | one (g.member & Leader)
}
and even better to put this fact in the invariant of GroupOfPeople:
one (member & Leader)

EF 5.0 new object: assign foreign key property does not set the foreign key id, or add to the collection

EF 5.0, using code-first on existing database workflow.
Database has your basic SalesOrder and SalesOrderLine tables with required foreign key on the SalesOrderLine as follows;
public class SalesOrder
{
public SalesOrder()
{
this.SalesOrderLines = new List<SalesOrderLine>();
}
public int SalesOrderID { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<SalesOrderLine> SalesOrderLines { get; set; }
}
public class SalesOrderLine
{
public SalesOrderLine()
{
}
public int SalesOrderLineID { get; set; }
public int SalesOrderID { get; set; }
public virtual SalesOrder SalesOrder { get; set; }
}
public SalesOrderLineMap()
{
// Primary Key
this.HasKey(t => t.SalesOrderLineID);
// Table & Column Mappings
this.ToTable("SalesOrderLine");
this.Property(t => t.SalesOrderLineID).HasColumnName("SalesOrderLineID");
this.Property(t => t.SalesOrderID).HasColumnName("SalesOrderID");
// Relationships
this.HasRequired(t => t.SalesOrder)
.WithMany(t => t.SalesOrderLines)
.HasForeignKey(d => d.SalesOrderID);
}
Now according to this page:
http://msdn.microsoft.com/en-us/data/jj713564
...we are told that:
The following code removes a relationship by setting the foreign key
to null. Note, that the foreign key property must be nullable.
course.DepartmentID = null;
Note: If the reference is in the added state (in this example, the
course object), the reference navigation property will not be
synchronized with the key values of a new object until SaveChanges is
called. Synchronization does not occur because the object context does
not contain permanent keys for added objects until they are saved. If
you must have new objects fully synchronized as soon as you set the
relationship, use one of the following methods.
By assigning a new object to a navigation property. The following code
creates a relationship between a course and a department. If the
objects are attached to the context, the course is also added to the
department.Courses collection, and the corresponding foreign key
property on the course object is set to the key property value of the
department.
course.Department = department;
...sounds good to me!
Now my problem:
I have the following code, and yet both of the the Asserts fail - why?
using (MyContext db = new MyContext ())
{
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
sol.SalesOrder = so;
Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));
}
Both objects are attached to the context - are they not? Do I need to do a SaveChanges() before this will work? If so, that seems a little goofy and it's rather annoying that I need to set all of the references on the objects by hand when a new object is added to a foreign-key collection.
-- UPDATE --
I should mark Gert's answer as correct, but I'm not very happy about it, so I'll wait a day or two. ...and here's why:
The following code does not work either:
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
db.SalesOrderLines.Add(sol);
sol.SalesOrder = so;
Trace.Assert(so.SalesOrderLines.Contains(sol));
The only code that does work is this:
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);
Trace.Assert(so.SalesOrderLines.Contains(sol));
...in other words, you have to set all of your foreign key relationships first, and then call TYPE.Add(newObjectOfTYPE)
before any of the relationships and foreign-key fields are wired up. This means that from the time the Create is done until the time you do the Add(), the object is basically in a half-baked state. I had (mistakenly) thought that since I used Create(), and since Create() returns a sub-classed dynamic object (as opposed to using "new" which returns a POCO object) that the relationships wire-ups would be handled for me. It's also odd to me, that you can call Add() on an object created with the new operator and it will work, even though the object is not a sub-classed type...
In other words, this will work:
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = new SalesOrderLine();
sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);
Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));
...I mean, that's cool and all, but it makes me wonder; what's the point of using "Create()" instead of new, if you're always going to have to Add() the object in either case if you want it properly attached?
Most annoying to me is that the following fails;
SalesOrder so = db.SalesOrders.OrderBy(p => p.SalesOrderID).First();
SalesOrderLine sol = db.SalesOrderLines.Create();
sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);
// NOTE: at this point in time, the SalesOrderId field has indeed been set to the SalesOrderId of the SalesOrder, and the Asserts will pass...
Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));
sol.SalesOrder = db.SalesOrders.OrderBy(p => p.SalesOrderID).Skip(5).First();
// NOTE: at this point in time, the SalesOrderId field is ***STILL*** set to the SalesOrderId of the original SO, so the relationships are not being maintained!
// The Exception will be thrown!
if (so.SalesOrderID == sol.SalesOrderID)
throw new Exception("salesorderid not changed");
...that seems like total crap to me, and makes me feel like the EntityFramework, even in version 5, is like a minefield on a rice-paper bridge. Why would the above code not be able to sync the SalesOrderId on the second assignment of the SalesOrder property? What essential trick am I missing here?
I've found what I was looking for! (and learned quite a bit along the way)
What I thought the EF was generating in it's dynamic proxies were "Change-Tracking Proxies". These proxy classes behave more like the old EntityObject derived partial classes from the ADO.Net Entity Data Model.
By doing some reflection on the dynamically generated proxy classes (thanks to the information i found in this post: http://davedewinter.com/2010/04/08/viewing-generated-proxy-code-in-the-entity-framework/ ), I saw that the "get" of my relationship properties was being overridden to do Lazy Loading, but the "set" was not being overriden at all, so of course nothing was happening until DetectChanges was called, and DetectChanges was using the "compare to snapshot" method of detecting changes.
Further digging ultimately lead me to this pair of very informative posts, and I recommend them for anyone using EF:
http://blog.oneunicorn.com/2011/12/05/entity-types-supported-by-the-entity-framework/
http://blog.oneunicorn.com/2011/12/05/should-you-use-entity-framework-change-tracking-proxies/
Unfortunately, in order for EF to generate Change-Tracking Proxies, the following must occur (quoted from the above):
The rules that your classes must follow to enable change-tracking
proxies are quite strict and restrictive. This limits how you can
define your entities and prevents the use of things like private
properties or even private setters. The rules are: The class must be
public and not sealed. All properties must have public/protected
virtual getters and setters. Collection navigation properties must be
declared as ICollection<T>. They cannot be IList<T>, List<T>,
HashSet<T>, and so on.
Because the rules are so restrictive it’s easy to get something wrong and the result is you won’t get a change-tracking proxy. For example,
missing a virtual, or making a setter internal.
...he goes on to mention other things about Change-Tracking proxies and why they may show better or worse performance.
In my opinion, the change-tracking proxy classes would be nice as I'm coming from the ADO.Net Entity Model world, and I'm used to things working that way, but I've also got some rather rich classes and I'm not sure if I will be able to meet all of the criteria. Additionally that second bullet point makes me rather nervous (although I suppose I could just create a unit test that loops through all of my entities, does a Create(0 on each and then tests the resulting object for the IEntityWithChangeTracker interface).
By setting all of my properties to virtual in my original example I did indeed get IEntityWithChangeTracker typed proxy classes, but I felt a little ... I don't know... "dirty" ...for using them, so I think I will just have to suck it up and remember to always set both sides of my relationships when doing assignments.
Anyway, thanks for the help!
Cheers,
Chris
No, SalesOrderLine sol is not attached to the context (although it is created by a DbSet). You must do
db.SalesOrderLines.Add(sol);
to have it attached to the context in a way that the ChangeTracker executes DetectChanges() (DbSet.Add() is one of the methods that trigger this) and, thus, also executes relationship fixup, which sets sol.SalesOrderID and ensures that so.SalesOrderLines contains the new object.
So, no, you don't need to execute SaveChanges(), but the object must be added to the context and relationship fixup must have been triggered.

Resources