A java.net.UnknownHostException occurs after following the instructions below:
Instructions:
Why does this happen? I imagine that should not happen.
Simple Code:
public class TestUrlConnection{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
createAndShowGui();
}
});
}
private static void createAndShowGui(){
final JFrame frame = new JFrame("Test URL Connection");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btOk = new JButton("Perform Test");
btOk.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
try{
String content = readContentFromTestUrl();
if(content!=null)
JOptionPane.showMessageDialog(frame, "OK. URL Connection returned Content.\nContent length = "+content.length());
else
JOptionPane.showMessageDialog(frame, "Content is null, but no exception");
}
catch(IOException exc){
JOptionPane.showMessageDialog(frame, "Exception:\n\n"+stackTraceToString(exc));
}
}
});
frame.setContentPane(btOk);
frame.setMinimumSize(new Dimension(250,100));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static String readContentFromTestUrl() throws IOException{
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
URL url = new URL("http://test.com");
URLConnection urlConnection = url.openConnection();
urlConnection.setUseCaches(false);
is = urlConnection.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String inputLine;
String content = "";
while ((inputLine = br.readLine()) != null)
content += inputLine + "\n";
return content;
}
finally{
if(is!=null){try{is.close();}catch(IOException e){e.printStackTrace();}}
if(isr!=null){try{isr.close();}catch(IOException e){e.printStackTrace();}}
if(br!=null){try{br.close();}catch(IOException e){e.printStackTrace();}}
}
}
private static String stackTraceToString(IOException exc){
exc.printStackTrace();
StringWriter sw = new StringWriter();
exc.printStackTrace(new PrintWriter(sw));
String s = sw.toString();
return s.substring(0, s.length()>600 ? 600 : s.length());
}
}
DNS queries are expensive and their results changes rarely, so almost every network implementations cache the DNS lookup results so that if you open 100 connections in a few seconds it does not have to do 100 DNS queries returning the same IP address.
Java implementation is not different, and it caches both positive and negative (failed) queries.
By default negative results gets cached for 10 seconds, but obviously your test pointed out that :
So, what happens is that Java caches that test.com is unresolvable. It should be there only for 10 seconds, so it's placed there with a timestamp. The you change the clock, and this timestamp instead of invalidating after 10 seconds, probably invalidates after 14 days and 10 seconds.
You can see it is using a cached value because the first click on the button takes a lot of time, while the other clicks are almost istantaneous.
One simple solution, that also proves the problem is in the DNS cache, is to add this line as first line in your main :
java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "0");
This tells java not to cache negative DNS results, and if you try you'll see it will behave as expected. However, disabling such caches can reduce your performances a lot, and cause security problems, so I would rather advice to restart your JVM (and most other long-running processes) if you suddenly change the date of your machines.