# HG changeset patch # User Jiri Vanek # Date 1453234449 -3600 # Node ID 978b3c7070b7f908445e7c62325cee6b3681b89d # Parent 7a3e06b56eba8f0c43b34973593083b2fe89b2de 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. diff -r 7a3e06b56eba -r 978b3c7070b7 ChangeLog --- 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 + + 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 Fridrich Strba diff -r 7a3e06b56eba -r 978b3c7070b7 acinclude.m4 --- 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 ]) ]) diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/GuiLaunchHandler.java --- 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; diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/MalformedXMLParser.java --- 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; } } diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/ParseException.java --- 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 ""; + } + } + } diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/Parser.java --- 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 { diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/resources/Messages.properties --- 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. diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java --- 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 } diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/runtime/html/AppletExtractor.java --- 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 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); } } diff -r 7a3e06b56eba -r 978b3c7070b7 netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java --- 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; + } }