public static void checkForUpdatesWithUi(
      final Window parent,
      final String productName,
      final String currentVersion,
      final String currentChannel) {
    final URL checkUrl;
    try {
      checkUrl =
          new URL(
              String.format(
                  "%s/%s/%s",
                  UPDATE_CHECK_BASE_URL, productName.toLowerCase(), currentChannel.toLowerCase()));
    } catch (final MalformedURLException e) {
      // Should never happen
      throw new RuntimeException("Malformed URL template", e);
    }

    final List<String> lines = new ArrayList<>();
    final CEndlessHelperThread helper =
        new CEndlessHelperThread() {
          @Override
          protected void runExpensiveCommand() throws Exception {
            final long startTime = new Date().getTime();

            // Read the actual version info
            lines.addAll(
                StreamUtils.readLinesFromReader(
                    new InputStreamReader(checkUrl.openStream(), UTF_8)));

            // Make this dialog visible for at least 400 msec so that users have a chance to read
            // the "Checking for updates..." text.
            final long duration = new Date().getTime() - startTime;
            if (duration < 400) {
              Thread.sleep(400 - duration);
            }
          }
        };
    CEndlessProgressDialog.show(
        parent,
        System.getProperty(CMessageBox.DEFAULT_WINDOW_TITLE_PROPERTY),
        "Checking for updates...",
        helper);
    final Exception e = helper.getException();
    if (e instanceof FileNotFoundException) {
      CMessageBox.showWarning(
          parent, "Could not check for updates. The update site is unavailable.");
      return;
    }
    if (e != null) {
      CMessageBox.showWarning(parent, "Could not check for updates: " + e.getMessage());
      return;
    }

    if (lines.isEmpty()) {
      CMessageBox.showWarning(
          parent, "Could not check for updates. The update site returned no data.");
      return;
    }

    // Make sure we have at least 2 lines and the second one is a date of the form YYYY-MM-DD (to be
    // used later)
    if ((lines.size() < 2) || !lines.get(1).matches("\\d{4}-\\d\\d-\\d\\d")) {
      CMessageBox.showWarning(parent, "Could not check for updates. Could not parse the response.");
      return;
    }

    final String remoteVersion = lines.get(0);
    final int result = versionCompare(currentVersion, remoteVersion);
    if (result < 0) {
      CMessageBox.showInformation(
          parent, String.format("A newer version (%s) is available.", remoteVersion));
      return;
    }
    CMessageBox.showInformation(
        parent, String.format("Your version of zynamics %s is up to date.", productName));
  }
Checks for available product updates and displays the results in a user interface.

@param parent a {@link Window} to be used as a parent for modal dialogs. Can be {@code null}.
@param productName the name of the product to check for updates. Should not include a leading
    "zynamics ".
@param currentVersion the version string of the product that denotes the current version (i.e.
    "4.0.0").
@param currentChannel the release channel to check for updates. This can be used to distinguish
    beta versions ("testing") from release versions ("stable").
java/zylib/src/main/java/com/google/security/zynamics/zylib/gui/license/UpdateCheckHelper.java