Create Flowable from while loop - java

I am pretty new to RxJava and I need to create repository with several datasources. It is complex to me because there are several smaller subtasks which I don't know how to implement with RxJava.
First I have self written dao, which process InputStream, and provides Items in the specified range. Currently it simply collects data in a list, but I want to provide Items one by one using flowable; Currently it privides Maybe<List<Item>>. Also there several errors need to be transmitted to higher level (datasource). Such as EndOfFile, to notify DataSource that data fully cached;
Dao.class:
List<Item> loadRange(int start, int number) throws ... {
...
while(...) {
...
//TODO contribute item to flowable
resultList.add(new Item(...))
}
return resultList;
}
Maybe<List<Item>> method just created Maybe.fromCallable();
Please help me!

Something like this should work for this :
Flowable<Item> loadRange(int start, int number) {
return Flowable.create(emitter -> {
try {
while (...){
emitter.onNext(new Item());
}
emitter.onComplete();
} catch (IOException e) {
emitter.onError(e);
}
}, BackpressureStrategy.BUFFER);
}
I assume once the loop is done you want to complete, also send errors downstream, rather than handle on the method signature. Also you can change the BackPressureStrategy to suit your usecase i.e DROP, LATEST etc..
As you're new to RxJava, the anonymous class would be :
Flowable<Item> loadRange(int start, int number) {
return Flowable.create(new FlowableOnSubscribe<Item>() {
#Override public void subscribe(FlowableEmitter<Item> emitter) {
try {
while (...){
emitter.onNext(new Item());
}
emitter.onComplete();
} catch (IOException e) {
emitter.onError(e);
}
}
}, BackpressureStrategy.BUFFER);
}

Related

How to avoid repetition with same params

I am trying to find out a way to avoid the kind of repetition below
try {
await().pollInterval(5, TimeUnit.SECONDS).pollDelay(500, TimeUnit.MILLISECONDS)
.atMost(30, TimeUnit.SECONDS).until(() -> {
// 1. methods in here
});
} catch (final Exception e) {
//TODO: can be handled internally
}
It happens in several places in my code, and I want to make it less repetitive, but I am not finding a way to do so. I thought about lambdas, but I don`t know much about it nor if it would fit in here.
Inside of it can be many different things, it is not the same for all nor they have the same inheritance.
public static void main(String... args) {
awaitUntil(() -> {
// payload 1
return true;
});
awaitUntil(() -> {
// payload 2
return true;
});
}
public static void awaitUntil(Callable<Boolean> conditionEvaluator) {
try {
Awaitility.await()
.pollInterval(5, TimeUnit.SECONDS)
.pollDelay(500, TimeUnit.MILLISECONDS)
.atMost(30, TimeUnit.SECONDS)
.until(conditionEvaluator);
} catch(Exception e) {
//TODO: can be handled internally
}
}

Asynchronous microservices in java

My task is to create two simple microservices for movie management. One of them is responsible for movies and another for reviews. I have to create function for adding reviews (reviews will be added after approve). To check review movie service should call approving (review) service asynchronously. This is my very first time with asynchronous methods and I am not sure how should I create it.
Below is my simple method from movie service to adding review.
public boolean addReviewForMovie(Review review, String movieId){
Movie movie = movieRepository.findById(movieId);
if(movie == null){
return false;
}
review.setMovieId(movieId);
return reviewService.addReview(review);
}
My approving algorithm is really simple - I want just to check couple of parameters. Here is my code.
public boolean addReview(Review review){
if (review.getReviewContent().length() < 10
|| review.getReviewContent().length() > 250) {
return false;
}else if(review.getRating()<1d || review.getRating() > 10d){
return false;
}else if(review.getUserName().length() < 1
|| review.getUserName().length() > 15){
return false;
}
review.setApproved(true);
reviewRepository.save(review);
return review.isApproved();
}
Could you please explain me how to create these methods asynchronous? I would appreciate if you send me some articles about it.
I refecator my code however I am not sure if this is the proper way. I exepect something else I guess.
Below is my method in movie service class. I use it to add review. This method should ask for asynchronous one.
public void addReviewForMovie(Review review){
CompletableFuture<Boolean> completableFuture = reviewService.addReview(review);
try {
Boolean result = completableFuture.get();
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
And here is my approving method
public CompletableFuture addReview(Review review){
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(()->{
try{
Thread.sleep(10000);
boolean addedFlag = true;
if (review.getReviewContent().length() < 10
|| review.getReviewContent().length() > 250) {
addedFlag = false;
completableFuture.complete(addedFlag);
}else {
review.setApproved(true);
reviewRepository.save(review);
completableFuture.complete(addedFlag);
}
} catch (Exception e){
e.printStackTrace();
}
return null;
});
return completableFuture;
Is implementation correct? I thought that the idea is that the first method will not be waiting for the second one and send it back once the addReview will be complited.
There are all kinds of ways to make them asynchronous. I think the question is too broad, however...
The first thing is to stop returning a boolean, otherwise the caller blocks while the method runs. In asynchronous code, the caller does not block, but is "called back" when the operation has completed.
You could return a CompletableFuture which provides lots of ways to chain asynchronous actions.
public CompletableFuture addReview(Review review) {
// TODO
}
Or make the caller provide a callback function which you will call when the result is ready.
public void addReview(Review review, Callback callback) {
// TODO: Add the review and when finished
callback.onSuccess();
}
Where Callback is an interface that would look something like this:
interface Callback {
void onSuccess();
void onFailure(Throwable cause);
}

RxJava: Conditionally catch error and stop propagation

I use Retrofit with RxJava Observables and lambda expressions. I'm new to RxJava and cannot find out how to do the following:
Observable<ResponseBody> res = api.getXyz();
res.subscribe(response -> {
// I don't need the response here
}, error -> {
// I might be able to handle an error here. If so, it shall not go to the second error handler.
});
res.subscribe(response -> {
// This is where I want to process the response
}, error -> {
// This error handler shall only be invoked if the first error handler was not able to handle the error.
});
I looked at the error handling operators, but I don't understand how they can help me with my usecase.
Method 1: Keep the two Subscribers but cache the Observable.
Just keep everything as it is now, but change the first line to:
Observable<ResponseBody> res = api.getXyz().cache();
The cache will make sure that the request is only sent once but that sill both Subscribers get all the same events.
This way whether and how you handle the error in the first Subscriber does not affect what the second Subscriber sees.
Method 2: Catch some errors with onErrorResumeNext but forward all others.
Add onErrorResumeNext to your Observable to produce something like this (in the "inner" object):
Observable observable = Observable.error(new IllegalStateException())
.onErrorResumeNext(new Func1<Throwable, Observable<?>>() {
#Override
public Observable<?> call(Throwable throwable) {
if (throwable instanceof NumberFormatException) {
System.out.println("NFE - handled");
return Observable.empty();
} else {
System.out.println("Some other exception - panic!");
return Observable.error(throwable);
}
}
});
And only subscribe once (in the "outer" object):
observable.subscribe(new Subscriber() {
#Override
public void onCompleted() {
System.out.println("onCompleted");
}
#Override
public void onError(Throwable e) {
System.out.println("onError");
e.printStackTrace();
}
#Override
public void onNext(Object o) {
System.out.println(String.format("onNext: %s", String.valueOf(o)));
}
});
This way, the error is only forwarded if it cannot be handled in the onErrorResumeNext - if it can, the Subscriber will only get a call to onCompleted and nothing else.
Having side effects in onErrorResumeNext makes me a bit uncomfortable, though. :-)
EDIT: Oh, and if you want to be extra strict, you could use Method 3: Wrap every case in a new object.
public abstract class ResultOrError<T> {
}
public final class Result<T> extends ResultOrError<T> {
public final T result;
public Result(T result) {
this.result = result;
}
}
public final class HandledError<T> extends ResultOrError<T> {
public final Throwable throwable;
public Result(Throwable throwable) {
this.throwable = throwable;
}
}
public final class UnhandledError<T> extends ResultOrError<T> {
public final Throwable throwable;
public Result(Throwable throwable) {
this.throwable = throwable;
}
}
And then:
Wrap proper results in Result (using map)
Wrap handle-able errors in HandledError and
un-handle-able errors in UnhandledError (using onErrorResumeNext with an if clause)
handle the HandledErrors (using doOnError)
have a Subscriber<ResultOrError<ResponseBody>> - it will get notifications (onNext) for all three types but will just ignore the HandledErrors and handle the other two types.

RxAndroid Simplify a common pattern?

I find myself writing over and over again:
Observable.create(new Observable.OnSubscribe</* some type */>() {
#Override
public void call(Subscriber<? super /* some type */> subscriber) {
try {
subscriber.onNext(/* do something */);
subscriber.onCompleted();
} catch (IOException e) {
subscriber.onError(e);
}
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.newThread());
for network operations.
Is there any way to make it less repetative ?
The first create can be replaced by fromCallable.
Observable.fromCallable(() -> calculationReturnsAValue());
The application of schedulers can be achieved by creating a Transformer:
Transformer schedulers = o ->
o.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
and composing with it:
source.compose(schedulers);

RxJava retryWhen resubscribe propagation

I'm using Retrofit with RxJava in an Android app for communications and have to handle error on parsing the response from a seemly ok HTTP response (status 200 code).
I have also implemented a way of handling the error using retryWhen operator which is connected to user's input to decide whether to retry it or not. This works by resubscribing to the original Observable.
The first approach I have tried was to have something like this:
services.getSomething()
.map(response -> {
if (checkBadResponse(response)) {
throw new RuntimeException("Error on service");
} else {
return parseResponse(response);
}
}).retryWhen(this::shouldRetry);
With this the service is not called again. It seems the retryWhen operator cannot resubscribe to the service's Observable.
What end up working was implementing another operator which doesn't send the onCompleted forward and use it with lift like the following:
public class CheckResponseStatus<T> implements Observable.Operator<ResponsePayload<T>, ResponsePayload<T>> {
#Override
public Subscriber<? super ResponsePayload<T>> call(Subscriber<? super ResponsePayload<T>> subscriber) {
return new Subscriber<ResponsePayload<T>>() {
private boolean hasError = false;
#Override
public void onCompleted() {
if (!hasError)
subscriber.onCompleted();
}
#Override
public void onError(Throwable e) {
hasError = true;
subscriber.onError(e);
}
#Override
public void onNext(ResponsePayload<T> response) {
if (response.isOk()) {
subscriber.onNext(response);
} else {
hasError = true;
subscriber.onError(new RuntimeException(response.getMessage()));
}
}
};
}
}
Using it like:
services.getSomething()
.lift(new CheckResponseStatus())
.map(response -> parseResponse(response))
.retryWhen(this::shouldRetry);
Is this the correct way of dealing with it or is there a simpler, better way?
It's looks like a bug in rx-java implementation. Anyway, throwing an exception from map function is a bad thing since the function is supposed to be pure (e.g. without side effects). You should use a flatMap operator in your case:
services.getSomething()
.flatMap(response -> {
if (checkBadResponse(response)) {
return Observable.<ResponseType>error(new RuntimeException("Error on service"));
} else {
return Observable.<ResponseType>just(parseResponse(response);
}
}).retryWhen(this::shouldRetry);
The code above works as expected and really retries the request if error occurs.

Categories