I'm making a REST call to an external system from Java. If there are any connection interruptions like if the external system goes offline, I need a listener to detect that and perform corresponding actions. Kindly let me know if I can achieve this in Java. Preferably in Java 8.
Currently i'm not getting any exception if I get into any such situation. I having the below code currently
Client client = ClientBuilder.newClient();
WebTarget target = client.target(HOSTNAME);
Invocation.Builder requestBuilder;
requestBuilder = target.path(URL).request(MediaType.APPLICATION_JSON)
.header(HEADER_AUTHORIZATION, AUTH_TOKEN);
Response response = null;
if (HTTP_POST.equalsIgnoreCase(method)) {
try{
response = requestBuilder.post(Entity.entity(message, MediaType.APPLICATION_JSON_TYPE));
}catch(Exception ex ){
ex.printStackTrace();
}
} else if (HTTP_GET.equalsIgnoreCase(method)) {
response = requestBuilder.get();
}
String executeMessage = null;
if(response != null){
if (response.getStatus() == 200) {
executeMessage = response.readEntity(String.class);
return new JSONObject(executeMessage);
} else {
executeMessage = response.readEntity(String.class);
final JSONObject status = new JSONObject();
status.put(STATUS_CODE, response.getStatus());
status.put(STATUS_INFO, response.getStatusInfo());
status.put("response", executeMessage);
final JSONObject error = new JSONObject();
error.put(ERROR, status);
return error;
}
}
If you use Spring Boot you can try a declarative REST client called Feign:
@FeignClient(url = "example.com", fallback = YourTestFeignClient.YourTestFeignClientFallback.class)
public interface YourTestFeignClient {
@RequestMapping(method = RequestMethod.POST, value = "/example/path/to/resource/{id}")
YourTestResponse requestExternalResource(@RequestParam("id") Long id, SomeRequestDTO requestDTO);
@Component
public static class YourTestFeignClientFallback implements YourTestFeignClient {
@Override
public YourTestResponse requestExternalResource(Long id, SomeRequestDTO requestDTO) {
YourTestResponse testResponse = new YourTestResponse();
testResponse.setMessage("Service unavailable");
return testResponse;
}
}
}
All you need to do here is to inject YourTestFeignClient in your code and invoke method requestExternalResource on it. This will call POST example.com/example/path/to/resource/34with JSON body taken from SomeRequestDTO. In case a request fails a fallback method inside YourTestFeignClientFallback will get called, which then returns some default data.
If you want to constantly check external REST service whether it is offline you have to setup some sort of periodical ping request. Any response will mean that service is online. Absence of response during some period of time will mean that something is wrong.
The problem you are facing rises from that java TCP Socket connect method is blocking and java socket default connect timeout is 0, which is actually infinity as it is said in javadoc.
So that means that you won't get any response at all by default if the service is offline.
The only correct and simple option here is to set a timeout. In your case the easiest way would be to use Jersey Client property setup, like this:
Client client = ClientBuilder.newClient();
// One second timeout may not be a really good choice unless your network is really fast
client.property(ClientProperties.CONNECT_TIMEOUT, 1000);
And only in this case you will get an exception, which will indicate, that REST service you are trying to ping is not accepting connections.
Set timeout with caution according to the real network capabilities, in some cases it should be more than 5 or even 15 seconds (e.g. WiFi and GPRS connections).
You could create your own Listener and make your Http calls async with the results passed back to the calling class once the HTTP response/error is ready. For example (with typos):
Create an interface that your main class will implement and your Http Client will make use of...
public interface MyHttpListener {
public httpComplete(MyHttpResults results);
}
Implement in your main class.
public MyClass implements MyHttpListener {
public void processHttpRequests(){
for(int i=0; i<10; i++){
// instantiate your Http Client class
HttpClient client = new HttpClient();
// register the listener
client.addHttpListener(this);
// execute whatever URL you want and you are notified later when complete
client.executeRequest("http://whatever");
}
}
public httpRequestComplete(MyHttpResults results) {
// do something with the results
results.getResponseCode();
results.getRawResponse();
results.whatever();
}
}
Add method to your HttpClient to accept listeners
public class MyHttpClient {
List<MyHttpListener> httpListenerList = new ArrayList();
// register listeners
public void addHttpListener(MyHttpListener listener){
httpListenerList.add(listener);
}
// this is the method that processes the request
public void executeRequest(String url) {
// do whatever you were doing previously here
// optional POJO to wrap the results and/or exceptions
MyHttpResults results = new MyHttpResults();
results.withResponseCode(response.getResponseCode());
results.withResponse(responseAsString);
results.withException(ex);
results.withWhatever(whatever);
// notify listeners
notify(results);
}
public void notify(MyHttpResults results){
// notify listeners
for(MyHttpListener listener : httpListenerList){
listener.httpComplete(results);
}
}
}