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
}
}
Related
My Reactive knowledge is very basic and I was wondering what the right way would be if I like to return an observable from a function which is using an observable. I wanna extend the observable which I am calling with a check.
In my example, I think it is a lot of code for not much. I think I would also need to worry about the disposable of the inner observable. Do I?
public Completable updateUserPhotoURL(Uri photoURL, UserProfileChangeRequest profileUpdates) {
return Completable.create(emitter -> {
if (mFirebaseUser == null) {
emitter.onError(new Exception("Firebase User is not initiated"));
}
RxFirebaseUser.updateProfile(mFirebaseUser, profileUpdates).complete()
.subscribe(new DisposableCompletableObserver() {
#Override
public void onComplete() {
emitter.onComplete();
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
emitter.onError(e);
}
});
});
}
What would be the right (more elegant) way of doing so?
I am trying to compose a chain of steps such that I can avoid a large nested chain of if and else calls by creating methods that return CompletableFuture<Boolean> in a manner such as....
client.connect(identifier).thenCompose(b -> client.authenticate())
.thenCompose(b -> client.sendSetting(settings))
.thenCompose(b -> client.saveSettings())
.thenCompose(b -> client.sendKey(key))
.thenCompose(b -> client.setBypassMode(true))
.thenCompose(b -> client.start())
.whenComplete((success, ex) -> {
if(ex == null) {
System.out.println("Yay");
} else {
System.out.println("Nay");
}
});
If the client methods return a CompletableFuture<Boolean> deciding whether to continue processing has to be done in each lambda in the chain and doesn't provide a method to abort early if one of the calls fail. I would rather have the calls return CompletableFuture<Void> and use Exceptions to control if 1) each successive step in the chain executes and 2) final determination of success of the full chain.
I am having trouble finding which method on CompletableFuture<Void> to swap for thenCompose to make things work (let alone compile).
public class FutureChaings {
public static CompletableFuture<Void> op(boolean fail) {
CompletableFuture<Void> future = new CompletableFuture<Void>();
System.out.println("op");
Executors.newScheduledThreadPool(1).schedule(() -> {
if(fail) {
future.completeExceptionally(new Exception());
}
future.complete(null);
}, 1, TimeUnit.SECONDS);
return future;
}
public static void main(String[] args) {
op(false).thenCompose(b -> op(false)).thenCompose(b -> op(true)).whenComplete((b, ex) -> {
if(ex != null) {
System.out.println("fail");
} else {
System.out.println("success");
}
});
}
}
I was able to contrive an example that behaved the way I wanted. So I know what calls to put together to get what I want. Now to figure out what the compiler doesn't like in my real code. Thanks for the comments.
I have a class that has many methods. All the methods throw one exception when data is not ready. In that case, I want to retry the method after a certain interval. So in catch, I need to add retry logic. The same logic i need to add for all methods.
Is there some way/pattern to execute same logic for all catch clause without copy paste
One way I could think of is to write my own Exception class and Throw that exception. And do this retry logic from My Exception class.
Is there any other better way to this?
class MyClass {
public void method1() {
try {
//do some logic
} catch (Exception e) {
//retry logic
//existing exception handling logic
}
}
public void method2() {
try {
//do some logic
} catch (Exception e) {
//retry logic
//existing exception handling logic
}
}
public void method3() {
try {
//do some logic
} catch (Exception e) {
//retry logic
//existing exception handling logic
}
}
}
EDIT:
class MyClass {
public void method1(int a, int b) {
try {
//do some logic
} catch (Exception e) {
Object args[] = {a,b};
executeLater("method1",args);
//retry logic
//existing exception handling logic
}
}
public void method2() {
try {
//do some logic
} catch (Exception e) {
Object args[] = null;
executeLater("method1",args);
//retry logic
//existing exception handling logic
}
}
public void method3(String abcd, int a) {
try {
//do some logic
} catch (Exception e) {
Object args[] = {abcd,a};
executeLater("method1",args);
//retry logic
//existing exception handling logic
}
}
public boolean executeLater(String methodName, Object args[]){
//Execute given method with the supplied args
return true;
}
}
Added code that shows what i would be doing in each catch clause
boolean processCompleted=false;
while(!processCompleted){
try{
doProcess();
processCompleted=true;
}catch(Exception e){
Thread.sleep(10000);
}
}
This might give you an idea. It keeps try to call doProcess until it doesn't throw exception. If any exception occurs, waits 10 seconds.
Well, you could extract the whole catch block content to a method and call that one, but this only works if your retry logic is not dependent on the specific method. And it also requires a try-catch in every method.
Instead, use functional programming to shorten it:
public class Playground
{
public static void main(String[] args)
{
new Playground().method2(1, 2);
new Playground().method1();
}
public void method1()
{
tryAndTryAgain(() -> {
// logic 1
System.out.println("no params");
throw new RuntimeException();
});
}
public void method2(int a, int b)
{
tryAndTryAgain(() -> {
// logic 2
System.out.println(a + " " + b);
throw new RuntimeException();
});
}
public static void tryAndTryAgain(Runnable tryThis)
{
try
{
tryThis.run();
}
catch (Exception e)
{
new Timer().schedule(new TimerTask()
{
#Override
public void run()
{
tryAndTryAgain(tryThis);
}
}, 1000);
// existing exception handling logic
}
}
}
The exact structure depends on your specfic implementation, but it should give you an idea how to structure it. The benefit is that all those methods can concentrate on the business logic, and the retry logic and exception handling are done in a util method. And that util method doesn't even need to know anything about parameters, methods, or anything, because all the business logic is contained in the Runnable.
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);
I'm experimenting with RxJava and Java 8's CompletableFuture class
and do not quite get how to handle timeout conditions.
import static net.javacrumbs.futureconverter.java8rx.FutureConverter.toObservable;
// ...
Observable<String> doSomethingSlowly() {
CompletableFuture<PaymentResult> task = CompletableFuture.supplyAsync(() -> {
// this call may be very slow - if it takes too long,
// we want to time out and cancel it.
return processor.slowExternalCall();
});
return toObservable(task);
}
// ...
doSomethingSlowly()
.single()
.timeout(3, TimeUnit.SECONDS, Observable.just("timeout"));
This basically works (if the timeout of three seconds is reached, "timeout" is published). I would however additionally want to cancel the future task that I've wrapped in an Observable - is that possible with an RxJava-centric approach?
I know that one option would be to handle the timeout myself, using task.get(3, TimeUnit.SECONDS), but I wonder if it's possible to do all task handling stuff in RxJava.
Yes, you can do this. You would add a Subscription to the Subscriber.
This allows you to listen in on unsubscriptions, which will happen if you explicitly call subscribe().unsubscribe() or if the Observable completes successfully or with an error.
If you see an unsubscription before the future has completed, you can assume it's because of either an explicit unsubscribe or a timeout.
public class FutureTest {
public static void main(String[] args) throws IOException {
doSomethingSlowly()
.timeout(1, TimeUnit.SECONDS, Observable.just("timeout"))
.subscribe(System.out::println);
System.in.read(); // keep process alive
}
private static Observable<String> doSomethingSlowly() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return "Something";
});
return toObservable(future);
}
private static <T> Observable<T> toObservable(CompletableFuture<T> future) {
return Observable.create(subscriber -> {
subscriber.add(new Subscription() {
private boolean unsubscribed = false;
#Override
public void unsubscribe() {
if (!future.isDone()){
future.cancel(true);
}
unsubscribed = true;
}
#Override
public boolean isUnsubscribed() {
return unsubscribed;
}
});
future.thenAccept(value -> {
if (!subscriber.isUnsubscribed()){
subscriber.onNext(value);
subscriber.onCompleted();
}
}).exceptionally(throwable -> {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(throwable);
}
return null;
});
});
}
}