From 4e0e32aba4372d374956121853e13eda47d4f598 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 07 2019 04:42:21 +0000 Subject: import icedtea-web-1.7.1-9.el8 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..76075c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/icedtea-web-1.7.1.tar.gz diff --git a/.icedtea-web.metadata b/.icedtea-web.metadata new file mode 100644 index 0000000..55e3c5d --- /dev/null +++ b/.icedtea-web.metadata @@ -0,0 +1 @@ +a484daa20cadefe4d4ba2c1e3b28dbb39c986f4b SOURCES/icedtea-web-1.7.1.tar.gz diff --git a/SOURCES/1473-1480.patch b/SOURCES/1473-1480.patch new file mode 100644 index 0000000..4380668 --- /dev/null +++ b/SOURCES/1473-1480.patch @@ -0,0 +1,4716 @@ +diff -r dbb8dc397d15 -r 4abd0f089773 ChangeLog +--- a/ChangeLog Mon Dec 18 13:22:51 2017 +0100 ++++ b/ChangeLog Fri Mar 02 10:41:29 2018 +0100 +@@ -1,3 +1,56 @@ ++2018-02-06 Jiri Vanek ++ ++ Added test for javafx-desc ++ * tests/reproducers/custom/JavaFx/resources/JavaFx.jar ++ * tests/reproducers/custom/JavaFx/resources/JavaFx.jnlp ++ * tests/reproducers/custom/JavaFx/srcs/Controller.class ++ * tests/reproducers/custom/JavaFx/srcs/Controller.java ++ * tests/reproducers/custom/JavaFx/srcs/Main.class ++ * tests/reproducers/custom/JavaFx/srcs/Main.java ++ * tests/reproducers/custom/JavaFx/srcs/Makefile ++ * tests/reproducers/custom/JavaFx/srcs/helloworld.fxml ++ * tests/reproducers/custom/JavaFx/testcases/JavaFxTest.java ++ ++2018-02-05 Jiri Vanek ++ ++ Added basic support for javafx desc ++ * netx/net/sourceforge/jnlp/ApplicationDesc.java: added flag fx to rember what was initiator ++ * netx/net/sourceforge/jnlp/Node.java: Added abstraction ElementName over string of element name to hold namespace ++ and separate it for name if present ++ * netx/net/sourceforge/jnlp/Parser.java: for javafx-desc ApplicationDesc is instantiated. Adapted to ElementName ++ * tests/netx/unit/net/sourceforge/jnlp/ParserCornerCases.java: ElementName ++ * tests/netx/unit/net/sourceforge/jnlp/ParserTest.java: ElementName ++ ++2018-02-05 Jiri Vanek ++ ++ Fixed news for latest changes ++ * NEWS: mentioned javafx-desc, -nosecurity enhancement and j2se/java resources ++ ++2018-02-03 Jiri Vanek ++ ++ Made ITW to load resources from j2se/java tag too ++ * netx/net/sourceforge/jnlp/Parser.java: constructors/methods made public to help unittests ++ * netx/net/sourceforge/jnlp/ShortcutDesc.java: same ++ * netx/net/sourceforge/jnlp/ResourcesDesc.java: getJars made to iterate recursively over content of j2se ++ * tests/netx/unit/net/sourceforge/jnlp/ParserBasic.java: added testcase ++ * tests/netx/unit/net/sourceforge/jnlp/jarsInJreDesc.jnlp: testfile copied form omegat which have this strange resources ++ ++2018-02-03 Jiri Vanek ++ ++ nosecurity switch made extendable also for certificate issues ++ * netx/net/sourceforge/jnlp/config/Defaults.java: set deployment.security.itw.ignorecertissues ++ * netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java: added deployment.security.itw.ignorecertissues ++ * netx/net/sourceforge/jnlp/resources/Messages.properties: BONosecurity is now tailed by rumor about deployment.security.itw.ignorecertissues ++ * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: when ITW was about to throw certificate-caused launch exception, ++ it i snow consulted with nosecurity and deployment.security.itw.ignorecertissues. If both are here, exception is only printed ++ ++2018-02-03 Jiri Vanek ++ ++ * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: autoformatted ++ ++2018-02-03 Jiri Vanek ++ * netx/net/sourceforge/jnlp/Parser.java: auto-formatted ++ + 2017-12-15 Jiri Vanek + + Pre-release tuning +diff -r dbb8dc397d15 -r 4abd0f089773 NEWS +--- a/NEWS Mon Dec 18 13:22:51 2017 +0100 ++++ b/NEWS Fri Mar 02 10:41:29 2018 +0100 +@@ -7,6 +7,11 @@ + GX - http://bugs.gentoo.org/show_bug.cgi?id=X + + CVE-XXXX-YYYY: http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=XXXX-YYYY ++ ++New in release 1.7.2 (YYYY-MM-DD): ++* added support for javafx-desc and so allwong run of pure-javafx only applications ++* --nosecurity enhanced for possibility to skip invalid signatures ++* enhanced to allow resources to be read also from j2se/java element (OmegaT) + + New in release 1.7.1 (2017-12-15): + * better work with authors file +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/ApplicationDesc.java +--- a/netx/net/sourceforge/jnlp/ApplicationDesc.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/ApplicationDesc.java Fri Mar 02 10:41:29 2018 +0100 +@@ -30,7 +30,8 @@ + private final String mainClass; + + /** the arguments */ +- private String arguments[]; ++ private String arguments[]; ++ private final boolean fx; + + /** + * Create an Application descriptor. +@@ -38,9 +39,10 @@ + * @param mainClass the main class name and package + * @param arguments the arguments + */ +- public ApplicationDesc(String mainClass, String arguments[]) { ++ public ApplicationDesc(String mainClass, String[] arguments, boolean isFX) { + this.mainClass = mainClass; + this.arguments = arguments; ++ this.fx = isFX; + } + + /** +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/Node.java +--- a/netx/net/sourceforge/jnlp/Node.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/Node.java Fri Mar 02 10:41:29 2018 +0100 +@@ -40,6 +40,7 @@ + import java.util.ArrayList; + import java.util.Enumeration; + import java.util.List; ++import java.util.Objects; + + import net.sourceforge.nanoxml.XMLElement; + +@@ -52,7 +53,7 @@ + * regular XML Node interface (for the methods used by Parser). + */ + /* NANO */ +-class Node { ++public class Node { + private XMLElement xml; + private Node next; + private Node children[]; +@@ -124,18 +125,62 @@ + return (String) xml.getAttribute(name); + } + +- String getNodeName() { ++ public ElementName getNodeName() { + if (xml.getName() == null) { +- return ""; ++ return new ElementName(""); + } + else { +- return xml.getName(); ++ return new ElementName(xml.getName()); + } + } + ++ + @Override + public String toString() { +- return getNodeName(); ++ return getNodeName().getOriginal(); ++ } ++ ++ public static class ElementName { ++ ++ private final String base; ++ ++ public ElementName(String base) { ++ this.base = base; ++ } ++ ++ @Override ++ public boolean equals(Object obj) { ++ if (obj instanceof ElementName) { ++ return ((ElementName) obj).base.equals(base); ++ } else { ++ return false; ++ } ++ } ++ ++ @Override ++ public int hashCode() { ++ return base.hashCode(); ++ } ++ ++ public String getName() { ++ if (base.contains(":")) { ++ return base.split(":")[1]; ++ } else { ++ return base; ++ } ++ } ++ public String getPrefix() { ++ if (base.contains(":")) { ++ return base.split(":")[0]; ++ } else { ++ return ""; ++ } ++ } ++ ++ private String getOriginal() { ++ return base + "(" + getPrefix() + ":" + getName() + ")"; ++ } ++ + } + } + +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/Parser.java +--- a/netx/net/sourceforge/jnlp/Parser.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/Parser.java Fri Mar 02 10:41:29 2018 +0100 +@@ -14,7 +14,6 @@ + // You should have received a copy of the GNU Lesser General Public + // License along with this library; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +- + package net.sourceforge.jnlp; + + import static net.sourceforge.jnlp.runtime.Translator.R; +@@ -33,26 +32,25 @@ + import net.sourceforge.jnlp.util.logging.OutputController; + + /** +- * Contains methods to parse an XML document into a JNLPFile. +- * Implements JNLP specification version 1.0. ++ * Contains methods to parse an XML document into a JNLPFile. Implements JNLP ++ * specification version 1.0. + * +- * @author Jon A. Maxwell (JAM) - initial author ++ * @author Jon A. Maxwell ++ * (JAM) - initial author + * @version $Revision: 1.13 $ + */ + public final class Parser { +- ++ + private static String CODEBASE = "codebase"; + private static String MAINCLASS = "main-class"; + private static final Pattern anyWhiteSpace = Pattern.compile("\\s"); + + // defines netx.jnlp.Node class if using Tiny XML or Nano XML +- + // Currently uses the Nano XML parse. Search for "SAX" or + // "TINY" or "NANO" and uncomment those blocks and comment the + // active ones (if any) to switch XML parsers. Also + // (un)comment appropriate Node class at end of this file and + // do a clean build. +- + /** + * Ensure consistent error handling. + */ +@@ -69,80 +67,96 @@ + OutputController.getLogger().log(OutputController.Level.ERROR_ALL, exception); + } + }; +- */ +- ++ */ + // fix: some descriptors need to use the jnlp file at a later + // date and having file ref lets us pass it to their + // constructors + // +- /** the file reference */ ++ /** ++ * the file reference ++ */ + private final JNLPFile file; // do not use (uninitialized) + +- /** the root node */ ++ /** ++ * the root node ++ */ + private final Node root; + +- /** the specification version */ ++ /** ++ * the specification version ++ */ + private final Version spec; + +- /** the base URL that all hrefs are relative to */ ++ /** ++ * the base URL that all hrefs are relative to ++ */ + private final URL base; + +- /** the codebase URL */ ++ /** ++ * the codebase URL ++ */ + private URL codebase; + +- /** the file URL */ ++ /** ++ * the file URL ++ */ + private final URL fileLocation; + +- /** whether to throw errors on non-fatal errors. */ ++ /** ++ * whether to throw errors on non-fatal errors. ++ */ + private final boolean strict; // if strict==true parses a file with no error then strict==false should also + +- /** whether to allow extensions to the JNLP specification */ ++ /** ++ * whether to allow extensions to the JNLP specification ++ */ + private final boolean allowExtensions; // true if extensions to JNLP spec are ok +- ++ + /** +- * Create a parser for the JNLP file. If the location +- * parameters is not null it is used as the default codebase +- * (does not override value of jnlp element's href +- * attribute). ++ * Create a parser for the JNLP file. If the location parameters is not null ++ * it is used as the default codebase (does not override value of jnlp ++ * element's href attribute). + *

+- * The root node may be normalized as a side effect of this +- * constructor. ++ * The root node may be normalized as a side effect of this constructor. + *

++ * + * @param file the (uninitialized) file reference +- * @param base if codebase is not specified, a default base for relative URLs ++ * @param base if codebase is not specified, a default base for relative ++ * URLs + * @param root the root node + * @param settings the parser settings to use when parsing the JNLP file + * @throws ParseException if the JNLP file is invalid + */ +- Parser(JNLPFile file, URL base, Node root, ParserSettings settings) throws ParseException { +- this(file, base, root, settings, null); ++ public Parser(JNLPFile file, URL base, Node root, ParserSettings settings) throws ParseException { ++ this(file, base, root, settings, null); + } + + /** +- * Create a parser for the JNLP file. If the location +- * parameters is not null it is used as the default codebase +- * (does not override value of jnlp element's href +- * attribute). ++ * Create a parser for the JNLP file. If the location parameters is not null ++ * it is used as the default codebase (does not override value of jnlp ++ * element's href attribute). + *

+- * The root node may be normalized as a side effect of this +- * constructor. ++ * The root node may be normalized as a side effect of this constructor. + *

++ * + * @param file the (uninitialized) file reference +- * @param base if codebase is not specified, a default base for relative URLs ++ * @param base if codebase is not specified, a default base for relative ++ * URLs + * @param root the root node + * @param settings the parser settings to use when parsing the JNLP file + * @param codebase codebase to use if we did not parse one from JNLP file. + * @throws ParseException if the JNLP file is invalid + */ +- Parser(JNLPFile file, URL base, Node root, ParserSettings settings, URL codebase) throws ParseException { ++ public Parser(JNLPFile file, URL base, Node root, ParserSettings settings, URL codebase) throws ParseException { + this.file = file; + this.root = root; + this.strict = settings.isStrict(); + this.allowExtensions = settings.isExtensionAllowed(); + + // ensure it's a JNLP node +- if (root == null || !root.getNodeName().equals("jnlp")) ++ if (root == null || !root.getNodeName().getName().equals("jnlp")) { + throw new ParseException(R("PInvalidRoot")); ++ } + + // JNLP tag information + this.spec = getVersion(root, "spec", "1.0+"); +@@ -154,7 +168,9 @@ + } + + if (this.codebase == null) // Codebase is overwritten if codebase was not specified in file or if parsing of it failed ++ { + this.codebase = codebase; ++ } + + this.base = (this.codebase != null) ? this.codebase : base; // if codebase not specified use default codebase + fileLocation = getURL(root, "href", this.base); +@@ -165,6 +181,7 @@ + + /** + * Returns the file version. ++ * + * @return version of file + */ + public Version getFileVersion() { +@@ -173,6 +190,7 @@ + + /** + * Returns the file location. ++ * + * @return url of source file + */ + public URL getFileLocation() { +@@ -188,7 +206,7 @@ + + /** + * @return the specification version. +- * ++ * + */ + public Version getSpecVersion() { + return spec; +@@ -198,7 +216,7 @@ + UpdateDesc updateDesc = null; + Node child = parent.getFirstChild(); + while (child != null) { +- if (child.getNodeName().equals("update")) { ++ if (child.getNodeName().getName().equals("update")) { + if (strict && updateDesc != null) { + throw new ParseException(R("PTwoUpdates")); + } +@@ -254,16 +272,15 @@ + // + // This section loads the resources elements + // +- + /** +- * @return all of the ResourcesDesc elements under the specified +- * node (jnlp or j2se). ++ * @return all of the ResourcesDesc elements under the specified node (jnlp ++ * or j2se). + * + * @param parent the parent node (either jnlp or j2se) + * @param j2se true if the resources are located under a j2se or java node + * @throws ParseException if the JNLP file is invalid + */ +- List getResources(Node parent, boolean j2se) ++ public List getResources(Node parent, boolean j2se) + throws ParseException { + List result = new ArrayList<>(); + Node resources[] = getChildNodes(parent, "resources"); +@@ -285,34 +302,39 @@ + * @param j2se true if the resources are located under a j2se or java node + * @throws ParseException if the JNLP file is invalid + */ +- private ResourcesDesc getResourcesDesc(Node node, boolean j2se) throws ParseException { ++ private ResourcesDesc getResourcesDesc(Node node, boolean j2se) throws ParseException { + boolean mainFlag = false; // if found a main tag + + // create resources +- ResourcesDesc resources = +- new ResourcesDesc(file, +- getLocales(node), +- splitString(getAttribute(node, "os", null)), +- splitString(getAttribute(node, "arch", null))); ++ ResourcesDesc resources ++ = new ResourcesDesc(file, ++ getLocales(node), ++ splitString(getAttribute(node, "os", null)), ++ splitString(getAttribute(node, "arch", null))); + + // step through the elements + Node child = node.getFirstChild(); + while (child != null) { +- String name = child.getNodeName(); ++ String name = child.getNodeName().getName(); + + // check for nativelib but no trusted environment +- if ("nativelib".equals(name)) +- if (!isTrustedEnvironment()) ++ if ("nativelib".equals(name)) { ++ if (!isTrustedEnvironment()) { + throw new ParseException(R("PUntrustedNative")); ++ } ++ } + + if ("j2se".equals(name) || "java".equals(name)) { +- if (getChildNode(root, "component-desc") != null) +- if (strict) ++ if (getChildNode(root, "component-desc") != null) { ++ if (strict) { + throw new ParseException(R("PExtensionHasJ2SE")); +- if (!j2se) ++ } ++ } ++ if (!j2se) { + resources.addResource(getJRE(child)); +- else ++ } else { + throw new ParseException(R("PInnerJ2SE")); ++ } + } + + if ("jar".equals(name) || "nativelib".equals(name)) { +@@ -331,14 +353,17 @@ + resources.addResource(jar); + } + +- if ("extension".equals(name)) ++ if ("extension".equals(name)) { + resources.addResource(getExtension(child)); ++ } + +- if ("property".equals(name)) ++ if ("property".equals(name)) { + resources.addResource(getProperty(child)); ++ } + +- if ("package".equals(name)) ++ if ("package".equals(name)) { + resources.addResource(getPackage(child)); ++ } + + child = child.getNextSibling(); + } +@@ -378,16 +403,18 @@ + * @throws ParseException if the JNLP file is invalid + */ + private JARDesc getJAR(Node node) throws ParseException { +- boolean nativeJar = "nativelib".equals(node.getNodeName()); ++ boolean nativeJar = "nativelib".equals(node.getNodeName().getName()); + URL location = getRequiredURL(node, "href", base); + Version version = getVersion(node, "version", null); + String part = getAttribute(node, "part", null); + boolean main = "true".equals(getAttribute(node, "main", "false")); + boolean lazy = "lazy".equals(getAttribute(node, "download", "eager")); + +- if (nativeJar && main) +- if (strict) ++ if (nativeJar && main) { ++ if (strict) { + throw new ParseException(R("PNativeHasMain")); ++ } ++ } + + return new JARDesc(location, version, part, lazy, main, nativeJar, true); + +@@ -445,14 +472,15 @@ + // + // This section loads the information elements + // +- + /** + * Make sure a title and vendor are present and nonempty and localized as + * best matching as possible for the JVM's current locale. Fallback to a +- * generalized title and vendor otherwise. If none is found, throw an exception. ++ * generalized title and vendor otherwise. If none is found, throw an ++ * exception. + * +- * Additionally prints homepage, description, title and vendor to stdout +- * if in Debug mode. ++ * Additionally prints homepage, description, title and vendor to stdout if ++ * in Debug mode. ++ * + * @throws RequiredElementException + */ + void checkForInformation() throws RequiredElementException { +@@ -462,30 +490,34 @@ + String title = file.getTitle(); + String vendor = file.getVendor(); + +- if (title == null || title.trim().isEmpty()) ++ if (title == null || title.trim().isEmpty()) { + throw new MissingTitleException(); +- else OutputController.getLogger().log("Acceptable title tag found, contains: " + title); ++ } else { ++ OutputController.getLogger().log("Acceptable title tag found, contains: " + title); ++ } + +- if (vendor == null || vendor.trim().isEmpty()) ++ if (vendor == null || vendor.trim().isEmpty()) { + throw new MissingVendorException(); +- else OutputController.getLogger().log("Acceptable vendor tag found, contains: " + vendor); ++ } else { ++ OutputController.getLogger().log("Acceptable vendor tag found, contains: " + vendor); ++ } + } + + /** +- * @return all of the information elements under the specified +- * node. ++ * @return all of the information elements under the specified node. + * + * @param parent the parent node (jnlp) + * @throws ParseException if the JNLP file is invalid + */ +- List getInfo(Node parent) ++ public List getInfo(Node parent) + throws ParseException { + List result = new ArrayList<>(); + Node info[] = getChildNodes(parent, "information"); + + // ensure that there are at least one information section present +- if (info.length == 0) ++ if (info.length == 0) { + throw new MissingInformationException(); ++ } + + // create objects from the info sections + for (Node infoNode : info) { +@@ -501,7 +533,7 @@ + * @param node the information node + * @throws ParseException if the JNLP file is invalid + */ +- InformationDesc getInformationDesc(Node node) throws ParseException { ++ InformationDesc getInformationDesc(Node node) throws ParseException { + List descriptionsUsed = new ArrayList<>(); + + // locale +@@ -513,30 +545,38 @@ + // step through the elements + Node child = node.getFirstChild(); + while (child != null) { +- String name = child.getNodeName(); ++ String name = child.getNodeName().getName(); + +- if ("title".equals(name)) ++ if ("title".equals(name)) { + addInfo(info, child, null, getSpanText(child, false)); +- if ("vendor".equals(name)) ++ } ++ if ("vendor".equals(name)) { + addInfo(info, child, null, getSpanText(child, false)); ++ } + if ("description".equals(name)) { + String kind = getAttribute(child, "kind", "default"); +- if (descriptionsUsed.contains(kind)) +- if (strict) ++ if (descriptionsUsed.contains(kind)) { ++ if (strict) { + throw new ParseException(R("PTwoDescriptions", kind)); ++ } ++ } + + descriptionsUsed.add(kind); + addInfo(info, child, kind, getSpanText(child, false)); + } +- if ("homepage".equals(name)) ++ if ("homepage".equals(name)) { + addInfo(info, child, null, getRequiredURL(child, "href", base)); +- if ("icon".equals(name)) ++ } ++ if ("icon".equals(name)) { + addInfo(info, child, getAttribute(child, "kind", "default"), getIcon(child)); +- if ("offline-allowed".equals(name)) ++ } ++ if ("offline-allowed".equals(name)) { + addInfo(info, child, null, Boolean.TRUE); ++ } + if ("sharing-allowed".equals(name)) { +- if (strict && !allowExtensions) ++ if (strict && !allowExtensions) { + throw new ParseException(R("PSharing")); ++ } + addInfo(info, child, null, Boolean.TRUE); + } + if ("association".equals(name)) { +@@ -566,10 +606,11 @@ + protected void addInfo(InformationDesc info, Node node, String mod, Object value) { + String modStr = (mod == null) ? "" : "-" + mod; + +- if (node == null) ++ if (node == null) { + return; ++ } + +- info.addItem(node.getNodeName() + modStr, value); ++ info.addItem(node.getNodeName().getName() + modStr, value); + } + + /** +@@ -592,22 +633,23 @@ + // + // This section loads the security descriptor element + // +- + /** +- * @return the security descriptor element. If no security +- * element was specified in the JNLP file then a SecurityDesc +- * with applet permissions is returned. ++ * @return the security descriptor element. If no security element was ++ * specified in the JNLP file then a SecurityDesc with applet permissions is ++ * returned. + * + * @param parent the parent node + * @throws ParseException if the JNLP file is invalid + */ +- SecurityDesc getSecurity(Node parent) throws ParseException { ++ public SecurityDesc getSecurity(Node parent) throws ParseException { + Node nodes[] = getChildNodes(parent, "security"); + + // test for too many security elements +- if (nodes.length > 1) +- if (strict) ++ if (nodes.length > 1) { ++ if (strict) { + throw new ParseException(R("PTwoSecurity")); ++ } ++ } + + Object type = SecurityDesc.SANDBOX_PERMISSIONS; + RequestedPermissionLevel requestedPermissionLevel = RequestedPermissionLevel.NONE; +@@ -633,16 +675,17 @@ + } + + /** +- * Returns whether the JNLP file requests a trusted execution +- * environment. ++ * Returns whether the JNLP file requests a trusted execution environment. + */ + private boolean isTrustedEnvironment() { + Node security = getChildNode(root, "security"); + +- if (security != null) ++ if (security != null) { + if (getChildNode(security, "all-permissions") != null +- || getChildNode(security, "j2ee-application-client-permissions") != null) ++ || getChildNode(security, "j2ee-application-client-permissions") != null) { + return true; ++ } ++ } + + return false; + } +@@ -650,7 +693,6 @@ + // + // This section loads the launch descriptor element + // +- + /** + * @return the launch descriptor element, either AppletDesc, + * ApplicationDesc, or InstallerDesc. +@@ -658,23 +700,31 @@ + * @param parent the parent node + * @throws ParseException if the JNLP file is invalid + */ +- LaunchDesc getLauncher(Node parent) throws ParseException { ++ public LaunchDesc getLauncher(Node parent) throws ParseException { + // check for other than one application type + if (1 < getChildNodes(parent, "applet-desc").length + + getChildNodes(parent, "application-desc").length +- + getChildNodes(parent, "installer-desc").length) ++ + getChildNodes(parent, "javafx-desc").length ++ + getChildNodes(parent, "installer-desc").length) { + throw new ParseException(R("PTwoDescriptors")); ++ } + + Node child = parent.getFirstChild(); + while (child != null) { +- String name = child.getNodeName(); ++ String name = child.getNodeName().getName(); + +- if ("applet-desc".equals(name)) ++ if ("applet-desc".equals(name)) { + return getApplet(child); +- if ("application-desc".equals(name)) +- return getApplication(child); +- if ("installer-desc".equals(name)) ++ } ++ if ("application-desc".equals(name)) { ++ return getApplication(child, false); ++ } ++ if ("installer-desc".equals(name)) { + return getInstaller(child); ++ } ++ if ("javafx-desc".equals(name)) { ++ return getApplication(child, true); ++ } + + child = child.getNextSibling(); + } +@@ -682,6 +732,8 @@ + // not reached + return null; + } ++ ++ + + /** + * @param node +@@ -701,8 +753,9 @@ + width = Integer.parseInt(getRequiredAttribute(node, "width", "100")); + height = Integer.parseInt(getRequiredAttribute(node, "height", "100")); + } catch (NumberFormatException nfe) { +- if (width <= 0) ++ if (width <= 0) { + throw new ParseException(R("PBadWidth")); ++ } + throw new ParseException(R("PBadWidth")); + } + +@@ -721,13 +774,12 @@ + * @param node + * @throws ParseException if the JNLP file is invalid + */ +- private ApplicationDesc getApplication(Node node) throws ParseException { ++ private ApplicationDesc getApplication(Node node, boolean isFx) throws ParseException { + String main = getMainClass(node, false); + List argsList = new ArrayList<>(); + + // if (main == null) + // only ok if can be found in main jar file (can't check here but make a note) +- + // read parameters + Node args[] = getChildNodes(node, "argument"); + for (Node arg : args) { +@@ -738,7 +790,7 @@ + + String argStrings[] = argsList.toArray(new String[argsList.size()]); + +- return new ApplicationDesc(main, argStrings); ++ return new ApplicationDesc(main, argStrings, isFx); + } + + /** +@@ -754,10 +806,11 @@ + + Node child = parent.getFirstChild(); + while (child != null) { +- String name = child.getNodeName(); ++ String name = child.getNodeName().getName(); + +- if ("component-desc".equals(name)) ++ if ("component-desc".equals(name)) { + return new ComponentDesc(); ++ } + + child = child.getNextSibling(); + } +@@ -801,19 +854,23 @@ + // step through the elements + Node child = node.getFirstChild(); + while (child != null) { +- String name = child.getNodeName(); ++ String name = child.getNodeName().getName(); + +- if (null != name) switch (name) { +- case "desktop": +- if (showOnDesktop && strict) { +- throw new ParseException(R("PTwoDesktops")); +- } showOnDesktop = true; +- break; +- case "menu": +- if (menu != null && strict) { +- throw new ParseException(R("PTwoMenus")); +- } menu = getMenu(child); +- break; ++ if (null != name) { ++ switch (name) { ++ case "desktop": ++ if (showOnDesktop && strict) { ++ throw new ParseException(R("PTwoDesktops")); ++ } ++ showOnDesktop = true; ++ break; ++ case "menu": ++ if (menu != null && strict) { ++ throw new ParseException(R("PTwoMenus")); ++ } ++ menu = getMenu(child); ++ break; ++ } + } + + child = child.getNextSibling(); +@@ -850,24 +907,29 @@ + // step through the elements + Node child = node.getFirstChild(); + while (child != null) { +- String name = child.getNodeName(); ++ String name = child.getNodeName().getName(); + +- if (null != name) switch (name) { +- case "title": +- if (title != null && strict) { +- throw new ParseException(R("PTwoTitles")); +- } title = getSpanText(child, false); +- break; +- case "description": +- if (description != null && strict) { +- throw new ParseException(R("PTwoDescriptions")); +- } description = getSpanText(child, false); +- break; +- case "icon": +- if (icon != null && strict) { +- throw new ParseException(R("PTwoIcons")); +- } icon = getIcon(child); +- break; ++ if (null != name) { ++ switch (name) { ++ case "title": ++ if (title != null && strict) { ++ throw new ParseException(R("PTwoTitles")); ++ } ++ title = getSpanText(child, false); ++ break; ++ case "description": ++ if (description != null && strict) { ++ throw new ParseException(R("PTwoDescriptions")); ++ } ++ description = getSpanText(child, false); ++ break; ++ case "icon": ++ if (icon != null && strict) { ++ throw new ParseException(R("PTwoIcons")); ++ } ++ icon = getIcon(child); ++ break; ++ } + } + + child = child.getNextSibling(); +@@ -883,16 +945,16 @@ + } + + // other methods +- + /** +- * @return an array of substrings seperated by spaces (spaces +- * escaped with backslash do not separate strings). This method +- * splits strings as per the spec except that it does replace +- * escaped other characters with their own value. ++ * @return an array of substrings seperated by spaces (spaces escaped with ++ * backslash do not separate strings). This method splits strings as per the ++ * spec except that it does replace escaped other characters with their own ++ * value. + */ + private String[] splitString(String source) { +- if (source == null) ++ if (source == null) { + return new String[0]; ++ } + + List result = new ArrayList(); + StringTokenizer st = new StringTokenizer(source, " "); +@@ -904,18 +966,20 @@ + while (true) { + part.append(st.nextToken()); + +- if (st.hasMoreTokens() && part.charAt(part.length() - 1) == '\\') ++ if (st.hasMoreTokens() && part.charAt(part.length() - 1) == '\\') { + part.setCharAt(part.length() - 1, ' '); // join with the space +- else ++ } else { + break; // bizarre while format gets \ at end of string right (no extra space added at end) ++ } + } + + // delete \ quote chars +- for (int i = part.length(); i-- > 0;) +- // sweet syntax for reverse loop +- if (part.charAt(i) == '\\') ++ for (int i = part.length(); i-- > 0;) // sweet syntax for reverse loop ++ { ++ if (part.charAt(i) == '\\') { + part.deleteCharAt(i--); // and skip previous char so \\ becomes \ +- ++ } ++ } + result.add(part.toString()); + } + +@@ -929,13 +993,14 @@ + */ + private Locale[] getLocales(Node node) { + List locales = new ArrayList<>(); +- String localeParts[] = +- splitString(getAttribute(node, "locale", "")); ++ String localeParts[] ++ = splitString(getAttribute(node, "locale", "")); + + for (String localePart : localeParts) { + Locale l = getLocale(localePart); +- if (l != null) ++ if (l != null) { + locales.add(l); ++ } + } + + return locales.toArray(new Locale[locales.size()]); +@@ -948,8 +1013,9 @@ + * @return locale of document + */ + public Locale getLocale(String localeStr) { +- if (localeStr.length() < 2) ++ if (localeStr.length() < 2) { + return null; ++ } + + String language = localeStr.substring(0, 2); + String country = (localeStr.length() < 5) ? "" : localeStr.substring(3, 5); +@@ -965,7 +1031,7 @@ + * "<description>text</description>". + * + * @param node the node with text under it +- * @return ++ * @return + * @throws ParseException if the JNLP file is invalid + */ + private String getSpanText(Node node) throws ParseException { +@@ -974,9 +1040,9 @@ + + /** + * Returns the implied text under a node, for example "text" in +- * "<description>text</description>". If preserveSpacing is false, +- * sequences of whitespace characters are turned into a single +- * space character. ++ * "<description>text</description>". If preserveSpacing is ++ * false, sequences of whitespace characters are turned into a single space ++ * character. + * + * @param node the node with text under it + * @param preserveSpacing if true, preserve whitespace +@@ -984,19 +1050,18 @@ + */ + private String getSpanText(Node node, boolean preserveSpacing) + throws ParseException { +- if (node == null) ++ if (node == null) { + return null; ++ } + + // NANO + String val = node.getNodeValue(); + if (preserveSpacing) { + return val; ++ } else if (val == null) { ++ return null; + } else { +- if (val == null) { +- return null; +- } else { +- return val.replaceAll("\\s+", " "); +- } ++ return val.replaceAll("\\s+", " "); + } + + /* TINY +@@ -1005,13 +1070,13 @@ + if (child == null) { + if (strict) + // not sure if this is an error or whether "" is proper +- throw new ParseException("No text specified (node="+node.getNodeName()+")"); ++ throw new ParseException("No text specified (node="+node.getNodeName().getName()+")"); + else + return ""; + } + + return child.getNodeValue(); +- */ ++ */ + } + + /** +@@ -1019,10 +1084,11 @@ + */ + private static Node getChildNode(Node node, String name) { + Node[] result = getChildNodes(node, name); +- if (result.length == 0) ++ if (result.length == 0) { + return null; +- else ++ } else { + return result[0]; ++ } + } + + /** +@@ -1033,8 +1099,9 @@ + + Node child = node.getFirstChild(); + while (child != null) { +- if (child.getNodeName().equals(name)) ++ if (child.getNodeName().getName().equals(name)) { + result.add(child); ++ } + child = child.getNextSibling(); + } + +@@ -1042,12 +1109,13 @@ + } + + /** +- * Returns a URL with a trailing / appended to it if there is no +- * trailing slash on the specifed URL. ++ * Returns a URL with a trailing / appended to it if there is no trailing ++ * slash on the specifed URL. + */ + private URL addSlash(URL source) { +- if (source == null) ++ if (source == null) { + return null; ++ } + + if (!source.toString().endsWith("/")) { + try { +@@ -1060,8 +1128,8 @@ + } + + /** +- * @return the same result as getURL except that a +- * ParseException is thrown if the attribute is null or empty. ++ * @return the same result as getURL except that a ParseException is thrown ++ * if the attribute is null or empty. + * + * @param node the node + * @param name the attribute containing an href +@@ -1077,17 +1145,16 @@ + } + + /** +- * @return a URL object from a href string relative to the +- * code base. If the href denotes a relative URL, it must +- * reference a location that is a subdirectory of the +- * codebase. ++ * @return a URL object from a href string relative to the code base. If the ++ * href denotes a relative URL, it must reference a location that is a ++ * subdirectory of the codebase. + * + * @param node the node + * @param name the attribute containing an href + * @param base the base URL + * @throws ParseException if the JNLP file is invalid + */ +- URL getURL(Node node, String name, URL base) throws ParseException { ++ public URL getURL(Node node, String name, URL base) throws ParseException { + String href; + if (CODEBASE.equals(name)) { + href = getCleanAttribute(node, name); +@@ -1099,17 +1166,17 @@ + } else { + href = getAttribute(node, name, null); + } +- return getURL(href, node.getNodeName(), base, strict); ++ return getURL(href, node.getNodeName().getName(), base, strict); + } +- ++ + public static URL getURL(String href, String nodeName, URL base, boolean strict) throws ParseException { +- if (href == null) { ++ if (href == null) { + return null; // so that code can throw an exception if attribute was required + } + try { +- if (base == null) ++ if (base == null) { + return new URL(href); +- else { ++ } else { + try { + return new URL(href); + } catch (MalformedURLException ex) { +@@ -1119,7 +1186,7 @@ + URL result = new URL(base, href); + + // check for going above the codebase +- if (!result.toString().startsWith(base.toString()) && !base.toString().startsWith(result.toString())){ ++ if (!result.toString().startsWith(base.toString()) && !base.toString().startsWith(result.toString())) { + if (strict) { + throw new ParseException(R("PUrlNotInCodebase", nodeName, href, base)); + } +@@ -1128,16 +1195,16 @@ + } + + } catch (MalformedURLException ex) { +- if (base == null) ++ if (base == null) { + throw new ParseException(R("PBadNonrelativeUrl", nodeName, href)); +- else ++ } else { + throw new ParseException(R("PBadRelativeUrl", nodeName, href, base)); ++ } + } + } + + /** +- * @return a Version from the specified attribute and default +- * value. ++ * @return a Version from the specified attribute and default value. + * + * @param node the node + * @param name the attribute +@@ -1146,14 +1213,16 @@ + */ + private Version getVersion(Node node, String name, String defaultValue) { + String version = getAttribute(node, name, defaultValue); +- if (version == null) ++ if (version == null) { + return null; +- else ++ } else { + return new Version(version); ++ } + } + + /** + * Check that the VM args are valid and safe ++ * + * @param vmArgs a string containing the args + * @throws ParseException if the VM arguments are invalid or dangerous + */ +@@ -1191,76 +1260,75 @@ + /** + * Returns an array of valid (ie safe and supported) arguments for the JVM + * +- * Based on http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/syntax.html ++ * Based on ++ * http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/syntax.html + */ + private String[] getValidVMArguments() { +- return new String[] { +- "-d32", /* use a 32-bit data model if available */ +- "-client", /* to select the client VM */ +- "-server", /* to select the server VM */ +- "-verbose", /* enable verbose output */ +- "-version", /* print product version and exit */ +- "-showversion", /* print product version and continue */ +- "-help", /* print this help message */ +- "-X", /* print help on non-standard options */ +- "-ea", /* enable assertions */ +- "-enableassertions", /* enable assertions */ +- "-da", /* disable assertions */ +- "-disableassertions", /* disable assertions */ +- "-esa", /* enable system assertions */ +- "-enablesystemassertions", /* enable system assertions */ +- "-dsa", /* disable system assertione */ +- "-disablesystemassertions", /* disable system assertione */ +- "-Xmixed", /* mixed mode execution (default) */ +- "-Xint", /* interpreted mode execution only */ +- "-Xnoclassgc", /* disable class garbage collection */ +- "-Xincgc", /* enable incremental garbage collection */ +- "-Xbatch", /* disable background compilation */ +- "-Xprof", /* output cpu profiling data */ +- "-Xdebug", /* enable remote debugging */ +- "-Xfuture", /* enable strictest checks, anticipating future default */ +- "-Xrs", /* reduce use of OS signals by Java/VM (see documentation) */ +- "-XX:+ForceTimeHighResolution", /* use high resolution timer */ +- "-XX:-ForceTimeHighResolution", /* use low resolution (default) */ +- }; ++ return new String[]{ ++ "-d32", /* use a 32-bit data model if available */ ++ "-client", /* to select the client VM */ ++ "-server", /* to select the server VM */ ++ "-verbose", /* enable verbose output */ ++ "-version", /* print product version and exit */ ++ "-showversion", /* print product version and continue */ ++ "-help", /* print this help message */ ++ "-X", /* print help on non-standard options */ ++ "-ea", /* enable assertions */ ++ "-enableassertions", /* enable assertions */ ++ "-da", /* disable assertions */ ++ "-disableassertions", /* disable assertions */ ++ "-esa", /* enable system assertions */ ++ "-enablesystemassertions", /* enable system assertions */ ++ "-dsa", /* disable system assertione */ ++ "-disablesystemassertions", /* disable system assertione */ ++ "-Xmixed", /* mixed mode execution (default) */ ++ "-Xint", /* interpreted mode execution only */ ++ "-Xnoclassgc", /* disable class garbage collection */ ++ "-Xincgc", /* enable incremental garbage collection */ ++ "-Xbatch", /* disable background compilation */ ++ "-Xprof", /* output cpu profiling data */ ++ "-Xdebug", /* enable remote debugging */ ++ "-Xfuture", /* enable strictest checks, anticipating future default */ ++ "-Xrs", /* reduce use of OS signals by Java/VM (see documentation) */ ++ "-XX:+ForceTimeHighResolution", /* use high resolution timer */ ++ "-XX:-ForceTimeHighResolution", /* use low resolution (default) */}; + } + + /** + * Returns an array containing the starts of valid (ie safe and supported) + * arguments for the JVM + * +- * Based on http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/syntax.html ++ * Based on ++ * http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/syntax.html + */ + private String[] getValidStartingVMArguments() { +- return new String[] { +- "-ea", /* enable assertions for classes */ +- "-enableassertions", /* enable assertions for classes */ +- "-da", /* disable assertions for classes */ +- "-disableassertions", /* disable assertions for classes */ +- "-verbose", /* enable verbose output */ +- "-Xms", /* set initial Java heap size */ +- "-Xmx", /* set maximum Java heap size */ +- "-Xss", /* set java thread stack size */ +- "-XX:NewRatio", /* set Ratio of new/old gen sizes */ +- "-XX:NewSize", /* set initial size of new generation */ +- "-XX:MaxNewSize", /* set max size of new generation */ +- "-XX:PermSize", /* set initial size of permanent gen */ +- "-XX:MaxPermSize", /* set max size of permanent gen */ +- "-XX:MaxHeapFreeRatio", /* heap free percentage (default 70) */ +- "-XX:MinHeapFreeRatio", /* heap free percentage (default 40) */ +- "-XX:UseSerialGC", /* use serial garbage collection */ +- "-XX:ThreadStackSize", /* thread stack size (in KB) */ +- "-XX:MaxInlineSize", /* set max num of bytecodes to inline */ +- "-XX:ReservedCodeCacheSize", /* Reserved code cache size (bytes) */ +- "-XX:MaxDirectMemorySize", +- +- }; ++ return new String[]{ ++ "-ea", /* enable assertions for classes */ ++ "-enableassertions", /* enable assertions for classes */ ++ "-da", /* disable assertions for classes */ ++ "-disableassertions", /* disable assertions for classes */ ++ "-verbose", /* enable verbose output */ ++ "-Xms", /* set initial Java heap size */ ++ "-Xmx", /* set maximum Java heap size */ ++ "-Xss", /* set java thread stack size */ ++ "-XX:NewRatio", /* set Ratio of new/old gen sizes */ ++ "-XX:NewSize", /* set initial size of new generation */ ++ "-XX:MaxNewSize", /* set max size of new generation */ ++ "-XX:PermSize", /* set initial size of permanent gen */ ++ "-XX:MaxPermSize", /* set max size of permanent gen */ ++ "-XX:MaxHeapFreeRatio", /* heap free percentage (default 70) */ ++ "-XX:MinHeapFreeRatio", /* heap free percentage (default 40) */ ++ "-XX:UseSerialGC", /* use serial garbage collection */ ++ "-XX:ThreadStackSize", /* thread stack size (in KB) */ ++ "-XX:MaxInlineSize", /* set max num of bytecodes to inline */ ++ "-XX:ReservedCodeCacheSize", /* Reserved code cache size (bytes) */ ++ "-XX:MaxDirectMemorySize",}; + } + + /** +- * @return the same result as getAttribute except that if strict +- * mode is enabled or the default value is null a parse +- * exception is thrown instead of returning the default value. ++ * @return the same result as getAttribute except that if strict mode is ++ * enabled or the default value is null a parse exception is thrown instead ++ * of returning the default value. + * + * @param node the node + * @param name the attribute +@@ -1270,19 +1338,22 @@ + private String getRequiredAttribute(Node node, String name, String defaultValue) throws ParseException { + String result = getAttribute(node, name, null); + +- if (result == null || result.length() == 0) +- if (strict || defaultValue == null) +- throw new ParseException(R("PNeedsAttribute", node.getNodeName(), name)); ++ if (result == null || result.length() == 0) { ++ if (strict || defaultValue == null) { ++ throw new ParseException(R("PNeedsAttribute", node.getNodeName().getName(), name)); ++ } ++ } + +- if (result == null) ++ if (result == null) { + return defaultValue; +- else ++ } else { + return result; ++ } + } + + /** +- * @return an attribute or the specified defaultValue if there is +- * no such attribute. ++ * @return an attribute or the specified defaultValue if there is no such ++ * attribute. + * + * @param node the node + * @param name the attribute +@@ -1305,32 +1376,31 @@ + return result; + } + +- + public static final String MALFORMED_PARSER_CLASS = "net.sourceforge.jnlp.MalformedXMLParser"; + public static final String NORMAL_PARSER_CLASS = "net.sourceforge.jnlp.XMLParser"; ++ + /** +- * @return the root node from the XML document in the specified +- * input stream. ++ * @return the root node from the XML document in the specified input ++ * stream. + * + * @throws ParseException if the JNLP file is invalid + */ +- static Node getRootNode(InputStream input, ParserSettings settings) throws ParseException { ++ public static Node getRootNode(InputStream input, ParserSettings settings) throws ParseException { + try { + 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()); ++ throw (ParseException) (e.getCause()); + } + throw new ParseException(R("PBadXML"), e); + } catch (Exception e) { + throw new ParseException(R("PBadXML"), e); + } + } +- + +- public static Object getParserInstance(ParserSettings settings) throws ClassNotFoundException, IllegalAccessException, InstantiationException { ++ public static Object getParserInstance(ParserSettings settings) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + String className; + if (settings.isMalformedXmlAllowed()) { + className = MALFORMED_PARSER_CLASS; +@@ -1364,7 +1434,7 @@ + return instance; + } + +- private String getOptionalMainClass(Node node) { ++ private String getOptionalMainClass(Node node) { + try { + return getMainClass(node, false); + } catch (ParseException ex) { +@@ -1401,7 +1471,7 @@ + OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, "Invlaid char in main-class: '" + main.charAt(0) + "'"); + } + for (int i = 1; i < main.length(); i++) { +- if (main.charAt(i)=='.'){ ++ if (main.charAt(i) == '.') { + //dot connects identifiers + continue; + } +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/ResourcesDesc.java +--- a/netx/net/sourceforge/jnlp/ResourcesDesc.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/ResourcesDesc.java Fri Mar 02 10:41:29 2018 +0100 +@@ -213,15 +213,34 @@ + */ + public List getResources(Class type) { + List result = new ArrayList<>(); +- + for (Object resource : resources) { +- if (type.isAssignableFrom(resource.getClass())) +- result.add(type.cast(resource)); ++ if (resource instanceof JREDesc) { ++ JREDesc jre = (JREDesc) resource; ++ List descs = jre.getResourcesDesc(); ++ for (ResourcesDesc desc : descs) { ++ result.addAll(desc.getResources(type)); ++ } ++ } ++ if (isWontedResource(resource, type)) { ++ result.add(getWontedResource(resource, type)); ++ } + } + + return result; + } + ++ private static boolean isWontedResource(Object resource, Class type) { ++ T l = getWontedResource(resource, type); ++ return l != null; ++ } ++ ++ private static T getWontedResource(Object resource, Class type) { ++ if (type.isAssignableFrom(resource.getClass())) { ++ return type.cast(resource); ++ } ++ return null; ++ } ++ + /** + * Add a resource. + * @param resource to be added +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/ShortcutDesc.java +--- a/netx/net/sourceforge/jnlp/ShortcutDesc.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/ShortcutDesc.java Fri Mar 02 10:41:29 2018 +0100 +@@ -74,7 +74,7 @@ + * For testing purposes. Verify if it have been parsed out correctly. + * @return whether the shortcut requires being online. + */ +- boolean isOnlineValue() { ++ public boolean isOnlineValue() { + return requiresOnline; + } + +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/config/Defaults.java +--- a/netx/net/sourceforge/jnlp/config/Defaults.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/config/Defaults.java Fri Mar 02 10:41:29 2018 +0100 +@@ -226,6 +226,11 @@ + String.valueOf(false) + }, + { ++ DeploymentConfiguration.KEY_SECURITY_ITW_IGNORECERTISSUES, ++ BasicValueValidators.getBooleanValidator(), ++ String.valueOf(false) ++ }, ++ { + DeploymentConfiguration.KEY_SECURITY_PROMPT_USER_FOR_JNLP, + BasicValueValidators.getBooleanValidator(), + String.valueOf(true) +@@ -445,4 +450,4 @@ + + return result; + } +-} +\ No newline at end of file ++} +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java +--- a/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java Fri Mar 02 10:41:29 2018 +0100 +@@ -150,6 +150,9 @@ + /** Boolean. Only install the custom authenticator if true */ + public static final String KEY_SECURITY_INSTALL_AUTHENTICATOR = "deployment.security.authenticator"; + ++ /** Boolean. Only install the custom authenticator if true */ ++ public static final String KEY_SECURITY_ITW_IGNORECERTISSUES = "deployment.security.itw.ignorecertissues"; ++ + public static final String KEY_STRICT_JNLP_CLASSLOADER = "deployment.jnlpclassloader.strict"; + + /** Boolean. Do not prefere https over http */ +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/resources/Messages.properties +--- a/netx/net/sourceforge/jnlp/resources/Messages.properties Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/resources/Messages.properties Fri Mar 02 10:41:29 2018 +0100 +@@ -337,7 +337,7 @@ + BOVerbose = Enable verbose output. + BOAbout = Shows a sample application. + BOVersion = Print the IcedTea-Web version and exit. +-BONosecurity= Disables the secure runtime environment. ++BONosecurity= Disables the secure runtime environment. You need also deployment.security.itw.ignorecertissues to workaround corrupted signatures + BONoupdate = Disables checking for updates. + BOHeadless = Disables download window, other UIs. + BOStrict = Enables strict checking of JNLP file format. +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java +--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Fri Mar 02 10:41:29 2018 +0100 +@@ -12,7 +12,6 @@ + // You should have received a copy of the GNU Lesser General Public + // License along with this library; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +- + package net.sourceforge.jnlp.runtime; + + import static net.sourceforge.jnlp.runtime.Translator.R; +@@ -69,6 +68,7 @@ + import net.sourceforge.jnlp.LaunchDesc; + import net.sourceforge.jnlp.LaunchException; + import net.sourceforge.jnlp.NullJnlpFileException; ++import net.sourceforge.jnlp.OptionsDefinitions; + import net.sourceforge.jnlp.ParseException; + import net.sourceforge.jnlp.ParserSettings; + import net.sourceforge.jnlp.PluginBridge; +@@ -90,14 +90,16 @@ + import net.sourceforge.jnlp.util.StreamUtils; + import net.sourceforge.jnlp.util.UrlUtils; + import net.sourceforge.jnlp.util.logging.OutputController; ++import static net.sourceforge.jnlp.runtime.Translator.R; + + /** +- * Classloader that takes it's resources from a JNLP file. If the +- * JNLP file defines extensions, separate classloaders for these +- * will be created automatically. Classes are loaded with the +- * security context when the classloader was created. ++ * Classloader that takes it's resources from a JNLP file. If the JNLP file ++ * defines extensions, separate classloaders for these will be created ++ * automatically. Classes are loaded with the security context when the ++ * classloader was created. + * +- * @author Jon A. Maxwell (JAM) - initial author ++ * @author Jon A. Maxwell ++ * (JAM) - initial author + * @version $Revision: 1.20 $ + */ + public class JNLPClassLoader extends URLClassLoader { +@@ -105,12 +107,15 @@ + // todo: initializePermissions should get the permissions from + // extension classes too so that main file classes can load + // resources in an extension. +- +- /** Signed JNLP File and Template */ ++ /** ++ * Signed JNLP File and Template ++ */ + final public static String TEMPLATE = "JNLP-INF/APPLICATION_TEMPLATE.JNLP"; + final public static String APPLICATION = "JNLP-INF/APPLICATION.JNLP"; + +- /** Actions to specify how cache is to be managed **/ ++ /** ++ * Actions to specify how cache is to be managed * ++ */ + public static enum DownloadAction { + DOWNLOAD_TO_CACHE, REMOVE_FROM_CACHE, CHECK_CACHE + } +@@ -119,101 +124,148 @@ + FULL, PARTIAL, NONE + } + +- /** True if the application has a signed JNLP File */ ++ /** ++ * True if the application has a signed JNLP File ++ */ + private boolean isSignedJNLP = false; +- +- /** map from JNLPFile unique key to shared classloader */ ++ ++ /** ++ * map from JNLPFile unique key to shared classloader ++ */ + private static Map uniqueKeyToLoader = new ConcurrentHashMap<>(); + +- /** map from JNLPFile unique key to lock, the lock is needed to enforce correct +- * initialization of applets that share a unique key*/ ++ /** ++ * map from JNLPFile unique key to lock, the lock is needed to enforce ++ * correct initialization of applets that share a unique key ++ */ + private static Map uniqueKeyToLock = new HashMap<>(); + +- /** Provides a search path & temporary storage for native code */ ++ /** ++ * Provides a search path & temporary storage for native code ++ */ + private NativeLibraryStorage nativeLibraryStorage; + +- /** security context */ ++ /** ++ * security context ++ */ + private final AccessControlContext acc = AccessController.getContext(); + +- /** the permissions for the cached jar files */ ++ /** ++ * the permissions for the cached jar files ++ */ + private List resourcePermissions; + +- /** the app */ ++ /** ++ * the app ++ */ + private ApplicationInstance app = null; // here for faster lookup in security manager + +- /** list of this, local and global loaders this loader uses */ ++ /** ++ * list of this, local and global loaders this loader uses ++ */ + private JNLPClassLoader loaders[] = null; // ..[0]==this + +- /** whether to strictly adhere to the spec or not */ ++ /** ++ * whether to strictly adhere to the spec or not ++ */ + private final boolean strict; + +- /** loads the resources */ ++ /** ++ * loads the resources ++ */ + private final ResourceTracker tracker = new ResourceTracker(true); // prefetch + +- /** the update policy for resources */ ++ /** ++ * the update policy for resources ++ */ + private UpdatePolicy updatePolicy; + +- /** the JNLP file */ ++ /** ++ * the JNLP file ++ */ + private JNLPFile file; + +- /** the resources section */ ++ /** ++ * the resources section ++ */ + private ResourcesDesc resources; + +- /** the security section */ ++ /** ++ * the security section ++ */ + private SecurityDesc security; + +- /** Permissions granted by the user during runtime. */ ++ /** ++ * Permissions granted by the user during runtime. ++ */ + private final ArrayList runtimePermissions = new ArrayList<>(); + +- /** all jars not yet part of classloader or active +- * Synchronized since this field may become shared data between multiple classloading threads. +- * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String). ++ /** ++ * all jars not yet part of classloader or active Synchronized since this ++ * field may become shared data between multiple classloading threads. See ++ * loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String). + */ + private final List available = Collections.synchronizedList(new ArrayList()); + +- /** the jar cert verifier tool to verify our jars */ ++ /** ++ * the jar cert verifier tool to verify our jars ++ */ + private final JarCertVerifier jcv; + + private SigningState signing = SigningState.NONE; + +- /** ArrayList containing jar indexes for various jars available to this classloader +- * Synchronized since this field may become shared data between multiple classloading threads/ +- * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String). ++ /** ++ * ArrayList containing jar indexes for various jars available to this ++ * classloader Synchronized since this field may become shared data between ++ * multiple classloading threads/ See loadClass(String) and ++ * CodebaseClassLoader.findClassNonRecursive(String). + */ + private final List jarIndexes = Collections.synchronizedList(new ArrayList()); + +- /** Set of classpath strings declared in the manifest.mf files +- * Synchronized since this field may become shared data between multiple classloading threads. +- * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String). ++ /** ++ * Set of classpath strings declared in the manifest.mf files Synchronized ++ * since this field may become shared data between multiple classloading ++ * threads. See loadClass(String) and ++ * CodebaseClassLoader.findClassNonRecursive(String). + */ + private final Set classpaths = Collections.synchronizedSet(new HashSet()); + +- /** File entries in the jar files available to this classloader +- * Synchronized sinc this field may become shared data between multiple classloading threads. +- * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String). ++ /** ++ * File entries in the jar files available to this classloader Synchronized ++ * sinc this field may become shared data between multiple classloading ++ * threads. See loadClass(String) and ++ * CodebaseClassLoader.findClassNonRecursive(String). + */ + private final Set jarEntries = Collections.synchronizedSet(new TreeSet()); + +- /** Map of specific original (remote) CodeSource Urls to securitydesc +- * Synchronized since this field may become shared data between multiple classloading threads. +- * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String). ++ /** ++ * Map of specific original (remote) CodeSource Urls to securitydesc ++ * Synchronized since this field may become shared data between multiple ++ * classloading threads. See loadClass(String) and ++ * CodebaseClassLoader.findClassNonRecursive(String). + */ +- private final Map jarLocationSecurityMap = +- Collections.synchronizedMap(new HashMap()); ++ private final Map jarLocationSecurityMap ++ = Collections.synchronizedMap(new HashMap()); + + /*Set to prevent once tried-to-get resources to be tried again*/ + private final Set alreadyTried = Collections.synchronizedSet(new HashSet()); +- +- /** Loader for codebase (which is a path, rather than a file) */ ++ ++ /** ++ * Loader for codebase (which is a path, rather than a file) ++ */ + private CodeBaseClassLoader codeBaseLoader; +- +- /** True if the jar with the main class has been found +- * */ +- private boolean foundMainJar= false; +- +- /** Name of the application's main class */ ++ ++ /** ++ * True if the jar with the main class has been found ++ * ++ */ ++ private boolean foundMainJar = false; ++ ++ /** ++ * Name of the application's main class ++ */ + private String mainClass = null; +- ++ + /** + * Variable to track how many times this loader is in use + */ +@@ -242,16 +294,18 @@ + * @param file the JNLP file + * @param policy the UpdatePolicy for this class loader + * @param mainName name of the application's main class +- * @param enableCodeBase switch whether this classloader can search in codebase or not +- * @throws net.sourceforge.jnlp.LaunchException when need to kill an app comes. +- * ++ * @param enableCodeBase switch whether this classloader can search in ++ * codebase or not ++ * @throws net.sourceforge.jnlp.LaunchException when need to kill an app ++ * comes. ++ * + */ + protected JNLPClassLoader(JNLPFile file, UpdatePolicy policy, String mainName, boolean enableCodeBase) throws LaunchException { + super(new URL[0], JNLPClassLoader.class.getClassLoader()); + + OutputController.getLogger().log("New classloader: " + file.getFileLocation()); +- strict = Boolean.valueOf(JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_STRICT_JNLP_CLASSLOADER)); +- ++ strict = Boolean.valueOf(JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_STRICT_JNLP_CLASSLOADER)); ++ + this.file = file; + this.updatePolicy = policy; + this.resources = file.getResources(); +@@ -262,10 +316,9 @@ + + this.enableCodeBase = enableCodeBase; + +- + AppVerifier verifier; + +- if (file instanceof PluginBridge && !((PluginBridge)file).useJNLPHref()) { ++ if (file instanceof PluginBridge && !((PluginBridge) file).useJNLPHref()) { + verifier = new PluginAppVerifier(); + } else { + verifier = new JNLPAppVerifier(); +@@ -288,15 +341,26 @@ + initializeReadJarPermissions(); + + installShutdownHooks(); +- +- ++ ++ } ++ ++ public static boolean isCertUnderestimated() { ++ return Boolean.valueOf(JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_SECURITY_ITW_IGNORECERTISSUES)) ++ && !JNLPRuntime.isSecurityEnabled(); ++ } ++ ++ private static void consultCertificateSecurityException(LaunchException ex) throws LaunchException { ++ if (isCertUnderestimated()) { ++ OutputController.getLogger().log(OptionsDefinitions.OPTIONS.NOSEC.option + " and " + DeploymentConfiguration.KEY_SECURITY_ITW_IGNORECERTISSUES + " are declared. Ignoring certificate issue"); ++ OutputController.getLogger().log(ex); ++ } else { ++ throw ex; ++ } + } + + public boolean isStrict() { + return strict; + } +- +- + + /** + * Install JVM shutdown hooks to clean up resources allocated by this +@@ -322,9 +386,9 @@ + } + + /** +- * Gets the lock for a given unique key, creating one if it does not yet exist. +- * This operation is atomic & thread-safe. +- * ++ * Gets the lock for a given unique key, creating one if it does not yet ++ * exist. This operation is atomic & thread-safe. ++ * + * @param uniqueKey the file whose unique key should be used + * @return the lock + */ +@@ -342,10 +406,10 @@ + } + + /** +- * Creates a fully initialized JNLP classloader for the specified JNLPFile, +- * to be used as an applet/application's classloader. +- * In contrast, JNLP classloaders can also be constructed simply to merge +- * its resources into another classloader. ++ * Creates a fully initialized JNLP classloader for the specified JNLPFile, ++ * to be used as an applet/application's classloader. In contrast, JNLP ++ * classloaders can also be constructed simply to merge its resources into ++ * another classloader. + * + * @param file the file to load classes for + * @param policy the update policy to use when downloading resources +@@ -366,7 +430,7 @@ + if (loader.getSigningState() == SigningState.PARTIAL) { + loader.securityDelegate.promptUserOnPartialSigning(); + } else if (!loader.getSigning() && !loader.securityDelegate.userPromptedForSandbox() && file instanceof PluginBridge) { +- UnsignedAppletTrustConfirmation.checkUnsignedWithUserIfRequired((PluginBridge)file); ++ UnsignedAppletTrustConfirmation.checkUnsignedWithUserIfRequired((PluginBridge) file); + } + + // New loader init may have caused extentions to create a +@@ -384,7 +448,7 @@ + // loader is now current + ext. But we also need to think of + // the baseLoader + if (baseLoader != null && baseLoader != loader) { +- loader.merge(baseLoader); ++ loader.merge(baseLoader); + } + + return loader; +@@ -392,12 +456,13 @@ + + /** + * Returns a JNLP classloader for the specified JNLP file. +- * ++ * + * @param file the file to load classes for + * @param policy the update policy to use when downloading resources +- * @param enableCodeBase true if codebase can be searched (ok for applets,false for apps) +- * @return existing classloader. creates new if none reliable exists +- * @throws net.sourceforge.jnlp.LaunchException when launch is doomed ++ * @param enableCodeBase true if codebase can be searched (ok for ++ * applets,false for apps) ++ * @return existing classloader. creates new if none reliable exists ++ * @throws net.sourceforge.jnlp.LaunchException when launch is doomed + */ + public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy, boolean enableCodeBase) throws LaunchException { + return getInstance(file, policy, null, enableCodeBase); +@@ -409,22 +474,23 @@ + * @param file the file to load classes for + * @param policy the update policy to use when downloading resources + * @param mainName Overrides the main class name of the application +- * @param enableCodeBase ue if codebase can be searched (ok for applets,false for apps) +- * @return existing classloader. creates new if none reliable exists +- * @throws net.sourceforge.jnlp.LaunchException when launch is doomed ++ * @param enableCodeBase ue if codebase can be searched (ok for ++ * applets,false for apps) ++ * @return existing classloader. creates new if none reliable exists ++ * @throws net.sourceforge.jnlp.LaunchException when launch is doomed + */ + public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy, String mainName, boolean enableCodeBase) throws LaunchException { + JNLPClassLoader loader; + String uniqueKey = file.getUniqueKey(); + +- synchronized ( getUniqueKeyLock(uniqueKey) ) { ++ synchronized (getUniqueKeyLock(uniqueKey)) { + JNLPClassLoader baseLoader = uniqueKeyToLoader.get(uniqueKey); + + // A null baseloader implies that no loader has been created + // for this codebase/jnlp yet. Create one. +- if (baseLoader == null || +- (file.isApplication() && +- !baseLoader.getJNLPFile().getFileLocation().equals(file.getFileLocation()))) { ++ if (baseLoader == null ++ || (file.isApplication() ++ && !baseLoader.getJNLPFile().getFileLocation().equals(file.getFileLocation()))) { + + loader = createInstance(file, policy, mainName, enableCodeBase); + } else { +@@ -433,15 +499,15 @@ + // If this is an applet, we do need to consider its loader + loader = new JNLPClassLoader(file, policy, mainName, enableCodeBase); + +- if (baseLoader != null) ++ if (baseLoader != null) { + baseLoader.merge(loader); ++ } + } + loader = baseLoader; + } + + // loaders are mapped to a unique key. Only extensions and parent + // share a key, so it is safe to always share based on it +- + loader.incrementLoaderUseCount(); + + uniqueKeyToLoader.put(uniqueKey, loader); +@@ -451,8 +517,7 @@ + } + + /** +- * Returns a JNLP classloader for the JNLP file at the specified +- * location. ++ * Returns a JNLP classloader for the JNLP file at the specified location. + * + * @param location the file's location + * @param uniqueKey key to manage applets/applications in shared vm +@@ -463,15 +528,15 @@ + * @param enableCodeBase whether to enable codebase search or not + * @return classlaoder of this appp + * @throws java.io.IOException when IO fails +- * @throws net.sourceforge.jnlp.ParseException when parsing fails +- * @throws net.sourceforge.jnlp.LaunchException when launch is doomed ++ * @throws net.sourceforge.jnlp.ParseException when parsing fails ++ * @throws net.sourceforge.jnlp.LaunchException when launch is doomed + */ + public static JNLPClassLoader getInstance(URL location, String uniqueKey, Version version, ParserSettings settings, UpdatePolicy policy, String mainName, boolean enableCodeBase) + throws IOException, ParseException, LaunchException { + + JNLPClassLoader loader; + +- synchronized ( getUniqueKeyLock(uniqueKey) ) { ++ synchronized (getUniqueKeyLock(uniqueKey)) { + loader = uniqueKeyToLoader.get(uniqueKey); + + if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation())) { +@@ -542,18 +607,20 @@ + + /** + * Check if a described jar file is invalid ++ * + * @param jar the jar to check + * @return true if file exists AND is an invalid jar, false otherwise + */ +- boolean isInvalidJar(JARDesc jar){ ++ boolean isInvalidJar(JARDesc jar) { + File cacheFile = tracker.getCacheFile(jar.getLocation()); +- if (cacheFile == null) ++ if (cacheFile == null) { + return false;//File cannot be retrieved, do not claim it is an invalid jar ++ } + boolean isInvalid = false; + try { + JarFile jarFile = new JarFile(cacheFile.getAbsolutePath()); + jarFile.close(); +- } catch (IOException ioe){ ++ } catch (IOException ioe) { + //Catch a ZipException or any other read failure + isInvalid = true; + } +@@ -562,11 +629,12 @@ + + /** + * Determine how invalid jars should be handled ++ * + * @return whether to filter invalid jars, or error later on + */ +- private boolean shouldFilterInvalidJars(){ +- if (file instanceof PluginBridge){ +- PluginBridge pluginBridge = (PluginBridge)file; ++ private boolean shouldFilterInvalidJars() { ++ if (file instanceof PluginBridge) { ++ PluginBridge pluginBridge = (PluginBridge) file; + /*Ignore on applet, ie !useJNLPHref*/ + return !pluginBridge.useJNLPHref(); + } +@@ -574,14 +642,14 @@ + } + + /** +- * Load all of the JARs used in this JNLP file into the +- * ResourceTracker for downloading. ++ * Load all of the JARs used in this JNLP file into the ResourceTracker for ++ * downloading. + */ + void initializeResources() throws LaunchException { +- if (file instanceof PluginBridge){ +- PluginBridge bridge = (PluginBridge)file; +- +- for (String codeBaseFolder : bridge.getCodeBaseFolders()){ ++ if (file instanceof PluginBridge) { ++ PluginBridge bridge = (PluginBridge) file; ++ ++ for (String codeBaseFolder : bridge.getCodeBaseFolders()) { + try { + addToCodeBaseLoader(new URL(file.getCodeBase(), codeBaseFolder)); + } catch (MalformedURLException mfe) { +@@ -624,16 +692,16 @@ + + available.add(jar); + +- if (jar.isEager()) ++ if (jar.isEager()) { + initialJars.add(jar); // regardless of part +- ++ } + tracker.addResource(jar.getLocation(), + jar.getVersion(), file.getDownloadOptions(), + jar.isCacheable() ? JNLPRuntime.getDefaultUpdatePolicy() : UpdatePolicy.FORCE); + } + + //If there are no eager jars, initialize the first jar +- if(initialJars.isEmpty()) { ++ if (initialJars.isEmpty()) { + initialJars.add(jars[0]); + } + +@@ -644,10 +712,10 @@ + waitForJars(initialJars); //download the jars first. + + //A ZipException will propagate later on if the jar is invalid and not checked here +- if (shouldFilterInvalidJars()){ ++ if (shouldFilterInvalidJars()) { + //We filter any invalid jars + Iterator iterator = initialJars.iterator(); +- while (iterator.hasNext()){ ++ while (iterator.hasNext()) { + JARDesc jar = iterator.next(); + if (isInvalidJar(jar)) { + //Remove this jar as an available jar +@@ -667,8 +735,9 @@ + //Note: one of these exceptions could be from not being able + //to read the cacerts or trusted.certs files. + OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e); +- throw new LaunchException(null, null, R("LSFatal"), +- R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo") + ": " +e.getMessage()); ++ LaunchException ex = new LaunchException(null, null, R("LSFatal"), ++ R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo") + ": " + e.getMessage()); ++ consultCertificateSecurityException(ex); + } + + //Case when at least one jar has some signing +@@ -679,8 +748,9 @@ + checkForMain(initialJars); + + // If jar with main class was not found, check available resources +- while (!foundMainJar && available != null && !available.isEmpty()) ++ while (!foundMainJar && available != null && !available.isEmpty()) { + addNextResource(); ++ } + + // If the jar with main class was not found, check extension + // jnlp's resources +@@ -712,16 +782,18 @@ + } + + // If main jar was found, but a signed JNLP file was not located +- if (!isSignedJNLP && foundMainJar) ++ if (!isSignedJNLP && foundMainJar) { + file.setSignedJNLPAsMissing(); ++ } + + //user does not trust this publisher + if (!jcv.isTriviallySigned()) { + checkTrustWithUser(); + } else { + /** +- * If the user trusts this publisher (i.e. the publisher's certificate +- * is in the user's trusted.certs file), we do not show any dialogs. ++ * If the user trusts this publisher (i.e. the publisher's ++ * certificate is in the user's trusted.certs file), we do ++ * not show any dialogs. + */ + } + } else { +@@ -803,12 +875,13 @@ + } + return codebase; + } +- +- /*** +- * Checks for the jar that contains the attribute. +- * ++ ++ /** ++ * * ++ * Checks for the jar that contains the attribute. ++ * + * @param jars Jars that are checked to see if they contain the main class +- * @param name attribute to be found ++ * @param name attribute to be found + * @return value of attribute if found + */ + public String checkForAttributeInJars(List jars, Attributes.Name name) { +@@ -816,7 +889,6 @@ + return null; + } + +- + // Check main jar + JARDesc mainJarDesc = ResourcesDesc.getMainJAR(jars); + String result = getManifestAttribute(mainJarDesc.getLocation(), name); +@@ -827,33 +899,36 @@ + + // Check first jar + JARDesc firstJarDesc = jars.get(0); +- result = getManifestAttribute(firstJarDesc.getLocation(),name); +- ++ result = getManifestAttribute(firstJarDesc.getLocation(), name); ++ + if (result != null) { + return result; + } + + // Still not found? Iterate and set if only 1 was found +- for (JARDesc jarDesc: jars) { ++ for (JARDesc jarDesc : jars) { + String attributeInThisJar = getManifestAttribute(jarDesc.getLocation(), name); +- if (attributeInThisJar != null) { +- if (result == null) { // first main class +- result = attributeInThisJar; +- } else { // There is more than one main class. Set to null and break. +- result = null; +- break; ++ if (attributeInThisJar != null) { ++ if (result == null) { // first main class ++ result = attributeInThisJar; ++ } else { // There is more than one main class. Set to null and break. ++ result = null; ++ break; + } + } + } + return result; + } +- /*** ++ ++ /** ++ * * + * Checks for the jar that contains the main class. If the main class was + * found, it checks to see if the jar is signed and whether it contains a + * signed JNLP file +- * ++ * + * @param jars Jars that are checked to see if they contain the main class +- * @throws LaunchException Thrown if the signed JNLP file, within the main jar, fails to be verified or does not match ++ * @throws LaunchException Thrown if the signed JNLP file, within the main ++ * jar, fails to be verified or does not match + */ + void checkForMain(List jars) throws LaunchException { + +@@ -866,7 +941,6 @@ + } + + // The main class may be specified in the manifest +- + if (mainClass == null) { + mainClass = checkForAttributeInJars(jars, Attributes.Name.MAIN_CLASS); + } +@@ -910,31 +984,32 @@ + * Gets the name of the main method if specified in the manifest + * + * @param location The JAR location +- * @return the main class name, null if there isn't one of if there was an error ++ * @return the main class name, null if there isn't one of if there was an ++ * error + */ + String getMainClassName(URL location) { + return getManifestAttribute(location, Attributes.Name.MAIN_CLASS); + } +- +- ++ + /** + * Gets the name of the main method if specified in the manifest + * + * @param location The JAR location + * @param attribute name of the attribute to find +- * @return the attribute value, null if there isn't one of if there was an error ++ * @return the attribute value, null if there isn't one of if there was an ++ * error + */ +- public String getManifestAttribute(URL location, Attributes.Name attribute) { ++ public String getManifestAttribute(URL location, Attributes.Name attribute) { + + String attributeValue = null; + File f = tracker.getCacheFile(location); + +- if( f != null) { ++ if (f != null) { + JarFile mainJar = null; + try { + mainJar = new JarFile(f); + Manifest manifest = mainJar.getManifest(); +- if (manifest == null || manifest.getMainAttributes() == null){ ++ if (manifest == null || manifest.getMainAttributes() == null) { + //yes, jars without manifest exists + return null; + } +@@ -972,10 +1047,11 @@ + /** + * Is called by checkForMain() to check if the jar file is signed and if it + * contains a signed JNLP file. +- * ++ * + * @param jarDesc JARDesc of jar + * @param jarFile the jar file +- * @throws LaunchException thrown if the signed JNLP file, within the main jar, fails to be verified or does not match ++ * @throws LaunchException thrown if the signed JNLP file, within the main ++ * jar, fails to be verified or does not match + */ + private void verifySignedJNLP(JARDesc jarDesc, JarFile jarFile) + throws LaunchException { +@@ -1014,13 +1090,14 @@ + matcher = new JNLPMatcher(inStream, jnlpStream, true, jnlp.getParserSettings()); + } + // If signed JNLP file does not matches launching JNLP file, throw JNLPMatcherException +- if (!matcher.isMatch()) ++ if (!matcher.isMatch()) { + throw new JNLPMatcherException("Signed Application did not match launching JNLP File"); ++ } + + this.isSignedJNLP = true; + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Signed Application Verification Successful"); + +- break; ++ break; + } + } + } +@@ -1030,17 +1107,16 @@ + * Throws LaunchException if signed JNLP file fails to be verified + * or fails to match the launching JNLP file + */ +- +- throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), ++ LaunchException ex = new LaunchException(file, null, R("LSFatal"), R("LCClient"), + R("LSignedJNLPFileDidNotMatch"), R(e.getMessage())); +- ++ consultCertificateSecurityException(ex); + /* + * Throwing this exception will fail to initialize the application + * resulting in the termination of the application + */ + + } catch (Exception e) { +- ++ + OutputController.getLogger().log(e); + + /* +@@ -1049,21 +1125,21 @@ + * JarCertVerifier.add) it assumes the jar file is unsigned and + * skip the check for a signed JNLP file + */ +- + } + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Ending check for signed JNLP file..."); + } + + /** + * Prompt the user for trust on all the signers that require approval. ++ * + * @throws LaunchException if the user does not approve every dialog prompt. + */ + private void checkTrustWithUser() throws LaunchException { +- ++ + if (securityDelegate.getRunInSandbox()) { + return; + } +- ++ + if (getSigningState() == SigningState.FULL && jcv.isFullySigned() && !jcv.getAlreadyTrustPublisher()) { + jcv.checkTrustWithUser(securityDelegate, file); + } +@@ -1086,10 +1162,9 @@ + } + + /** +- * Add applet's codebase URL. This allows compatibility with +- * applets that load resources from their codebase instead of +- * through JARs, but can slow down resource loading. Resources +- * loaded from the codebase are not cached. ++ * Add applet's codebase URL. This allows compatibility with applets that ++ * load resources from their codebase instead of through JARs, but can slow ++ * down resource loading. Resources loaded from the codebase are not cached. + */ + public void enableCodeBase() { + addToCodeBaseLoader(file.getCodeBase()); +@@ -1097,11 +1172,12 @@ + + /** + * Sets the JNLP app this group is for; can only be called once. ++ * + * @param app application to be ser to this group + */ + public void setApplication(ApplicationInstance app) { + if (this.app != null) { +- OutputController.getLogger().log(new IllegalStateException("Application can only be set once")); ++ OutputController.getLogger().log(new IllegalStateException("Application can only be set once")); + return; + } + +@@ -1132,7 +1208,6 @@ + + // should check for extensions or boot, automatically give all + // access w/o security dialog once we actually check certificates. +- + // copy security permissions from SecurityDesc element + if (security != null) { + // Security desc. is used only to track security settings for the +@@ -1182,9 +1257,10 @@ + } + + // Class from host X should be allowed to connect to host X +- if (cs.getLocation() != null && cs.getLocation().getHost().length() > 0) ++ if (cs.getLocation() != null && cs.getLocation().getHost().length() > 0) { + result.add(new SocketPermission(UrlUtils.getHostAndPort(cs.getLocation()), + "connect, accept")); ++ } + + return result; + } catch (RuntimeException ex) { +@@ -1198,33 +1274,34 @@ + } + + /** +- * Adds to the specified list of JARS any other JARs that need +- * to be loaded at the same time as the JARs specified (ie, are +- * in the same part). ++ * Adds to the specified list of JARS any other JARs that need to be loaded ++ * at the same time as the JARs specified (ie, are in the same part). ++ * + * @param jars jar archives to be added + */ + protected void fillInPartJars(List jars) { + //can not use iterator, will rise ConcurrentModificationException on jars.add(jar); +- for (int x = 0 ; x< jars.size() ; x++) { ++ for (int x = 0; x < jars.size(); x++) { + String part = jars.get(x).getPart(); + + // "available" field can be affected by two different threads + // working in loadClass(String) + synchronized (available) { + for (JARDesc jar : available) { +- if (part != null && part.equals(jar.getPart())) +- if (!jars.contains(jar)) ++ if (part != null && part.equals(jar.getPart())) { ++ if (!jars.contains(jar)) { + jars.add(jar); ++ } ++ } + } + } + } + } + + /** +- * Ensures that the list of jars have all been transferred, and +- * makes them available to the classloader. If a jar contains +- * native code, the libraries will be extracted and placed in +- * the path. ++ * Ensures that the list of jars have all been transferred, and makes them ++ * available to the classloader. If a jar contains native code, the ++ * libraries will be extracted and placed in the path. + * + * @param jars the list of jars to load + */ +@@ -1256,13 +1333,13 @@ + // particularly when using The FileManager applet from Webmin. + try (JarFile jarFile = new JarFile(localFile)) { + for (JarEntry je : Collections.list(jarFile.entries())) { +- ++ + // another jar in my jar? it is more likely than you think + if (je.getName().endsWith(".jar")) { + // We need to extract that jar so that it can be loaded + // (inline loading with "jar:..!/..." path will not work + // with standard classloader methods) +- ++ + String extractedJarLocation = localFile + ".nested/" + je.getName(); + File parentDir = new File(extractedJarLocation).getParentFile(); + if (!parentDir.isDirectory() && !parentDir.mkdirs()) { +@@ -1270,7 +1347,7 @@ + } + FileOutputStream extractedJar = new FileOutputStream(extractedJarLocation); + InputStream is = jarFile.getInputStream(je); +- ++ + byte[] bytes = new byte[1024]; + int read = is.read(bytes); + int fileSize = read; +@@ -1279,41 +1356,41 @@ + read = is.read(bytes); + fileSize += read; + } +- ++ + is.close(); + extractedJar.close(); +- ++ + // 0 byte file? skip + if (fileSize <= 0) { + continue; + } +- ++ + tracker.addResource(new File(extractedJarLocation).toURL(), null, null, null); +- ++ + URL codebase = file.getCodeBase(); + if (codebase == null) { + //FIXME: codebase should be the codebase of the Main Jar not + //the location. Although, it still works in the current state. + codebase = file.getResources().getMainJAR().getLocation(); + } +- ++ + final SecurityDesc jarSecurity = securityDelegate.getJarPermissions(codebase); +- ++ + try { + URL fileURL = new URL("file://" + extractedJarLocation); + // there is no remote URL for this, so lets fake one + URL fakeRemote = new URL(jar.getLocation().toString() + "!" + je.getName()); + CachedJarFileCallback.getInstance().addMapping(fakeRemote, fileURL); + addURL(fakeRemote); +- ++ + jarLocationSecurityMap.put(fakeRemote, jarSecurity); +- ++ + } catch (MalformedURLException mfue) { + OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Unable to add extracted nested jar to classpath"); + OutputController.getLogger().log(OutputController.Level.ERROR_ALL, mfue); + } + } +- ++ + jarEntries.add(je.getName()); + } + } +@@ -1328,7 +1405,7 @@ + + try (JarFile jarFile = new JarFile(localFile.getAbsolutePath())) { + Manifest mf = jarFile.getManifest(); +- ++ + // Only check classpath if this is the plugin and there is no jnlp_href usage. + // Note that this is different from proprietary plugin behaviour. + // If jnlp_href is used, the app should be treated similarly to when +@@ -1336,19 +1413,19 @@ + if (file instanceof PluginBridge && !((PluginBridge) file).useJNLPHref()) { + classpaths.addAll(getClassPathsFromManifest(mf, jar.getLocation().getPath())); + } +- ++ + JarIndexAccess index = JarIndexAccess.getJarIndex(jarFile); +- if (index != null) ++ if (index != null) { + jarIndexes.add(index); ++ } + } + } else { + CachedJarFileCallback.getInstance().addMapping(jar.getLocation(), jar.getLocation()); + } + + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Activate jar: " + location); +- } +- catch (Exception ex) { +- OutputController.getLogger().log(ex); ++ } catch (Exception ex) { ++ OutputController.getLogger().log(ex); + } + + // some programs place a native library in any jar +@@ -1374,14 +1451,16 @@ + } + + String result = super.findLibrary(lib); +- if (result != null) ++ if (result != null) { + return result; ++ } + + return findLibraryExt(lib); + } + + /** + * Try to find the library path from another peer classloader. ++ * + * @param lib library to be found + * @return location of library + */ +@@ -1389,19 +1468,21 @@ + for (JNLPClassLoader loader : loaders) { + String result = null; + +- if (loader != this) ++ if (loader != this) { + result = loader.findLibrary(lib); +- +- if (result != null) ++ } ++ ++ if (result != null) { + return result; ++ } + } + + return null; + } + + /** +- * Wait for a group of JARs, and send download events if there +- * is a download listener or display a progress window otherwise. ++ * Wait for a group of JARs, and send download events if there is a download ++ * listener or display a progress window otherwise. + * + * @param jars the jars + */ +@@ -1419,6 +1500,7 @@ + + /** + * Find the loaded class in this loader or any of its extension loaders. ++ * + * @param name name of class + * @return the class found by name + */ +@@ -1432,41 +1514,43 @@ + result = loader.findLoadedClassAll(name); + } + +- if (result != null) ++ if (result != null) { + return result; ++ } + } +- ++ + // Result is still null. Return what the codebaseloader + // has (which returns null if it is not loaded there either) +- if (codeBaseLoader != null) ++ if (codeBaseLoader != null) { + return codeBaseLoader.findLoadedClassFromParent(name); +- else ++ } else { + return null; ++ } + } + + /** +- * Find a JAR in the shared 'extension' classloaders, this +- * classloader, or one of the classloaders for the JNLP file's +- * extensions. +- * This method used to be qualified "synchronized." This was done solely for the +- * purpose of ensuring only one thread entered the method at a time. This was not ++ * Find a JAR in the shared 'extension' classloaders, this classloader, or ++ * one of the classloaders for the JNLP file's extensions. This method used ++ * to be qualified "synchronized." This was done solely for the purpose of ++ * ensuring only one thread entered the method at a time. This was not + * strictly necessary - ensuring that all affected fields are thread-safe is +- * sufficient. Locking on the JNLPClassLoader instance when this method is called +- * can result in deadlock if another thread is dealing with the CodebaseClassLoader +- * at the same time. This solution is very heavy-handed as the instance lock is not +- * truly required, and taking the lock on the classloader instance when not needed is +- * not in general a good idea because it can and will lead to deadlock when multithreaded +- * classloading is in effect. The solution is to keep the fields thread safe on their own. +- * This is accomplished by wrapping them in Collections.synchronized* to provide +- * atomic add/remove operations, and synchronizing on them when iterating or performing +- * multiple mutations. +- * See bug report RH976833. On some systems this bug will manifest itself as deadlock on +- * every webpage with more than one Java applet, potentially also causing the browser +- * process to hang. +- * More information in the mailing list archives: ++ * sufficient. Locking on the JNLPClassLoader instance when this method is ++ * called can result in deadlock if another thread is dealing with the ++ * CodebaseClassLoader at the same time. This solution is very heavy-handed ++ * as the instance lock is not truly required, and taking the lock on the ++ * classloader instance when not needed is not in general a good idea ++ * because it can and will lead to deadlock when multithreaded classloading ++ * is in effect. The solution is to keep the fields thread safe on their ++ * own. This is accomplished by wrapping them in Collections.synchronized* ++ * to provide atomic add/remove operations, and synchronizing on them when ++ * iterating or performing multiple mutations. See bug report RH976833. On ++ * some systems this bug will manifest itself as deadlock on every webpage ++ * with more than one Java applet, potentially also causing the browser ++ * process to hang. More information in the mailing list archives: + * http://mail.openjdk.java.net/pipermail/distro-pkg-dev/2013-September/024536.html +- * +- * Affected fields: available, classpaths, jarIndexes, jarEntries, jarLocationSecurityMap ++ * ++ * Affected fields: available, classpaths, jarIndexes, jarEntries, ++ * jarLocationSecurityMap + */ + @Override + public Class loadClass(String name) throws ClassNotFoundException { +@@ -1476,8 +1560,9 @@ + if (result == null) { + try { + ClassLoader parent = getParent(); +- if (parent == null) ++ if (parent == null) { + parent = ClassLoader.getSystemClassLoader(); ++ } + + return parent.loadClass(name); + } catch (ClassNotFoundException ex) { +@@ -1486,7 +1571,6 @@ + + // filter out 'bad' package names like java, javax + // validPackage(name); +- + // search this and the extension loaders + if (result == null) { + try { +@@ -1518,7 +1602,6 @@ + } + + // As a last resort, look in any available indexes +- + // Currently this loads jars directly from the site. We cannot cache it because this + // call is initiated from within the applet, which does not have disk read/write permissions + // This field synchronized before iterating over it since it may +@@ -1563,9 +1646,10 @@ + /** + * Adds a new JARDesc into this classloader. + *

+- * This will add the JARDesc into the resourceTracker and block until it +- * is downloaded. ++ * This will add the JARDesc into the resourceTracker and block until it is ++ * downloaded. + *

++ * + * @param desc the JARDesc for the new jar + */ + private void addNewJar(final JARDesc desc) { +@@ -1574,6 +1658,7 @@ + + /** + * Adds a new JARDesc into this classloader. ++ * + * @param desc the JARDesc for the new jar + * @param updatePolicy the UpdatePolicy for the resource + */ +@@ -1585,7 +1670,7 @@ + desc.getVersion(), + null, + updatePolicy +- ); ++ ); + + // Give read permissions to the cached jar file + AccessController.doPrivileged(new PrivilegedAction() { +@@ -1604,11 +1689,10 @@ + final URL cachedUrl = tracker.getCacheURL(remoteURL); // blocks till download + + available.remove(desc); // Resource downloaded. Remove from available list. +- ++ + try { + + // Verify if needed +- + final List jars = new ArrayList<>(); + jars.add(desc); + +@@ -1617,7 +1701,6 @@ + // having AllPermissions as those actions normally happen + // during initialization. We therefore need to do those + // actions as privileged. +- + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { +@@ -1656,11 +1739,11 @@ + final String fName = name; + return AccessController.doPrivileged( + new PrivilegedExceptionAction>() { +- @Override +- public Class run() throws ClassNotFoundException { +- return JNLPClassLoader.super.findClass(fName); +- } +- }, getAccessControlContextForClassLoading()); ++ @Override ++ public Class run() throws ClassNotFoundException { ++ return JNLPClassLoader.super.findClass(fName); ++ } ++ }, getAccessControlContextForClassLoading()); + } else { + return loader.findClass(name); + } +@@ -1673,17 +1756,17 @@ + } + + // Try codebase loader +- if (codeBaseLoader != null) ++ if (codeBaseLoader != null) { + return codeBaseLoader.findClassNonRecursive(name); ++ } + + // All else failed. Throw CNFE + throw new ClassNotFoundException(name); + } + + /** +- * Search for the class by incrementally adding resources to the +- * classloader and its extension classloaders until the resource +- * is found. ++ * Search for the class by incrementally adding resources to the classloader ++ * and its extension classloaders until the resource is found. + */ + private Class loadClassExt(String name) throws ClassNotFoundException { + // make recursive +@@ -1698,7 +1781,7 @@ + // add resources until found + while (true) { + JNLPClassLoader addedTo = null; +- ++ + try { + addedTo = addNextResource(); + } catch (LaunchException e) { +@@ -1708,12 +1791,12 @@ + * [It is handled in initializeResources()]. Therefore, this + * exception will never be thrown here and is escaped + */ +- + throw new IllegalStateException(e); + } + +- if (addedTo == null) ++ if (addedTo == null) { + throw new ClassNotFoundException(name); ++ } + + try { + return addedTo.findClass(name); +@@ -1723,11 +1806,10 @@ + } + + /** +- * Finds the resource in this, the parent, or the extension +- * class loaders. ++ * Finds the resource in this, the parent, or the extension class loaders. + * +- * @return a {@link URL} for the resource, or {@code null} +- * if the resource could not be found. ++ * @return a {@link URL} for the resource, or {@code null} if the resource ++ * could not be found. + */ + @Override + public URL findResource(String name) { +@@ -1741,17 +1823,18 @@ + } catch (IOException e) { + OutputController.getLogger().log(e); + } +- ++ + // If result is still null, look in the codebase loader +- if (result == null && codeBaseLoader != null) ++ if (result == null && codeBaseLoader != null) { + result = codeBaseLoader.findResource(name); ++ } + + return result; + } + + /** +- * Find the resources in this, the parent, or the extension +- * class loaders. Load lazy resources if not found in current resources. ++ * Find the resources in this, the parent, or the extension class loaders. ++ * Load lazy resources if not found in current resources. + */ + @Override + public Enumeration findResources(String name) throws IOException { +@@ -1770,8 +1853,7 @@ + } + + /** +- * Find the resources in this, the parent, or the extension +- * class loaders. ++ * Find the resources in this, the parent, or the extension class loaders. + */ + private Enumeration findResourcesBySearching(String name) throws IOException { + List lresources = new ArrayList<>(); +@@ -1787,11 +1869,11 @@ + try { + e = AccessController.doPrivileged( + new PrivilegedExceptionAction>() { +- @Override +- public Enumeration run() throws IOException { +- return JNLPClassLoader.super.findResources(fName); +- } +- }, getAccessControlContextForClassLoading()); ++ @Override ++ public Enumeration run() throws IOException { ++ return JNLPClassLoader.super.findResources(fName); ++ } ++ }, getAccessControlContextForClassLoading()); + } catch (PrivilegedActionException pae) { + } + } else { +@@ -1801,16 +1883,16 @@ + final Enumeration fURLEnum = e; + try { + lresources.addAll(AccessController.doPrivileged( +- new PrivilegedExceptionAction>() { +- @Override +- public Collection run() { +- List resources = new ArrayList<>(); +- while (fURLEnum != null && fURLEnum.hasMoreElements()) { +- resources.add(fURLEnum.nextElement()); +- } +- return resources; ++ new PrivilegedExceptionAction>() { ++ @Override ++ public Collection run() { ++ List resources = new ArrayList<>(); ++ while (fURLEnum != null && fURLEnum.hasMoreElements()) { ++ resources.add(fURLEnum.nextElement()); + } +- }, getAccessControlContextForClassLoading())); ++ return resources; ++ } ++ }, getAccessControlContextForClassLoading())); + } catch (PrivilegedActionException pae) { + } + } +@@ -1819,8 +1901,9 @@ + // otherwise the server will get hammered) + if (lresources.isEmpty() && codeBaseLoader != null) { + e = codeBaseLoader.findResources(name); +- while (e.hasMoreElements()) ++ while (e.hasMoreElements()) { + lresources.add(e.nextElement()); ++ } + } + + return Collections.enumeration(lresources); +@@ -1837,8 +1920,7 @@ + } + + /** +- * Adds whatever resources have already been downloaded in the +- * background. ++ * Adds whatever resources have already been downloaded in the background. + */ + protected void addAvailable() { + // go through available, check tracker for it and all of its +@@ -1850,21 +1932,23 @@ + } + + /** +- * Adds the next unused resource to the classloader. That +- * resource and all those in the same part will be downloaded +- * and added to the classloader before returning. If there are +- * no more resources to add, the method returns immediately. ++ * Adds the next unused resource to the classloader. That resource and all ++ * those in the same part will be downloaded and added to the classloader ++ * before returning. If there are no more resources to add, the method ++ * returns immediately. + * + * @return the classloader that resources were added to, or null +- * @throws LaunchException Thrown if the signed JNLP file, within the main jar, fails to be verified or does not match ++ * @throws LaunchException Thrown if the signed JNLP file, within the main ++ * jar, fails to be verified or does not match + */ + protected JNLPClassLoader addNextResource() throws LaunchException { + if (available.isEmpty()) { + for (int i = 1; i < loaders.length; i++) { + JNLPClassLoader result = loaders[i].addNextResource(); + +- if (result != null) ++ if (result != null) { + return result; ++ } + } + return null; + } +@@ -1882,25 +1966,28 @@ + + // this part compatibility with previous classloader + /** +- * @return title if available. Substitutions if not. ++ * @return title if available. Substitutions if not. + * @deprecated + */ + @Deprecated + public String getExtensionName() { + String result = file.getInformation().getTitle(); + +- if (result == null) ++ if (result == null) { + result = file.getInformation().getDescription(); +- if (result == null && file.getFileLocation() != null) ++ } ++ if (result == null && file.getFileLocation() != null) { + result = file.getFileLocation().toString(); +- if (result == null && file.getCodeBase() != null) ++ } ++ if (result == null && file.getCodeBase() != null) { + result = file.getCodeBase().toString(); ++ } + + return result; + } + + /** +- * @return location if jnlp ++ * @return location if jnlp + * @deprecated + */ + @Deprecated +@@ -1914,14 +2001,13 @@ + + /** + * Call this when it's suspected that an applet's permission level may have +- * just changed from Full Signing to Partial Signing. +- * This will display a one-time prompt asking the user to confirm running +- * the partially signed applet. +- * Partially Signed applets always start off as appearing to be Fully +- * Signed, and then during the initialization or loading process, we find +- * that we actually need to demote the applet to Partial, either due to +- * finding that not all of its JARs are actually signed, or because it +- * needs to load something unsigned out of the codebase. ++ * just changed from Full Signing to Partial Signing. This will display a ++ * one-time prompt asking the user to confirm running the partially signed ++ * applet. Partially Signed applets always start off as appearing to be ++ * Fully Signed, and then during the initialization or loading process, we ++ * find that we actually need to demote the applet to Partial, either due to ++ * finding that not all of its JARs are actually signed, or because it needs ++ * to load something unsigned out of the codebase. + */ + private void checkPartialSigningWithUser() { + if (signing == SigningState.FULL && JNLPRuntime.isVerifying()) { +@@ -1949,9 +2035,8 @@ + * @param source the origin (remote) url of the code + * @return The SecurityDescriptor for that source + */ +- + protected SecurityDesc getCodeSourceSecurity(URL source) { +- SecurityDesc sec=jarLocationSecurityMap.get(source); ++ SecurityDesc sec = jarLocationSecurityMap.get(source); + synchronized (alreadyTried) { + if (sec == null && !alreadyTried.contains(source)) { + alreadyTried.add(source); +@@ -1967,8 +2052,8 @@ + } + } + } +- if (sec == null){ +- OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("LNoSecInstance",source.toString())); ++ if (sec == null) { ++ OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("LNoSecInstance", source.toString())); + } + return sec; + } +@@ -1988,9 +2073,10 @@ + } + + // jars +- for (URL u : extLoader.getURLs()) ++ for (URL u : extLoader.getURLs()) { + addURL(u); +- ++ } ++ + // Codebase + addToCodeBaseLoader(extLoader.file.getCodeBase()); + +@@ -2009,7 +2095,7 @@ + + /** + * Adds the given path to the path loader +- * ++ * + * @param u the path to add + * @throws IllegalArgumentException If the given url is not a path + */ +@@ -2026,7 +2112,7 @@ + // If there is no loader yet, create one, else add it to the + // existing one (happens when called from merge()) + if (codeBaseLoader == null) { +- codeBaseLoader = new CodeBaseClassLoader(new URL[] { u }, this); ++ codeBaseLoader = new CodeBaseClassLoader(new URL[]{u}, this); + } else { + codeBaseLoader.addURL(u); + } +@@ -2036,11 +2122,12 @@ + * Returns a set of paths that indicate the Class-Path entries in the + * manifest file. The paths are rooted in the same directory as the + * originalJarPath. ++ * + * @param mf the manifest +- * @param originalJarPath the remote/original path of the jar containing +- * the manifest +- * @return a Set of String where each string is a path to the jar on +- * the original jar's classpath. ++ * @param originalJarPath the remote/original path of the jar containing the ++ * manifest ++ * @return a Set of String where each string is a path to the jar on the ++ * original jar's classpath. + */ + private Set getClassPathsFromManifest(Manifest mf, String originalJarPath) { + Set result = new HashSet<>(); +@@ -2069,20 +2156,21 @@ + } + return result; + } +- ++ + /** + * Increments loader use count by 1 +- * ++ * + * @throws SecurityException if caller is not trusted + */ + private void incrementLoaderUseCount() { + + // For use by trusted code only +- if (System.getSecurityManager() != null) ++ if (System.getSecurityManager() != null) { + System.getSecurityManager().checkPermission(new AllPermission()); ++ } + + // NB: There will only ever be one class-loader per unique-key +- synchronized ( getUniqueKeyLock(file.getUniqueKey()) ){ ++ synchronized (getUniqueKeyLock(file.getUniqueKey())) { + useCount++; + } + } +@@ -2105,8 +2193,8 @@ + try { + tracker.removeResource(eachJar.getLocation()); + } catch (Exception e) { +- OutputController.getLogger().log(e); +- OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Failed to remove resource from tracker, continuing.."); ++ OutputController.getLogger().log(e); ++ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Failed to remove resource from tracker, continuing.."); + } + + File cachedFile = CacheUtil.getCacheFile(eachJar.getLocation(), null); +@@ -2144,9 +2232,11 @@ + + /** + * Manages DownloadService jars which are not mentioned in the JNLP file ++ * + * @param ref Path to the resource. + * @param version The version of resource. If null, no version is specified. +- * @param action The action to perform with the resource. Either DOWNLOADTOCACHE, REMOVEFROMCACHE, or CHECKCACHE. ++ * @param action The action to perform with the resource. Either ++ * DOWNLOADTOCACHE, REMOVEFROMCACHE, or CHECKCACHE. + * @return true if CHECKCACHE and the resource is cached. + */ + boolean manageExternalJars(URL ref, String version, DownloadAction action) { +@@ -2154,17 +2244,18 @@ + JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByResourceUrl(this, ref, version); + Version resourceVersion = (version == null) ? null : new Version(version); + +- if (foundLoader != null) ++ if (foundLoader != null) { ++ approved = true; ++ } else if (ref.toString().startsWith(file.getNotNullProbalbeCodeBase().toString())) { + approved = true; +- +- else if (ref.toString().startsWith(file.getNotNullProbalbeCodeBase().toString())) ++ } else if (SecurityDesc.ALL_PERMISSIONS.equals(security.getSecurityType())) { + approved = true; +- else if (SecurityDesc.ALL_PERMISSIONS.equals(security.getSecurityType())) +- approved = true; ++ } + + if (approved) { +- if (foundLoader == null) ++ if (foundLoader == null) { + foundLoader = this; ++ } + + if (action == DownloadAction.DOWNLOAD_TO_CACHE) { + JARDesc jarToCache = new JARDesc(ref, resourceVersion, null, false, true, false, true); +@@ -2173,7 +2264,7 @@ + foundLoader.addNewJar(jarToCache, UpdatePolicy.FORCE); + + } else if (action == DownloadAction.REMOVE_FROM_CACHE) { +- JARDesc[] jarToRemove = { new JARDesc(ref, resourceVersion, null, false, true, false, true) }; ++ JARDesc[] jarToRemove = {new JARDesc(ref, resourceVersion, null, false, true, false, true)}; + foundLoader.removeJars(jarToRemove); + + } else if (action == DownloadAction.CHECK_CACHE) { +@@ -2185,21 +2276,22 @@ + + /** + * Decrements loader use count by 1 +- * ++ * + * If count reaches 0, loader is removed from list of available loaders +- * ++ * + * @throws SecurityException if caller is not trusted + */ + public void decrementLoaderUseCount() { + + // For use by trusted code only +- if (System.getSecurityManager() != null) ++ if (System.getSecurityManager() != null) { + System.getSecurityManager().checkPermission(new AllPermission()); ++ } + + String uniqueKey = file.getUniqueKey(); + + // NB: There will only ever be one class-loader per unique-key +- synchronized ( getUniqueKeyLock(uniqueKey) ) { ++ synchronized (getUniqueKeyLock(uniqueKey)) { + useCount--; + + if (useCount <= 0) { +@@ -2209,17 +2301,18 @@ + } + + /** +- * Returns an appropriate AccessControlContext for loading classes in +- * the running instance. ++ * Returns an appropriate AccessControlContext for loading classes in the ++ * running instance. + * + * The default context during class-loading only allows connection to + * codebase. However applets are allowed to load jars from arbitrary +- * locations and the codebase only access falls short if a class from +- * one location needs a class from another. ++ * locations and the codebase only access falls short if a class from one ++ * location needs a class from another. + * + * Given protected access since CodeBaseClassloader uses this function too. + * +- * @return The appropriate AccessControlContext for loading classes for this instance ++ * @return The appropriate AccessControlContext for loading classes for this ++ * instance + */ + public AccessControlContext getAccessControlContextForClassLoading() { + AccessControlContext context = AccessController.getContext(); +@@ -2244,7 +2337,7 @@ + // Permissions for all remote hosting urls + synchronized (jarLocationSecurityMap) { + for (URL u : jarLocationSecurityMap.keySet()) { +- permissions.add(new SocketPermission(UrlUtils.getHostAndPort(u), ++ permissions.add(new SocketPermission(UrlUtils.getHostAndPort(u), + "connect, accept")); + } + } +@@ -2259,26 +2352,27 @@ + + ProtectionDomain pd = new ProtectionDomain(null, permissions); + +- return new AccessControlContext(new ProtectionDomain[] { pd }); ++ return new AccessControlContext(new ProtectionDomain[]{pd}); + } +- ++ + public String getMainClass() { + return mainClass; + } +- +- +- +- /** +- * SecurityDelegate, in real usage, relies on having a "parent" JNLPClassLoader instance. +- * However, JNLPClassLoaders are very large, heavyweight, difficult-to-mock objects, which +- * means that unit testing on anything that uses a SecurityDelegate can become very difficult. +- * For example, JarCertVerifier is designed separated from the ClassLoader so it can be tested +- * in isolation. However, JCV needs some sort of access back to JNLPClassLoader instances to +- * be able to invoke setRunInSandbox(). The SecurityDelegate handles this, allowing JCV to be +- * tested without instantiating JNLPClassLoaders, by creating a fake SecurityDelegate that does +- * not require one. ++ ++ /** ++ * SecurityDelegate, in real usage, relies on having a "parent" ++ * JNLPClassLoader instance. However, JNLPClassLoaders are very large, ++ * heavyweight, difficult-to-mock objects, which means that unit testing on ++ * anything that uses a SecurityDelegate can become very difficult. For ++ * example, JarCertVerifier is designed separated from the ClassLoader so it ++ * can be tested in isolation. However, JCV needs some sort of access back ++ * to JNLPClassLoader instances to be able to invoke setRunInSandbox(). The ++ * SecurityDelegate handles this, allowing JCV to be tested without ++ * instantiating JNLPClassLoaders, by creating a fake SecurityDelegate that ++ * does not require one. + */ + public static interface SecurityDelegate { ++ + public boolean isPluginApplet(); + + public boolean userPromptedForPartialSigning(); +@@ -2305,10 +2399,11 @@ + } + + /** +- * Handles security decision logic for the JNLPClassLoader, eg which permission level to assign +- * to JARs. ++ * Handles security decision logic for the JNLPClassLoader, eg which ++ * permission level to assign to JARs. + */ + public static class SecurityDelegateImpl implements SecurityDelegate { ++ + private final JNLPClassLoader classLoader; + private boolean runInSandbox; + private boolean promptedForPartialSigning; +@@ -2331,27 +2426,25 @@ + return new SecurityDesc(classLoader.file, + SecurityDesc.SANDBOX_PERMISSIONS, + codebaseHost); +- } else { +- if (isPluginApplet()) { +- try { +- if (JarCertVerifier.isJarSigned(jarDesc, new PluginAppVerifier(), classLoader.tracker)) { +- return new SecurityDesc(classLoader.file, +- SecurityDesc.ALL_PERMISSIONS, +- codebaseHost); +- } else { +- return new SecurityDesc(classLoader.file, +- SecurityDesc.SANDBOX_PERMISSIONS, +- codebaseHost); +- } +- } catch (final Exception e) { +- OutputController.getLogger().log(e); ++ } else if (isPluginApplet()) { ++ try { ++ if (JarCertVerifier.isJarSigned(jarDesc, new PluginAppVerifier(), classLoader.tracker)) { ++ return new SecurityDesc(classLoader.file, ++ SecurityDesc.ALL_PERMISSIONS, ++ codebaseHost); ++ } else { + return new SecurityDesc(classLoader.file, + SecurityDesc.SANDBOX_PERMISSIONS, + codebaseHost); + } +- } else { +- return classLoader.file.getSecurity(); ++ } catch (final Exception e) { ++ OutputController.getLogger().log(e); ++ return new SecurityDesc(classLoader.file, ++ SecurityDesc.SANDBOX_PERMISSIONS, ++ codebaseHost); + } ++ } else { ++ return classLoader.file.getSecurity(); + } + } + +@@ -2367,8 +2460,7 @@ + SecurityDesc.SANDBOX_PERMISSIONS, + codebaseHost); + } +- } else { +- /* ++ } else /* + * Various combinations of the jars being signed and tags being + * present are possible. They are treated as follows + * +@@ -2379,21 +2471,27 @@ + * Unsigned Error + * Unsigned no Sandbox + * +- */ +- if (!runInSandbox && !classLoader.getSigning() +- && !classLoader.file.getSecurity().getSecurityType().equals(SecurityDesc.SANDBOX_PERMISSIONS)) { +- if (classLoader.jcv.allJarsSigned()) { +- throw new LaunchException(classLoader.file, null, R("LSFatal"), R("LCClient"), R("LSignedJNLPAppDifferentCerts"), R("LSignedJNLPAppDifferentCertsInfo")); +- } else { +- throw new LaunchException(classLoader.file, null, R("LSFatal"), R("LCClient"), R("LUnsignedJarWithSecurity"), R("LUnsignedJarWithSecurityInfo")); +- } +- } else if (!runInSandbox && classLoader.getSigning()) { +- return classLoader.file.getSecurity(); ++ */ if (!runInSandbox && !classLoader.getSigning() ++ && !classLoader.file.getSecurity().getSecurityType().equals(SecurityDesc.SANDBOX_PERMISSIONS)) { ++ if (classLoader.jcv.allJarsSigned()) { ++ LaunchException ex = new LaunchException(classLoader.file, null, R("LSFatal"), R("LCClient"), R("LSignedJNLPAppDifferentCerts"), R("LSignedJNLPAppDifferentCertsInfo")); ++ consultCertificateSecurityException(ex); ++ return consultResult(codebaseHost); + } else { +- return new SecurityDesc(classLoader.file, +- SecurityDesc.SANDBOX_PERMISSIONS, +- codebaseHost); ++ LaunchException ex = new LaunchException(classLoader.file, null, R("LSFatal"), R("LCClient"), R("LUnsignedJarWithSecurity"), R("LUnsignedJarWithSecurityInfo"));; ++ consultCertificateSecurityException(ex); ++ return consultResult(codebaseHost); + } ++ } else return consultResult(codebaseHost); ++ } ++ ++ private SecurityDesc consultResult(URL codebaseHost){ ++ if (!runInSandbox && classLoader.getSigning()) { ++ return classLoader.file.getSecurity(); ++ } else { ++ return new SecurityDesc(classLoader.file, ++ SecurityDesc.SANDBOX_PERMISSIONS, ++ codebaseHost); + } + } + +@@ -2470,7 +2568,7 @@ + } + + } +- ++ + + /* + * Helper class to expose protected URLClassLoader methods. +@@ -2487,7 +2585,7 @@ + public static class CodeBaseClassLoader extends URLClassLoader { + + JNLPClassLoader parentJNLPClassLoader; +- ++ + /** + * Classes that are not found, so that findClass can skip them next time + */ +@@ -2499,8 +2597,8 @@ + } + + @Override +- public void addURL(URL url) { +- super.addURL(url); ++ public void addURL(URL url) { ++ super.addURL(url); + } + + /* +@@ -2508,18 +2606,19 @@ + */ + Class findClassNonRecursive(final String name) throws ClassNotFoundException { + // If we have searched this path before, don't try again +- if (Arrays.equals(super.getURLs(), notFoundResources.get(name))) ++ if (Arrays.equals(super.getURLs(), notFoundResources.get(name))) { + throw new ClassNotFoundException(name); ++ } + + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction>() { +- public Class run() throws ClassNotFoundException { +- Class c = CodeBaseClassLoader.super.findClass(name); +- parentJNLPClassLoader.checkPartialSigningWithUser(); +- return c; +- } +- }, parentJNLPClassLoader.getAccessControlContextForClassLoading()); ++ public Class run() throws ClassNotFoundException { ++ Class c = CodeBaseClassLoader.super.findClass(name); ++ parentJNLPClassLoader.checkPartialSigningWithUser(); ++ return c; ++ } ++ }, parentJNLPClassLoader.getAccessControlContextForClassLoading()); + } catch (PrivilegedActionException pae) { + notFoundResources.put(name, super.getURLs()); + throw new ClassNotFoundException("Could not find class " + name, pae); +@@ -2542,11 +2641,12 @@ + + /** + * Returns the output of super.findLoadedClass(). +- * ++ * + * The method is renamed because ClassLoader.findLoadedClass() is final +- * ++ * + * @param name The name of the class to find +- * @return Output of ClassLoader.findLoadedClass() which is the class if found, null otherwise ++ * @return Output of ClassLoader.findLoadedClass() which is the class if ++ * found, null otherwise + * @see java.lang.ClassLoader#findLoadedClass(String) + */ + public Class findLoadedClassFromParent(String name) { +@@ -2555,7 +2655,7 @@ + + /** + * Returns JNLPClassLoader that encompasses this loader +- * ++ * + * @return parent JNLPClassLoader + */ + public JNLPClassLoader getParentJNLPClassLoader() { +@@ -2566,8 +2666,9 @@ + public Enumeration findResources(String name) throws IOException { + + // If we have searched this path before, don't try again +- if (Arrays.equals(super.getURLs(), notFoundResources.get(name))) ++ if (Arrays.equals(super.getURLs(), notFoundResources.get(name))) { + return (new Vector(0)).elements(); ++ } + + if (!name.startsWith("META-INF")) { + Enumeration urls = super.findResources(name); +@@ -2586,8 +2687,9 @@ + public URL findResource(String name) { + + // If we have searched this path before, don't try again +- if (Arrays.equals(super.getURLs(), notFoundResources.get(name))) ++ if (Arrays.equals(super.getURLs(), notFoundResources.get(name))) { + return null; ++ } + + URL url = null; + if (!name.startsWith("META-INF")) { +@@ -2595,12 +2697,12 @@ + final String fName = name; + url = AccessController.doPrivileged( + new PrivilegedExceptionAction() { +- public URL run() { +- return CodeBaseClassLoader.super.findResource(fName); +- } +- }, parentJNLPClassLoader.getAccessControlContextForClassLoading()); ++ public URL run() { ++ return CodeBaseClassLoader.super.findResource(fName); ++ } ++ }, parentJNLPClassLoader.getAccessControlContextForClassLoading()); + } catch (PrivilegedActionException pae) { +- } ++ } + + if (url == null) { + notFoundResources.put(name, super.getURLs()); +@@ -2612,6 +2714,5 @@ + return null; + } + } +- +- ++ + } +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/security/dialogs/AccessWarningPane.java +--- a/netx/net/sourceforge/jnlp/security/dialogs/AccessWarningPane.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/security/dialogs/AccessWarningPane.java Fri Mar 02 10:41:29 2018 +0100 +@@ -197,7 +197,7 @@ + fromLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + +- final JButton run = new JButton(R("ButAllow")); ++ final JButton run = new JButton(R("ButOk")); + final JButton cancel = new JButton(R("ButCancel")); + + JPanel infoPanel = new JPanel(new GridBagLayout()); +@@ -241,23 +241,6 @@ + htmlPanelDesktop.setVisible(false); + c.gridy++; + } +- ActionListener al = new ActionListener() { +- +- @Override +- public void actionPerformed(ActionEvent e) { +- if (desktopCheck.isSelected() || menuCheck.isSelected()){ +- run.setEnabled(true); +- cancel.setEnabled(false); +- } else { +- run.setEnabled(false); +- cancel.setEnabled(true); +- } +- +- } +- }; +- desktopCheck.addActionListener(al); +- menuCheck.addActionListener(al); +- al.actionPerformed(null); + infoPanel.add(menuCheck,c); + c.gridy++; + if (!JNLPRuntime.isWebstartApplication()) { +diff -r dbb8dc397d15 -r 4abd0f089773 netx/net/sourceforge/jnlp/util/FileUtils.java +--- a/netx/net/sourceforge/jnlp/util/FileUtils.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/netx/net/sourceforge/jnlp/util/FileUtils.java Fri Mar 02 10:41:29 2018 +0100 +@@ -33,12 +33,12 @@ + import java.io.Writer; + import java.nio.channels.FileChannel; + import java.nio.channels.FileLock; ++import java.nio.file.Files; ++import java.nio.file.attribute.*; + import java.security.DigestInputStream; + import java.security.MessageDigest; + import java.security.NoSuchAlgorithmException; +-import java.util.ArrayList; +-import java.util.Arrays; +-import java.util.List; ++import java.util.*; + + import javax.swing.JFrame; + import javax.swing.JOptionPane; +@@ -307,7 +307,6 @@ + throw new IOException(R("RCantRename", tempFile, file)); + } + } +- + } + + /** +diff -r dbb8dc397d15 -r 4abd0f089773 tests/netx/unit/net/sourceforge/jnlp/ParserBasic.java +--- a/tests/netx/unit/net/sourceforge/jnlp/ParserBasic.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/tests/netx/unit/net/sourceforge/jnlp/ParserBasic.java Fri Mar 02 10:41:29 2018 +0100 +@@ -33,8 +33,7 @@ + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. +-*/ +- ++ */ + package net.sourceforge.jnlp; + + import java.io.InputStream; +@@ -46,8 +45,10 @@ + import org.junit.BeforeClass; + import org.junit.Test; + +-/** Test that the parser works with basic jnlp files */ +-public class ParserBasic extends NoStdOutErrTest{ ++/** ++ * Test that the parser works with basic jnlp files ++ */ ++public class ParserBasic extends NoStdOutErrTest { + + private static Node root; + private static Parser parser; +@@ -214,6 +215,22 @@ + } + + @Test ++ public void testResourcesInsideJava() throws ParseException { ++ ClassLoader cl = ParserBasic.class.getClassLoader(); ++ if (cl == null) { ++ cl = ClassLoader.getSystemClassLoader(); ++ } ++ ParserSettings defaultParser = new ParserSettings(); ++ InputStream jnlpStream = cl.getResourceAsStream("net/sourceforge/jnlp/jarsInJreDesc.jnlp"); ++ Node omega = Parser.getRootNode(jnlpStream, defaultParser); ++ Parser omegaParser = new Parser(new DummyJNLPFile(), null, omega, defaultParser); ++ ResourcesDesc resources = omegaParser.getResources(omega, false).get(0); ++ JARDesc[] r = resources.getJARs(); ++ // we ensures that also in j2se hars ar eloaded.it is 7 withutt them. ++ Assert.assertTrue(r.length>30); ++ } ++ ++ @Test + public void testResourcesJar() throws ParseException { + ResourcesDesc resources = parser.getResources(root, false).get(0); + +@@ -276,7 +293,7 @@ + ApplicationDesc app = (ApplicationDesc) parser.getLauncher(root); + Assert.assertNotNull(app); + Assert.assertEquals("MainClass", app.getMainClass()); +- Assert.assertArrayEquals(new String[] { "arg1", "arg2" }, app.getArguments()); ++ Assert.assertArrayEquals(new String[]{"arg1", "arg2"}, app.getArguments()); + } + + } +diff -r dbb8dc397d15 -r 4abd0f089773 tests/netx/unit/net/sourceforge/jnlp/ParserCornerCases.java +--- a/tests/netx/unit/net/sourceforge/jnlp/ParserCornerCases.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/tests/netx/unit/net/sourceforge/jnlp/ParserCornerCases.java Fri Mar 02 10:41:29 2018 +0100 +@@ -66,7 +66,7 @@ + Assert.assertTrue(target.getContent().contains("value")); + + Node node = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("argument", node.getNodeName()); ++ Assert.assertEquals("argument", node.getNodeName().getName()); + String contents = node.getNodeValue(); + Assert.assertTrue(contents.contains("xml")); + Assert.assertTrue(contents.contains("DOCTYPE")); +@@ -94,7 +94,7 @@ + + Node node = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); + node = node.getFirstChild().getFirstChild(); +- Assert.assertEquals("argument", node.getNodeName()); ++ Assert.assertEquals("argument", node.getNodeName().getName()); + String contents = node.getNodeValue(); + Assert.assertTrue(contents.contains("xml")); + Assert.assertTrue(contents.contains("DOCTYPE")); +diff -r dbb8dc397d15 -r 4abd0f089773 tests/netx/unit/net/sourceforge/jnlp/ParserTest.java +--- a/tests/netx/unit/net/sourceforge/jnlp/ParserTest.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/tests/netx/unit/net/sourceforge/jnlp/ParserTest.java Fri Mar 02 10:41:29 2018 +0100 +@@ -67,7 +67,7 @@ + String data = "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -82,7 +82,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -105,7 +105,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -135,7 +135,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -162,7 +162,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -185,7 +185,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -216,7 +216,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -247,7 +247,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -277,7 +277,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -306,7 +306,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -334,7 +334,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -361,7 +361,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -385,7 +385,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -409,7 +409,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -431,7 +431,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -454,7 +454,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -493,7 +493,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(ALL_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -516,7 +516,7 @@ + String data = "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -531,7 +531,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -554,7 +554,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -580,7 +580,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -607,7 +607,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -630,7 +630,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -661,7 +661,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -692,7 +692,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -722,7 +722,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -751,7 +751,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -779,7 +779,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -806,7 +806,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -830,7 +830,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -854,7 +854,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -876,7 +876,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -899,7 +899,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -938,7 +938,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_COUNTRY_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -961,7 +961,7 @@ + String data = "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -976,7 +976,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -999,7 +999,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -1021,7 +1021,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -1045,7 +1045,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -1068,7 +1068,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -1099,7 +1099,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -1130,7 +1130,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -1156,7 +1156,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = parser.getInfo(root); +@@ -1184,7 +1184,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -1211,7 +1211,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -1235,7 +1235,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -1259,7 +1259,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); + List infoDescs = new ArrayList(); +@@ -1281,7 +1281,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -1304,7 +1304,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -1343,7 +1343,7 @@ + + "\n"; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser); +@@ -1371,7 +1371,7 @@ + ""; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + URL overwrittenCodebase = new URL("http://icedtea.classpath.org"); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); +@@ -1390,7 +1390,7 @@ + ""; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + URL overwrittenCodebase = new URL("http://icedtea.classpath.org"); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); +@@ -1408,7 +1408,7 @@ + ""; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + URL overwrittenCodebase = new URL("http://icedtea.classpath.org"); + + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); +@@ -1427,7 +1427,7 @@ + + ""; + + Node root = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root.getNodeName().getName()); + MockJNLPFile file = new MockJNLPFile(LANG_LOCALE); + Parser parser = new Parser(file, null, root, defaultParser, null); + ParseException eex = null; +@@ -1453,7 +1453,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + String main1 = parser1.getLauncher(root1).getMainClass(); +@@ -1461,7 +1461,7 @@ + + //strict also ok + Node root2 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), strictParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName().getName()); + MockJNLPFile file2 = new MockJNLPFile(LANG_LOCALE); + Parser parser2 = new Parser(file2, null, root2, defaultParser, null); + String main2 = parser2.getLauncher(root2).getMainClass(); +@@ -1478,7 +1478,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + String main1 = parser1.getLauncher(root1).getMainClass(); +@@ -1486,7 +1486,7 @@ + + //strict also ok + Node root2 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), strictParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName().getName()); + MockJNLPFile file2 = new MockJNLPFile(LANG_LOCALE); + Parser parser2 = new Parser(file2, null, root2, strictParser, null); + String main2 = parser2.getLauncher(root2).getMainClass(); +@@ -1503,7 +1503,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + parser1.getLauncher(root1).getMainClass(); +@@ -1520,7 +1520,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + String main1 = parser1.getLauncher(root1).getMainClass(); +@@ -1528,7 +1528,7 @@ + + //strict also ok + Node root2 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), strictParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName().getName()); + MockJNLPFile file2 = new MockJNLPFile(LANG_LOCALE); + Parser parser2 = new Parser(file2, null, root2, strictParser, null); + String main2 = parser2.getLauncher(root2).getMainClass(); +@@ -1546,7 +1546,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + String main1 = parser1.getLauncher(root1).getMainClass(); +@@ -1554,7 +1554,7 @@ + + //strict throws + Node root2 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), strictParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName().getName()); + MockJNLPFile file2 = new MockJNLPFile(LANG_LOCALE); + Parser parser2 = new Parser(file2, null, root2, strictParser, null); + parser2.getLauncher(root2).getMainClass(); +@@ -1570,7 +1570,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + String main1 = parser1.getLauncher(root1).getMainClass(); +@@ -1578,7 +1578,7 @@ + + //strict throws + Node root2 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), strictParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName().getName()); + MockJNLPFile file2 = new MockJNLPFile(LANG_LOCALE); + Parser parser2 = new Parser(file2, null, root2, strictParser, null); + parser2.getLauncher(root2).getMainClass(); +@@ -1594,7 +1594,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + String main1 = parser1.getLauncher(root1).getMainClass(); +@@ -1602,7 +1602,7 @@ + + //strict throws + Node root2 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), strictParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName().getName()); + MockJNLPFile file2 = new MockJNLPFile(LANG_LOCALE); + Parser parser2 = new Parser(file2, null, root2, strictParser, null); + parser2.getLauncher(root2).getMainClass(); +@@ -1617,7 +1617,7 @@ + + ""; + + Node root1 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), defaultParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root1.getNodeName().getName()); + MockJNLPFile file1 = new MockJNLPFile(LANG_LOCALE); + Parser parser1 = new Parser(file1, null, root1, defaultParser, null); + String main1 = parser1.getLauncher(root1).getMainClass(); +@@ -1625,7 +1625,7 @@ + + //strict throws + Node root2 = Parser.getRootNode(new ByteArrayInputStream(data.getBytes()), strictParser); +- Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName()); ++ Assert.assertEquals("Root name is not jnlp", "jnlp", root2.getNodeName().getName()); + MockJNLPFile file2 = new MockJNLPFile(LANG_LOCALE); + Parser parser2 = new Parser(file2, null, root2, strictParser, null); + parser2.getLauncher(root2).getMainClass(); +diff -r dbb8dc397d15 -r 4abd0f089773 tests/netx/unit/net/sourceforge/jnlp/jarsInJreDesc.jnlp +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/tests/netx/unit/net/sourceforge/jnlp/jarsInJreDesc.jnlp Fri Mar 02 10:41:29 2018 +0100 +@@ -0,0 +1,100 @@ ++ ++ ++ ++ ++ ++ OmegaT ++ OmegaT development team ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff -r dbb8dc397d15 -r 4abd0f089773 tests/netx/unit/net/sourceforge/jnlp/util/FileUtilsTest.java +--- a/tests/netx/unit/net/sourceforge/jnlp/util/FileUtilsTest.java Mon Dec 18 13:22:51 2017 +0100 ++++ b/tests/netx/unit/net/sourceforge/jnlp/util/FileUtilsTest.java Fri Mar 02 10:41:29 2018 +0100 +@@ -37,6 +37,9 @@ + package net.sourceforge.jnlp.util; + + import java.io.File; ++import java.nio.file.Files; ++import java.nio.file.attribute.AclEntry; ++import java.nio.file.attribute.AclFileAttributeView; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; +diff -r dbb8dc397d15 -r 4abd0f089773 tests/reproducers/custom/JavaFx/resources/JavaFx.jar +Binary file tests/reproducers/custom/JavaFx/resources/JavaFx.jar has changed +diff -r dbb8dc397d15 -r 4abd0f089773 tests/reproducers/custom/JavaFx/resources/JavaFx.jnlp +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/tests/reproducers/custom/JavaFx/resources/JavaFx.jnlp Fri Mar 02 10:41:29 2018 +0100 +@@ -0,0 +1,15 @@ ++ ++ ++ ++ JavaFx ++ ITW ++ JavaFx ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff -r dbb8dc397d15 -r 4abd0f089773 tests/reproducers/custom/JavaFx/srcs/Controller.java +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/tests/reproducers/custom/JavaFx/srcs/Controller.java Fri Mar 02 10:41:29 2018 +0100 +@@ -0,0 +1,11 @@ ++import javafx.fxml.FXML; ++import javafx.scene.text.Text; ++ ++public class Controller { ++ @FXML private Text text; ++ ++ @FXML ++ public void onPressButton() { ++ text.setVisible(true); ++ } ++} +diff -r dbb8dc397d15 -r 4abd0f089773 tests/reproducers/custom/JavaFx/srcs/Main.java +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/tests/reproducers/custom/JavaFx/srcs/Main.java Fri Mar 02 10:41:29 2018 +0100 +@@ -0,0 +1,23 @@ ++import javafx.application.Application; ++import javafx.fxml.FXMLLoader; ++import javafx.scene.Parent; ++import javafx.scene.Scene; ++import javafx.stage.Stage; ++ ++public class Main extends Application { ++ ++ @Override ++ public void start(Stage primaryStage) throws Exception { ++ Parent root = FXMLLoader.load(getClass().getResource("helloworld.fxml")); ++ primaryStage.setTitle("Hello World"); ++ primaryStage.setScene(new Scene(root, 500, 200)); ++ primaryStage.show(); ++ System.out.println("jnlp-javafx started"); ++ System.out.println("jnlp-javafx can be terminated"); ++ } ++ ++ ++ public static void main(String[] args) { ++ launch(args); ++ } ++} +diff -r dbb8dc397d15 -r 4abd0f089773 tests/reproducers/custom/JavaFx/srcs/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/tests/reproducers/custom/JavaFx/srcs/Makefile Fri Mar 02 10:41:29 2018 +0100 +@@ -0,0 +1,25 @@ ++TESTNAME=JavaFx ++ ++JAVAC_CLASSPATH=$(TEST_EXTENSIONS_DIR):$(NETX_DIR)/lib/classes.jar ++JAVAC=$(EXPORTED_JAVAC) ++JAR=$(EXPORTED_JAR) ++JARSIGNER=$(EXPORTED_JARSIGNER) ++ ++TMPDIR:=$(shell mktemp -d) ++ ++prepare-reproducer: ++ echo PREPARING REPRODUCER $(TESTNAME) ++ #this test contains prebuild binary, as javafx, when installed on computer, preven ITW from building ++ #due to JSObject differennt implementation ++ #$(JAVAC) -d $(TMPDIR) -classpath $(JAVAC_CLASSPATH) Controller.java Main.java; \ ++ #cp helloworld.fxml $(TMPDIR) ; \ ++ #pushd $(TMPDIR); \ ++ #$(JAR) cf $(TESTNAME).jar *.class *.fxml; \ ++ #popd ++ #cp $(TMPDIR)/$(TESTNAME).jar $(REPRODUCERS_TESTS_SERVER_DEPLOYDIR); \ ++ cp ../resources/* $(REPRODUCERS_TESTS_SERVER_DEPLOYDIR); \ ++ rm -rf $(TMPDIR); \ ++ echo PREPARED REPRODUCER $(TESTNAME); \ ++ ++clean-reproducer: ++ echo NOTHING TO CLEAN FOR $(TESTNAME) +diff -r dbb8dc397d15 -r 4abd0f089773 tests/reproducers/custom/JavaFx/srcs/helloworld.fxml +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/tests/reproducers/custom/JavaFx/srcs/helloworld.fxml Fri Mar 02 10:41:29 2018 +0100 +@@ -0,0 +1,17 @@ ++ ++ ++ ++ ++ ++ ++ ++