[rfc] [icedtea-web] better error reporting for LaunchException in plugin

Adam Domurad adomurad at redhat.com
Tue Jan 29 08:01:09 PST 2013


On 01/21/2013 06:35 AM, Jiri Vanek wrote:
> Launch errors are thrown from netx, and printed out .. somewhere. At 
> the end plugin (correctly) fails with NPE.
> It Is not nice. Eg in SplashError dialogue they can not be shown.
>
> I have added static accumulator for LaunchErrors (== all errors 
> preceding npe in plugin) and then I'm adding this chain of exception 
> to Splash error report.
>
> It is quite useful - see example - but there is one pitfall. As 
> accumulator being static, it is cumulating errors from all running 
> applets :(
> However I have not found a way how to distinguish between individual 
> applets :( (any idea welcomed!)

Hmm. Well each applet has an associated thread-group -- you could use 
that to determine the current applet.

As well, I do not like adding a static accumulator to each constructor 
-- I would prefer a special launch error utility class that is always 
used, that takes a JNLPFile (in cases where its available) -or- tries to 
determine one by the current ThreadGroup. This will unfortunately need 
some additional 'infrastructure'.

> I have added small warkaround  with timestamps and localised 
> explanation.. and.. it is still better then nothing :)
>
>
> J.

I know you want this in as 'better than nothing' but it does seem too 
hackish to me :-/ IMO constructors should not have such side-effects.
However I am all for LaunchException's capturing a time-stamp in their 
constructor.

>
>
> **example**
>
> So now instead of plain, nothing saying
> "IcedTea-Web Plugin version: 1.4pre+rb646c8b9c2e2+
> Mon Jan 21 12:29:17 CET 2013
> java.lang.NullPointerException
>     at net.sourceforge.jnlp.NetxPanel.runLoader(NetxPanel.java:130)
>     at sun.applet.AppletPanel.run(AppletPanel.java:380)
>     at java.lang.Thread.run(Thread.java:679)"
>
> Is there:
>
> IcedTea-Web Plugin version: 1.4pre+rb646c8b9c2e2+
> Mon Jan 21 12:29:17 CET 2013
> java.lang.NullPointerException
>     at net.sourceforge.jnlp.NetxPanel.runLoader(NetxPanel.java:130)
>     at sun.applet.AppletPanel.run(AppletPanel.java:380)
>     at java.lang.Thread.run(Thread.java:679)
>
>  Chain:
> 1) at Mon Jan 21 12:27:27 CET 2013
> net.sourceforge.jnlp.LaunchException: Fatal: Application Error: The 
> applet was unsigned. The applet was unsigned, and the security policy 
> prevented it from running.
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.initializeResources(JNLPClassLoader.java:680)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.<init>(JNLPClassLoader.java:240)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:374)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:347)
>     at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:751)
>     at net.sourceforge.jnlp.Launcher.getApplet(Launcher.java:713)
>     at net.sourceforge.jnlp.Launcher$TgThread.run(Launcher.java:942)
> 2) at Mon Jan 21 12:27:27 CET 2013
> net.sourceforge.jnlp.LaunchException: Fatal: Initialization Error: 
> Could not initialize applet.
>     at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:784)
>     at net.sourceforge.jnlp.Launcher.getApplet(Launcher.java:713)
>     at net.sourceforge.jnlp.Launcher$TgThread.run(Launcher.java:942)
> Caused by: net.sourceforge.jnlp.LaunchException: Fatal: Application 
> Error: The applet was unsigned. The applet was unsigned, and the 
> security policy prevented it from running.
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.initializeResources(JNLPClassLoader.java:680)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.<init>(JNLPClassLoader.java:240)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:374)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:347)
>     at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:751)
>     ... 2 more
> 3) at Mon Jan 21 12:27:29 CET 2013
> net.sourceforge.jnlp.LaunchException: Fatal: Application Error: The 
> applet was unsigned. The applet was unsigned, and the security policy 
> prevented it from running.
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.initializeResources(JNLPClassLoader.java:680)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.<init>(JNLPClassLoader.java:240)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:374)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:347)
>     at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:751)
>     at net.sourceforge.jnlp.Launcher.getApplet(Launcher.java:713)
>     at net.sourceforge.jnlp.Launcher$TgThread.run(Launcher.java:942)
> 4) at Mon Jan 21 12:27:29 CET 2013
> net.sourceforge.jnlp.LaunchException: Fatal: Initialization Error: 
> Could not initialize applet.
>     at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:784)
>     at net.sourceforge.jnlp.Launcher.getApplet(Launcher.java:713)
>     at net.sourceforge.jnlp.Launcher$TgThread.run(Launcher.java:942)
> Caused by: net.sourceforge.jnlp.LaunchException: Fatal: Application 
> Error: The applet was unsigned. The applet was unsigned, and the 
> security policy prevented it from running.
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.initializeResources(JNLPClassLoader.java:680)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.<init>(JNLPClassLoader.java:240)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:374)
>     at 
> net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:347)
>     at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:751)
>     ... 2 more
>

Comments inline.


> diff -r b646c8b9c2e2 netx/net/sourceforge/jnlp/LaunchException.java
> --- a/netx/net/sourceforge/jnlp/LaunchException.java    Fri Jan 18 
> 12:49:37 2013 +0100
> +++ b/netx/net/sourceforge/jnlp/LaunchException.java    Mon Jan 21 
> 12:20:20 2013 +0100
> @@ -16,6 +16,10 @@
>
>  package net.sourceforge.jnlp;
>
> +import java.util.Date;
> +import java.util.LinkedList;
> +import java.util.List;
> +
>  /**
>   * Thrown when a JNLP application, applet, or installer could not
>   * be created.
> @@ -25,6 +29,29 @@
>   */
>  public class LaunchException extends Exception {
>
> +
> +    public static class LaunchExceptionWithStamp{
> +        private final LaunchException ex;
> +        private final Date stamp;
> +
> +        private LaunchExceptionWithStamp(LaunchException ex) {
> +            this.ex=ex;
> +            this.stamp=new Date();
> +        }
> +
> +        public LaunchException getEx() {
> +            return ex;
> +        }
> +
> +        public Date getStamp() {
> +            return stamp;
> +        }
> +
> +
> +
> +    }
> +    public static final List<LaunchExceptionWithStamp> 
> launchExceptionChain = new LinkedList<LaunchExceptionWithStamp>();
> +
>      private static final long serialVersionUID = 7283827853612357423L;
>
>      /** the file being launched */
> @@ -54,6 +81,7 @@
>          this.summary = summary;
>          this.description = description;
>          this.severity = severity;
> +        saveLaunchException(this);

Bit too much of a hack, for me.

>      }
>
>      /**
> @@ -61,6 +89,7 @@
>       */
>      public LaunchException(Throwable cause) {
>          super(cause);
> +        saveLaunchException(this);
>      }
>
>      /**
> @@ -68,6 +97,7 @@
>       */
>      public LaunchException(String message, Throwable cause) {
>          super(message, cause);
> +        saveLaunchException(this);
>      }
>
>      /**
> @@ -78,6 +108,7 @@
>       */
>      public LaunchException(String message) {
>          super(message);
> +        saveLaunchException(this);
>      }
>
>      /**
> @@ -117,4 +148,9 @@
>          return severity;
>      }
>
> +    private void saveLaunchException(LaunchException ex) {

Should be synchronized, surely ?

> +        launchExceptionChain.add(new LaunchExceptionWithStamp(ex));
> +
> +    }
> +
>  }
> diff -r b646c8b9c2e2 
> netx/net/sourceforge/jnlp/resources/Messages.properties
> --- a/netx/net/sourceforge/jnlp/resources/Messages.properties  Fri Jan 
> 18 12:49:37 2013 +0100
> +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties  Mon Jan 
> 21 12:20:20 2013 +0100
> @@ -478,3 +478,4 @@
>  SPLASHdefaultHomepage = Unspecified homepage, verify source rather
>  SPLASHerrorInInformation = Error during loading of information 
> element, verify source rather
>  SPLASHmissingInformation = Information element is missing, verify 
> source rather
> +SPLASHchainWas = There is list of exceptions which provided start of 
> you applet. Please note, those exceptions can be from multiple 
> applets. For good bug report, it is wothy to run your applet isolated.

Hm, s/wothy/worthy/, but probably better is:
'This is the list of exceptions that occurred launching your applet' ... 
'For a good bug report, be sure to run only one applet.'

> diff -r b646c8b9c2e2 
> netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties
> --- a/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties 
>  Fri Jan 18 12:49:37 2013 +0100
> +++ b/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties 
>  Mon Jan 21 12:20:20 2013 +0100
> @@ -468,4 +468,5 @@
>  SPLASHanotherInfo= Dal\u0161\u00ed dostupn\u00e9 informace
>  SPLASHdefaultHomepage = Nespecifikovan\u00e1 domovsk\u00e1 
> st\u00e1nka, je doporu\u010deno zkontrolovat zdroj
>  SPLASHerrorInInformation = Chyba na\u010d\u00edt\u00e1n\u00ed 
> informa\u010dn\u00edho elementu, je doporu\u010deno zkontrolovat zdroj
> -SPLASHmissingInformation = Informa\u010dn\u00ed element chyb\u00fd, 
> je doporu\u010deno zkontrolovat zdroj
> \ No newline at end of file
> +SPLASHmissingInformation = Informa\u010dn\u00ed element chyb\u00fd, 
> je doporu\u010deno zkontrolovat zdroj
> +SPLASHchainWas = N\u00ed\u017ee je seznam v\u00fdjimek, kter\u00e9 
> prov\u00e1zely start appeltu. Tento seznam ale m\u016f\u017er 
> poch\u00e1zet z n\u011bkolik\u00e1 r\u016fzn\u00fdch applet\u016f. Pro 
> dob\u00e9 chybo\u00e9 hl\u00e1\u0161en\u00ed stoj\u00e9 za to pustit 
> applet izolovane.
> \ No newline at end of file
> diff -r b646c8b9c2e2 
> netx/net/sourceforge/jnlp/splashscreen/parts/JEditorPaneBasedExceptionDialog.java
> --- 
> a/netx/net/sourceforge/jnlp/splashscreen/parts/JEditorPaneBasedExceptionDialog.java 
>  Fri Jan 18 12:49:37 2013 +0100
> +++ 
> b/netx/net/sourceforge/jnlp/splashscreen/parts/JEditorPaneBasedExceptionDialog.java 
>  Mon Jan 21 12:20:20 2013 +0100
> @@ -42,6 +42,8 @@
>  import java.awt.event.WindowEvent;
>  import java.io.PrintWriter;
>  import java.io.StringWriter;
> +import java.text.DateFormat;
> +import java.util.Date;
>  import java.util.List;
>  import javax.swing.BorderFactory;
>  import javax.swing.GroupLayout;
> @@ -60,6 +62,7 @@
>  import javax.swing.WindowConstants;
>  import javax.swing.event.HyperlinkEvent;
>  import javax.swing.event.HyperlinkListener;
> +import net.sourceforge.jnlp.LaunchException;
>  import net.sourceforge.jnlp.runtime.Translator;
>
>  public class JEditorPaneBasedExceptionDialog extends JDialog 
> implements HyperlinkListener {
> @@ -78,15 +81,19 @@
>      // End of components declaration
>      private final String message;
>      private final Throwable exception;
> +    private final Date shown;
> +    private final String anotherInfo;
>
>      /** Creates new form JEditorPaneBasedExceptionDialog */
>      public JEditorPaneBasedExceptionDialog(java.awt.Frame parent, 
> boolean modal, Throwable ex, InformationElement information, String 
> anotherInfo) {
>          super(parent, modal);
> +        shown = new Date();
>          initComponents();
>          htmlErrorAndHelpPanel.setContentType("text/html");
>          htmlErrorAndHelpPanel.setEditable(false);
> +        this.anotherInfo=anotherInfo;
>          List<String> l = infoElementToList(information);
> -        this.message = getText(ex, l, anotherInfo);
> +        this.message = getText(ex, l, anotherInfo, shown);
>          this.exception = ex;
>          if (exception == null) {
>              closeAndCopyButton.setVisible(false);
> @@ -199,7 +206,7 @@
>      private void 
> copyAndCloseButtonActionPerformed(java.awt.event.ActionEvent evt) {
>          if (exception != null) {
>              try {
> -                StringSelection data = new 
> StringSelection(getExceptionStackTraceAsString(exception));
> +                StringSelection data = new 
> StringSelection(anotherInfo+"\n"+shown.toString()+"\n"+getExceptionStackTraceAsString(exception)+addPlainChain());
>                  Clipboard clipboard = 
> Toolkit.getDefaultToolkit().getSystemClipboard();
>                  clipboard.setContents(data, data);
>              } catch (Exception ex) {
> @@ -241,7 +248,7 @@
>          });
>      }
>
> -    static String getText(Throwable ex, List<String> l, String 
> anotherInfo) {
> +    static String getText(Throwable ex, List<String> l, String 
> anotherInfo,Date shown) {
>          StringBuilder s = new StringBuilder("<html><body>");
>          String info = "<p>"
>                  + Translator.R(InfoItem.SPLASH + "mainL1", createLink())
> @@ -258,9 +265,11 @@
>                      + Translator.R(InfoItem.SPLASH + "mainL4")
>                      + " </p>\n"
>                      + info + formatListInfoList(l) + 
> formatInfo(anotherInfo)
> + +"<br>"+DateFormat.getInstance().format(shown)+"<br>"
>                      + "<p>"
>                      + Translator.R(InfoItem.SPLASH + "exWas")
> -                    + " <br/>\n" + "<pre>" + 
> getExceptionStackTraceAsString(ex) + "</pre>";
> +                    + " <br/>\n" + "<pre>" + 
> getExceptionStackTraceAsString(ex) + "</pre>"
> +                    + addChain();
>
>
>          } else {
> @@ -354,4 +363,47 @@
>      }
>
>
> +    private static String addChain() {
> +        if (LaunchException.launchExceptionChain.isEmpty()) {
> +            return "";
> +        }
> +        return Translator.R(InfoItem.SPLASH + "chainWas")
> +                + " <br/>\n" + "<pre>" + getChainAsString(true) + 
> "</pre>";
> +
> +    }
> +
> +    private static String addPlainChain() {
> +        if (LaunchException.launchExceptionChain.isEmpty()) {
> +            return "";
> +        }
> +        return "\n Chain: \n" + getChainAsString(false);
> +
> +    }
> +
> +    private static String getChainAsString(boolean formatTime) {
> +        return getChainAsString(LaunchException.launchExceptionChain, 
> formatTime);
> +    }
> +
> +    private static String 
> getChainAsString(List<LaunchException.LaunchExceptionWithStamp> 
> launchExceptionChain, boolean formatTime) {
> +        String s = "";
> +        if (launchExceptionChain != null) {
> +            int i = 0;
> +            for (LaunchException.LaunchExceptionWithStamp 
> launchException : launchExceptionChain) {
> +                i++;
> +                s = s + i + ") at " + 
> formatTime(launchException.getStamp(), formatTime) + "\n" + 
> getExceptionStackTraceAsString(launchException.getEx());
> +            }
> +        }
> +        return s;
> +    }
> +
> +    private static String formatTime(Date dateTime, boolean formatTime) {
> +        if (dateTime == null) {
> +            return "unknown time";
> +        }
> +        if (formatTime) {
> +            return DateFormat.getInstance().format(dateTime);
> +        } else {
> +            return dateTime.toString();
> +        }
> +    }
>  }




More information about the distro-pkg-dev mailing list