Exiting from the middle of a drools rule - return

In java method we can return from the middle skipping the rest of the method code being executed. e.g.
public String doSomething(){
step 1
step 2
if(some condition){
return "Exited from the middle";
}
step 4
return "Whole code is executed"
}
Is there a way to do such things in a drools rule?

It's quite simple:
return;
Since there's no place of invocation for a single rule you can control, or write code doing that, a return with an expression is not vailable. You can collect values you'd like to return in a global variable, List<String> or, perhaps, Map<String,List<String>> with rule names acting as keys.
Clarification
A rule's right hand side results in a static method with void as result type. A return statement just acts naturally.

Related

Pass multiple types as parameter in filter function of Iterable object in Xtend

I am using the DSL generator interface of Xtext in order to generate some models based on my Xtext DSL. This is working fine, but right now I am facing a bit of a problem in writing the generator. I am using the generator to filter out Rules declared in my Xtext DSL. I do this by selecting certain Rules and then convert them in an Iterable object, which I can then use to filter on certain types (see the toIterable.filter() parts in my code below). The code below contains one for loop which itself again contains 3 nested for loops. These nested loops all filter on one specific kind of Method Statement (types that I declared in my DSL). I would like to combine these 3 for loops in one for loop by passing the 3 types as parameters in the filter() method. In this case there would be one nested for loop where the condition would ideally look something like:
for (eachMethodStatement : ifStatement.expression.eAllContents.toIterable.filter(StatementSort1, StatementSort2, StatementSort3)
The problem is that the filter() method only takes one argument (one type), so right now I have to write three dispatch methods called getDemand which all basically do the same. It works right now, but this forces me to write a lot of boilerplate code for each type that I want to filter.
Is there a way to filter multiple types (in one for loop) without creating a lot of boilerplate code?
for (ifStatement : ifElseStatement.eAllContents.toIterable.filter(IfStatements)){
for (persistenceFunction : ifStatement.expression.eAllContents.toIterable.filter(SingleLibraryPersistenceMethodStatement)) {
expressionDemand += getDemand(persistenceFunction,resourceTable)
}
for (interfaceFunction : ifStatement.expression.eAllContents.toIterable.filter(SingleLibraryInterFaceMethodStatement)) {
expressionDemand += getDemand(interfaceFunction,resourceTable)
}
for (businessFunction : ifStatement.expression.eAllContents.toIterable.filter(SingleLibraryBusinessMethodStatement)) {
expressionDemand += getDemand(businessFunction,resourceTable)
}
for (persistenceFunction : ifStatement.expression.eAllContents.toIterable.filter(RelationalOperator)) {
expressionDemand += getDemand(persistenceFunction,resourceTable)
}
}
<T> T filter(Class<T>) cannot do multiple types because then the return type could not be T but - in the extreme case Object which must be cast later.
But: If your four types (SingleLibraryPersistenceMethodStatement, SingleLibraryInterFaceMethodStatement, SingleLibraryBusinessMethodStatement, RelationalOperator) share a specific interface or supertype you can used that with the existing filter() method:
for (ifStatement : ifElseStatement.eAllContents.toIterable.filter(IfStatements)){
for (statement : ifStatement.expression.eAllContents.toIterable.filter(Statement)) {
expressionDemand += getDemand(statement,resourceTable)
}
}
def Demand getDemand(Statement statement, ResourceTable resourceTable){
...
}
Another solution is to avoid filter in this case and use switch with type guards like this:
for (ifStatement : ifElseStatement.eAllContents.toIterable.filter(IfStatements)){
for (it : ifStatement.expression.eAllContents) {
switch(it){
SingleLibraryPersistenceMethodStatement,
SingleLibraryPersistenceMethodStatement,
SingleLibraryBusinessMethodStatement:
expressionDemand += getDemand(it,resourceTable)
}
}
}

How to I make a "select case"-like operation in reactor

I am making a discord bot that needs to read a list of arguments, and with the first argument given, have it determine which branch to run.
Something kinda like this.
Mono.just(stringList)
.ifSelectmap(conditional1, branch1)
.ifSelectmap(conditional2, branch2)
.ifSelectmap(conditional3, branch3)
// non branch logic here
The only way I can figure out to do anything like this would just cause several deeply nested switchIfEmpty statements. Which would be hard to manage.
if the conditional logic doesn't involve latency-heavy operations (ie performing IO), then there is nothing wrong in passing a more fleshed out Function to map/flatMap.
I'm going to assume your "branches" are actually asynchronous operations represented as a Mono<R> or Flux<R> (that is, all the branches share the same return type R), so we're talking flatMap:
Flux<V> source; //...
Flux<R> result = source.flatMap(v -> {
if (conditional1) return branch1(v);
if (conditional2) return branch2(v);
if (conditional3) return branch3(v);
return Mono.empty(); //no conditional match == ignore
//you might want a default processing instead for the above
};

RxJava2 order of sequence called with compleatable andThen operator

I am trying to migrate from RxJava1 to RxJava2. I am replacing all code parts where I previously had Observable<Void> to Compleatable. However I ran into one problem with order of stream calls. When I previously was dealing with Observables and using maps and flatMaps the code worked 'as expected'. However the andthen() operator seems to work a little bit differently. Here is a sample code to simplify the problem itself.
public Single<String> getString() {
Log.d("Starting flow..")
return getCompletable().andThen(getSingle());
}
public Completable getCompletable() {
Log.d("calling getCompletable");
return Completable.create(e -> {
Log.d("doing actuall completable work");
e.onComplete();
}
);
}
public Single<String> getSingle() {
Log.d("calling getSingle");
if(conditionBasedOnActualCompletableWork) {
return getSingleA();
}else{
return getSingleB();
}
}
What I see in the logs in the end is :
1-> Log.d("Starting flow..")
2-> Log.d("calling getCompletable");
3-> Log.d("calling getSingle");
4-> Log.d("doing actuall completable work");
And as you can probably figure out I would expect line 4 to be called before line 3 (afterwards the name of andthen() operator suggest that the code would be called 'after' Completable finishes it's job). Previously I was creating the Observable<Void> using the Async.toAsync() operator and the method which is now called getSingle was in flatMap stream - it worked like I expected it to, so Log 4 would appear before 3. Now I tried changing the way the Compleatable is created - like using fromAction or fromCallable but it behaves the same. I also couldn't find any other operator to replace andthen(). To underline - the method must be a Completable since it doesn't have any thing meaning full to return - it changes the app preferences and other settings (and is used like that globally mostly working 'as expected') and those changes are needed later in the stream. I also tried to wrap getSingle() method to somehow create a Single and move the if statement inside the create block but I don't know how to use getSingleA/B() methods inside there. And I need to use them as they have their complexity of their own and it doesn't make sense to duplicate the code. Any one have any idea how to modify this in RxJava2 so it behaves the same? There are multiple places where I rely on a Compleatable job to finish before moving forward with the stream (like refreshing session token, updating db, preferences etc. - no problem in RxJava1 using flatMap).
You can use defer:
getCompletable().andThen(Single.defer(() -> getSingle()))
That way, you don't execute the contents of getSingle() immediately but only when the Completablecompletes and andThen switches to the Single.

closure verification override default mocking

I have a method looks like this:
public void save(DbSession session,Wrappe wrapper,Wrappe wrappe){
//...other logic
//save wrapper
wrapper=(Wrapper)session.save(wrapper)
//set wrapper's id into wrappee
wrappee.setWrapperId(wrapper.getId());
//save wrappee
session.save(wrappee);
}
and test code looks like this:
given:
session.save(_) >> wrapperWithGeneratedId
when:
obj.save(session,wrapper,wrappee)
then:"wrapper got saved"
1*session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
}
and:"wrappee"
1*session.save(_) >> {Wrappe saved ->
diffs(wrappee,saved)==null
}
These test code will give an exception:
java.lang.ClassCastException: java.lang.Boolean cannot be cast to com.company.model.Wrapper
If commented verification closure in "then" section,test will pass,so I guess this section
1*session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
}
overrode this mocking:
session.save(_) >> wrapperWithGeneratedId
Is any way do both correctly?
1st. 'and' is syntactic sugar. It's just a way to visually separate code within the same block. Your last two mocks are effectively the same (although since you're testing behaviorally it will still verify that save is called twice.)
2nd. Assuming you want to verify thatdiffs(wrapper,saved)==null, that won't currently happen because it's not a 'base level' evaluation. Anything within then/where/closures/etc needs to be prepended with 'assert ' if you want to evaluate it.
3rd. A then block is scoped to its when block and can override existing mocks; your assumption that your mock was being overwritten is correct.
4th. Is there any reason you don't just include your return value alongside your evaluation?
2 * session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
return wrapperWithGeneratedId
}
5th. Your error is due to your mock returning a boolean (your assertion logic) which Groovy then tries (and fails) to parse into a Wrapper. My assumption for why this is happening is that .save() has a return type of Wrapper. To fix that you will either need to create a boolean constructor for Wrapper, or change your mock to return something Groovy can turn into a Wrapper (how-to in point 4)
Official Stub/Mock/Spy documentation (quite good, worth a read)

grails withTransaction - why is it on a domain object?

We need to be able to rollback a complex transaction in a service, without throwing an exception to the caller. My understanding is that the only way to achieve this is to use withTransaction.
The question is:
why do I have to call this on a domain object, such as Books.withTransaction
What if there is no relevant domain object, what is the consequence of picking a random one?
Below is more or less what I am trying to do. The use case is for withdrawing from an account and putting it onto a credit card. If the transfer fails, we want to rollback the transaction, but not the payment record log, which must be committed in a separate transaction (using RequiresNew). In any case, the service method must return a complex object, not an exception.
someService.groovy
Class SomeService {
#NotTransactional
SomeComplexObject someMethod() {
SomeDomainObject.withTransaction{ status ->
DomainObject ob1 = new DomainObject.save()
LogDomainObject ob2 = insertAndCommitLogInNewTransaction()
SomeComplexObject ob3 = someAction()
if (!ob3.worked) {
status.setRollbackOnly() // only rollback ob1, not ob2!
}
return ob3
}
}
}
The above is flawed - I assume "return ob3" wont return ob3 from the method, as its in a closure. Not sure how to communicate from inside a closure to outside it.
To your primary question: you can pick a random domain object if you want, it won't do any harm. Or, if you prefer, you can find the current session and open a transaction on that instead:
grailsApplication.sessionFactory.currentSession.withTransaction { /* Do the things */ }
Stylistically I don't have a preference here. Others might.
Not sure how to communicate from inside a closure to outside it.
In general this could be hard; withTransaction could in principle return anything it wants, no matter what its closure argument returns. But it turns out that withTransaction returns the value returned by its closure. Here, watch:
groovy> println(MyDomainObject.withTransaction { 2 + 2 })
4
By convention, all withFoo methods which take a closure should work this way, precisely so that you can do the thing you're trying to do.
I'm assuming this question was from a grails 2 application and this problem from 2015 has been fixed before now.
I can't find this in any of the grails 2 documentation, but services have a magic transactionStatus variable injected into their methods. (at least in grails 2.3.11)
You can just leave all the annotations off and use that injected variable.
Class SomeService {
SomeComplexObject someMethod() {
DomainObject ob1 = new DomainObject.save()
LogDomainObject ob2 = insertAndCommitLogInNewTransaction()
SomeComplexObject ob3 = someAction()
if (!ob3.worked) {
transactionStatus.setRollbackOnly() // transactionStatus is magically injected.
}
return ob3
}
}
This feature is in grails 2, but not documented. It is documented in grails 3.
https://docs.grails.org/latest/guide/services.html#declarativeTransactions
search for transactionStatus.

Resources