10

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;
        }
    }
Gautam R
  • 326
  • 1
  • 4
  • 14
  • 1
    You'll get an IOException, which you'll have to catch, so put any special code in there. – Steve Smith Apr 04 '17 at 11:35
  • 1
    Some more details of what framework you are using to make the HTTP request and a code snippet of what the calling code is like will help you getting more useful answers. – Michael Peyper Apr 04 '17 at 11:47
  • @Michael Peyper - I have updated with the code. Steve Smith - Currently i'm not getting any exception, system waits for the response. – Gautam R Apr 04 '17 at 12:21
  • @Gautam R You just need to add a timeout. TCP has very good error-detection already built in. – Steve Smith Apr 05 '17 at 09:43
  • Possible duplicate of [How to set the connection timeout with Jersey 2](http://stackoverflow.com/questions/19543209/how-to-set-the-connection-timeout-with-jersey-2) – ssan Apr 05 '17 at 20:24
  • @Steve Smith & user3915609 - I would like to know if there are any listeners or any flags in Java other than timeout for this scenario. Kindly suggest if there are any such listeners or approaches other than timeout. – Gautam R Apr 06 '17 at 08:07
  • What client are you using? I used Apache client and detecting network failures was my problem until I set timeout (there is no by default). And with timeout it began raising exceptions when there were some troubles. I think you can check for timeout settings in your client and give it a try. – ba3a Aug 24 '17 at 14:18

3 Answers3

1

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.

Danylo Zatorsky
  • 5,856
  • 2
  • 25
  • 49
0

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);
      }
  }


 }
Matt
  • 363
  • 3
  • 11
0

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).

Клаус Шварц
  • 3,158
  • 28
  • 44