2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
7 package gov
.nasa
.worldwind
.util
;
9 import gov
.nasa
.worldwind
.avlist
.*;
10 import gov
.nasa
.worldwind
.Configuration
;
13 import java
.util
.concurrent
.ConcurrentHashMap
;
14 import java
.util
.concurrent
.atomic
.*;
15 import java
.io
.IOException
;
18 * Provides tracking of per-host network availability. Host computers that fail network requests can be logged to this
19 * class' tracking list. When a host has been logged a specified number of times, it is marked as unreachable. Users can
20 * query instances of this class to determine whether a host has been marked as unreachable.
22 * Users are expected to invoke this class' {@link #logUnavailableHost(java.net.URL)} method when an attempt to contact
23 * a host fails. Each invocation increments the failure count by one. When the count exceeds the attempt limit, the host
24 * is marked as unreachable. When attempts to contact the host <em>are</em> successful, users should invoke this class'
25 * {@link #logAvailableHost(java.net.URL)} method to clear its status.
27 * A host may become reachable at a time subsequent to its being logged. To detect this, this class will mark a host as
28 * not unreachable after a specifiable interval of time. If the host is once more logged as unavailable, its entry will
29 * return to the unavailable state. This cycle continues indefinitely.
31 * Methods are also provided to determine whether the public network can be reached and whether the NASA World Wind
32 * servers cab be reached.
35 * @version $Id: BasicNetworkStatus.java 3735 2007-12-06 02:20:43Z tgaskins $
37 public class BasicNetworkStatus
extends AVListImpl
implements NetworkStatus
39 private static final long DEFAULT_TRY_AGAIN_INTERVAL
= (long) 12e3
; // seconds
40 private static final int DEFAULT_ATTEMPT_LIMIT
= 10; // number of unavailable events to declare host unavailable
41 private static final String
[] networkTestSites
= new String
[]
42 {"www.nasa.gov", "worldwind.arc.nasa.gov", "google.com", "microsoft.com", "yahoo.com"};
43 private static final long NETWORK_STATUS_REPORT_INTERVAL
= (long) 60e3
;
45 private static class HostInfo
47 private final long tryAgainInterval
;
48 private final int attemptLimit
;
49 private AtomicInteger logCount
= new AtomicInteger();
50 private AtomicLong lastLogTime
= new AtomicLong();
52 private HostInfo(int attemptLimit
, long tryAgainInterval
)
54 this.lastLogTime
.set(System
.currentTimeMillis());
56 this.tryAgainInterval
= tryAgainInterval
;
57 this.attemptLimit
= attemptLimit
;
60 private boolean isUnavailable()
62 return this.logCount
.get() >= this.attemptLimit
;
65 private boolean isTimeToTryAgain()
67 return System
.currentTimeMillis() - this.lastLogTime
.get() >= this.tryAgainInterval
;
71 private ConcurrentHashMap
<String
, HostInfo
> hostMap
= new ConcurrentHashMap
<String
, HostInfo
>();
73 private AtomicLong tryAgainInterval
= new AtomicLong(DEFAULT_TRY_AGAIN_INTERVAL
);
74 private AtomicInteger attemptLimit
= new AtomicInteger(DEFAULT_ATTEMPT_LIMIT
);
76 // Fields for determining overall network status.
77 private boolean offlineMode
;
78 private AtomicLong lastUnavailableLogTime
= new AtomicLong(System
.currentTimeMillis());
79 private AtomicLong lastAvailableLogTime
= new AtomicLong(System
.currentTimeMillis() + 1);
80 private AtomicLong lastNetworkCheckTime
= new AtomicLong(System
.currentTimeMillis());
81 private AtomicLong lastNetworkStatusReportTime
= new AtomicLong(0);
82 private AtomicBoolean lastNetworkUnavailableResult
= new AtomicBoolean(false);
84 public BasicNetworkStatus()
86 String oms
= Configuration
.getStringValue(AVKey
.OFFLINE_MODE
, "false");
87 this.offlineMode
= oms
.startsWith("t") || oms
.startsWith("T");
91 * Indicates whether World Wind will attempt to connect to the network to retrieve data or for other reasons.
93 * @return <code>true</code> if World Wind is in off-line mode, <code>false</code> if not.
95 public boolean isOfflineMode()
101 * Indicate whether World Wind should attempt to connect to the network to retrieve data or for other reasons.
102 * The default value for this attribute is <code>false</code>, indicating that the network should be used.
104 * @param offlineMode <code>true</code> if World Wind should use the network, <code>false</code> otherwise
106 public void setOfflineMode(boolean offlineMode
)
108 this.offlineMode
= offlineMode
;
112 * Set the number of times a host must be logged as unavailable before it is marked unavailable in this class.
114 * @param limit the number of log-unavailability invocations necessary to consider the host unreachable.
115 * @throws IllegalArgumentException if the limit is less than 1.
117 public void setAttemptLimit(int limit
)
121 String message
= Logging
.getMessage("NetworkStatus.InvalidAttemptLimit");
122 Logging
.logger().severe(message
);
123 throw new IllegalArgumentException(message
);
126 this.attemptLimit
.set(limit
);
130 * Set the length of time to wait until a host is marked as not unreachable subsequent to its being marked
133 * @param interval The length of time, in milliseconds, to wait to unmark a host as unreachable.
134 * @throws IllegalArgumentException if the interval is less than 0.
136 public void setTryAgainInterval(long interval
)
140 String message
= Logging
.getMessage("NetworkStatus.InvalidTryAgainInterval");
141 Logging
.logger().severe(message
);
142 throw new IllegalArgumentException(message
);
145 this.tryAgainInterval
.set(interval
);
149 * Returns the number of times a host must be logged as unavailable before it is marked unavailable in this class.
153 public int getAttemptLimit()
155 return this.attemptLimit
.get();
159 * Returns the length of time to wait until a host is marked as not unreachable subsequent to its being marked
162 * @return the interval, in milliseconds.
164 public long getTryAgainInterval()
166 return this.tryAgainInterval
.get();
170 * Log a host as unavailable. Each invocation increments the host's attempt count. When the count equals or exceeds
171 * the attempt limit, the host is marked as unavailable.
173 * @param url a url containing the host to mark as unavailable.
175 public void logUnavailableHost(URL url
)
177 if (this.offlineMode
)
182 String message
= Logging
.getMessage("nullValue.URLIsNull");
183 Logging
.logger().severe(message
);
184 throw new IllegalArgumentException(message
);
187 String hostName
= url
.getHost();
188 if (this.hostMap
.containsKey(hostName
))
190 HostInfo hi
= this.hostMap
.get(hostName
);
191 if (!hi
.isUnavailable())
192 hi
.logCount
.incrementAndGet();
193 hi
.lastLogTime
.set(System
.currentTimeMillis());
197 HostInfo hi
= new HostInfo(this.attemptLimit
.get(), this.tryAgainInterval
.get());
198 this.hostMap
.put(hostName
, hi
);
201 this.lastUnavailableLogTime
.set(System
.currentTimeMillis());
205 * Log a host as available. Each invocation causes the host to no longer be marked as unavailable. Its
206 * unavailability count is effectively set to 0.
208 * @param url a url containing the host to mark as available.
210 public void logAvailableHost(URL url
)
212 if (this.offlineMode
)
217 String message
= Logging
.getMessage("nullValue.URLIsNull");
218 Logging
.logger().severe(message
);
219 throw new IllegalArgumentException(message
);
222 String hostName
= url
.getHost();
223 if (this.hostMap
.containsKey(hostName
))
224 this.hostMap
.remove(hostName
);
226 this.lastAvailableLogTime
.set(System
.currentTimeMillis());
230 * Indicates whether the host has been marked as unavailable. To be marked unavailable a host's attempt count must
231 * exceed the specified attempt limit.
233 * @param url a url containing the host to check for availability.
234 * @return true if the host is marked as unavailable, otherwise false.
236 public boolean isHostUnavailable(URL url
)
238 if (this.offlineMode
)
243 String message
= Logging
.getMessage("nullValue.URLIsNull");
244 Logging
.logger().severe(message
);
245 throw new IllegalArgumentException(message
);
248 String hostName
= url
.getHost();
249 if (!this.hostMap
.containsKey(hostName
))
252 HostInfo hi
= this.hostMap
.get(hostName
);
253 if (hi
.isTimeToTryAgain())
255 this.removeKey(hostName
);
259 return hi
.isUnavailable();
263 * Indicates whether a public network can be reached or has been reached in the previous five seconds.
265 * @return false if the network can be reached or has been reached in the previous five seconds, otherwise true.
267 public boolean isNetworkUnavailable()
269 return this.offlineMode
|| this.isNetworkUnavailable(5000L);
273 * Indicates whether a public network can be reached or has been reached in a specified previous amount of time.
275 * @param checkInterval the number of milliseconds in the past used to determine whether the server was avaialble
277 * @return false if the network can be reached or has been reached in a specified time, otherwise true.
279 public boolean isNetworkUnavailable(long checkInterval
)
281 if (this.offlineMode
)
284 // If there's been success since failure, network assumed to be reachable.
285 if (this.lastAvailableLogTime
.get() > this.lastUnavailableLogTime
.get())
287 this.lastNetworkUnavailableResult
.set(false);
288 return this.lastNetworkUnavailableResult
.get();
291 long now
= System
.currentTimeMillis();
293 // If there's been success recently, network assumed to be reachable.
294 if (!this.lastNetworkUnavailableResult
.get() && now
- this.lastAvailableLogTime
.get() < checkInterval
)
296 return this.lastNetworkUnavailableResult
.get();
299 // If query comes too soon after an earlier one that addressed the network, return the earlier result.
300 if (now
- this.lastNetworkCheckTime
.get() < checkInterval
)
302 return this.lastNetworkUnavailableResult
.get();
305 this.lastNetworkCheckTime
.set(now
);
307 if (!this.isWorlWindServerUnavailable())
309 this.lastNetworkUnavailableResult
.set(false); // network not unreachable
310 return this.lastNetworkUnavailableResult
.get();
313 for (String testHost
: networkTestSites
)
315 if (this.isHostReachable(testHost
))
318 this.lastNetworkUnavailableResult
.set(false); // network not unreachable
319 return this.lastNetworkUnavailableResult
.get();
324 if (now
- this.lastNetworkStatusReportTime
.get() > NETWORK_STATUS_REPORT_INTERVAL
)
326 this.lastNetworkStatusReportTime
.set(now
);
327 String message
= Logging
.getMessage("NetworkStatus.NetworkUnreachable");
328 Logging
.logger().info(message
);
331 this.lastNetworkUnavailableResult
.set(true); // if no successful contact then network is unreachable
332 return this.lastNetworkUnavailableResult
.get();
336 * Indicates whether the NASA World Wind servers can be reached.
338 * @return false if the servers can be reached, otherwise true.
340 public boolean isWorlWindServerUnavailable()
342 return this.offlineMode
|| !this.isHostReachable("worldwind.arc.nasa.gov");
345 private boolean isHostReachable(String hostName
)
349 // Assume host is unreachable if we can't get its dns entry without getting an exception
350 //noinspection ResultOfMethodCallIgnored
351 InetAddress
.getByName(hostName
);
353 catch (UnknownHostException e
)
355 String message
= Logging
.getMessage("NetworkStatus.UnreachableTestHost", hostName
);
356 Logging
.logger().fine(message
);
361 String message
= Logging
.getMessage("NetworkStatus.ExceptionTestingHost", hostName
);
362 Logging
.logger().info(message
);
366 // Was able to get internet address, but host still might not be reachable because the address might have been
367 // cached earlier when it was available. So need to try something else.
369 URLConnection connection
= null;
372 URL url
= new URL("http://" + hostName
);
373 Proxy proxy
= WWIO
.configureProxy();
375 connection
= url
.openConnection(proxy
);
377 connection
= url
.openConnection();
379 connection
.setConnectTimeout(2000);
380 String ct
= connection
.getContentType();
384 catch (IOException e
)
386 String message
= Logging
.getMessage("NetworkStatus.ExceptionTestingHost", hostName
);
387 Logging
.logger().info(message
);
391 if (connection
!= null && connection
instanceof HttpURLConnection
)
392 ((HttpURLConnection
) connection
).disconnect();
398 // public static void main(String[] args)
402 // NetworkStatus ns = new BasicNetworkStatus();
403 // boolean tf = ns.isWorlWindServerUnavailable();
404 // tf = ns.isNetworkUnavailable();
406 // catch (Exception e)
408 // e.printStackTrace();