blob: b6d5f8fe29e73e74c1cb6f5a4856d08027cc4f74 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs.condition;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectComponent;
/**
* <p>Test for a host being reachable using ICMP "ping" packets &amp; echo operations.
* Ping packets are very reliable for assessing reachability in a LAN or WAN,
* but they do not get through any well-configured firewall. Echo (port 7) may.</p>
*
* <p>This condition turns unknown host exceptions into false conditions. This is
* because on a laptop, DNS is one of the first services lost when the network
* goes; you are implicitly offline.</p>
*
* <p>If a URL is supplied instead of a host, the hostname is extracted and used in
* the test--all other parts of the URL are discarded.</p>
*
* <p>The test may not work through firewalls; that is, something may be reachable
* using a protocol such as HTTP, while the lower level ICMP packets get dropped
* on the floor. Similarly, a host may be detected as reachable with ICMP, but not
* reachable on other ports (i.e. port 80), because of firewalls.</p>
*
* @since Ant 1.7
*/
public class IsReachable extends ProjectComponent implements Condition {
/**
* The default timeout.
*/
public static final int DEFAULT_TIMEOUT = 30;
private static final int SECOND = 1000; // millis per second
/**
* Error when no hostname is defined
*/
public static final String ERROR_NO_HOSTNAME = "No hostname defined";
/**
* Error when invalid timeout value is defined
*/
public static final String ERROR_BAD_TIMEOUT = "Invalid timeout value";
/**
* Unknown host message is seen.
*/
private static final String WARN_UNKNOWN_HOST = "Unknown host: ";
/**
* Network error message is seen.
*/
public static final String ERROR_ON_NETWORK = "network error to ";
/** Error message when url and host are specified. */
public static final String ERROR_BOTH_TARGETS
= "Both url and host have been specified";
/** Error message when no reachably test avail. */
public static final String MSG_NO_REACHABLE_TEST
= "cannot do a proper reachability test on this Java version";
/** Error message when an invalid url is used. */
public static final String ERROR_BAD_URL = "Bad URL ";
/** Error message when no hostname in url. */
public static final String ERROR_NO_HOST_IN_URL = "No hostname in URL ";
/**
* The method name to look for in InetAddress
* @deprecated Since 1.10.6
*/
@Deprecated
public static final String METHOD_NAME = "isReachable";
private String host;
private String url;
private int timeout = DEFAULT_TIMEOUT;
/**
* Set the host to ping.
*
* @param host the host to ping.
*/
public void setHost(final String host) {
this.host = host;
}
/**
* Set the URL from which to extract the hostname.
*
* @param url a URL object.
*/
public void setUrl(final String url) {
this.url = url;
}
/**
* Set the timeout for the reachability test in seconds.
*
* @param timeout the timeout in seconds.
*/
public void setTimeout(final int timeout) {
this.timeout = timeout;
}
/**
* emptyness test
*
* @param string param to check
*
* @return true if it is isNullOrEmpty
*/
private boolean isNullOrEmpty(final String string) {
return string == null || string.isEmpty();
}
/**
* Evaluate the condition.
*
* @return true if the condition is true.
*
* @throws BuildException
* if an error occurs
*/
@Override
public boolean eval() throws BuildException {
if (isNullOrEmpty(host) && isNullOrEmpty(url)) {
throw new BuildException(ERROR_NO_HOSTNAME);
}
if (timeout < 0) {
throw new BuildException(ERROR_BAD_TIMEOUT);
}
String target = host;
if (!isNullOrEmpty(url)) {
if (!isNullOrEmpty(host)) {
throw new BuildException(ERROR_BOTH_TARGETS);
}
try {
//get the host of a url
final URL realURL = new URL(url);
target = realURL.getHost();
if (isNullOrEmpty(target)) {
throw new BuildException(ERROR_NO_HOST_IN_URL + url);
}
} catch (final MalformedURLException e) {
throw new BuildException(ERROR_BAD_URL + url, e);
}
}
log("Probing host " + target, Project.MSG_VERBOSE);
InetAddress address;
try {
address = InetAddress.getByName(target);
} catch (final UnknownHostException e1) {
log(WARN_UNKNOWN_HOST + target);
return false;
}
log("Host address = " + address.getHostAddress(),
Project.MSG_VERBOSE);
boolean reachable;
try {
reachable = address.isReachable(timeout * SECOND);
} catch (final IOException ioe) {
reachable = false;
log(ERROR_ON_NETWORK + target + ": " + ioe.toString());
}
log("host is" + (reachable ? "" : " not") + " reachable", Project.MSG_VERBOSE);
return reachable;
}
}