tags:

views:

133

answers:

4

I need a monitor class that regularly checks whether a given HTTP URL is available. I can take care of the "regularly" part using the Spring TaskExecutor abstraction, so that's not the topic here. The Question is: What is the preferred way to ping a URL in java?

Here is my current code as a starting point:

try{
    final URLConnection connection = new URL(url).openConnection();
    connection.connect();
    LOG.info("Service " + url + " available, yeah!");
    available = true;
} catch(final MalformedURLException e){
    throw new IllegalStateException("Bad URL: " + url, e);
} catch(final IOException e){
    LOG.info("Service " + url + " unavailable, oh no!", e);
    available = false;
}
  1. Is this any good at all (will it do what I want?)
  2. Do I have to somehow close the connection?
  3. I suppose this is a GET request. Is there a way to send HEAD instead?
+4  A: 

You could also use HttpURLConnection, which allows you to set the request method (to HEAD for example). Here's an example that shows how to send a request, read the response, and disconnect.

Bill the Lizard
+4  A: 
  1. You can do so. Another feasible way is using java.net.Socket.

    Socket socket = null;
    boolean reachable = false;
    try {
        socket = new Socket(hostnameOrIP, 80);
        reachable = true;
    } finally {            
        if (socket != null) try { socket.close(); } catch(IOException e) {}
    }
    

    There's also the InetAddress#isReachable():

    boolean reachable = InetAddress.getByName(hostname).isReachable();
    

    This however doesn't explicitly test port 80. You risk to get false negatives due to a Firewall blocking other ports.

  2. No, you don't explicitly need. It's handled and pooled under the hoods.

  3. You can cast the obtained URLConnection to HttpURLConnection and then use setRequestMethod() to set the request method. However, you need to take into account that some servers might return HTTP 405 error for a HEAD (i.e. not available, not implemented, not allowed) while a GET works perfectly fine. So it's not a good test.


Update as per the comments: connecting a host only informs if the host is available, not if the content is available. You seem to be more interested in the content since it can as good happen that a webserver has started without problems, but the webapp failed to deploy during server's start. This will however usually not cause the entire server to go down. So you'd like to determine the HTTP response code.

HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("HEAD");
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
    // Not OK.
}

// < 100 is undertermined.
// 1nn is informal (shouldn't happen on a GET/HEAD)
// 2nn is success
// 3nn is redirect
// 4nn is client error
// 5nn is server error

For more detail about response status codes see RFC 2616 section 10. Calling connect() is by the way not needed if you're determining the response data. It will implicitly connect.

BalusC
Thanks for the details, answers like these are what makes SO a great place. Testing the server for availability is not enough in my case, I need to test the URL (the webapp may not be deployed), so I'll stick with the HttpURLConnection. About HEAD not being a good test: it is a good method if I know the target URL supports HEAD, I'll check that.
seanizer
If that's the functional requirement, then the `HttpURLConnection` is the best way to go. You'd namely like to determine the response code as well. You can also do this using `Socket` but that only adds verbosity and requires knowledge of HTTP spec.
BalusC
A: 

Instead of using URLConnection use HttpURLConnection by calling openConnection() on your URL object.

Then use getResponseCode() will give you the HTTP response once you've read from the connection.

here is code:

    HttpURLConnection connection = null;
    try {
        URL u = new URL("http://www.google.com/");
        connection = (HttpURLConnection) u.openConnection();
        connection.setRequestMethod("HEAD");
        int code = connection.getResponseCode();
        System.out.println("" + code);
        // You can determine on HTTP return code received. 200 is success.
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        if (connection != null) {
            connection.disconnect();
        }
    }

Also check similar question http://stackoverflow.com/questions/1378199/how-to-check-if-a-url-exists-or-returns-404-with-java

Hope this helps.

YoK
A: 

Consider using the Restlet framework, which has great semantics for this sort of thing. It's powerful and flexible.

The code could be as simple as:

Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
    // uh oh!
}
Avi Flax