changeset 1290:978b3c7070b7

When tagsoup is missing, parsing errors are more informative * acinclude.m4: when building without tagsoup, more verbose warning is printed * netx/net/sourceforge/jnlp/GuiLaunchHandler.java: (launchError) is now noting that BasicExceptionDialog will be shown. * netx/net/sourceforge/jnlp/MalformedXMLParser.java: Now react on NoClassDefFoundError by returning original stream. * netx/net/sourceforge/jnlp/ParseException.java: Stores information about parsers loading, and add this info to ParseException message. * netx/net/sourceforge/jnlp/Parser.java: (getRootNode) logic retrieving parser class extracted to separate method getParserInstance * netx/net/sourceforge/jnlp/resources/Messages.properties: added family of TAGSOUP for messages about its state * netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java: (exit) now waits for BasicExceptionDialog. * netx/net/sourceforge/jnlp/runtime/html/AppletExtractor.java: (cleanStreamIfPossible) now uses Parser.getParserInstance ratehr then its own. * netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java: Is now capable of publishing number of shown instances.
author Jiri Vanek <jvanek@redhat.com>
date Tue, 19 Jan 2016 21:14:09 +0100
parents 7a3e06b56eba
children 530bb97e9f08
files ChangeLog acinclude.m4 netx/net/sourceforge/jnlp/GuiLaunchHandler.java netx/net/sourceforge/jnlp/MalformedXMLParser.java netx/net/sourceforge/jnlp/ParseException.java netx/net/sourceforge/jnlp/Parser.java netx/net/sourceforge/jnlp/resources/Messages.properties netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java netx/net/sourceforge/jnlp/runtime/html/AppletExtractor.java netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java
diffstat 10 files changed, 154 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Jan 14 16:28:48 2016 +0100
+++ b/ChangeLog	Tue Jan 19 21:14:09 2016 +0100
@@ -1,3 +1,24 @@
+2016-01-19  Jiri Vanek <jvanek@redhat.com>
+
+	When tagsoup is missing, parsing errors are more informative
+	* acinclude.m4: when building without tagsoup, more verbose warning is printed
+	* netx/net/sourceforge/jnlp/GuiLaunchHandler.java: (launchError) is now noting
+	that BasicExceptionDialog will be shown.
+	* netx/net/sourceforge/jnlp/MalformedXMLParser.java: Now react on NoClassDefFoundError
+	by returning original stream.
+	* netx/net/sourceforge/jnlp/ParseException.java: Stores information about
+	parsers loading, and add this info to ParseException message.
+	* netx/net/sourceforge/jnlp/Parser.java: (getRootNode) logic retrieving parser
+	class extracted to separate method getParserInstance
+	* netx/net/sourceforge/jnlp/resources/Messages.properties: added family of TAGSOUP
+	for messages about its state
+	* netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java: (exit) now waits for 
+	BasicExceptionDialog.
+	* netx/net/sourceforge/jnlp/runtime/html/AppletExtractor.java: (cleanStreamIfPossible)
+	now uses Parser.getParserInstance ratehr then its own.
+	* netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java: Is now capable of
+	publishing number of shown instances.
+
 2016-01-14  Jiri Vanek <jvanek@redhat.com>
             Fridrich Strba  <fridrich.strba@suse.com>
 
--- a/acinclude.m4	Thu Jan 14 16:28:48 2016 +0100
+++ b/acinclude.m4	Tue Jan 19 21:14:09 2016 +0100
@@ -446,6 +446,12 @@
     done
   fi
   AC_MSG_RESULT(${TAGSOUP_JAR})
+  if test -z "${TAGSOUP_JAR}"; then
+    AC_MSG_RESULT(***********************************************)
+    AC_MSG_RESULT(*  Warning you are building without tagsoup   *)
+    AC_MSG_RESULT(* Some jnlps and most htmls will be malformed *)
+    AC_MSG_RESULT(***********************************************)
+  fi
   AC_SUBST(TAGSOUP_JAR)
   AM_CONDITIONAL([HAVE_TAGSOUP], [test x$TAGSOUP_JAR != xno -a x$TAGSOUP_JAR != x ])
 ])
--- a/netx/net/sourceforge/jnlp/GuiLaunchHandler.java	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/GuiLaunchHandler.java	Tue Jan 19 21:14:09 2016 +0100
@@ -69,6 +69,7 @@
 
     @Override
     public void launchError(final LaunchException exception) {
+        BasicExceptionDialog.willBeShown();
         SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
@@ -102,6 +103,7 @@
     }
 
     @Override
+    @SuppressWarnings("empty-statement")
     public void launchInitialized(final JNLPFile file) {
 
         int preferredWidth = 500;
--- a/netx/net/sourceforge/jnlp/MalformedXMLParser.java	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/MalformedXMLParser.java	Tue Jan 19 21:14:09 2016 +0100
@@ -111,10 +111,12 @@
 
             reader.parse(s);
             return new ByteArrayInputStream(out.toByteArray());
-        } catch (SAXException e) {
-            throw new ParseException(R("PBadXML"), e);
-        } catch (IOException e) {
-            throw new ParseException(R("PBadXML"), e);
+        } catch (SAXException | IOException e1) {
+            throw new ParseException(R("PBadXML"), e1);
+        } catch (NoClassDefFoundError  e2) {
+            OutputController.getLogger().log(e2);
+            ParseException.setUsed(null);
+            return original;
         }
 
     }
--- a/netx/net/sourceforge/jnlp/ParseException.java	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/ParseException.java	Tue Jan 19 21:14:09 2016 +0100
@@ -16,6 +16,9 @@
 
 package net.sourceforge.jnlp;
 
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.runtime.Translator;
+
 /**
  * Thrown to indicate that an error has occurred while parsing a
  * JNLP file.
@@ -34,7 +37,7 @@
      * @param message to be shown in exception
      */
     public ParseException(String message) {
-        super(message);
+        super(getParserSettingsMessage() + message);
     }
 
     /**
@@ -44,7 +47,48 @@
      * @param cause cause of exception
      */
     public ParseException(String message, Throwable cause) {
-        super(message, cause);
+        super(getParserSettingsMessage() + message, cause);
     }  
 
+    public ParseException(Throwable cause) {
+        super(getParserSettingsMessage(), cause);
+    }
+    
+    
+    static enum UsedParsers {
+
+        MALFORMED, NORMAL
+    }
+
+    private static UsedParsers expected;
+    private static UsedParsers used;
+
+    static void setExpected(UsedParsers ex) {
+        expected = ex;
+    }
+
+    static void setUsed(UsedParsers us) {
+        used = us;
+    }
+    
+    private static String getParserSettingsMessage() {
+        final String tail = ""
+                + " "
+                + Translator.R("TAGSOUPtail")
+                + " ";
+        if (expected == UsedParsers.NORMAL && used == UsedParsers.NORMAL) {
+            //warn about xml mode
+            return Translator.R("TAGSOUPnotUsed", OptionsDefinitions.OPTIONS.XML.option)+tail;
+        }
+        if (expected == UsedParsers.MALFORMED && used != UsedParsers.MALFORMED) {
+            //warn about TagSoup
+            return Translator.R("TAGSOUPbroken") + tail;
+        }
+        if (JNLPRuntime.isDebug()) {
+            return expected + " " + used + "; ";
+        } else {
+            return "";
+        }
+    }
+
 }
--- a/netx/net/sourceforge/jnlp/Parser.java	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/Parser.java	Tue Jan 19 21:14:09 2016 +0100
@@ -1315,24 +1315,10 @@
      * @throws ParseException if the JNLP file is invalid
      */
     static Node getRootNode(InputStream input, ParserSettings settings) throws ParseException {
-        String className;
-        if (settings.isMalformedXmlAllowed()) {
-            className = MALFORMED_PARSER_CLASS;
-        } else {
-            className = NORMAL_PARSER_CLASS;
-        }
-
         try {
-            Class<?> klass;
-            try {
-                klass = Class.forName(className);
-            } catch (ClassNotFoundException e) {
-                klass = Class.forName(NORMAL_PARSER_CLASS);
-            }
-            Object instance = klass.newInstance();
-            Method m = klass.getMethod("getRootNode", InputStream.class);
-
-            return (Node) m.invoke(instance, input);
+            Object parser = getParserInstance(settings);
+            Method m = parser.getClass().getMethod("getRootNode", InputStream.class);
+            return (Node) m.invoke(parser, input);
         } catch (InvocationTargetException e) {
             if (e.getCause() instanceof ParseException) {
                 throw (ParseException)(e.getCause());
@@ -1342,6 +1328,41 @@
             throw new ParseException(R("PBadXML"), e);
         }
     }
+    
+
+     public static Object getParserInstance(ParserSettings settings) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        String className;
+        if (settings.isMalformedXmlAllowed()) {
+            className = MALFORMED_PARSER_CLASS;
+            ParseException.setExpected(ParseException.UsedParsers.MALFORMED);
+        } else {
+            className = NORMAL_PARSER_CLASS;
+            ParseException.setExpected(ParseException.UsedParsers.NORMAL);
+        }
+
+        Class<?> klass;
+        Object instance;
+
+        try {
+            klass = Class.forName(className);
+            instance = klass.newInstance();
+            //catch both, for case that tagsoup was removed after build
+        } catch (ClassNotFoundException | NoClassDefFoundError | InstantiationException e) {
+            OutputController.getLogger().log(e);
+            klass = Class.forName(NORMAL_PARSER_CLASS);
+            instance = klass.newInstance();
+        }
+
+        switch (instance.getClass().getName()) {
+            case MALFORMED_PARSER_CLASS:
+                ParseException.setUsed(ParseException.UsedParsers.MALFORMED);
+                break;
+            case NORMAL_PARSER_CLASS:
+                ParseException.setUsed(ParseException.UsedParsers.NORMAL);
+                break;
+        }
+        return instance;
+    }
 
   private String getOptionalMainClass(Node node) {
         try {
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties	Tue Jan 19 21:14:09 2016 +0100
@@ -1101,6 +1101,12 @@
 FILEopera64=Location of plugin library for global purposes  on opera compliant browser, 64-bit systems.
 FILEopera32=Location of plugin library for global purposes  on opera compliant browser, 32-bit systems.
 
+TAGSOUPtail=You may have missing tagsoup installation or your ITW was not built against it. Check your installation and/or consult distribution.
+TAGSOUPnotUsed"You are not using Malformed parser. If you have set {0}, remove it. Or...
+TAGSOUPbroken=Broken Malformed parser.
+TAGSOUPhtmlNotUsed=Tagsoup''s html2xml cleaning is Disabled. Remove {0}. Parsing will probably fail.
+TAGSOUPhtmlBroken=Tagsoup''s html2xml cleaning not loaded. Install tagsoup (and build ITW against). Parsing will probably fail.
+
 FILEcache=Contains cached runtime entries.
 FILErecentlyUsed=Additional information about items in cache
 FILEappdata=Contains saved application data.
--- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Tue Jan 19 21:14:09 2016 +0100
@@ -67,6 +67,7 @@
 import net.sourceforge.jnlp.security.SecurityDialogMessageHandler;
 import net.sourceforge.jnlp.security.SecurityUtil;
 import net.sourceforge.jnlp.services.XServiceManagerStub;
+import net.sourceforge.jnlp.util.BasicExceptionDialog;
 import net.sourceforge.jnlp.util.FileUtils;
 import net.sourceforge.jnlp.util.logging.JavaConsole;
 import net.sourceforge.jnlp.util.logging.LogConfig;
@@ -882,6 +883,9 @@
     public static void exit(int i) {
         try {
             OutputController.getLogger().close();
+            while (BasicExceptionDialog.areShown()){
+                Thread.sleep(100);
+            }
         } catch (Exception ex) {
             //to late
         }
--- a/netx/net/sourceforge/jnlp/runtime/html/AppletExtractor.java	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/runtime/html/AppletExtractor.java	Tue Jan 19 21:14:09 2016 +0100
@@ -46,10 +46,12 @@
 import javax.xml.parsers.ParserConfigurationException;
 import net.sourceforge.jnlp.JNLPFile;
 import net.sourceforge.jnlp.OptionsDefinitions;
+import net.sourceforge.jnlp.ParseException;
 import net.sourceforge.jnlp.Parser;
 import net.sourceforge.jnlp.ParserSettings;
 import net.sourceforge.jnlp.cache.UpdatePolicy;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.runtime.Translator;
 import net.sourceforge.jnlp.util.logging.OutputController;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -88,14 +90,14 @@
     private InputStream cleanStreamIfPossible(InputStream is) {
         try {
             if (ps != null && ps.isMalformedXmlAllowed()){
-                Class<?> klass = Class.forName(Parser.MALFORMED_PARSER_CLASS);
-                Method m = klass.getMethod("xmlizeInputStream", InputStream.class);
+                Object parser = Parser.getParserInstance(ps);
+                Method m = parser.getClass().getMethod("xmlizeInputStream", InputStream.class);
                 return (InputStream) m.invoke(null, is);
             } else {
-                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Tagsoup's html2xml cleaning is Disabled. Remove "+OptionsDefinitions.OPTIONS.XML.option+". Parsing will probably fail.");    
+                OutputController.getLogger().log(OutputController.Level.WARNING_ALL, Translator.R("TAGSOUPhtmlNotUsed", OptionsDefinitions.OPTIONS.XML.option));    
             }
         } catch (Exception ex) {
-            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Tagsoup's html2xml cleaning not loaded. Install tagsoup. Parsing will probably fail.");
+            OutputController.getLogger().log(OutputController.Level.WARNING_ALL, Translator.R("TAGSOUPhtmlBroken"));
             OutputController.getLogger().log(ex);
         }
         return is;
@@ -104,7 +106,9 @@
     public List<Element> findAppletsOnPage() {
         try{
         return findAppletsOnPageImpl(openDocument(cleanStreamIfPossible(JNLPFile.openURL(html, null, UpdatePolicy.ALWAYS))));
-        }catch (IOException | SAXException | ParserConfigurationException ex){
+        } catch (SAXException sex) {
+            throw new RuntimeException(new ParseException(sex));
+        } catch (IOException | ParserConfigurationException ex) {
             throw new RuntimeException(ex);
         }
     }
--- a/netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java	Thu Jan 14 16:28:48 2016 +0100
+++ b/netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java	Tue Jan 19 21:14:09 2016 +0100
@@ -45,6 +45,7 @@
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
@@ -65,6 +66,7 @@
  */
 public class BasicExceptionDialog {
 
+    private static final AtomicInteger dialogInstancess = new AtomicInteger();
 
     /**
      * Must be invoked from the Swing EDT.
@@ -144,6 +146,7 @@
         ScreenFinder.centerWindowsToCurrentScreen(errorDialog);
         errorDialog.setVisible(true);
         errorDialog.dispose();
+        BasicExceptionDialog.willBeHidden();
     }
 
      public static JButton getShowButton(final Component parent) {
@@ -191,4 +194,17 @@
         });
         return clearAllButton;
     }
+
+    private synchronized static int willBeHidden() {
+        return dialogInstancess.decrementAndGet();
+    }
+
+    //must be called out of EDT, otherise -- will happen before ++
+    public synchronized static int  willBeShown() {
+        return dialogInstancess.incrementAndGet();
+    }
+    
+    public synchronized static boolean areShown() {
+        return dialogInstancess.intValue() > 0;
+    }
 }