I am writing automated tests, and I want each to retry twice. So I wrote a method:
public void retry(int retries, Retryable retryable) {
for (int i = 0; i < retries; i++) {
try {
retryable.run();
break;
} catch (Exception e) {
log.warn(WARN_TEXT, retryable, (i + 1), e);
if (i == retries - 1) {
log.error(ERR_TEXT, retryable, retries, e);
retryable.handleException(e);
throw e;
}
}
}
}
public interface Retryable extends Runnable {
void handleException(Exception e);
}
Now I have couple of test methods, let's write 3 here:
#TestRailID(29828) // 1
#Test(description = "Try saving a filter without a name.",
groups = Group.PREPROD)
public void tryCreatingNoNameFilter() {
Retry.retry(2, new Retryable() {
#Override
public void handleException(Exception e) {
log.error(TEST_RUN_FAIL, 2);
}
#Override
public void run() {
userTriesCreatingNoNameFilter();
}
});
}
#TestRailID(31391) // 2
#Test(description = "Try saving a filter with too long name.",
groups = Group.PREPROD)
public void tryCreatingTooLongFilterName() {
Retry.retry(2, new Retryable() {
#Override
public void handleException(Exception e) {
log.error(TEST_RUN_FAIL, 2);
}
#Override
public void run() {
userTriesCreatingTooLongFilerName();
}
});
}
#TestRailID(29829) // 3
#Test(description = "Create and save a new filter.",
groups = Group.PREPROD)
public void createNewFilter() {
Retry.retry(2, new Retryable() {
#Override
public void handleException(Exception e) {
log.error(TEST_RUN_FAIL, 2);
}
#Override
public void run() {
userTriesCreatingNewFilter();
}
});
}
So we all can see that these methods differ only with run() method implemetation (single line).
How can I do it without copy pasting that long blocks of code?
Thank you in advacne :)
To reduce the repetitive blocks and number of lines (and make this overall look cleaner), you could:
Instead of extending Runnable, split up the exception handling and the run logic into two separate functional interfaces (see #FunctionalInterface):
#FunctionalInterface
interface ExceptionHandler {
void handleException(Exception e);
}
Runnable is in fact already a functional interface, so you can stick to this.
Then you can write these as lambdas:
Retry.retry(
2,
() -> userTriesCreatingTooLongFilerName(),
exception -> log.error(TEST_RUN_FAIL, 2)
);
As your exception handling seems to be the same for all calls, define it once:
var exceptionHandler = (ExceptionHandler) e -> log.error(TEST_RUN_FAIL, 2);
Retry.retry(2, () -> userTriesCreatingNoNameFilter(), exceptionHandler);
Retry.retry(2, () -> userTriesCreatingTooLongFilerName(), exceptionHandler);
Retry.retry(2, () -> userTriesCreatingNewFilter(), exceptionHandler);
// …
Further, alternative options:
Subclass your existing Retryable and pull up the common code.
Add a default implementation to your existing interface with the common code.
Related
I have the next RestController:
#PostMapping("/play")
public Mono<PlayResponse> play(#RequestBody String body) {
//business logic here;
}
And I wanna add some additional logic after the controller call. For example, I want to add to my application some modes logic:
timeout mode - after the successful call, the response will wait until timeout happens
long answer mode - after the successful call, the response will wait a particular amount of ms
failure mode - after the successful call, the response will answer with FORBIDDEN code
etc.
I'm trying to achieve that through WebFilter:
#Component
public class OutgoingFilter implements WebFilter {
Mode mode = new TimeoutMode();
#NonNull
#Override
public Mono<Void> filter(#NonNull final ServerWebExchange exchange, final WebFilterChain chain) {
return chain.filter(exchange)
.doOnNext(this::onNext)
.map(this::onMap)
.doFinally(this::onFinally);
}
private Void onMap(final Void unused) {
mode.run();
return unused;
}
private void onNext(final Void unused) {
mode.run();
}
private void onFinally(final SignalType signalType) {
mode.run();
}
}
As you can see, I've tried onMap, doOnNext andonFinally methods and none of them seem not working.
Is it the right way to use WebFilter there? Maybe I'm doing something wrong?
How can I implement such logic in the Spring WebFlux application?
Update
There is my Mode interface:
public interface Mode {
void run() throws Forbidden;
}
Implementations:
public class Fail implements Mode {
#Override
public void run() throws Forbidden {
throw new Forbidden("Fail mode enabled");
}
}
public class Wait implements Mode {
private final int ms;
public Wait() {
this(0);
}
public Wait(final int ms) {
this.ms = ms;
}
#Override
public void run() throws Forbidden {
sleep();
}
private void sleep() {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
But the implementations aren't final. I will change them to a reactive style if it's needed.
I've been given an interface which is like this:
MyInterface {
List<FirebaseVisionFace> getFaceList();
}
I have to implement it in a class (let's call it MyFirebaseFaceClass) in such a way that we can then do
List<FirebaseVisionFace> faceList = myFirebaseFaceClass.getFaceList()
The problem is that to get this list of faces, the following is required:
Task<List<FirebaseVisionFace>> result =
detector.detectInImage(image)
.addOnSuccessListener(
new OnSuccessListener<List<FirebaseVisionFace>>() {
#Override
public void onSuccess(List<FirebaseVisionFace> faces) {
// Task completed successfully
// ...
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Task failed with an exception
// ...
}
});
Is it possible to implement this getFaceList() method without passing in a callback as a parameter and using the callback to get the list?
You might try using a CompletableFuture. In an implementation of your interface:
class MyImplementation implements MyInterface {
#Override
List<FirebaseVisionFace> getFaceList() {
final CompletableFuture<List<FirebaseVisionFace>> future = new CompletableFuture<>();
final DetectorOfSomeKindYouDidNotSpecifyAbove detector = // ... get detector
detector.detectInImage(image)
.addOnSuccessListener(
new OnSuccessListener<List<FirebaseVisionFace>>() {
#Override
public void onSuccess(List<FirebaseVisionFace> faces) {
// Task completed successfully
future.complete(faces);
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Task failed with an exception
future.completeExceptionally(e);
}
});
try {
return future.get(); // blocks until completion by one of the listeners above
} catch (final RuntimeException throwMe) {
throw throwMe;
} catch (final InterruptedException interruptedException) {
Thread.currentThread().interrupt();
throw new IllegalStateException(interruptedException.getMessage(), interruptedException);
} catch (final Exception everythingElse) {
throw new IllegalStateException(everythingElse.getMessage(), everythingElse);
}
}
}
My error handling code above is stupid for brevity. All code above is untested and written off the cuff. I am assuming that the listeners are called when all discovery is done, and are called once. I'm also assuming that only one of the listeners is called, not both of them. I'm also assuming that they're called by another thread.
Lastly, do note that (as you seem to be aware) an interface like the kind you're trying to implement will inherently remove all benefits of the asynchronicity taking place in its underlying implementation.
Hopefully this will at least point you in the right direction!
If you work with asynchronous tasks in Java, you can't avoid callbacks. You use Task class that uses callbacks a lot. If you don't like this syntax, you can use lambdas:
Task<List<FirebaseVisionFace>> result =
detector.detectInImage(image)
.addOnSuccessListener((List<FirebaseVisionFace> faces) -> {
// Task completed successfully
})
.addOnFailureListener((#NotNull Exception e) -> {
// Task failed with an exception
})
You cannot avoid callbacks, but you can use method references as callbacks, so the whole code looks cleaner:
class MyFirebaseFaceClass implements MyInterface {
List<FirebaseVisionFace> faces;
Exception exception;
boolean done = false;
// Task completed successfully
private synchronized void onSuccess(List<FirebaseVisionFace> faces) {
this.faces = faces;
done = true;
notifyAll();
}
// Task failed with an exception
private synchronized void onError(Exception exception) {
this.exception = exception;
done = true;
notifyAll();
}
List<FirebaseVisionFace> getFaceList() {
detector.detectInImage(image)
.addOnSuccessListener(this::onSuccess)
.addOnFailureListener(this::onError);
synchronized (this) {
while (!done) {
wait();
}
if (exception == null) {
return faces;
} else {
throw new ExcecutionException(exception);
}
}
}
}
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'm trying make a reactive application that listens to a network socket on a separate thread for prices and got a bit stumped with how exactly to construct the Observable. Much of the interfaces I have are constrained by the API I am using and therefore cannot change. I distilled what I am trying to do as a test below, but I can't see how to fill in the body of the getPriceReactive() method such that the prices are printed on the console by the subscriber (see the comment in the code).
public class PriceObservableTest {
// This interface is defined externally and used by the API
private interface ITickHandler {
void priceReceived(double price);
}
// Stores the price (currently just one double for illustration)
private class Tick {
double price = Double.NaN;
}
// Implementation of handler called by API when it receives a price
private class TickHandler implements ITickHandler {
private final Tick tick;
TickHandler() { this.tick = new Tick(); }
#Override public void priceReceived(double x) { tick.price = x; }
}
// This class emulates the API delivering prices from the socket
private class PriceSource {
private final Thread thread;
PriceSource(final ITickHandler handler) {
thread = new Thread(new Runnable() {
final Random r = new Random();
#Override public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
handler.priceReceived(r.nextDouble() * 100);
} catch (InterruptedException e) {
break;
}
}
System.out.println("Price thread closed");
}
});
}
void subscribe() { thread.start(); }
void unsubscribe() { thread.interrupt(); }
}
#Test
public void simpleTest() throws Exception {
final ITickHandler handler = new TickHandler();
// Simulate some prices received periodically from a socket
PriceSource prices = new PriceSource(handler);
Observable<Tick> reactive = getPriceReactive(handler);
reactive.subscribe(new Subscriber<Tick>() {
#Override public void onCompleted() { }
#Override public void onError(Throwable e) { }
#Override public void onNext(Tick tick) {
System.out.println("Received price: " + tick.price);
}});
// Observe prices for 1 second. The subscriber should print them to console
prices.subscribe();
Thread.sleep(1000);
prices.unsubscribe();
}
// Returns an observable that reacts to price changes
private Observable<Tick> getPriceReactive(ITickHandler handler) {
return Observable.create(new Observable.OnSubscribe<Tick>() {
#Override public void call(Subscriber<? super Tick> subscriber) {
// How to call subscriber.onNext() whenever
// priceReceived() is called with a new price?
}
});
}
}
Somehow subscriber.onNext() needs to be called whenever the API calls priceReceived(), but I can't quite see how to achieve this. Of course I could store a reference to the subscriber in the TickHandler but this kind of defeats the purpose of having an Observable, doesn't it?
Transition to Observable in ITickHandler implementation. You are not controlling the subscriber(s) but the publisher
private class TickHandler implements ITickHandler {
private final Tick tick;
private final PublishSubject<Tick> priceSubject;
TickHandler() {
this.tick = new Tick();
this.priceSubject = PublishSubject.create();
}
#Override public void priceReceived(double x)
{
tick.price = x;
priceSubject.onNext(tick);
}
public Observable<Tick> priceReceivedObservable()
{
return priceSubject.asObservable();
}
}
And you can use it in your tests like:
final ITickHandler handler = new TickHandler();
PriceSource prices = new PriceSource(handler);
handler.priceReceivedObservable()
.subscribe(new Subscriber<Tick>() {
#Override public void onCompleted() { }
#Override public void onError(Throwable e) { }
#Override public void onNext(Tick tick) {
System.out.println("Received price: " + tick.price);
}});
I warn you, it's not tested since I don't do a lot of Java :)
In order to not repeat myself, I want to re-use a Subscriber variable between two observables. How do you do accomplish this? My current code below does not work, because after the subscriber is used once, it is unsubscribed and no longer works again. If I new a Subscriber instead of reusing a variable, my subscription works. I don't want to write the same code twice, if possible.
public class HomePresenter extends BasePresenter<HomeView> {
ArticleRepo articleRepo;
#Inject
public HomePresenter(ArticleRepo articleRepo) {
this.articleRepo = articleRepo;
}
#Override
public void onCreate(#Nullable PresenterBundle bundle) {
super.onCreate(bundle);
}
public void onEvent(ArticleCategoryClickedEvent event) {
Timber.v("Adapter position clicked at position: '%d'", event.getAdapterPosition());
view.launchArticleActivity(event.getArticleCategory());
}
public void onEvent(SeabeeOnlineExternalLinkClickedEvent event) {
view.launchExternalLink(event.getSeabeeOnlineExternalLink());
}
public void loadArticleImages() {
articleRepo.getArticleBuckets()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
public void refreshData() {
articleRepo.refreshAndSaveArticles()
.flatMap(new Func1<List<ArticleEntity>, Observable<List<ImageArticleCategoryEntity>>>() {
#Override
public Observable<List<ImageArticleCategoryEntity>> call(List<ArticleEntity> articleEntityList) {
return articleRepo.getArticleBuckets();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
final Subscriber<List<ImageArticleCategoryEntity>> subscriber = new Subscriber<List<ImageArticleCategoryEntity>>() {
#Override
public void onCompleted() {
Timber.v("Loading article images complete!");
view.hideLoadingAnimation();
}
#Override
public void onError(Throwable e) {
Timber.e("Error loading article images", e);
Log.e("tag", "Error loading article images", e);
}
#Override
public void onNext(List<ImageArticleCategoryEntity> integerImageArticleCategoryEntityHashMap) {
view.loadArticleImages(integerImageArticleCategoryEntityHashMap);
}
};
}
A Subscriber should not be reused. It will not work because it is a Subscription and once unsubscribed it is done.
Use an Observer instead if you want to reuse it.
source
You can reuse your subscriber, you just need to create an actual class out of it.
private static class MySubscriber extends Subscriber<List<ImageArticleCategoryEntity>> {...}
Subscriber<> subscriber1 = new MySubscriber();
Subscriber<> subscriber2 = new MySubscriber();
And there you go.