1 16 package com.google.gwt.dev.shell; 17 18 import com.google.gwt.dev.About; 19 20 import org.w3c.dom.Document ; 21 import org.w3c.dom.Element ; 22 import org.w3c.dom.Node ; 23 import org.w3c.dom.NodeList ; 24 import org.xml.sax.ErrorHandler ; 25 import org.xml.sax.SAXException ; 26 import org.xml.sax.SAXParseException ; 27 28 import java.io.ByteArrayInputStream ; 29 import java.io.ByteArrayOutputStream ; 30 import java.io.IOException ; 31 import java.io.InputStream ; 32 import java.net.MalformedURLException ; 33 import java.net.URL ; 34 import java.net.URLConnection ; 35 import java.util.Date ; 36 import java.util.prefs.Preferences ; 37 38 import javax.xml.parsers.DocumentBuilder ; 39 import javax.xml.parsers.DocumentBuilderFactory ; 40 import javax.xml.parsers.ParserConfigurationException ; 41 42 46 public abstract class CheckForUpdates { 47 48 51 public static interface UpdateAvailableCallback { 52 void onUpdateAvailable(String html); 53 } 54 55 protected static final String LAST_SERVER_VERSION = "lastServerVersion"; 56 private static final boolean DEBUG_VERSION_CHECK; 57 private static final String FIRST_LAUNCH = "firstLaunch"; 58 private static final String NEXT_PING = "nextPing"; 59 60 63 67 71 75 private static final String QUERY_URL = "http://tools.google.com/webtoolkit/currentversion.xml"; 77 78 private static final int VERSION_PARTS = 3; 79 private static final String VERSION_REGEXP = "\\d+\\.\\d+\\.\\d+"; 80 81 static { 82 boolean debugVersionCheck = false; 85 try { 86 if (System.getProperty("gwt.debugVersionCheck") != null) { 87 debugVersionCheck = true; 88 } 89 } catch (Throwable e) { 90 } finally { 93 DEBUG_VERSION_CHECK = debugVersionCheck; 94 } 95 } 96 97 106 protected static boolean isServerVersionNewer(String clientVersion, 107 String serverVersion) { 108 if (clientVersion == null || serverVersion == null) { 109 return false; 110 } 111 112 if (!clientVersion.matches(VERSION_REGEXP) 114 || !serverVersion.matches(VERSION_REGEXP)) { 115 return false; 116 } 117 118 String [] clientParts = clientVersion.split("\\."); 120 String [] serverParts = serverVersion.split("\\."); 121 if (clientParts.length != VERSION_PARTS 122 || serverParts.length != VERSION_PARTS) { 123 return false; 124 } 125 126 for (int i = 0; i < VERSION_PARTS; ++i) { 128 try { 129 int clientPart = Integer.parseInt(clientParts[i]); 130 int serverPart = Integer.parseInt(serverParts[i]); 131 if (serverPart < clientPart) { 132 return false; 133 } 134 135 if (serverPart > clientPart) { 136 return true; 137 } 138 } catch (NumberFormatException e) { 139 return false; 140 } 141 } 142 143 return false; 144 } 145 146 private static String getTextOfLastElementHavingTag(Document doc, 147 String tagName) { 148 NodeList nodeList = doc.getElementsByTagName(tagName); 149 int n = nodeList.getLength(); 150 if (n > 0) { 151 Element elem = (Element ) nodeList.item(n - 1); 152 Node firstChild = elem.getFirstChild(); 155 if (firstChild != null) { 156 String text = firstChild.getNodeValue(); 157 return text; 158 } 159 } 160 161 return null; 162 } 163 164 private static void parseResponse(Preferences prefs, byte[] response, 165 UpdateAvailableCallback callback) throws IOException , 166 ParserConfigurationException , SAXException { 167 168 if (DEBUG_VERSION_CHECK) { 169 System.out.println("Parsing response (length " + response.length + ")"); 170 } 171 172 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 173 DocumentBuilder builder = factory.newDocumentBuilder(); 174 ByteArrayInputStream bais = new ByteArrayInputStream (response); 175 176 builder.setErrorHandler(new ErrorHandler () { 179 180 public void error(SAXParseException exception) throws SAXException { 181 } 183 184 public void fatalError(SAXParseException exception) throws SAXException { 185 } 187 188 public void warning(SAXParseException exception) throws SAXException { 189 } 191 }); 192 Document doc = builder.parse(bais); 193 194 String version = getTextOfLastElementHavingTag(doc, "latest-version"); 197 if (version == null) { 198 if (DEBUG_VERSION_CHECK) { 201 System.out.println("Failed to find <latest-version>"); 202 } 203 return; 204 } else { 205 version = version.trim(); 206 } 207 208 String [] versionParts = version.split("\\."); 209 if (versionParts.length != 3) { 210 if (DEBUG_VERSION_CHECK) { 213 System.out.println("Bad version format: " + version); 214 } 215 return; 216 } 217 try { 218 Integer.parseInt(versionParts[0]); 219 Integer.parseInt(versionParts[1]); 220 Integer.parseInt(versionParts[2]); 221 } catch (NumberFormatException e) { 222 if (DEBUG_VERSION_CHECK) { 225 System.out.println("Bad version number: " + version); 226 } 227 return; 228 } 229 230 String pingDelaySecsStr = getTextOfLastElementHavingTag(doc, 233 "min-wait-seconds"); 234 int pingDelaySecs = 0; 235 if (pingDelaySecsStr == null) { 236 if (DEBUG_VERSION_CHECK) { 239 System.out.println("Missing <min-wait-seconds>"); 240 } 241 return; 242 } else { 243 try { 244 pingDelaySecs = Integer.parseInt(pingDelaySecsStr.trim()); 245 } catch (NumberFormatException e) { 246 if (DEBUG_VERSION_CHECK) { 249 System.out.println("Bad min-wait-seconds number: " + pingDelaySecsStr); 250 } 251 return; 252 } 253 } 254 255 String html = getTextOfLastElementHavingTag(doc, "notification"); 258 259 if (html == null) { 260 if (DEBUG_VERSION_CHECK) { 263 System.out.println("Missing <notification>"); 264 } 265 return; 266 } 267 268 processResponse(prefs, version, pingDelaySecs, html, callback); 271 } 272 273 private static void processResponse(Preferences prefs, String version, 274 int pingDelaySecs, String html, UpdateAvailableCallback callback) { 275 276 long nextPingTime = System.currentTimeMillis() + pingDelaySecs * 1000; 279 prefs.put(NEXT_PING, String.valueOf(nextPingTime)); 280 281 if (DEBUG_VERSION_CHECK) { 282 System.out.println("Ping delay is " + pingDelaySecs + "; next ping at " 283 + new Date (nextPingTime)); 284 } 285 286 290 String lastServerVersion = prefs.get(LAST_SERVER_VERSION, null); 291 prefs.put(LAST_SERVER_VERSION, version); 292 293 if (!isServerVersionNewer(About.GWT_VERSION_NUM, version)) { 296 297 if (DEBUG_VERSION_CHECK) { 300 System.out.println("Server version is not newer"); 301 } 302 return; 303 } 304 305 if (version.equals(lastServerVersion)) { 308 309 if (DEBUG_VERSION_CHECK) { 312 System.out.println("A notification has already been shown for " 313 + version); 314 } 315 return; 316 } 317 318 if (DEBUG_VERSION_CHECK) { 319 System.out.println("Server version has changed to " + version 320 + "; notification will be shown"); 321 } 322 323 callback.onUpdateAvailable(html); 326 } 327 328 public void check(final UpdateAvailableCallback callback) { 329 330 try { 331 String forceCheckURL = System.getProperty("gwt.forceVersionCheckURL"); 332 333 if (forceCheckURL != null && DEBUG_VERSION_CHECK) { 334 System.out.println("Explicit version check URL: " + forceCheckURL); 335 } 336 337 long currentTimeMillis = System.currentTimeMillis(); 340 Preferences prefs = Preferences.userNodeForPackage(CheckForUpdates.class); 341 342 String firstLaunch = prefs.get(FIRST_LAUNCH, null); 345 if (firstLaunch == null) { 346 firstLaunch = Long.toHexString(currentTimeMillis); 347 prefs.put(FIRST_LAUNCH, firstLaunch); 348 349 if (DEBUG_VERSION_CHECK) { 350 System.out.println("Setting first launch to " + firstLaunch); 351 } 352 } else { 353 if (DEBUG_VERSION_CHECK) { 354 System.out.println("First launch was " + firstLaunch); 355 } 356 } 357 358 String nextPing = prefs.get(NEXT_PING, "0"); 361 if (nextPing != null) { 362 try { 363 long nextPingTime = Long.parseLong(nextPing); 364 if (currentTimeMillis < nextPingTime) { 365 if (DEBUG_VERSION_CHECK) { 367 System.out.println("Next ping is not until " 368 + new Date (nextPingTime)); 369 } 370 return; 371 } 372 } catch (NumberFormatException e) { 373 } 375 } 376 377 String queryURL = forceCheckURL != null ? forceCheckURL : QUERY_URL; 380 String url = queryURL + "?v=" + About.GWT_VERSION_NUM + "&id=" 381 + firstLaunch; 382 383 if (DEBUG_VERSION_CHECK) { 384 System.out.println("Checking for new version at " + url); 385 } 386 387 byte[] response; 390 String fullUserAgent = makeUserAgent(); 391 if (System.getProperty("gwt.forceVersionCheckNonNative") == null) { 392 response = doHttpGet(fullUserAgent, url); 395 } else { 396 response = httpGetNonNative(fullUserAgent, url); 399 } 400 401 if (response == null) { 402 if (DEBUG_VERSION_CHECK) { 405 System.out.println("Failed to obtain current version info via HTTP"); 406 } 407 return; 408 } 409 410 parseResponse(prefs, response, callback); 414 415 } catch (Throwable e) { 416 if (DEBUG_VERSION_CHECK) { 419 System.out.println("Exception while processing version info"); 420 e.printStackTrace(); 421 } 422 } 423 } 424 425 protected abstract byte[] doHttpGet(String userAgent, String url); 426 427 432 protected byte[] httpGetNonNative(String userAgent, String url) { 433 Throwable caught; 434 InputStream is = null; 435 try { 436 URL urlToGet = new URL (url); 437 URLConnection conn = urlToGet.openConnection(); 438 conn.setRequestProperty("User-Agent", userAgent); 439 is = conn.getInputStream(); 440 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 441 byte[] buffer = new byte[4096]; 442 int bytesRead; 443 while ((bytesRead = is.read(buffer)) != -1) { 444 baos.write(buffer, 0, bytesRead); 445 } 446 byte[] response = baos.toByteArray(); 447 return response; 448 } catch (MalformedURLException e) { 449 caught = e; 450 } catch (IOException e) { 451 caught = e; 452 } finally { 453 if (is != null) { 454 try { 455 is.close(); 456 } catch (IOException e) { 457 } 458 } 459 } 460 461 if (System.getProperty("gwt.debugLowLevelHttpGet") != null) { 462 caught.printStackTrace(); 463 } 464 465 return null; 466 } 467 468 private void appendUserAgentProperty(StringBuffer sb, String propName) { 469 String propValue = System.getProperty(propName); 470 if (propValue != null) { 471 if (sb.length() > 0) { 472 sb.append("; "); 473 } 474 sb.append(propName); 475 sb.append("="); 476 sb.append(propValue); 477 } 478 } 479 480 483 private String makeUserAgent() { 484 String ua = "GWT Freshness Checker"; 485 486 StringBuffer extra = new StringBuffer (); 487 appendUserAgentProperty(extra, "java.vendor"); 488 appendUserAgentProperty(extra, "java.version"); 489 appendUserAgentProperty(extra, "os.arch"); 490 appendUserAgentProperty(extra, "os.name"); 491 appendUserAgentProperty(extra, "os.version"); 492 493 if (extra.length() > 0) { 494 ua += " (" + extra.toString() + ")"; 495 } 496 497 return ua; 498 } 499 } 500 | Popular Tags |