# HG changeset patch # User Jiri Vanek # Date 1384337718 -3600 # Node ID 7d2759e4bc980f8c8623bf3473650b1a242b4ddf # Parent acbada276d2339036e6efc9092e2e6349c2cd1b6 Backported enabled access to manifests' attributes from JNLPFile class, implemented http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_name diff -r acbada276d23 -r 7d2759e4bc98 ChangeLog --- a/ChangeLog Wed Nov 06 14:46:43 2013 +0100 +++ b/ChangeLog Wed Nov 13 11:15:18 2013 +0100 @@ -1,3 +1,27 @@ +2013-11-13 Jiri Vanek + + Enabled access to manifests' attributes from JNLPFile class + Implemented http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_name + * netx/net/sourceforge/jnlp/JNLPFile.java: Added (manifestsAttributes) field. + Added (ManifestsAttributes) inner class, to encapsulate access to attributes. + (getTitle) can handle manifests too. + * netx/net/sourceforge/jnlp/PluginBridge.java: is following app_name recommendations. + * netx/net/sourceforge/jnlp/ResourcesDesc.java: (getMainJAR) made more granular + * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: (init) inject itself + to file's ManifestsAttributes. (checkForAttributeInJars) renamed field + mainClassInThisJar to attributeInThisJar. Added getter for mainClass. + * netx/net/sourceforge/jnlp/security/CertWarningPane.java: bracketing cleanup. + * tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPFileTest.java: new test to + check new functionalites + * tests/netx/unit/net/sourceforge/jnlp/runtime/ResourcesDescTest.java: same + * tests/test-extensions/net/sourceforge/jnlp/mock/DummyJNLPFileWithJar.java: + can set info + * NEWS: mentioned first u45 attribute, dialog centering + * tests/test-extensions/net/sourceforge/jnlp/mock/DummyJNLPFileWithJar.java: backported + * tests/test-extensions/net/sourceforge/jnlp/util/FileTestUtils.java: backported + * netx/net/sourceforge/jnlp/InformationDesc.java: partial backport of constructor change + + 2013-11-06 Jiri Vanek Enabled java console for plugin diff -r acbada276d23 -r 7d2759e4bc98 NEWS --- a/NEWS Wed Nov 06 14:46:43 2013 +0100 +++ b/NEWS Wed Nov 13 11:15:18 2013 +0100 @@ -10,6 +10,7 @@ New in release 1.4.2 (2013-MM-DD): * Dialogs center on screen before becoming visible +* Support for u45 new manifest attributes (Application-Name) * Plugin - RH976833: Multiple applets on one page cause deadlock - Enabled javaconsole diff -r acbada276d23 -r 7d2759e4bc98 netx/net/sourceforge/jnlp/InformationDesc.java --- a/netx/net/sourceforge/jnlp/InformationDesc.java Wed Nov 06 14:46:43 2013 +0100 +++ b/netx/net/sourceforge/jnlp/InformationDesc.java Wed Nov 13 11:15:18 2013 +0100 @@ -52,18 +52,21 @@ /** the data as list of key,value pairs */ private List info; - /** the JNLPFile this information is for */ - private JNLPFile jnlpFile; /** * Create an information element object. * - * @param jnlpFile file that the information is for * @param locales the locales the information is for */ + public InformationDesc(Locale locales[]) { + this.locales = locales; + } + + /** + * 1.4 comaptibility + */ public InformationDesc(JNLPFile jnlpFile, Locale locales[]) { - this.jnlpFile = jnlpFile; - this.locales = locales; + this(locales); } /** @@ -171,6 +174,8 @@ } } + // FIXME if there's no larger icon, choose the closest smaller icon + // instead of the first if (best == null) best = icons[0]; @@ -185,13 +190,6 @@ } /** - * Returns the JNLPFile the information is for. - */ - public JNLPFile getJNLPFile() { - return jnlpFile; - } - - /** * Returns whether offline execution allowed. */ public boolean isOfflineAllowed() { diff -r acbada276d23 -r 7d2759e4bc98 netx/net/sourceforge/jnlp/JNLPFile.java --- a/netx/net/sourceforge/jnlp/JNLPFile.java Wed Nov 06 14:46:43 2013 +0100 +++ b/netx/net/sourceforge/jnlp/JNLPFile.java Wed Nov 13 11:15:18 2013 +0100 @@ -28,9 +28,11 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.jar.Attributes; import net.sourceforge.jnlp.cache.ResourceTracker; import net.sourceforge.jnlp.cache.UpdatePolicy; +import net.sourceforge.jnlp.runtime.JNLPClassLoader; import net.sourceforge.jnlp.runtime.JNLPRuntime; /** @@ -51,6 +53,13 @@ * @version $Revision: 1.21 $ */ public class JNLPFile { + + + public static final String APP_NAME = "Application-Name"; + public static final String CALLER_ALLOWABLE = "Caller-Allowable-Codebase"; + public static final String APP_LIBRARY_ALLOWABLE = "Application-Library-Allowable-Codebase"; + + // todo: save the update policy, then if file was not updated // then do not check resources for being updated. @@ -118,6 +127,10 @@ * List of acceptable properties (not-special) */ private String[] generalProperties = SecurityDesc.getJnlpRIAPermissions(); + + /** important manifests' attributes */ + private final ManifestsAttributes manifestsAttributes = new ManifestsAttributes(); + { // initialize defaults if security allows try { @@ -301,10 +314,46 @@ /** * Returns the JNLP file's best localized title. This method returns the same * value as InformationDesc.getTitle(). + * + * Since jdk7 u45, also manifest title, and mainclass are taken to consideration; + * See PluginBridge */ public String getTitle() { + String jnlpTitle = getTitleFromJnlp(); + String manifestTitle = getTitleFromManifest(); + if (jnlpTitle != null && manifestTitle != null) { + if (jnlpTitle.equals(manifestTitle)) { + return jnlpTitle; + } + return jnlpTitle+" ("+manifestTitle+")"; + } + if (jnlpTitle != null && manifestTitle == null) { + return jnlpTitle; + } + if (jnlpTitle == null && manifestTitle != null) { + return manifestTitle; + } + String mainClass = getManifestsAttributes().getMainClass(); + return mainClass; + } + + /** + * Returns the JNLP file's best localized title. This method returns the same + * value as InformationDesc.getTitle(). + */ + public String getTitleFromJnlp() { return getInformation().getTitle(); } + + public String getTitleFromManifest() { + String inManifestTitle = getManifestsAttributes().getApplicationName(); + if (inManifestTitle == null && getManifestsAttributes().isLoader()){ + System.err.println("Application title was not found in manifest. Check with application vendor"); + } + return inManifestTitle; + } + + /** * Returns the JNLP file's best localized vendor. This method returns the same @@ -820,4 +869,80 @@ public void setSignedJNLPAsMissing() { missingSignedJNLP = true; } + + public ManifestsAttributes getManifestsAttributes() { + return manifestsAttributes; + } + + + public class ManifestsAttributes{ + private JNLPClassLoader loader; + + + public void setLoader(JNLPClassLoader loader) { + this.loader = loader; + } + + public boolean isLoader() { + return loader != null; + } + + + + /** + * main class can be defined outside of manifest. + * This method is mostly for completeness + */ + public String getMainClass(){ + if (loader == null) { + if (JNLPRuntime.isDebug()) { + System.err.println("Jars not ready to provide main class"); + } + return null; + } + return loader.getMainClass(); + } + + /** + * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_name + */ + public String getApplicationName(){ + return getAttribute(APP_NAME); + } + + /** + * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#caller_allowable + */ + public String getCallerAllowableCodebase(){ + return getAttribute(CALLER_ALLOWABLE); + } + + /** + * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_library + */ + public String getApplicationLibraryAllowableCodebase(){ + return getAttribute(APP_LIBRARY_ALLOWABLE); + } + + /** + * get custom attribute. + */ + public String getAttribute(String name){ + return getAttribute(new Attributes.Name(name)); + } + + /** + * get standard attribute + */ + public String getAttribute(Attributes.Name name){ + if (loader == null) { + if (JNLPRuntime.isDebug()) { + System.err.println("Jars not ready to provide attribute "+ name); + } + return null; + } + return loader.checkForAttributeInJars(Arrays.asList(getResources().getJARs()), name); + } + } + } diff -r acbada276d23 -r 7d2759e4bc98 netx/net/sourceforge/jnlp/PluginBridge.java --- a/netx/net/sourceforge/jnlp/PluginBridge.java Wed Nov 06 14:46:43 2013 +0100 +++ b/netx/net/sourceforge/jnlp/PluginBridge.java Wed Nov 13 11:15:18 2013 +0100 @@ -179,7 +179,7 @@ // the class name should be of the form foo.bar.Baz not foo/bar/Baz String mainClass = main.replace('/', '.'); - launchType = new AppletDesc(params.getAppletTitle(), mainClass, documentBase, width, + launchType = new AppletDesc(getTitle(), mainClass, documentBase, width, height, params.getUnmodifiableMap()); if (main.endsWith(".class")) //single class file only @@ -226,7 +226,18 @@ return new DownloadOptions(usePack, useVersion); } + @Override public String getTitle() { + String inManifestTitle = super.getTitleFromManifest(); + if (inManifestTitle != null) { + return inManifestTitle; + } + //specification is recommending main class instead of html parameter + //http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_name + String mainClass = getManifestsAttributes().getMainClass(); + if (mainClass != null) { + return mainClass; + } return params.getAppletTitle(); } diff -r acbada276d23 -r 7d2759e4bc98 netx/net/sourceforge/jnlp/ResourcesDesc.java --- a/netx/net/sourceforge/jnlp/ResourcesDesc.java Wed Nov 06 14:46:43 2013 +0100 +++ b/netx/net/sourceforge/jnlp/ResourcesDesc.java Wed Nov 13 11:15:18 2013 +0100 @@ -67,23 +67,30 @@ return resources.toArray(new JREDesc[resources.size()]); } + public static JARDesc getMainJAR(JARDesc jars[] ) { + return getMainJAR(Arrays.asList(jars)); + } + + public static JARDesc getMainJAR(List jars) { + for (JARDesc jar : jars) { + if (jar.isMain()) { + return jar; + } + } + + if (jars.size() > 0) { + return jars.get(0); + } else { + return null; + } + } /** * Returns the main JAR for these resources. There first JAR * is returned if no JARs are specified as the main JAR, and if * there are no JARs defined then null is returned. */ public JARDesc getMainJAR() { - JARDesc jars[] = getJARs(); - - for (JARDesc jar : jars) { - if (jar.isMain()) - return jar; - } - - if (jars.length > 0) - return jars[0]; - else - return null; + return getMainJAR(getJARs()); } /** diff -r acbada276d23 -r 7d2759e4bc98 netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java --- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Wed Nov 06 14:46:43 2013 +0100 +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Wed Nov 13 11:15:18 2013 +0100 @@ -112,7 +112,7 @@ /** 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 **/ public static enum DownloadAction { DOWNLOAD_TO_CACHE, REMOVE_FROM_CACHE, CHECK_CACHE @@ -200,7 +200,7 @@ /** Name of the application's main class */ private String mainClass = null; - + /** * Variable to track how many times this loader is in use */ @@ -244,6 +244,9 @@ this.mainClass = mainName; + //as it is harmless, we can set is as soon as possible. + file.getManifestsAttributes().setLoader(this); + AppVerifier verifier; if (file instanceof PluginBridge && !((PluginBridge)file).useJNLPHref()) { @@ -258,13 +261,15 @@ initializeExtensions(); initializeResources(); + // initialize permissions initializePermissions(); setSecurity(); - + installShutdownHooks(); + } @@ -807,7 +812,7 @@ String result = null; // Check main jar - JARDesc mainJarDesc = file.getResources().getMainJAR(); + JARDesc mainJarDesc = ResourcesDesc.getMainJAR(jars); result = getManifestAttribute(mainJarDesc.getLocation(), name); if (result != null) { @@ -824,10 +829,10 @@ // Still not found? Iterate and set if only 1 was found for (JARDesc jarDesc: jars) { - String mainClassInThisJar = getManifestAttribute(jarDesc.getLocation(), name); - if (mainClassInThisJar != null) { + String attributeInThisJar = getManifestAttribute(jarDesc.getLocation(), name); + if (attributeInThisJar != null) { if (result == null) { // first main class - result = mainClassInThisJar; + result = attributeInThisJar; } else { // There is more than one main class. Set to null and break. result = null; break; @@ -2349,6 +2354,10 @@ return new AccessControlContext(new ProtectionDomain[] { pd }); } + + public String getMainClass() { + return mainClass; + } /* * Helper class to expose protected URLClassLoader methods. @@ -2473,6 +2482,6 @@ return null; } } - - + + } diff -r acbada276d23 -r 7d2759e4bc98 netx/net/sourceforge/jnlp/security/CertWarningPane.java --- a/netx/net/sourceforge/jnlp/security/CertWarningPane.java Wed Nov 06 14:46:43 2013 +0100 +++ b/netx/net/sourceforge/jnlp/security/CertWarningPane.java Wed Nov 13 11:15:18 2013 +0100 @@ -106,13 +106,14 @@ //these strings -- we just want to fill in as many as possible. try { if ((certVerifier instanceof HttpsCertVerifier) && - (c instanceof X509Certificate)) + (c instanceof X509Certificate)) { name = SecurityUtil.getCN(((X509Certificate) c) .getSubjectX500Principal().getName()); - else if (file instanceof PluginBridge) + } else if (file instanceof PluginBridge) { name = file.getTitle(); - else + } else { name = file.getInformation().getTitle(); + } } catch (Exception e) { } @@ -125,10 +126,11 @@ } try { - if (file instanceof PluginBridge) + if (file instanceof PluginBridge) { from = file.getCodeBase().getHost(); - else + } else { from = file.getInformation().getHomepage().toString(); + } } catch (Exception e) { } @@ -145,7 +147,7 @@ topLabelText = R("SHttpsUnverified") + " " + R("Continue"); propertyName = "OptionPane.warningIcon"; iconLocation += "warning.png"; - } else + } else { switch (type) { case VERIFIED: topLabelText = R("SSigVerified"); @@ -166,7 +168,7 @@ bottomLabelText += " " + R("SWarnFullPermissionsIgnorePolicy"); break; } - + } ImageIcon icon = new ImageIcon((new sun.misc.Launcher()) .getClassLoader().getResource(iconLocation)); JLabel topLabel = new JLabel(htmlWrap(topLabelText), icon, SwingConstants.LEFT); @@ -194,8 +196,9 @@ infoPanel.add(nameLabel); infoPanel.add(publisherLabel); - if (!(certVerifier instanceof HttpsCertVerifier)) + if (!(certVerifier instanceof HttpsCertVerifier)) { infoPanel.add(fromLabel); + } infoPanel.add(alwaysTrust); infoPanel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 25)); @@ -224,7 +227,7 @@ add(infoPanel); add(buttonPanel); - JLabel bottomLabel = new JLabel(htmlWrap(bottomLabelText));; + JLabel bottomLabel = new JLabel(htmlWrap(bottomLabelText)); JButton moreInfo = new JButton(R("ButMoreInformation")); moreInfo.addActionListener(new MoreInfoButtonListener()); diff -r acbada276d23 -r 7d2759e4bc98 netx/net/sourceforge/jnlp/util/StreamUtils.java --- a/netx/net/sourceforge/jnlp/util/StreamUtils.java Wed Nov 06 14:46:43 2013 +0100 +++ b/netx/net/sourceforge/jnlp/util/StreamUtils.java Wed Nov 13 11:15:18 2013 +0100 @@ -42,6 +42,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; public class StreamUtils { @@ -51,7 +52,7 @@ * * @param stream the stream that will be closed */ - public static void closeSilently (Closeable stream) { + public static void closeSilently(Closeable stream) { if (stream != null) { try { stream.close(); @@ -61,8 +62,27 @@ } } + /** + * Copy an input stream's contents into an output stream. + */ + public static void copyStream(InputStream input, OutputStream output) + throws IOException { + byte[] buffer = new byte[1024]; + while (true) { + int bytesRead = input.read(buffer); + if (bytesRead == -1) { + break; + } + output.write(buffer, 0, bytesRead); + } + } - public static String readStreamAsString(InputStream stream) throws IOException { + public static String readStreamAsString(InputStream stream) throws IOException { + return readStreamAsString(stream, false); + } + + public static String readStreamAsString(InputStream stream, boolean includeEndOfLines) + throws IOException { InputStreamReader is = new InputStreamReader(stream); StringBuilder sb = new StringBuilder(); BufferedReader br = new BufferedReader(is); @@ -72,6 +92,9 @@ break; } sb.append(read); + if (includeEndOfLines){ + sb.append('\n'); + } } diff -r acbada276d23 -r 7d2759e4bc98 tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPFileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPFileTest.java Wed Nov 13 11:15:18 2013 +0100 @@ -0,0 +1,162 @@ +/* + Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + 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.runtime; + +import java.io.File; +import java.util.Arrays; +import java.util.Locale; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import net.sourceforge.jnlp.InformationDesc; +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.cache.UpdatePolicy; +import net.sourceforge.jnlp.mock.DummyJNLPFileWithJar; +import net.sourceforge.jnlp.util.FileTestUtils; +import org.junit.Assert; +import org.junit.Test; + +public class JNLPFileTest { + + @Test + public void removeTitle() throws Exception { + File tempDirectory = FileTestUtils.createTempDirectory(); + tempDirectory.deleteOnExit(); + File jarLocation1 = new File(tempDirectory, "test1.jar"); + File jarLocation2 = new File(tempDirectory, "test2.jar"); + File jarLocation3 = new File(tempDirectory, "test3.jar"); + File jarLocation4 = new File(tempDirectory, "test4.jar"); + File jarLocation5 = new File(tempDirectory, "test5.jar"); + + /* Test with various attributes in manifest!s! */ + Manifest manifest1 = new Manifest(); + manifest1.getMainAttributes().put(Attributes.Name.MAIN_CLASS, "DummyClass1"); //two times, but one in main jar, see DummyJNLPFileWithJar constructor with int + + Manifest manifest2 = new Manifest(); + manifest2.getMainAttributes().put(Attributes.Name.IMPLEMENTATION_VENDOR, "rh1"); //two times, both in not main jar, see DummyJNLPFileWithJar constructor with int + + Manifest manifest3 = new Manifest(); + manifest3.getMainAttributes().put(Attributes.Name.IMPLEMENTATION_TITLE, "it"); //jsut once in not main jar, see DummyJNLPFileWithJar constructor with int + manifest3.getMainAttributes().put(Attributes.Name.IMPLEMENTATION_VENDOR, "rh2"); + + Manifest manifest4 = new Manifest(); + manifest4.getMainAttributes().put(Attributes.Name.MAIN_CLASS, "DummyClass2"); //see jnlpFile.setMainJar(3); + manifest4.getMainAttributes().put(Attributes.Name.IMPLEMENTATION_URL, "some url2"); //see DummyJNLPFileWithJar constructor with int + + //first jar + Manifest manifest5 = new Manifest(); + manifest5.getMainAttributes().put(Attributes.Name.IMPLEMENTATION_URL, "some url1"); //see DummyJNLPFileWithJar constructor with int + manifest5.getMainAttributes().put(new Attributes.Name(JNLPFile.APP_NAME), "Manifested Name"); + + + FileTestUtils.createJarWithContents(jarLocation1, manifest1); + FileTestUtils.createJarWithContents(jarLocation2, manifest2); + FileTestUtils.createJarWithContents(jarLocation3, manifest3); + FileTestUtils.createJarWithContents(jarLocation4, manifest4); + FileTestUtils.createJarWithContents(jarLocation5, manifest5); + + final DummyJNLPFileWithJar jnlpFile = new DummyJNLPFileWithJar(3, jarLocation5, jarLocation3, jarLocation4, jarLocation1, jarLocation2); //jar 1 should be main + Assert.assertNull("no classlaoder attached, should be null", jnlpFile.getManifestsAttributes().getMainClass()); + Assert.assertNull("no classlaoder attached, should be null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_VENDOR)); + Assert.assertNull("no classlaoder attached, should be null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_TITLE)); + Assert.assertNull("no classlaoder attached, should be null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.MAIN_CLASS)); + Assert.assertNull("no classlaoder attached, should be null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_VENDOR_ID)); + Assert.assertNull("no classlaoder attached, should be null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_URL)); + Assert.assertNull("no classlaoder attached, should be null", jnlpFile.getManifestsAttributes().getAttribute(new Attributes.Name(JNLPFile.APP_NAME))); + + Assert.assertNull(jnlpFile.getTitleFromJnlp()); + Assert.assertNull(jnlpFile.getTitleFromManifest()); + Assert.assertNull(jnlpFile.getTitle()); + + setTitle(jnlpFile); + + Assert.assertEquals("jnlp title", jnlpFile.getTitleFromJnlp()); + Assert.assertNull(jnlpFile.getTitleFromManifest()); + Assert.assertEquals("jnlp title", jnlpFile.getTitle()); + + removeTitle(jnlpFile); + + Assert.assertNull(jnlpFile.getTitleFromJnlp()); + Assert.assertNull(jnlpFile.getTitleFromManifest()); + Assert.assertNull(jnlpFile.getTitle()); + + final JNLPClassLoader classLoader = new JNLPClassLoader(jnlpFile, UpdatePolicy.ALWAYS); + + // thsi si strange, but not part of this test + // Assert.assertNotNull("classlaoder attached, should be not null", jnlpFile.getManifestsAttributes().getMainClass()); + Assert.assertNull("defined twice, shoud be null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_VENDOR)); + Assert.assertNotNull("classlaoder attached, should be not null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_TITLE)); + Assert.assertNotNull("classlaoder attached, should be not null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.MAIN_CLASS)); + Assert.assertNull("not deffined, should benull", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_VENDOR_ID)); + Assert.assertNotNull("classlaoder attached, should be not null", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_URL)); + Assert.assertNotNull("classlaoder attached, should be not null", jnlpFile.getManifestsAttributes().getAttribute(new Attributes.Name(JNLPFile.APP_NAME))); + //correct values are also tested in JnlpClassloaderTest + Assert.assertEquals("classlaoder attached, should be not null", "it", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_TITLE)); + Assert.assertEquals("classlaoder attached, should be not null", "DummyClass1", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.MAIN_CLASS)); + Assert.assertEquals("classlaoder attached, should be not null", "some url1", jnlpFile.getManifestsAttributes().getAttribute(Attributes.Name.IMPLEMENTATION_URL)); + Assert.assertEquals("classlaoder attached, should be not null", "Manifested Name", jnlpFile.getManifestsAttributes().getAttribute(new Attributes.Name(JNLPFile.APP_NAME))); + + Assert.assertNull(jnlpFile.getTitleFromJnlp()); + Assert.assertEquals("Manifested Name", jnlpFile.getTitleFromManifest()); + Assert.assertEquals("Manifested Name", jnlpFile.getTitle()); + + setTitle(jnlpFile); + + Assert.assertEquals("jnlp title", jnlpFile.getTitleFromJnlp()); + Assert.assertEquals("Manifested Name", jnlpFile.getTitleFromManifest()); + Assert.assertEquals("jnlp title (Manifested Name)", jnlpFile.getTitle()); + + } + + private void setTitle(final DummyJNLPFileWithJar jnlpFile) { + setTitle(jnlpFile, "jnlp title"); + } + + private void setTitle(final DummyJNLPFileWithJar jnlpFile, final String title) { + jnlpFile.setInfo(Arrays.asList(new InformationDesc[]{ + new InformationDesc(new Locale[]{}) { + @Override + public String getTitle() { + return title; + } + } + })); + } + + private void removeTitle(final DummyJNLPFileWithJar jnlpFile) { + jnlpFile.setInfo(Arrays.asList(new InformationDesc[]{})); + } +} diff -r acbada276d23 -r 7d2759e4bc98 tests/netx/unit/net/sourceforge/jnlp/runtime/ResourcesDescTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/netx/unit/net/sourceforge/jnlp/runtime/ResourcesDescTest.java Wed Nov 13 11:15:18 2013 +0100 @@ -0,0 +1,105 @@ +/* + Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + 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.runtime; + +import java.io.File; +import java.util.jar.Manifest; +import net.sourceforge.jnlp.JARDesc; +import net.sourceforge.jnlp.mock.DummyJNLPFileWithJar; +import net.sourceforge.jnlp.util.FileTestUtils; +import org.junit.Assert; +import org.junit.Test; + +public class ResourcesDescTest { + + @Test + public void checkGetMainJar_noMainSet() throws Exception { + File tempDirectory = FileTestUtils.createTempDirectory(); + tempDirectory.deleteOnExit(); + + File jarLocation1 = new File(tempDirectory, "test1.jar"); + File jarLocation2 = new File(tempDirectory, "test2.jar"); + File jarLocation3 = new File(tempDirectory, "test3.jar"); + + Manifest manifest1 = new Manifest(); + Manifest manifest2 = new Manifest(); + Manifest manifest3 = new Manifest(); + Manifest manifest4 = new Manifest(); + Manifest manifest5 = new Manifest(); + + FileTestUtils.createJarWithContents(jarLocation1, manifest1); + FileTestUtils.createJarWithContents(jarLocation2, manifest2); + FileTestUtils.createJarWithContents(jarLocation3, manifest3); + + final DummyJNLPFileWithJar jnlpFile = new DummyJNLPFileWithJar(jarLocation1, jarLocation2, jarLocation3); + JARDesc result = jnlpFile.getResources().getMainJAR(); + Assert.assertTrue("first jar must be returned", result.getLocation().getFile().endsWith("test1.jar")); + } + + @Test + public void checkGetMainJar_mainSet() throws Exception { + File tempDirectory = FileTestUtils.createTempDirectory(); + tempDirectory.deleteOnExit(); + + File jarLocation1 = new File(tempDirectory, "test1.jar"); + File jarLocation2 = new File(tempDirectory, "test2.jar"); + File jarLocation3 = new File(tempDirectory, "test3.jar"); + + Manifest manifest1 = new Manifest(); + Manifest manifest2 = new Manifest(); + Manifest manifest3 = new Manifest(); + Manifest manifest4 = new Manifest(); + Manifest manifest5 = new Manifest(); + + FileTestUtils.createJarWithContents(jarLocation1, manifest1); + FileTestUtils.createJarWithContents(jarLocation2, manifest2); + FileTestUtils.createJarWithContents(jarLocation3, manifest3); + + DummyJNLPFileWithJar jnlpFile = new DummyJNLPFileWithJar(0, jarLocation1, jarLocation2, jarLocation3); + JARDesc result = jnlpFile.getResources().getMainJAR(); + Assert.assertTrue("main jar must be returned", result.getLocation().getFile().endsWith("test1.jar")); + + jnlpFile = new DummyJNLPFileWithJar(1, jarLocation1, jarLocation2, jarLocation3); + result = jnlpFile.getResources().getMainJAR(); + Assert.assertTrue("main jar must be returned", result.getLocation().getFile().endsWith("test2.jar")); + + jnlpFile = new DummyJNLPFileWithJar(2, jarLocation1, jarLocation2, jarLocation3); + result = jnlpFile.getResources().getMainJAR(); + Assert.assertTrue("main jar must be returned", result.getLocation().getFile().endsWith("test3.jar")); + } + +} diff -r acbada276d23 -r 7d2759e4bc98 tests/test-extensions/net/sourceforge/jnlp/mock/DummyJNLPFileWithJar.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-extensions/net/sourceforge/jnlp/mock/DummyJNLPFileWithJar.java Wed Nov 13 11:15:18 2013 +0100 @@ -0,0 +1,100 @@ +package net.sourceforge.jnlp.mock; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import net.sourceforge.jnlp.InformationDesc; +import net.sourceforge.jnlp.JARDesc; +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.ResourcesDesc; +import net.sourceforge.jnlp.SecurityDesc; +import net.sourceforge.jnlp.Version; + +/* A mocked dummy JNLP file with a single JAR. */ +public class DummyJNLPFileWithJar extends JNLPFile { + + /* Create a JARDesc for the given URL location */ + static JARDesc makeJarDesc(URL jarLocation, boolean main) { + return new JARDesc(jarLocation, new Version("1"), null, false,main, false,false); + } + + private final JARDesc[] jarDescs; + private final File[] jarFiles; + + public DummyJNLPFileWithJar(File... jarFiles) throws MalformedURLException { + this(-1, jarFiles); + } + public DummyJNLPFileWithJar(int main, File... jarFiles) throws MalformedURLException { + codeBase = jarFiles[0].getParentFile().toURI().toURL(); + this.jarFiles = jarFiles; + jarDescs = new JARDesc[jarFiles.length]; + + for (int i = 0; i < jarFiles.length; i++) { + jarDescs[i] = makeJarDesc(jarFiles[i].toURI().toURL(), i==main); + + } + info = new ArrayList(); + } + + public URL getJarLocation() { + try { + return jarFiles[0].toURI().toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + public URL getJarLocation(int i) { + try { + return jarFiles[i].toURI().toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + public JARDesc[] getJarDescs() { + return jarDescs; + } + + public JARDesc getJarDesc() { + return jarDescs[0]; + } + + public JARDesc getJarDesc(int i) { + return jarDescs[i]; + } + + + @Override + public ResourcesDesc getResources() { + ResourcesDesc localResources = new ResourcesDesc(null, new Locale[0], new String[0], new String[0]); + for (JARDesc j : jarDescs) { + localResources.addResource(j); + } + return localResources; + } + @Override + public ResourcesDesc[] getResourcesDescs(final Locale locale, final String os, final String arch) { + return new ResourcesDesc[] { getResources() }; + } + + @Override + public URL getCodeBase() { + return codeBase; + } + + @Override + public SecurityDesc getSecurity() { + return new SecurityDesc(this, SecurityDesc.SANDBOX_PERMISSIONS, null); + } + + public void setInfo(List info) { + this.info = info; + } + + +} \ No newline at end of file diff -r acbada276d23 -r 7d2759e4bc98 tests/test-extensions/net/sourceforge/jnlp/util/FileTestUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-extensions/net/sourceforge/jnlp/util/FileTestUtils.java Wed Nov 13 11:15:18 2013 +0100 @@ -0,0 +1,129 @@ +/* +Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +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.util; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.management.ManagementFactory; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import net.sourceforge.jnlp.ServerAccess; + +public class FileTestUtils { + + /* Get the open file-descriptor count for the process. Note that this is + * specific to Unix-like operating systems. */ + static public long getOpenFileDescriptorCount() { + MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer(); + try { + return (Long) beanServer.getAttribute(new ObjectName( + "java.lang:type=OperatingSystem"), + "OpenFileDescriptorCount"); + } catch (Exception e) { + // Effectively disables leak tests + ServerAccess.logErrorReprint("Warning: Cannot get file descriptors for this platform!"); + return 0; + } + } + + /* Check the amount of file descriptors before and after a Runnable */ + static public void assertNoFileLeak(Runnable runnable) { + long filesOpenBefore = getOpenFileDescriptorCount(); + runnable.run(); + long filesLeaked = getOpenFileDescriptorCount() - filesOpenBefore; + assertEquals(0, filesLeaked); + } + + /* Creates a file with the given contents */ + static public void createFileWithContents(File file, String contents) + throws IOException { + PrintWriter out = new PrintWriter(file); + out.write(contents); + out.close(); + } + + /* Creates a jar in a temporary directory, with the given name & file contents */ + static public void createJarWithContents(File jarFile, Manifest manifestContents, File... fileContents) + throws Exception { + /* Manifest quite evilly ignores all attributes if we don't specify a version! + * Make sure it's set here. */ + manifestContents.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + + JarOutputStream jarWriter = new JarOutputStream(new FileOutputStream(jarFile), manifestContents); + for (File file : fileContents) { + jarWriter.putNextEntry(new JarEntry(file.getName())); + FileInputStream fileReader = new FileInputStream(file); + StreamUtils.copyStream(fileReader, jarWriter); + fileReader.close(); + jarWriter.closeEntry(); + } + jarWriter.close(); + } + + /* Creates a jar in a temporary directory, with the given name, manifest & file contents */ + static public void createJarWithContents(File jarFile, File... fileContents) throws Exception { + /* Note that we always specify a manifest, to avoid empty jars. + * Empty jars are not allowed by icedtea-web during the zip-file header check. */ + createJarWithContents(jarFile, new Manifest(), fileContents); + } + + /* Creates a temporary directory. Note that Java 7 has a method for this, + * but we want to remain 6-compatible. */ + static public File createTempDirectory() throws IOException { + File file = File.createTempFile("temp", + Long.toString(System.nanoTime())); + file.delete(); + if (!file.mkdir()) { + throw new IOException("Failed to create temporary directory '" + + file + "' for test."); + } + return file; + } + +}