All tests run against localhost. This *should* work everywhere, but no doubt someone with a confused /etc/hosts or no IPv4 stack will have different opinions. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277887 13f79535-47bb-0310-9956-ffa450edef68master
@@ -537,7 +537,11 @@ Check for Xerces-specific definition of the location of the no namespace schema. | |||
<p>Uses Java1.5+ networking APIs to probe for a (remote) system being | |||
reachable. Exactly what probe mechanisms are used is an implementation | |||
feature of the JVM. They may include ICMP "ping" packets | |||
feature of the JVM. They may include ICMP "ping" packets, UDP or TCP connections | |||
to port 7 "echo service" or other means. On Java1.4 and earlier, being able | |||
to resolve the hostname is considered success. This means that if DNS is not | |||
working or a URL/hostname is bad, the test will fail, but otherwise succeed | |||
even if the remote host is actually absent. | |||
</p> | |||
<p> | |||
@@ -0,0 +1,104 @@ | |||
<project name="isreachable"> | |||
<!-- | |||
* Copyright 2005 The Apache Software Foundation | |||
* | |||
* Licensed 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 | |||
* | |||
* http://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. | |||
* | |||
--> | |||
<macrodef name="assertHostReachable"> | |||
<attribute name="host"/> | |||
<sequential> | |||
<fail message="not reachable: @{host}"> | |||
<condition> | |||
<not> | |||
<isreachable host="@{host}"/> | |||
</not> | |||
</condition> | |||
</fail> | |||
</sequential> | |||
</macrodef> | |||
<macrodef name="assertHostNotReachable"> | |||
<attribute name="host"/> | |||
<sequential> | |||
<fail message="unexpectedly reachable: @{host}"> | |||
<condition> | |||
<isreachable host="@{host}"/> | |||
</condition> | |||
</fail> | |||
</sequential> | |||
</macrodef> | |||
<macrodef name="assertUrlReachable"> | |||
<attribute name="url"/> | |||
<sequential> | |||
<fail message="not reachable: @{url}"> | |||
<condition> | |||
<not> | |||
<isreachable url="@{url}"/> | |||
</not> | |||
</condition> | |||
</fail> | |||
</sequential> | |||
</macrodef> | |||
<target name="testLocalhost"> | |||
<assertHostReachable host="localhost"/> | |||
</target> | |||
<!-- bugs in XPSP2 mean this is the only IPv4 loopback addr allowed --> | |||
<target name="testIpv4localhost"> | |||
<assertHostReachable host="127.0.0.1"/> | |||
</target> | |||
<target name="testBoth"> | |||
<condition property="both"> | |||
<isreachable host="localhost" url="http://localhost"/> | |||
</condition> | |||
<fail>Expected failure before here</fail> | |||
</target> | |||
<target name="testLocalhostURL"> | |||
<assertUrlReachable url="http://localhost"/> | |||
</target> | |||
<target name="testIpv4localhostURL"> | |||
<assertUrlReachable url="http://127.0.0.1/"/> | |||
</target> | |||
<target name="testFTPURL"> | |||
<assertUrlReachable url="ftp://localhost"/> | |||
</target> | |||
<target name="testFile"> | |||
<assertUrlReachable url="file://build.xml"/> | |||
</target> | |||
<target name="testBadURL"> | |||
<assertUrlReachable url="uuid:3349-4404-0ac0ddee"/> | |||
</target> | |||
<target name="testBadTimeout"> | |||
<condition property="testBadTimeout"> | |||
<isreachable host="localhost" timeout="-1"/> | |||
</condition> | |||
</target> | |||
<target name="testNoTargets"> | |||
<condition property="none"> | |||
<isreachable/> | |||
</condition> | |||
</target> | |||
</project> |
@@ -15,42 +15,43 @@ | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.condition; | |||
package org.apache.tools.ant.taskdefs.condition; | |||
import org.apache.tools.ant.ProjectComponent; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.taskdefs.condition.Condition; | |||
import org.apache.tools.ant.ProjectComponent; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import java.net.InetAddress; | |||
import java.net.UnknownHostException; | |||
import java.net.URL; | |||
import java.net.MalformedURLException; | |||
import java.io.IOException; | |||
import java.net.URL; | |||
import java.net.UnknownHostException; | |||
/** | |||
* Test for a host being reachable using ICMP "ping" packets. | |||
* Test for a host being reachable using ICMP "ping" packets & 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. | |||
* but they do not get through any well-configured firewall. Echo (port 7) may. | |||
* <p/> | |||
* This condition turns unknown host exceptions into false conditions. This is | |||
* because on a laptop, DNS is one of the first services when the network goes; you | |||
* are implicitly offline. | |||
* because on a laptop, DNS is one of the first services when the network goes; | |||
* you are implicitly offline. | |||
* <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. | |||
* 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/> | |||
* 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 detected as reachable with ICMP, but | |||
* not reachable on other ports (i.e. port 80), because of firewalls. | |||
* on the floor. Similarly, a host may detected as reachable with ICMP, but not | |||
* reachable on other ports (i.e. port 80), because of firewalls. | |||
* <p/> | |||
* Requires Java1.5+ to work | |||
* Requires Java1.5+ to work properly. On Java1.4 and earlier, if a hostname is | |||
* resolveable, the destination is assumed to be reachable. | |||
* | |||
* @ant.condition name="isreachable" | |||
* @since Ant1.7 | |||
*/ | |||
public class IsPingable extends ProjectComponent implements Condition { | |||
public class IsReachable extends ProjectComponent implements Condition { | |||
private String host; | |||
private String url; | |||
@@ -71,12 +72,15 @@ public class IsPingable extends ProjectComponent implements Condition { | |||
/** | |||
* Unknown host message is seen. | |||
*/ | |||
public static final String ERROR_UNKNOWN_HOST = "Unknown host:"; | |||
public static final String WARN_UNKNOWN_HOST = "Unknown host:"; | |||
/** | |||
* Network error message is seen. | |||
*/ | |||
public static final String ERROR_ON_NETWORK = "network error to "; | |||
public static final String ERROR_BOTH_TARGETS = "Both url and host have been specified"; | |||
public static final String MSG_NO_REACHABLE_TEST = "cannot do a proper reachability test on this Java version"; | |||
public static final String ERROR_BAD_URL = "Bad URL "; | |||
public static final String ERROR_NO_HOST_IN_URL = "No hostname in URL "; | |||
/** | |||
* The host to ping. | |||
@@ -109,16 +113,20 @@ public class IsPingable extends ProjectComponent implements Condition { | |||
* emptyness test | |||
* | |||
* @param string param to check | |||
* | |||
* @return true if it is empty | |||
*/ | |||
private boolean empty(String string) { | |||
return string == null || string.length() == 0; | |||
} | |||
private static Class[] parameterTypes = {Integer.class}; | |||
/** | |||
* Is this condition true? | |||
* | |||
* @return true if the condition is true. | |||
* | |||
* @throws org.apache.tools.ant.BuildException | |||
* if an error occurs | |||
*/ | |||
@@ -138,25 +146,54 @@ public class IsPingable extends ProjectComponent implements Condition { | |||
//get the host of a url | |||
URL realURL = new URL(url); | |||
target = realURL.getHost(); | |||
if (empty(target)) { | |||
throw new BuildException(ERROR_NO_HOST_IN_URL + url); | |||
} | |||
} catch (MalformedURLException e) { | |||
throw new BuildException("Bad URL " + url, e); | |||
throw new BuildException(ERROR_BAD_URL + url, e); | |||
} | |||
} | |||
log("Probing host " + target, Project.MSG_VERBOSE); | |||
InetAddress address; | |||
try { | |||
log("Probing host " + target, Project.MSG_VERBOSE); | |||
InetAddress address = InetAddress.getByName(target); | |||
log("Host address =" + address.getHostAddress(), | |||
Project.MSG_VERBOSE); | |||
final boolean reachable = address.isReachable(timeout * 1000); | |||
log("host is " + (reachable ? "" : "not") + " reachable", | |||
Project.MSG_VERBOSE); | |||
return reachable; | |||
} catch (UnknownHostException e) { | |||
log(ERROR_UNKNOWN_HOST + target); | |||
return false; | |||
} catch (IOException e) { | |||
log(ERROR_ON_NETWORK + target + ": " + e.toString()); | |||
log(WARN_UNKNOWN_HOST + target); | |||
address = InetAddress.getByName(target); | |||
} catch (UnknownHostException e1) { | |||
return false; | |||
} | |||
log("Host address =" + address.getHostAddress(), | |||
Project.MSG_VERBOSE); | |||
boolean reachable; | |||
//Java1.5: reachable = address.isReachable(timeout * 1000); | |||
Method reachableMethod = null; | |||
try { | |||
reachableMethod = InetAddress.class.getMethod("reachable", | |||
parameterTypes); | |||
Object[] params = new Object[1]; | |||
params[0] = new Integer(timeout * 1000); | |||
try { | |||
reachable = ((Boolean) reachableMethod.invoke(address, params)) | |||
.booleanValue(); | |||
} catch (IllegalAccessException e) { | |||
//utterly implausible, but catered for anyway | |||
throw new BuildException("When calling " + reachableMethod); | |||
} catch (InvocationTargetException e) { | |||
//assume this is an IOexception about un readability | |||
Throwable nested = e.getTargetException(); | |||
log(ERROR_ON_NETWORK + target + ": " + nested.toString()); | |||
//any kind of fault: not reachable. | |||
reachable = false; | |||
} | |||
} catch (NoSuchMethodException e) { | |||
//java1.4 or earlier | |||
log(MSG_NO_REACHABLE_TEST); | |||
reachable = true; | |||
} | |||
log("host is " + (reachable ? "" : "not") + " reachable", | |||
Project.MSG_VERBOSE); | |||
return reachable; | |||
} | |||
} |
@@ -37,7 +37,7 @@ assertions=org.apache.tools.ant.types.Assertions | |||
concatfilter=org.apache.tools.ant.filters.ConcatFilter | |||
issigned=org.apache.tools.ant.taskdefs.condition.IsSigned | |||
isfileselected=org.apache.tools.ant.taskdefs.condition.IsFileSelected | |||
isreachable=org.apache.tools.ant.taskdefs.optional.condition.IsPingable | |||
isreachable=org.apache.tools.ant.taskdefs.condition.IsReachable | |||
mavenrepository=org.apache.tools.ant.taskdefs.repository.MavenRepository | |||
scriptselector=org.apache.tools.ant.types.optional.ScriptSelector | |||
scriptcondition=org.apache.tools.ant.types.optional.ScriptCondition | |||
@@ -0,0 +1,81 @@ | |||
/* | |||
* Copyright 2005 The Apache Software Foundation | |||
* | |||
* Licensed 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 | |||
* | |||
* http://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 org.apache.tools.ant.BuildFileTest; | |||
/** | |||
* test for reachable things | |||
*/ | |||
public class IsReachableTest extends BuildFileTest { | |||
public IsReachableTest(String name) { | |||
super(name); | |||
} | |||
public void setUp() { | |||
configureProject( | |||
"src/etc/testcases/taskdefs/conditions/isreachable.xml"); | |||
} | |||
public void testLocalhost() throws Exception { | |||
executeTarget("testLocalhost"); | |||
} | |||
public void testLocalhostURL() throws Exception { | |||
executeTarget("testLocalhostURL"); | |||
} | |||
public void testIpv4localhost() throws Exception { | |||
executeTarget("testIpv4localhost"); | |||
} | |||
public void testFTPURL() throws Exception { | |||
executeTarget("testFTPURL"); | |||
} | |||
public void testBoth() throws Exception { | |||
expectBuildExceptionContaining("testBoth", | |||
"error on two targets", | |||
IsReachable.ERROR_BOTH_TARGETS); | |||
} | |||
public void testNoTargets() throws Exception { | |||
expectBuildExceptionContaining("testNoTargets", | |||
"no params", | |||
IsReachable.ERROR_NO_HOSTNAME); | |||
} | |||
public void testBadTimeout() throws Exception { | |||
expectBuildExceptionContaining("testBadTimeout", | |||
"error on -ve timeout", | |||
IsReachable.ERROR_BAD_TIMEOUT); | |||
} | |||
public void NotestFile() throws Exception { | |||
expectBuildExceptionContaining("testFile", | |||
"error on file URL", | |||
IsReachable.ERROR_NO_HOST_IN_URL); | |||
} | |||
public void testBadURL() throws Exception { | |||
expectBuildExceptionContaining("testBadURL", | |||
"error in URL", | |||
IsReachable.ERROR_BAD_URL); | |||
} | |||
} |