Callback recursion in Java - java

I have method save. It saves entity using service which returns me com.google.common.util.concurrent.ListenableFuture<Void>. In case of fail I want to repeat save. I have next code for it:
public void save(Entity entity) {
ListenableFuture<Void> result = service.save(entity);
Futures.addCallback(result, new FutureCallback<Result>() {
#Override
public void onSuccess(Result callbackResult)
{
//do nothing
}
#Override
public void onFailure(Throwable throwable)
{
//some actions
save(entity);
}
});
}
But code above can be cause of StackOverflowException. If future will be done before addCallback then it will be recursive call. How can I optimize this code to remove recursion from it?

Related

SmallRye Mutiny unable to process events asynchronously using subscription

I am developing an application that returns Multi<String>, I would like to make some modifications to it, so I have added some methods, but for some reason it does not enter the next method at all.
My other methods are working absolutely fine. Because I am able to collect it and add it to a List, but I want to do some execution asynchronously, so using this approach.
private final ManagedExecutor managedExecutor;
public void writeTo(StreamingInfo streamingInfo) {
streamingInfo
.getEvents()
.runSubscriptionOn(managedExecutor)
.subscribe()
.withSubscriber(
new Subscriber < String > () {
#Override
public void onSubscribe(Subscription s) {
System.out.println("OnSubscription Method");
System.out.println("ON SUBS END");
}
#Override
public void onNext(String event) {
System.out.println("On Next Method");
}
#Override
public void onError(Throwable t) {
System.out.println("OnError Method");
}
#Override
public void onComplete() {
System.out.println("On Complete Method");
}
});
}
I get the following output:
OnSubscription Method
ON SUBS END
Which means that your subscription is not working for some reason. If I do not add subscription and directly collect to List then everything works as expected. Can anyone suggest what am I doing wrong here?
This is because the underlying Reactive Streams specification that SmallRye Mutiny implements has a built-in backpressure mechanism. The client (in your case your subscriber) needs to request the next item manually from the producer (events) otherwise, no item is sent down the reactive pipeline.
You need to save the Subscription object you receive in the onSubscribe method and call its request(long) method when you can process next item(s):
.withSubscriber(
new Subscriber<String>() {
private Subscription subscription;
#Override
public void onSubscribe(Subscription s) {
System.out.println("OnSubscription Method");
System.out.println("ON SUBS END");
subscription = s;
subscription.request(1);
}
#Override
public void onNext(String event) {
System.out.println("On Next Method");
subscription.request(1);
}
#Override
public void onError(Throwable t) {
System.out.println("OnError Method");
}
#Override
public void onComplete() {
System.out.println("On Complete Method");
}
});
In SmallRye there is also an easier way to do this:
events
.onSubscription()
.invoke(() -> {
System.out.println("OnSubscription Method");
System.out.println("ON SUBS END");
})
.onItem()
.invoke(event -> System.out.println("On Next Method"))
.onFailure()
.invoke(t -> System.out.println("OnError Method"))
.onCompletion()
.invoke(() -> System.out.println("On Complete Method"))
.subscribe()
.with(value -> {});

How can I change value of variable in side method from anonymous inner class?

How can I change the value of a variable inside the method from anonymous inner class, to access this variable it must be a final, but if the variable final can't change its value, how solve this problem using java?
This is My Code, I want to change the value of addFlag.
public static boolean addUser(UserModle user){
Boolean addFlag ;
dbUser = FirebaseDatabase.getInstance().getReference("user");
Task task = dbUser.child(user.getId()).setValue(user);
task.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
addFlag = true;
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
return addFlag;
}
IMHO, the current implementation of the addUser function is flawed. As per my understanding, you want to know if the user was added successfully to your firebase database based on the addFlag value that is returned from this function.
The addFlag will be updated once the Firebase database call will get back the data from the firebase realtime database. However, you are returning the flag immediately and hence you are not waiting for the result from your background network thread.
In order to achieve that, I would like to suggest an interface based implementation. You might have an interface as follows.
public interface FirebaseListener {
void onSuccess(boolean flag);
}
Then add an extra parameter in your addUser function to pass that interface from your Activity or Fragment where you are calling this function. Hence the function might look as follows.
// Change the return type to void, as we are not expecting anything from this function.
// Instead, we will wait for the success callback using the interface
public static void addUser(UserModle user, FirebaseListener listener) {
dbUser = FirebaseDatabase.getInstance().getReference("user");
Task task = dbUser.child(user.getId()).setValue(user);
task.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
listener.onSuccess(true);
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
listener.onSuccess(false);
}
});
}
Now implement the listener in your activity or fragment as follows.
public MyActivity extends AppCompatActivity implements FirebaseListener {
// ... Other functions of your activity
#Override
public void onSuccess(boolean flag) {
if (flag) {
// User add successful. Do something here
} else {
// User add not successful. Do something here
}
}
}
Now while calling the addUser function, you should pass the callback listener along with it as follows.
addUser(user, this);
I hope that helps.

How to convert a pre-instanced callback into Observable

I'm fairly new to RxJava and I have a basic understanding as to how to wrap a callback into an Observable but what I'm having difficulty with is doing so when the callback/listener is pre-instanced. Every example that I have found only shows instancing the callback directly into the Observable being created.
Some example code of what I'm talking about. I'm working with an Api that's works like this:
public class Api {
private ApiCallback callback;
void initialize(ApiCallback callback){
this.callback = callback;
}
void doAction1(){
this.callback.onAction1Complete();
}
}
interface ApiCallback {
void onInitialized();
void onAction1Complete();
}
With the real api I am working with I have no control over how it works so I must work with it in this state. In terms of trying to work with this Api using observables here is the struggle I am having. I have a member variable that holds the Api object:
private Api mApi = new Api();
Now in order to initialize this I have one of two options it seems.
Option 1:
Completable startApi() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
mApi.initialize(new ApiCallback() {
#Override
public void onInitialized() {
emitter.onComplete();
}
#Override
public void onAction1Complete() {
}
});
}
});
}
Option 2:
private ApiCallback premadeCallback = new ApiCallback() {
#Override
public void onInitialized() {
}
#Override
public void onAction1Complete() {
}
};
Completable startApi() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
mApi.initialize(premadeCallback);
}
});
}
Now the issue I have is that Option 2 makes more sense to me when I need to know when the other methods in the callback are called from Api calls. With my understanding of RxJava however I don't understand how I can reach these method calls with an Api that works like this.
For example:
Completable doAction1() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
// Api is already initialized with callback
// How do I reach the callback from here?
}
});
}
The only what that I can currently think of as to how to achieve this would be to create a member variable as an emitter (or a dictionary of emitters) and then call its appropriate method in the api callback when needed. My concerns with this are A. I'm unsure if RxJava can work this way B. This sounds like a terrible idea.

ListenableFutureCallback - onFailure is never called

I am playing around with 'ListenableFutureCallback'. onSuccess() works fine, but onFailure is never called. Below is some example code.
#Service
public class AsyncClass {
#Async
public ListenableFuture<String> execute(Callable<String> callable) throws Exception {
String str = callable.call();
//To force an exception to occur
str.toString();
return new AsyncResult<>(str);
}
}
public void futureMethod(String str) throws Exception {
AsyncClass asyncClass = new AsyncClass();
ListenableFuture<String> future = asyncClass.execute(() -> {
return str;
});
future.addCallback(new ListenableFutureCallback<Object>() {
#Override
public void onFailure(Throwable ex) {
System.out.println("FAIL");
}
#Override
public void onSuccess(Object result) {
System.out.println("SUCCESS");
}
});
}
onSuccess works correct.
futureMethod("test value");
Console: SUCCESS
onFailure does however not work.
futureMethod(null);
Console: java.lang.NullPointerException: null
You aren't using listenable futures. You are executing code and putting the result in a listenable future.
In order for onFailure to trigger you need to run the failing code inside the future or complete the future with an exception.
For example
Futures.immediateFailedFuture(new RuntimeException("woops"));
Listenable futures are generally expected to be retrieved from ListeningExecutorServices. ListenableFuture, unlike CompletableFuture, isn't completable externally.

RxJava 2, Flowable.doOnCancel not called when DisposableSubscriber disposed

I have a DisposableSubscriber to a Flowable. The Flowable runs for some timeUntilTimeout, but in some situations I need to kill it earlier. Right now I call .dispose() on the DisposableSubscriber but the Flowable continues to emit events. Eventually the Flowable times out and .doOnCancel() is called.
I have the following code:
private Disposable mDisposableSubscription = null;
public void start() {
mDisposableSubscription = getFlowable()
.timeout(timeUntilTimeout, TimeUnit.MILLISECONDS)
.subscribeWith(new DisposableSubscriber<T>() {
#Override
public void onComplete() {
}
#Override
public void onError(Throwable throwable) {
dispose();
}
#Override
public void onNext(T t) {
// Do something
}
});
}
public void stop() {
// Log "dispose"
mDisposableSubscription.dispose();
}
private Flowable<T> getFlowable() {
return Flowable.create(new FlowableOnSubscribe<T>() {
public void subscribe(FlowableEmitter<T> emitter) {
startSomeAsyncProcess();
}
}).doOnCancel(new Action() {
public void run() {
// Log "do on cancel"
stopSomeAsyncProcess();
}
});
}
Calling stop() to dispose of the DisposableSubscriber before the Flowable times out means events emitted by the Flowable are no longer handled, but the Flowable continues emitting events and the async process continues running. I was under the impression that calling .dispose() downstream of the Flowable kills the Flowable by calling .doOnCancel(), but this does not appear to be the case. What am I missing?
The flowable is getting disposed, but you are not checking it on your Flowable.create function, so what happens is that the startSomeAsyncProcess() ignores it and keeps going.
To solve the issue, you should check the emitter.isDisposed() flag to know if you should stop emitting.
Example:
Flowable<T> getFlowable() {
return Flowable.create(new FlowableOnSubscribe<T>() {
public void subscribe(FlowableEmitter<T> emitter) {
while(!emitter.isDisposed()) {
emitter.onNext(...);
}
}
});
}
If that startSomeAsyncProcess() function doesn't allow you to check the flag, surely there is some way to cancel it. Then you can attach a cancellable:
Flowable<T> getFlowable() {
return Flowable.create(new FlowableOnSubscribe<T>() {
public void subscribe(FlowableEmitter<T> emitter) {
startSomeAsyncProcess();
emitter.setCancellable(() -> stopSomeAsyncProcess());
// I don't remember if it's setCancellable() or setDisposable()
}
});
}
Update: the methods setCancellable(...) and setDisposable(...) should behave equally, they just take different arguments.

Categories