I need to make a library in which I will have synchronous and asynchronous methods in it and this library will be used by our customer in our company. Some customer will call the executeSynchronous
method to get the same feature and some customer will call our executeAsynchronous
method and with the latter method they will do future.get
in their code base.
executeSynchronous()
- waits until I have a result, returns the result.executeAsynchronous()
- returns a Future immediately which can be processed after other things are done, if needed.
In case of any exception, I need to log it into our company storage system with the logging I have both from synchronous and asynchronous method. This will ensure that I can log the way I want into our storage system, instead of asking each customer to do that.
This logging will log into our storage system.
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
Core Logic of my Library
The customer will use our library and they will call it by passing DataKey
builder object. We will then construct a URL by using that DataKey
object and make a HTTP client call to that URL by executing it and after we get the response back as a JSON String, we will send that JSON String back to our customer as it is by creating DataResponse
object.
Interface:
public interface Client {
// for synchronous
public DataResponse executeSynchronous(DataKey dataKey);
// for asynchronous
public Future<DataResponse> executeAsynchronous(DataKey dataKey);
}
And then I have my DataClient
which implements the above Client
interface:
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate();
private ExecutorService service = Executors.newFixedThreadPool(10);
// for synchronous call
@Override
public DataResponse executeSynchronous(DataKey dataKey) {
DataResponse dataResponse = null;
try {
Future<DataResponse> future = executeAsynchronous(dataKey);
dataResponse = future.get(dataKey.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
//for asynchronous call
@Override
public Future<DataResponse> executeAsynchronous(DataKey dataKey) {
DataClientFuture dataFuture = null;
try {
Task task = new Task(dataKey, restTemplate);
Future<DataResponse> future = executor.submit(task);
dataFuture = new DataClientFuture(future, dataKey);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
}
return dataFuture;
}
}
DataClientFuture
class:
(Does this look right or can I add more stuff to this?)
public class DataClientFuture implements Future<DataResponse> {
private final Future<DataResponse> delegate;
private final DataKey dataKey;
public DataClientFuture(Future<DataResponse> response, DataKey dataKey) {
this.delegate = response;
this.dataKey = dataKey;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return delegate.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
return delegate.isCancelled();
}
@Override
public boolean isDone() {
return delegate.isDone();
}
// should I still throw exception here and catch it as well?
// Since I need to log an exception into our company's storage system
// so I need to log it the way I want to log the exception instead of asking customer to do that
// so that's why I am catching it.
// May be after catching I should re-throw the same exception?
@Override
public DataResponse get() throws InterruptedException, ExecutionException {
DataResponse dataResponse = null;
try {
dataResponse = delegate.get();
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
// should I still throw exception here and catch it as well?
// Since I need to log an exception into our company's storage system
// so I need to log it the way I want to log the exception instead of asking customer to do that
// so that's why I am catching it.
// May be after catching I should re-throw the same exception?
@Override
public DataResponse get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException,
TimeoutException {
DataResponse dataResponse = null;
try {
dataResponse = delegate.get(timeout, unit);
} catch (TimeoutException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
}
Simple class which will perform the actual task:
public class Task implements Callable<DataResponse> {
private DataKey dataKey;
private RestTemplate restTemplate;
public Task(DataKey dataKey, RestTemplate restTemplate) {
this.dataKey = dataKey;
this.restTemplate = restTemplate;
}
// do I need to throw an Exception here, since I am already catching it?
@Override
public DataResponse call() throws Exception {
DataResponse dataResponse = null;
String response = null;
try {
String url = createURL();
response = restTemplate.getForObject(url, String.class);
// it is a successful response
dataResponse = new DataResponse(response, DataErrorEnum.NONE, DataStatusEnum.SUCCESS);
} catch (RestClientException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.SERVER_DOWN, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.SERVER_DOWN, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
// create a URL by using dataKey object
private String createURL() {
String url = somecode;
return url;
}
}
As I mentioned above, some customers will call executeSynchronous
method to get the data for that user id which they are passing in DataKey
object and some customers will call executeAsynchronous
method with DataKey
object but in latter case, they will do future.get
in their code base.
If you see my executeSynchronous
method, I am doing future.get
after calling executeAsynchronous
method and if there is any TimeoutException
, then I am logging using PotoLogging
class which is specific in our company and that logs will go to some storage system in our company which we use to look all our error logs on the dashboard from our library. And it mainly depends how we are logging it with what names so that we can see those names in the dashboard.
Now the problem is customer within our company can also call executeAsynchronous
method but that means, they will do future.get
in their code base and that can also result in TimeoutException
and I wanted to log this TimeoutException
as well from our library in the way I wanted so that it can show up in our storage system on the dashboard and because of that reason I created DataClientFuture
class and implemented most of the method in that instead of using default future.get
implementation.