F.Promise<Result> and nested async promises - java

I am using F.Promise in my async action in Playframework 2.4.6. I am able to get async calls to my DAO to work. I am able to use "map" and "flatMap" but I am not sure about the following situation.
I have an async call to find and object from the database. If that object is found, I then want to use parts of that object to then issue another async request to update that object in the database. This is part of an async update call in my controller. I am not doing something right though.
I am starting off with the following.
F.Promise<User> findUserPromise = userService.findAsync(id);
F.Promise<User> updateUserPromise = userService.updateAsync(updatedUser);
F.Promise<Result> resultPromise = findUserPromise.flatMap((foundUser){
// update foundUser with passed in Json criteria
foundUser.firstName = firstName; // etc...
return updateUserPromise.map((updatedUser) -> {
return ok(Json.toJson(u));
});
});
return resultPromise;
This doesn't seem to work. I do not want to define my updatedUserPromise until I get a response back from my findUserPromise, because maybe a user will not be found. If a user is not found, I will return F.Promise.pure(notFound("some json result")). If a user is found, then I want to update that user with the Json criteria that gets posted to my controller action. With my approach, it seems that I have to define the updateUserPromise's async call with an object (updatedUser) before I get back any results.
Can I define another promise inside the result of a promise?
I was thinking something like this, but this fails with compilation errors. inference variable B has incompatible bounds, equality constraints: play.mvc.Result, lower bounds: Play.libs.F.Promise.
F.Promise<User> findUserPromise = userService.findAsync(id);
F.Promise<Result> resultPromise = findUserPromise.map((foundUser) -> {
// foundUser is returned, now update it, or return not found...
// define our next promise with an updated foundUser object
F.Promise<User> userPromise = userService.updateAsync(foundUser);
F.Promise<Result> resultPromise2 = userPromise.map((u) -> {
return jsonResult(ok(Json.toJson(u)));
});
return resultPromise2;
});
return resultPromise;
Thanks for any help.

I am not sure if this is best way to do this, but this is working for my situation above.
F.Promise<User> findUserPromise = userService.findAsync(id);
return findUserPromise.flatMap((fu) -> {
if (fu == null) {
ObjectNode result = Json.newObject();
result.put("error", "Not found " + id);
return F.Promise.pure(jsonResult(notFound(result)));
}
// dynamically update fields on found user
fu.userName = userName;
fu.firstName = firstName;
// more updates...
// make a new promise that will use the updated foundUser object
F.Promise<User> updateUserPromise = userService.updateAsync(fu);
return updateUserPromise.map((uu) -> {
return jsonResult(ok(Json.toJson(uu)));
});
}
All the examples I found for chaining promises or nested promises, they seem to use web services as an example, and they all appear to be known at design time. In my situation, I do not know what my foundUser object will be until it is returned, so I need to create my inner promise inside the outer promise.

Related

Java how to Uni.createFrom().future() and return that Uni from the enclosing method?

I am very new to Java and Mutiny.
As indicated below, my test function asks Redis for the value of key "foo" which is "bar". That is working and the Future onCompleted() gets "bar".
So far so good.
I have two issues with the Uni.createFrom().future() bit.
The compiler says: The method future(Future<? extends T>) in the type UniCreate is not applicable for the arguments (Future<Response>). I have tried the suggested fixes but ended up in a deeper hole. My Java skills are insufficient to fully grasp the meaning of the error.
How do I get "bar" into the Uni<String> returned from test()? I have tried all sorts of subscribing and CompletableFutures and cannot make anything work. I figure I need to return a function to generate the Uni but am at a loss about how to do that.
// The abbreviated setup
import io.vertx.redis.client.Redis;
private final Redis redisClient;
this.redisClient = Redis.createClient(vertx);
public Uni<String> test () {
// Ask Redis for the value of key "foo" => "bar"
Future<Response> futureResponse = this.redisClient.send(Request.cmd(Command.create("JSON.GET")).arg("foo"))
.compose(response -> {
// response == 'bar'
return Future.succeededFuture(response);
}).onComplete(res -> {
// res == 'bar'
});
// How to make the return of the Uni<String> wait for the completed futureResponse
// so it makes a Uni<String> from "bar" and returns it from the method?
Uni<String> respUni = Uni.createFrom().future(futureResponse);
return respUni;
}
Thanks. Any suggestions gratefully accepted! (And yes, I have spent many hours trying to work it out for myself) ;-)
Updated the post, because of errors.
UniCreate.future() takes a java.util.concurrent.Future of some type and returns Uni of the same type. That is, you'll have to pass a java.util.concurrent.Future<String> to get a Uni<String>.
The send method of the Redis client returns a io.vertx.core.Future<Response> which is not assignment compatible to java.util.concurrent.Future.
Fortunately, the API provides io.vertx.core.Future#toCompletionStage to convert a vertx Future to a JDK CompletionStage while Mutiny provides UniCreate.completionStage() to get the job done.
public Uni<String> test () {
Future<String> futureResponse = this.redisClient.send(Request.cmd(Command.create("JSON.GET")).arg("foo"))
.compose(response -> {
return Future.succeededFuture(response.toString());
});
Uni<String> respUni = Uni.createFrom().completionStage(futureResponse.toCompletionStage());
return respUni;
}

Java Reactive stream how to map an object when the object being mapped is also needed on the next step of the stream

I am using Java 11 and project Reactor (from Spring). I need to make a http call to a rest api (I can only make it once in the whole flow).
With the response I need to compute two things:
Check if a document exists in the database (mongodb). If it does not exists then create it and return it. Otherwise just return it.
Compute some logic on the response and we are done.
In pseudo code it is something like this:
public void computeData(String id) {
httpClient.getData(id) // Returns a Mono<Data>
.flatMap(data -> getDocument(data.getDocumenId()))
// Issue here is we need access to the data object consumed in the previous flatMap but at the same time we also need the document object we get from the previous flatMap
.flatMap(document -> calculateValue(document, data))
.subscribe();
}
public Mono<Document> getDocument(String id) {
// Check if document exists
// If not create document
return document;
}
public Mono<Value> calculateValue(Document doc, Data data) {
// Do something...
return value;
}
The issue is that calculateValue needs the return value from http.getData but this was already consumed on the first flatMap but we also need the document object we get from the previous flatMap.
I tried to solve this issue using Mono.zip like below:
public void computeData(String id) {
final Mono<Data> dataMono = httpClient.getData(id);
Mono.zip(
new Mono<Mono<Document>>() {
#Override
public void subscribe(CoreSubscriber<? super Mono<Document>> actual) {
final Mono<Document> documentMono = dataMono.flatMap(data -> getDocument(data.getDocumentId()))
actual.onNext(documentMono);
}
},
new Mono<Mono<Value>>() {
#Override
public void subscribe(CoreSubscriber<? super Mono<Value>> actual) {
actual.onNext(dataMono);
}
}
)
.flatMap(objects -> {
final Mono<Document> documentMono = objects.getT1();
final Mono<Data> dataMono = objects.getT2();
return Mono.zip(documentMono, dataMono, (document, data) -> calculateValue(document, data))
})
}
But this is executing the httpClient.getData(id) twice which goes against my constrain of only calling it once. I understand why it is being executed twice (I subscribe to it twice).
Maybe my solution design can be improved somewhere but I do not see where. To me this sounds like a "normal" issue when designing reactive code but I could not find a suitable solution to it so far.
My question is, how can accomplish this flow in a reactive and non blocking way and only making one call to the rest api?
PS; I could add all the logic inside one single map but that would force me to subscribe to one of the Mono inside the map which is not recommended and I want to avoid following this approach.
EDIT regarding #caco3 comment
I need to subscribe inside the map because both getDocument and calculateValue methods return a Mono.
So, if I wanted to put all the logic inside one single map it would be something like:
public void computeData(String id) {
httpClient.getData(id)
.map(data -> getDocument(data).subscribe(s -> calculateValue(s, data)))
.subscribe();
}
You do not have to subscribe inside map, just continue building the reactive chain inside the flatMap:
getData(id) // Mono<Data>
.flatMap(data -> getDocument(data.getDocumentId()) // Mono<Document>
.switchIfEmpty(createDocument(data.getDocumentId())) // Mono<Document>
.flatMap(document -> calculateValue(document, data)) // Mono<Value>
)
.subscribe()
Boiling it down, your problem is analogous to:
Mono.just(1)
.flatMap(original -> process(original))
.flatMap(processed -> I need access to the original value and the processed value!
System.out.println(original); //Won't work
);
private static Mono<String> process(int in) {
return Mono.just(in + " is an integer").delayElement(Duration.ofSeconds(2));
}
(Silly example, I know.)
The problem is that map() (and by extension, flatMap()) are transformations - you get access to the new value, and the old one goes away. So in your second flatMap() call, you've got access to 1 is an integer, but not the original value (1.)
The solution here is to, instead of mapping to the new value, map to some kind of merged result that contains both the original and new values. Reactor provides a built in type for that - a Tuple. So editing our original example, we'd have:
Mono.just(1)
.flatMap(original -> operation(original))
.flatMap(processed -> //Help - I need access to the original value and the processed value!
System.out.println(processed.getT1()); //Original
System.out.println(processed.getT2()); //Processed
///etc.
);
private static Mono<Tuple2<Integer, String>> operation(int in) {
return Mono.just(in + " is an integer").delayElement(Duration.ofSeconds(2))
.map(newValue -> Tuples.of(in, newValue));
}
You can use the same strategy to "hold on" to both document and data - no need for inner subscribes or anything of the sort :-)

Unable to load value from Redis alone even if value is present

I am using Reactive Redis where I am trying to use Redis as cache for database. I am checking if value is present in the cache or not? If it is present then return it otherwise query database if result comes back; store the result cache it and return it.
However, even if value is present in Redis it is still querying the database all the time.
public Mono<User> getUser(String email) {
return reactiveRedisOperation.opsForValue().get("tango").switchIfEmpty(
// Always getting into this block (for breakpoint) :(
queryDatabase().flatMap(it -> {
reactiveRedisOperation.opsForValue().set("tango", it, Duration.ofSeconds(3600)).then(Mono.just(it));
})
);
}
private Mono<User> queryDatabase() {
return Mono.just(new User(2L,"test","test","test","test","test",true,"test","test","test"));
}
But call is always hitting the database even if value is present in Redis. What am I doing wrong here?
Base on this answer you can try with Mono.defer:
public Mono<User> getUser(String email) {
return reactiveRedisOperation.opsForValue().get("tango").switchIfEmpty(Mono.defer(() -> {
// Always getting into this block (for breakpoint) :(
queryDatabase().flatMap(it -> {
reactiveRedisOperation.opsForValue().set("tango", it, Duration.ofSeconds(3600)).then(Mono.just(it));
})})
);
}
UPDATE:
I don't have much experience with Mono. The answer that I pointed explain it:
... computation was already triggered at the point when we start composing our Mono types. To prevent unwanted computations we can wrap our future into a defered evaluation:
... is trapped in a lazy supplier and is scheduled for execution only when it will be requested.

Kotlin - Is it possible to return a variable from a higher order function?

I have a Kotlin function from a separate library that takes a function as a parameter and gets the variable I need from the callback:
object Session {
fun get(callback: (accessToken: String?) -> Unit): Boolean {
SomeOtherClass(callback).get()
return true
}
}
Then to call it from another class I make the call (in java):
public String getToken() {
Session.INSTANCE.get((accessToken) -> {
// I want the method getToken() to be able to 'return accessToken;'
// but this call back returns Unit and the get method itself returns Boolean
});
}
Is there a way to return the variable accessToken from getToken() directly, or at least the equivalent value? Session.get is async so creating a "global" variable returns null because the value hasn't been assigned yet. This is one thing I have tried:
public String getToken() {
String temp;
Session.INSTANCE.get((accessToken) -> {
temp = accessToken;
});
return temp;
}
Relatively new to functional programming so any help is appreciated!
If the call to get the access token is async then you can't just grab right away. This is because the code inside the get call is running on another thread while your code keeps going. It would look like this:
public String getToken() {
String temp; // 1. you make a variable
Session.INSTANCE.get((accessToken) -> { // 2. get call starts processing
temp = accessToken;
});
return temp; // 3. now you return your uninitialized variable
}
and then after your function ends the token callback happens, but its to late, you already returned nothing. If you run it in a debugger with a break point on each line and keep running you will see the order that the code is executed and it may make more sense.
Your best bet is to just handle what you need in the callback rather than returning it in getToken()...
Not sure if you wanted an answer in kotlin or java but your code may look something like this in kotlin:
Session.get { token ->
onToken(token)
}
where onToken handles whatever code you needed the token for
fun onToken(token: String) {
// do whatever code you would've executed after getToken() here
}
Hope I explained that alright.
You can't return a callback's eventual result from the method that calls it without blocking the thread that made the call. The reason callbacks exist is so you won't block the thread that's making the call. On Android, your app will crash with an Application Not Responding message if you block the main thread for a few seconds.
If you use Kotlin, you can wrap library callbacks using suspendCancellableCoroutine to make them coroutine-compatible. Coroutine suspend functions do allow you to return delayed results.

What approach to choose when refactoring method, so that it responds to the principles of clean code?

I have this method signature:
public User getActiveUser(String personId, User mainUser) throws MyExceptions {
if (personId== null) return mainUser;
User innerUser = userRepository.getByPersonId(personId);
checkForNull(innerUser);
checkIsActive(innerUser);
return innerUser;
}
private void checkForNull(User innerUser) throws UNPExceptions {
if (innerUser == null) throw new MyExceptions(USER_NOT_FOUND);
}
private void checkIsActive(User innerUser) throws UNPExceptions {
if (!innerUser.getIsActive()) throw new MyExceptions(USER_BLOCKED);
}
And I call this method from different places like this:
User user = userService.getActive(userRequest.getPersonId(), requestEntity.getUser());
I do not like this code because:
1) I pass 2 parameters to this method getActiveUser(String personId, User mainUser)
mainUser always return if personId is null. I can move this check inside method but then I have to do it every time before calling the method. And the method is called from many places. so I moved the check to one place. But it looks crooked and I do not know how to get around it. I don’t want to pass the second parameter just to do this check inside the method, but it looks better than copying this check before each method call. I do not know which solution is better. maybe there is another solution.
2) method name - getActiveUser is lying. because inside I do more checks. but I do not know how to call it - getActiveUserAndCheck? this is also not correct as the method is responsible for several duties
3) Is it necessary to divide checks into separate methods? checkForNull(innerUser);
checkIsActive(innerUser);
If the mainUser is always the same user you don't have to pass it as a method parameter, you can store it as an instance field and initialize it when appropriate.
If that's not the case, you can use AOP to handle the case with null personId and the aspect component will be responsible for retrieving the mainUser.
Using Java8+, you can simply replace
checkForNull(innerUser);
checkIsActive(innerUser);
return innerUser;
by means of Optional, as:
return Optional.ofNullable(innerUser)
.filter(User::getIsActive)
.orElseThrow(() -> new MyExceptions(""));
If you want to default to mainUser, you could do something on these lines(just that this is not throwing your custom exception) :
return Optional.ofNullable(personId) // check for person 'null'
.map(p -> userRepository.getByPersonId(personId)) if present evaluate 'innerUser'
.filter(Objects::nonNull) // check if innerUser is null
.filter(User::getIsActive) // check if innerUser is active
.orElse(defaultUser); if any of above fails return defaultUser

Categories