Апплет JNLP с пользовательским DownloadServiceListener & Versioning - PullRequest
1 голос
/ 24 августа 2011

Я столкнулся с проблемой при одновременном использовании апплета JNLP с пользовательским DownloadServiceListener, а также версионными файлами jar.

Структура проекта выглядит следующим образом:

/
+ WEB-INF/
|        + lib/
|        |    + jnlp-servlet.jar
|        + web.xml
+ lib/
|    + progress-0.1.jar
|    + MyApplet-1.0.jar
|    + applet.jnlp
|    + version.xml
+ index.jsp

содержимое моего web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">

    <!-- JNLP download servlet-->
    <servlet>
        <servlet-name>JnlpDownloadServlet</servlet-name>
        <servlet-class>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>JnlpDownloadServlet</servlet-name>
        <url-pattern>/lib/*</url-pattern>
    </servlet-mapping>

</web-app>

Мой файл applet.jnlp выглядит следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="6.0+" codebase="$$codebase" href="$$name">
    <information>
        <title>MyApplet</title>
        <vendor>My AG</vendor>
        <homepage href="http://www.nowhere.com"/>
        <description>XYZ</description>
    </information>
    <update check="always" policy="always"/>
    <resources>
        <j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+" initial-heap-size="128m" max-heap-size="128m"/>
        <property name="jnlp.versionEnabled" value="true"/>

    <jar href="progress.jar" version="0.1" download="progress"/>
    <jar href="MyApplet.jar" version="1.0" main="true"/>

    </resources>
    <applet-desc name="MyApplet"
                 main-class="test.MyApplet"
                 width="800" height="600"
                 progress-class="progress.CustomProgress">
        <param name="bgcolor" value="28,28,28"/>
        <param name="textcolor" value="255,222,123"/>
    </applet-desc>
</jnlp>

Для отображения апплета я использую следующий файл JSP (index.jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head><title>Simple jsp page</title></head>
  <body style="margin: 0;">

    <object width="100%" vspace="0" hspace="0" height="100%" align="top" name="MyApplet"
            classid="clsid:CAFEEFAC-0016-0000-0026-ABCDEFFEDCBA" onerror="alert('Invalid Java Version..')">
        <param value="MyApplet" name="name">
        <param value="application/x-java-applet;jpi-version=1.6.0_26" name="type">
        <param value="test.MyApplet.class" name="code">
        <param value="lib/MyApplet-1.0.jar" name="archive">
        <param value="true" name="mayscript">
        <param value="false" name="scriptable">
        <param value="lib/applet.jnlp" name="jnlp_href">
        <param value="true" name="progressbar">
        <param value="238,244,248" name="boxbgcolor">
        <param value="255,255,255" name="boxfgcolor">
        <param value="255,255,227" name="progresscolor">
        <param value="Loading MyApplet - please wait" name="boxmessage">
        <param value="-Djnlp.versionEnabled=true -Xms256m -Xmx256m" name="java_arguments">
        <param value="false" name="classloader_cache">
        <param value="true" name="separate_jvm">
        <comment>
            <embed width="100%" vspace="0" hspace="0" height="100%" align="top" separate_jvm="true"
                   classloader_cache="false" java_arguments="-Djnlp.packEnabled -Xms256m -Xmx256m"
                   boxmessage="Loading MyApplet - please wait" boxfgcolor="255,255,255"
                   boxbgcolor="238,244,248" progressbar="true"
                   pluginspage="http://java.sun.com/products/plugin/index.html#download"
                   jnlp_href="lib/applet.jnlp" scriptable="false" mayscript="true"
                   archive="lib/MyApplet-1.0.jar" code="test.MyApplet.class"
                   type="application/x-java-applet;jpi-version=1.6.0_26"
                   name="MyApplet" onerror="alert('Invalid Java version')">
        </comment>
    </object>
</body>
</html>

И файл для сопоставления версий (version.xml):

<?xml version="1.0"?>
<jnlp-versions>
  <resource>
    <pattern>
      <name>MyApplet.jar</name>
      <version-id>1.0</version-id>
    </pattern>
    <file>MyApplet-1.0.jar</file>
  </resource>
  <resource>
    <pattern>
      <name>progress.jar</name>
      <version-id>0.1</version-id>
    </pattern>
    <file>progress-0.1.jar</file>
  </resource>
</jnlp-versions>

Реализация DownloadServiceListener (которая является +/- точной копией Sun(или Oracle) пример (за исключением того, что изображение не используется):

package progress;

import javax.jnlp.DownloadServiceListener;
import java.awt.Container;
import java.awt.Color;
import java.awt.BorderLayout;
import javax.swing.*;
import java.net.URL;
import java.applet.AppletStub;

public class CustomProgress implements DownloadServiceListener {
    Container surfaceContainer = null;
    AppletStub appletStub = null;
    JProgressBar progressBar = null;
    JLabel statusLabel = null;
    boolean uiCreated = false;

    public CustomProgress(Object surface) {
       init(surface, null);
    }

    public CustomProgress(Object surface, Object stub) {
        init(surface, stub);
    }

    public void init(Object surface, Object stub) {
        try {
            surfaceContainer = (Container) surface;
            appletStub = (AppletStub) stub;
        } catch (ClassCastException cce) {
            cce.printStackTrace();
        }
    }

    public void downloadFailed(java.net.URL url, java.lang.String version) {        
    }

    public void progress(URL url, String version, long readSoFar, long total, int overallPercent) {
        // check progress of download and update display
        updateProgressUI(overallPercent);

    }

    public void upgradingArchive(java.net.URL url, java.lang.String version, int patchPercent, int overallPercent) {
        updateProgressUI(overallPercent);
    }

    public  void validating(java.net.URL url, java.lang.String version, long entry, long total, int overallPercent) {
        updateProgressUI(overallPercent);
    }

    private void updateProgressUI(int overallPercent) {
        if (!uiCreated && overallPercent > 0 && overallPercent < 100) {
            // create custom progress indicator's UI only if 
            // there is more work to do, meaning overallPercent > 0 and < 100
            // this prevents flashing when RIA is loaded from cache
            create(); 
            uiCreated = true;            
        }
        if (uiCreated) {
            progressBar.setValue(overallPercent);
        }
    }

    private void create() {
        JPanel top = createComponents();
        if (surfaceContainer != null) {
            // lay out the loading progress indicator UI in the given Container
            surfaceContainer.add(top, BorderLayout.NORTH);
            surfaceContainer.invalidate();
            surfaceContainer.validate();
        }
    }

    private JPanel createComponents() {
        JPanel top = new JPanel();
        top.setBackground(Color.WHITE);
        top.setLayout(new BorderLayout(20, 20));

        // get applet parameter using an instance of the AppletStub class
        // "tagLine" parameter specified in applet's JNLP file
        String tagLine = "";
        if (appletStub != null) {
            tagLine = appletStub.getParameter("tagLine");
        }
        String lblText = "<html><font color=red size=+2>JDK Documentation</font><br/>" +
                            tagLine + " <br/></html>";
        JLabel lbl = new JLabel(lblText);
        top.add(lbl, BorderLayout.NORTH);

        // use JSObject.getWindow(null) method to retrieve a reference to
        // the web page and make JavaScript calls. Duke logo displayed if
        // displayLogo variable set to "true" in the web page
//        String displayLogo = "true";
//        if (displayLogo.equals("true")) {
//            lbl = new JLabel();
//            ImageIcon logo = createImageIcon("images/DukeWave.gif", "logo");
//            lbl.setIcon(logo);
//            top.add(lbl, BorderLayout.EAST);
//        }

        statusLabel = new JLabel("<html><font color=green size=-2>Loading applet...</font></html>");
        top.add(statusLabel, BorderLayout.CENTER);

        progressBar = new JProgressBar(0, 100);
        progressBar.setValue(0);
        progressBar.setStringPainted(true);
        top.add(progressBar, BorderLayout.SOUTH);

        return top;
    }

    /** Returns an ImageIcon, or null if the path was invalid. */
    protected static ImageIcon createImageIcon(String path, String description) {
        java.net.URL imgURL = CustomProgress.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL, description);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }
}

И последний, но не менее важный мой (очень простой) апплет:

package test;

import javax.swing.*;

public class MyApplet extends JApplet {
    @Override
    public void init() {
        add(new JLabel("This is an applet .. "));
    }
}

Как видите,все максимально упрощено ..:)

Теперь, если я разверну веб-приложение и получу доступ к файлу index.jsp, произойдет следующее: доступны две java-консоли, одна для "DownloadServiceListener "и еще один для" настоящего "апплета.В первом случае можно найти следующее сообщение:

Ошибка при создании пользовательского прогресса: java.lang.ClassNotFoundException: progress.CustomProgress

Вторая консоль пуста, иапплет отображается правильно, показывая текст: «Это апплет ..».

В моем журнале доступа есть следующие записи: (Обратите внимание, что весь java-кэш очищался перед каждым тестом).

24/08/2011:14:57:09 +0200 'GET /AppletTest/ HTTP/1.1' 200 - 24/08/2011:14:57:09 +0200
127.0.0.1 24/08/2011:14:57:12 +0200 'GET /AppletTest/lib/applet.jnlp HTTP/1.1' 200 1041 24/08/2011:14:57:12 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/MyApplet__V1.0.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/progress__V0.1.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/progress.jar?version-id=0.1 HTTP/1.1' 200 3987 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/MyApplet.jar?version-id=1.0 HTTP/1.1' 200 2460484 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/progress.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/progress.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/MyApplet.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/MyApplet.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/progress.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/progress.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/MyApplet.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:13 +0200 'GET /AppletTest/lib/MyApplet.jar HTTP/1.1' 404 - 24/08/2011:14:57:13 +0200
127.0.0.1 24/08/2011:14:57:14 +0200 'GET /AppletTest/lib/applet.jnlp HTTP/1.1' 304 - 24/08/2011:14:57:14 +0200

Когда я смотрю в «Панели управления Java», появляется апплет «MyApplet», и все jar-файлы загружаются, как и ожидалось.

Когда я удаляю «jnlp».versionEnabled "-property, пропустите параметры версии jar-записей и добавьте номер версии к jar-file-names, тогда пользовательский DownloadServiceListener работает отлично.

Возможно ли, что две вещи(версионные jar-файлы и пользовательские DSL) нельзя использовать вместе?Я что-то пропустил?Есть идеи?

...