/* Main method to lookup an entry */
  public synchronized DownloadResponse getJnlpFile(JnlpResource jnlpres, DownloadRequest dreq)
      throws IOException {
    String path = jnlpres.getPath();
    URL resource = jnlpres.getResource();
    long lastModified = jnlpres.getLastModified();

    _log.addDebug("lastModified: " + lastModified + " " + new Date(lastModified));
    if (lastModified == 0) {
      _log.addWarning("servlet.log.warning.nolastmodified", path);
    }

    // fix for 4474854:  use the request URL as key to look up jnlp file
    // in hash map
    String reqUrl = HttpUtils.getRequestURL(dreq.getHttpRequest()).toString();

    // Check if entry already exist in HashMap
    JnlpFileEntry jnlpFile = (JnlpFileEntry) _jnlpFiles.get(reqUrl);

    if (jnlpFile != null && jnlpFile.getLastModified() == lastModified) {
      // Entry found in cache, so return it
      return jnlpFile.getResponse();
    }

    // Read information from WAR file
    long timeStamp = lastModified;
    String mimeType = _servletContext.getMimeType(path);
    if (mimeType == null) mimeType = JNLP_MIME_TYPE;

    StringBuilder jnlpFileTemplate = new StringBuilder();
    URLConnection conn = resource.openConnection();

    final InputStream is = conn.getInputStream();
    final InputStreamReader reader = new InputStreamReader(is);
    char[] chars = new char[1024];
    int read;

    while ((read = reader.read(chars)) != -1) {
      jnlpFileTemplate.append(chars, 0, read);
    }

    try {
      is.close();
    } catch (IOException e) {
      // should never happen and if it does, we're not handling this. It should be save to ignore
    }

    String jnlpFileContent =
        specializeJnlpTemplate(dreq.getHttpRequest(), path, jnlpFileTemplate.toString());

    // Convert to bytes as a UTF-8 encoding
    byte[] byteContent = jnlpFileContent.getBytes("UTF-8");

    // Create entry
    DownloadResponse resp =
        DownloadResponse.getFileDownloadResponse(
            byteContent, mimeType, timeStamp, jnlpres.getReturnVersionId());
    jnlpFile = new JnlpFileEntry(resp, lastModified);
    _jnlpFiles.put(reqUrl, jnlpFile);

    return resp;
  }
  /* Main method to lookup an entry (NEW for JavaWebStart 1.5+) */
  public synchronized DownloadResponse getJnlpFileEx(JnlpResource jnlpres, DownloadRequest dreq)
      throws IOException {
    String path = jnlpres.getPath();
    URL resource = jnlpres.getResource();
    long lastModified = jnlpres.getLastModified();

    _log.addDebug("lastModified: " + lastModified + " " + new Date(lastModified));
    if (lastModified == 0) {
      _log.addWarning("servlet.log.warning.nolastmodified", path);
    }

    // fix for 4474854:  use the request URL as key to look up jnlp file
    // in hash map
    String reqUrl = HttpUtils.getRequestURL(dreq.getHttpRequest()).toString();
    // SQE: To support query string, we changed the hash key from Request URL to (Request URL +
    // query string)
    if (dreq.getQuery() != null) reqUrl += dreq.getQuery();

    // Check if entry already exist in HashMap
    JnlpFileEntry jnlpFile = (JnlpFileEntry) _jnlpFiles.get(reqUrl);

    if (jnlpFile != null && jnlpFile.getLastModified() == lastModified) {
      // Entry found in cache, so return it
      return jnlpFile.getResponse();
    }

    // Read information from WAR file
    long timeStamp = lastModified;
    String mimeType = _servletContext.getMimeType(path);
    if (mimeType == null) mimeType = JNLP_MIME_TYPE;

    StringBuffer jnlpFileTemplate = new StringBuffer();
    URLConnection conn = resource.openConnection();
    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
    String line = br.readLine();
    if (line != null && line.startsWith("TS:")) {
      timeStamp = parseTimeStamp(line.substring(3));
      _log.addDebug("Timestamp: " + timeStamp + " " + new Date(timeStamp));
      if (timeStamp == 0) {
        _log.addWarning("servlet.log.warning.notimestamp", path);
        timeStamp = lastModified;
      }
      line = br.readLine();
    }
    while (line != null) {
      jnlpFileTemplate.append(line);
      line = br.readLine();
    }

    String jnlpFileContent =
        specializeJnlpTemplate(dreq.getHttpRequest(), path, jnlpFileTemplate.toString());

    /* SQE: We need to add query string back to href in jnlp file. We also need to handle JRE requirement for
     * the test. We reconstruct the xml DOM object, modify the value, then regenerate the jnlpFileContent.
     */
    String query = dreq.getQuery();
    String testJRE = dreq.getTestJRE();
    _log.addDebug("Double check query string: " + query);
    // For backward compatibility: Always check if the href value exists.
    // Bug 4939273: We will retain the jnlp template structure and will NOT add href value. Above
    // old
    // approach to always check href value caused some test case not run.

    // NOTE OTC:
    // This section has been rewritten:
    // - Switched from JAX to JDOM, allowing to preserve the formatting of the file
    // - regeneration based on the DOM will only be done if there are any changes to the file
    if (query != null && query.trim().length() > 0) {
      byte[] cb = jnlpFileContent.getBytes("UTF-8");

      try {

        final XMLInputFactory factory = XMLInputFactory.newFactory();
        final XMLEventReader reader = factory.createXMLEventReader(new ByteArrayInputStream(cb));

        final StAXEventBuilder builder = new StAXEventBuilder();
        final org.jdom2.Document document = builder.build(reader);

        boolean modified = false;

        final org.jdom2.Element root = document.getRootElement();

        if (root.getAttribute("href") != null) {
          String href = root.getAttribute("href").getValue();
          root.setAttribute("href", href + "?" + query);
          modified = true;
        }
        // Update version value for j2se tag
        if (testJRE != null) {
          org.jdom2.Element j2se = root.getChild("j2se");
          if (j2se != null) {
            String ver = j2se.getAttribute("version").getValue();
            if (ver.length() > 0) {
              j2se.setAttribute("version", testJRE);
              modified = true;
            }
          }
        }

        if (modified) {
          // we're only regenerating only if there have been any changes.
          final XMLOutputter outputter = new XMLOutputter();
          final StringWriter sw = new StringWriter();
          outputter.output(document, sw);
          jnlpFileContent = sw.toString();
        }

        _log.addDebug("Converted jnlpFileContent: " + jnlpFileContent);
        // Since we modified the file on the fly, we always update the timestamp value with current
        // time
        if (modified) {
          timeStamp = new Date().getTime();
          _log.addDebug("Last modified on the fly:  " + timeStamp);
        }
      } catch (Exception e) {
        _log.addDebug(e.toString(), e);
      }
    }

    // Convert to bytes as a UTF-8 encoding
    byte[] byteContent = jnlpFileContent.getBytes("UTF-8");

    // Create entry
    DownloadResponse resp =
        DownloadResponse.getFileDownloadResponse(
            byteContent, mimeType, timeStamp, jnlpres.getReturnVersionId());
    jnlpFile = new JnlpFileEntry(resp, lastModified);
    _jnlpFiles.put(reqUrl, jnlpFile);

    return resp;
  }