stateless4j parameterized StateMachineConfig - state-machine

I would like to use StateMachineConfig in https://github.com/stateless4j/stateless4j to configure various transitions of states based on events received from kafka. However in order to evaluate the conditions in either .permitIfElseIgnore (FuncBoolean guard) or .permitDynamic (Func interface), I would need to take the state of the objects into account, since we are unable to rely exclusively on the event type itself. Can this be accomplished with the stateless4j lib? Somehow define functions to the configuration and have the parameters evaluated at runtime in order to determine the correct transition?

Related

How can I implement it using DiffSuppressFunc()?

Context: I'm developing a TF Provider.
There's an attribute foo of type string in one of my resources. Different representations of values of foo can map to the same normalized version but only backend can return a normalized version of value of foo.
When implementing the resources, I was thinking I could store any user value for foo (i.e., it's not necessarily normalized). And then I could leverage DiffSuppressFunc to detect any potential differences. For example, main.tf stores any user input (by definition), TF state could store either normalized version return from a backend or user input version (don't matter a lot). And then, the biggest challenge is to differentiate between structural update (requires an update) and syntactic update (doesn't require update since it can be converted to the same normalized version).
In order to implement this I could use
"foo": {
...
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// Option #1
normalizedOld := network.GetNormalized(old)
normalizedNew := network.GetNormalized(new)
return normalizedOld == normalizedNew
// Option #2
// Backend also supports a check whether such a value exists already
// and returns such a object
if obj, ok := network.Exists(new); ok { return obj.Id == d.GetObjId(); }
}
}
However it seems like I can't send network requests in DiffSuppressFunc since it doesn't accept meta interface{} from:
func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
So I can't access my specific http client (even though I could send some generic network request).
Is there a smart way to avoid this limitation to pass meta interface{} to DiffSuppressFunc:
// The interface{} parameter is the result of the Provider type
// ConfigureFunc field execution. If the Provider does not define
// a ConfigureFunc, this will be nil. This parameter is conventionally
// used to store API clients and other provider instance specific data.
//
// The diagnostics return parameter, if not nil, can contain any
// combination and multiple of warning and/or error diagnostics.
ReadContext ReadContextFunc
The intention for DiffSuppressFunc is that it be only syntactic normalization that doesn't rely on information from outside of the provider. A DiffSuppressFunc should not typically interact with anything outside of the provider because the SDK can call it at various steps and expects it to return a consistent result each time, rather than varying based on the state of the remote system.
If you need to rely on information from the remote system then you'll need to implement the logic you're discussing in the CustomizeDiff function instead. That function is the lowest level of abstraction for diff customization in the SDK but in return for the low level of abstraction it also allows more flexibility than the higher-level built-in behaviors in the SDK.
In the CustomizeDiff function you will have access to meta and so you can make API requests if you need to.
Inside your CustomizeDiff function you can use d.GetChange to obtain both the previous value and the new value from the configuration to use in the same way as the old and new arguments to DiffSuppressFunc.
You can then use d.SetNew to change the planned value for a particular attribute based on what you learned. To approximate what DiffSuppressFunc would do you would call d.SetNew with the value from the prior state -- the "old" value.
When implementing CustomizeDiff you must respect the consistency rules that apply to all Terraform providers, which include:
When planning initial creation of an object, if the module author provided a specific value in the configuration then you must preserve exactly that value, without normalization.
When planning an update to an existing object, if the module author has provided a specific value in the configuration then you must return either the exact value they wrote without normalization or return exactly the value from the prior state to indicate that the new configuration value is functionally equivalent to the previous value.
When implementing Read there is also a similar consistency rule:
If the value you read from the remote system is not equal to what was in the prior state but the new value is functionally equivalent to the prior state then you must return the value from the prior state to preserve the way the author originally wrote it, rather than the way the remote system normalized it.
All of these rules exist to help ensure that a particular Terraform configuration can converge, which is to say that after running terraform apply it should be possible to immediately run terraform plan and see it report "No changes". If you don't stick to these rules then Terraform may return an explicit error (for problems it's able to detect) or it may just behave strangely due to the provider producing confusing information that doesn't match the assumptions of the protocol.

Activity Diagram: Reusing Activity/Action With different inherited type of object flow as output

I have a question regarding modeling on an Activity Diagram that has been bothering me for some time and I was not able to find any answers / Convention anywhere.
Here is an example to better understand my question:
Let say that I have two class named "flat" and "house". both are a generalization of the class "housing".
housing contain an attribute "residents" for the person living in it.
flat contain an attributes "floor" that says at which floor the flat is.
Here is the class diagram:
In an activity diagram, I want to represent the action of giving persons a housing.
this action can take either house or flat as input (so the use of "housing" type for the input pin is correct I think) as well as an undefined number of people.
I want this action to give an updated house or flat as output (not an updated housing as this would mean that information specific to the house or flat would be lost.
I don't really know if I must create two actions (one for house and another for flats) or if there is a way to reuse the action for both class and have a correct output out of it.
Here is the activity Diagram:
My question is: how to represent in an activity diagram, an action that is the same for different type of Object flows as input, and that give the updated Object flow as output (that may be therefore of different type)?
nb:
all type of object flow are class and inherit from a same other class.
I'm representing this in modelio but first had this issue in Cameo.
I'm Trying to fit as best as I can within the rules of UML Language.
Cameo is right in rejecting this model. Give Flat Floor expects a Flat and will not work with a House, but Assign Resident to Housing could return a House. I know, in your context it can only return a Flat, but how should the tool know that?
The correct way to capture this fact would be to add a postcondition to Activity Assign Resident to Housing that states that the type of the input and output pin will be the same.
However, it would be really hard to define a complete set of compatibilty rules that takes into account all the global and local pre- and postconditions and the tools would also be hard pressed to validate a model according to these rules. Therefore the UML specification choose the easy road and simply doesn't allow to connect the pins.
The solution is to use the transformation property of the ObjectFlow. Just assign an OpaqueBehavior that casts the Type House to the Type Flat. Cameo will then accept the model. It is the modelers responsibility to ensure, that this cast will always work, since no exception handling can be defined here. Maybe this should be documented with a local postcondition.
In your specific example there is an even easier solution: simply fork the ObjectFlow of Type Flat and omit the OutputPin of Assign Resident to Housing.
As a side note: Due to a bug in Cameo, you can change the type of the OutputPin to a more specific Type than that of the ActivityParameter. This is correct for InputPins, but should be the opposite for OutputPins. You could use this to let the Parameter be of type House, but the OutputPin-Type would be Flat.
The two flows (top object and lower control) in the blue frame could stay as they are. Give flat floor would commence only when it receives a Flat object and the control token is sent. In order to make the right action sort of optional I would just use the object flow, thus only triggering when a Flat object is passed. That would just be enough and no additional control flow is needed.
To make things clear I would also add a guarded flow from the Assign action to an exit reading [ house was assigned ] or the like.

Choco 4: calling a method whenever a Boolean variable gets assigned or unassigned

I have a technical question regarding the Choco 4 CP solver.
I would like to call a method (lets call it f()) whenever some Boolean variables in my model are assigned or unassigned during search. The purpose of f() is to update a data structure which is used extensively by propagators.
My first attempt was to implement a custom IVariableMonitor but the method onUpdate(Variable v, IEventType iEventType) is invoked only when a variable gets assigned to 0/1 but not unassigned.
I also tried to use search monitors but no success for now.
Is there a way to perform this task?
Thanks!
I have figured out how to solve this issue.
What I actually needed is a data structure that supports an automatic undo operation. That is, modified when a variable is assigned and reverted automatically if the corresponding variable that triggered the modification gets unassigned.
Luckily, choco provides such backtrackable data structures (see org.chocosolver.util.objects).
As far as I understand, the state of a backtrackable data structure is associated with a decision level. When the solver backtracks any modification above the current decision level is reverted.

How does lazy-evaluation allow for greater modularization?

In his article "Why Functional Programming Matters," John Hughes argues that "Lazy evaluation is perhaps the most powerful tool for modularization in the functional programmer's repertoire." To do so, he provides an example like this:
Suppose you have two functions, "infiniteLoop" and "terminationCondition." You can do the following:
terminationCondition(infiniteLoop input)
Lazy evaluation, in Hughes' words "allows termination conditions to be separated from loop bodies." This is definitely true, since "terminationCondition" using lazy evaluation here means this condition can be defined outside the loop -- infiniteLoop will stop executing when terminationCondition stops asking for data.
But couldn't higher-order functions achieve the same thing as follows?
infiniteLoop(input, terminationCondition)
How does lazy evaluation provide modularization here that's not provided by higher-order functions?
Yes you could use a passed in termination check, but for that to work the author of infiniteLoop would have had to forsee the possibility of wanting to terminate the loop with that sort of condition, and hardwire a call to the termination condition into their function.
And even if the specific condition can be passed in as a function, the "shape" of it is predetermined by the author of infiniteLoop. What if they give me a termination condition "slot" that is called on each element, but I need access to the last several elements to check some sort of convergence condition? Maybe for a simple sequence generator you could come up with "the most general possible" termination condition type, but it's not obvious how to do so and remain efficient and easy to use. Do I repeatedly pass the entire sequence so far into the termination condition, in case that's what it's checking? Do I force my callers to wrap their simple termination conditions up in a more complicated package so they fit the most general condition type?
The callers certainly have to know exactly how the termination condition is called in order to supply a correct condition. That could be quite a bit of dependence on this specific implementation. If they switch to a different implementation of infiniteLoop written by another third party, how likely is it that exactly the same design for the termination condition would be used? With a lazy infiniteLoop, I can drop in any implementation that is supposed to produce the same sequence.
And what if infiniteLoop isn't a simple sequence generator, but actually generates a more complex infinite data structure, like a tree? If all the branches of the tree are independently recursively generated (think of a move tree for a game like chess) it could make sense to cut different branches at different depths, based on all sorts of conditions on the information generated thus far.
If the original author didn't prepare (either specifically for my use case or for a sufficiently general class of use cases), I'm out of luck. The author of the lazy infiniteLoop can just write it the natural way, and let each individual caller lazily explore what they want; neither has to know much about the other at all.
Furthermore, what if the decision to stop lazily exploring the infinite output is actually interleaved with (and dependent on) the computation the caller is doing with that output? Think of the chess move tree again; how far I want to explore one branch of the tree could easily depend on my evaluation of the best option I've found in other branches of the tree. So either I do my traversal and calculation twice (once in the termination condition to return a flag telling infinteLoop to stop, and then once again with the finite output so I can actually have my result), or the author of infiniteLoop had to prepare for not just a termination condition, but a complicated function that also gets to return output (so that I can push my entire computation inside the "termination condition").
Taken to extremes, I could explore the output and calculate some results, display them to a user and get input, and then continue exploring the data structure (without recalling infiniteLoop based on the user's input). The original author of the lazy infiniteLoop need have no idea that I would ever think of doing such a thing, and it will still work. If we've got purity enforced by the type system, then that would be impossible with the passed-in termination condition approach unless the whole infiniteLoop was allowed to have side effects if the termination condition needs to (say by giving the whole thing a monadic interface).
In short, to allow the same flexibility you'd get with lazy evaluation by using a strict infiniteLoop that takes higher order functions to control it can be a large amount of extra complexity for both the author of infiniteLoop and its caller (unless a variety of simpler wrappers are exposed, and one of them matches the caller's use case). Lazy evaluation can allow producers and consumers to be almost completely decoupled, while still giving the consumer the ability to control how much output the producer generates. Everything you can do that way you can do with extra function arguments as you say, but it requires to the producer and consumer to essentially agree on a protocol for how the control functions work; and that protocol is almost always either specialised to the use case at hand (tying the consumer and producer together) or so complicated in order to be fully-general that the producer and consumer are up tied to that protocol, which is unlikely to be recreated elsewhere, and so they're still tied together.

How define external function call within a guard of state machine in EA

As a follow up topic of this question , I would like to use a external function call of a class ( bool MyClas:: myFunc()) in order to evaluate a guard in EA. Is it possible to do this? This topic showed me how to assign external actions and function calls to the Effect field. I would also like to do it for the Guard field
The reason behind is that I want to separate the logic regarding the state machine (" go from state A to state B ") from the logic regarding the transitions ( here I want to write manual code for each guard implementation).
You can not evaluate a method's return value as guard. You can only set the behavior of a transition to some method since the guard itself is plain text:
You could use some naming convention, though.
Also you can consider using a trigger like this:
Still, this is not a result from a function.

Resources