package com.bugsnag.callbacks;

import com.bugsnag.Report;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Locale;

public class DeviceCallback implements Callback {

    private static volatile String hostname;
    private static transient volatile boolean hostnameInitialised;
    private static final Object LOCK = new Object();

    /**
     * Memoises the hostname, as lookup can be expensive
     */
    public static String getHostnameValue() {
        if (!hostnameInitialised) {
            synchronized (LOCK) {
                if (!hostnameInitialised) {
                    hostname = lookupHostname();
                    hostnameInitialised = true;
                }
            }
        }
        return hostname;
    }

    private static String lookupHostname() {
        // Windows always sets COMPUTERNAME
        if (System.getProperty("os.name").startsWith("Windows")) {
            return System.getenv("COMPUTERNAME");
        }

        // Try the HOSTNAME env variable (most unix systems)
        String hostname = System.getenv("HOSTNAME");
        if (hostname != null) {
            return hostname;
        }

        // Resort to dns hostname lookup
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException ex) {
            // Give up
        }
        return null;
    }

    public static void initializeCache() {
        getHostnameValue();
    }

    @Override
    public void beforeNotify(Report report) {
        report
                .addToTab("device", "osArch", System.getProperty("os.arch"))
                .addToTab("device", "locale", Locale.getDefault())
                .setDeviceInfo("hostname", getHostnameValue())
                .setDeviceInfo("osName", System.getProperty("os.name"))
                .setDeviceInfo("osVersion", System.getProperty("os.version"));
    }
}

@@ -51,16 +51,61 @@
 .Report;
+%0Aimport com.bugsnag.util.DaemonThreadFactory;
 %0A%0Aimport
@@ -189,16 +189,306 @@
 .Locale;
+%0Aimport java.util.concurrent.Callable;%0Aimport java.util.concurrent.ExecutionException;%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors;%0Aimport java.util.concurrent.Future;%0Aimport java.util.concurrent.TimeUnit;%0Aimport java.util.concurrent.TimeoutException;
 %0A%0Apublic
@@ -696,16 +696,78 @@
 bject();
+%0A    private static final int HOSTNAME_LOOKUP_TIMEOUT = 10000;
 %0A%0A    /*
@@ -1607,16 +1607,17 @@
 e lookup
+.
 %0A       
@@ -1621,102 +1621,789 @@
     
-try %7B%0A            return InetAddress.getLocalHost().getHostName();%0A        %7D catch (UnknownHos
+// Look up the hostname in a daemon thread, with a timeout of HOSTNAME_LOOKUP_TIMEOUT.%0A        // This is to prevent applications hanging waiting for the dns lookup to resolve%0A        ExecutorService lookupService = Executors.newSingleThreadExecutor(new DaemonThreadFactory());%0A        Future%3CString%3E future = lookupService.submit(new Callable%3CString%3E() %7B%0A            @Override%0A            public String call() throws UnknownHostException %7B%0A                return InetAddress.getLocalHost().getHostName();%0A            %7D%0A        %7D);%0A%0A        try %7B%0A            return future.get(HOSTNAME_LOOKUP_TIMEOUT, TimeUnit.MILLISECONDS);%0A        %7D catch (ExecutionException ex) %7B%0A            // Give up%0A        %7D catch (InterruptedException ex) %7B%0A            // Give up%0A        %7D catch (Timeou
 tExc

Implement timeout for dns hostname lookup