The standard response on stack overflow is to use the following pattern to get a network address. In my version here if we can't resolve the name then we are assuming we are running on a developers laptop on VPN so all the tests are run on the same machine. (Hence localhost)
String hostName = "localhost"; try { InetAddress addr = InetAddress.getLocalHost(); String suggestedName = addr.getCanonicalHostName(); // Rough test for IP address, if IP address assume a local lookup // on VPN if (!suggestedName.matches("(\\d{1,3}\\.?){4}") && !suggestedName.contains(":")) { hostName = suggestedName; } } catch (UnknownHostException ex) { } System.out.println(hostName);
The problem comes is that we have to trust the local machine settings, for example /etc/hostname, which can result in a network name that is not accessible from another machine. To counter this I wrote the following code to work over the available network interfaces to find a remotely addressable network address name that can be used to talk back to this machine. (I could use an IP address but they are harder to remember, particularly as we are moving towards IPv6)
String hostName = stream(wrap(NetworkInterface::getNetworkInterfaces).get()) // Only alllow interfaces that are functioning .filter(wrap(NetworkInterface::isUp)) // Flat map to any bound addresses .flatMap(n -> stream(n.getInetAddresses())) // Fiter out any local addresses .filter(ia -> !ia.isAnyLocalAddress() && !ia.isLinkLocalAddress() && !ia.isLoopbackAddress()) // Map to a name .map(InetAddress::getCanonicalHostName) // Ignore if we just got an IP back .filter(suggestedName -> !suggestedName.matches("(\\d{1,3}\\.?){4}") && !suggestedName.contains(":")) .findFirst() // In my case default to localhost .orElse("localhost"); System.out.println(hostName);
You might notice there a are a few support methods being used in there to tidy up the code, here are the required support methods if you are interested.
@FunctionalInterface public interface ThrowingPredicate<T, E extends Exception>{ boolean test(T t) throws E; } @FunctionalInterface public interface ThrowingSupplier<T, E extends Exception>{ T get() throws E; } public static <T, E extends Exception> Predicate<T> wrap(ThrowingPredicate<T, E> th) { return t -> { try { return th.test(t); } catch (Exception ex) { throw new RuntimeException(ex); } }; } public static <T, E extends Exception> Supplier<T> wrap(ThrowingSupplier<T, E> th) { return () -> { try { return th.get(); } catch (Exception ex) { throw new RuntimeException(ex); } }; } // http://stackoverflow.com/a/23276455 public static <T> Stream<T> stream(Enumeration<T> e) { return StreamSupport.stream( Spliterators.spliteratorUnknownSize( new Iterator<T>() { public T next() { return e.nextElement(); } public boolean hasNext() { return e.hasMoreElements(); } }, Spliterator.ORDERED), false); }
No comments:
Post a Comment