I've got the com.eclipse.equinox.launcher plugin source in the debugger. The bundle loader for my bundle throws (and swallows) a ClassNotFoundException trying to load my IApplication implementation. Something changed a lot in classloading for web start on Java 7 Update 45.
I managed to get all of the warnings to go away by adding manifest entries, but still no luck launching the application.
I managed to get all of the warnings to go away by adding manifest entries, but still no luck launching the application.
import java.util.Properties; import java.util.Set; import org.eclipse.equinox.launcher.WebStartMain; public class WebStartLauncher { /** * @param args */ public static void main(String[] args) { Properties properties = System.getProperties(); // copy properties to avoid ConcurrentModificationException Properties copiedProperties = new Properties(); copiedProperties.putAll(properties); Set<Object> keys = copiedProperties.keySet(); for (Object key : keys) { if (key instanceof String) { String keyString = (String) key; if (keyString.startsWith("jnlp.")) { // re set all properties starting with the jnlp-prefix // and set them without the prefix String property = System.getProperty(keyString); String replacedKeyString = keyString.replaceFirst("jnlp.", ""); System.setProperty(replacedKeyString, property); } } } WebStartMain.main(args); }
From my point of view, it's difficult to modify MANIFEST.MF of a signed JAR. How can you achieve this?
<!-- put that somwhere in your main target --> <!-- set security manifest attributes in jar files --> <foreach target="unsignJarAndSetManifestAttributes" param="jar" inheritall="true"> <fileset dir="${pluginsBuildPath}" includes="**/*.jar" /> </foreach> <foreach target="unsignJarAndSetManifestAttributes" param="jar" inheritall="true"> <fileset dir="${featuresBuildPath}" includes="**/*.jar" /> </foreach> <signjar alias="${sign.alias}" keystore="${sign.keystore}" storepass="${sign.storepass}" keypass="${sign.keypass}"> <path> <fileset dir="${featuresBuildPath}" includes="**/*.jar" /> </path> </signjar> <signjar alias="${sign.alias}" keystore="${sign.keystore}" storepass="${sign.storepass}" keypass="${sign.keypass}"> <path> <fileset dir="${pluginsBuildPath}" includes="**/*.jar" /> </path> </signjar> <!-- the foreach task calls the following target --> <!-- ================================= target: unsignJar ================================= --> <target name="unsignJarAndSetManifestAttributes"> <property name="unjarredTempPath" value="${working.dir}\unjarredTemp" /> <unzip src="${jar}" dest="${unjarredTempPath}" /> <!-- delete the archive that was just unpacked --> <delete file="${jar}" /> <!-- remove old signer information --> <delete> <fileset dir="${unjarredTempPath}\META-INF" includes="**/*.RSA" /> <fileset dir="${unjarredTempPath}\META-INF" includes="**/*.SF" /> <fileset dir="${unjarredTempPath}\META-INF" includes="**/*.DSF" /> </delete> <manifest file="${unjarredTempPath}\META-INF\MANIFEST.MF" mode="update"> <attribute name="Trusted-Only" value="true" /> <attribute name="Trusted-Library" value="true" /> <attribute name="Permissions" value="all-permissions" /> <attribute name="Codebase" value="*" /> <attribute name="Application-Name" value="[YOUR_APPLICATION_NAME]" /> </manifest> <zip destfile="${jar}" basedir="${unjarredTempPath}" /> <delete dir="${unjarredTempPath}" /> </target>
<!-- Set class path to AntContrib library --> <path id="antcontrib.classpath"> <fileset dir="${antcontrib.classpath}"> <include name="*.jar" /> </fileset> </path> <typedef resource="net/sf/antcontrib/antlib.xml" classpathref="antcontrib.classpath" />
parallel="true" maxThreads="${threadCount}"
<property name="threadCount" value="12"/>
<tempfile property="unjarredTempPath" destDir="${workspace.dir}\temp" prefix="unjarredTemp"/>
<foreach target="signjar" param="jar" inheritall="true" parallel="true" maxThreads="${threadCount}"> <fileset dir="${featuresBuildPath}" includes="**/*.jar" /> </foreach> <target name="signjar"> <signjar alias="${sign.alias}" keystore="${sign.keystore}" storepass="${sign.storepass}" keypass="${sign.keypass}"> <path> <fileset file="${jar}" /> </path> </signjar> </target>
<target name="unsignJarAndSetManifestAttributes" depends="unsignJar, setManifestAttributes"> </target> <target name="unsignJar"> <move file="${jar}" tofile="${jar}.temp" /> <zip destfile="${jar}"> <zipfileset src="${jar}.temp" excludes="META-INF/*.RSA,META-INF/*.SF,META-INF/*.DSF,META-INF/*.EC" /> </zip> <delete file="${jar}.temp" /> </target> <target name="setManifestAttributes"> <jar file="${jar}" update="true"> <manifest> <attribute name="Trusted-Only" value="true" /> <attribute name="Trusted-Library" value="true" /> <attribute name="Permissions" value="all-permissions" /> <attribute name="Codebase" value="*" /> <attribute name="Application-Name" value="<your application name>" /> </manifest> </jar> </target>
I found a solution, too. Apparently properties aren't blocked if they have the prefix "jnlp". So an easy way to come around is to add the prefix to all the properties that are used. Of course the eclipse framework will not find these properties because of the prefix, but if one deploys his own launcher class that simply reads all "jnlp" properties and just resets them without the prefix, everything works fine. Adding your own launcher is quite easy, as it is possible to just forward the start to the equinox WebStartMain.
I added my own launcher to a new plugin which I put into the feature of which my product consists and made a reference to the jar in the jnlp file in addition to the reference to the equinox launcher (second line is new):
<jar href="plugins/org.eclipse.equinox.launcher_1.2.0.v20101119.jar"/>
<jar href="plugins/com.tp.webstart_1.0.0.jar"/>
Properties have to be changed from
<property
name="eclipse.product"
value="com.tp.someProduct"/>
to
<property
name="jnlp.eclipse.product"
value="com.tp.someProduct"/>
At last, I changed the class that is launched in the application-desc section:
<application-desc main-class="com.tp.webstart.WebStartLauncher">
.
The WebstartLauncher class is as simle as follows:
import java.util.Properties; import java.util.Set; import org.eclipse.equinox.launcher.WebStartMain; public class WebStartLauncher { /** * @param args */ public static void main(String[] args) { Properties properties = System.getProperties(); // copy properties to avoid ConcurrentModificationException Properties copiedProperties = new Properties(); copiedProperties.putAll(properties); Set<Object> keys = copiedProperties.keySet(); for (Object key : keys) { if (key instanceof String) { String keyString = (String) key; if (keyString.startsWith("jnlp.")) { // re set all properties starting with the jnlp-prefix // and set them without the prefix String property = System.getProperty(keyString); String replacedKeyString = keyString.replaceFirst("jnlp.", ""); System.setProperty(replacedKeyString, property); } } } WebStartMain.main(args); }
That should do it, at least it worked for me.
I hope this helps anyone that is having the same headaches I had the last days.
<?xml version="1.0" encoding="UTF-8"?> <jnlp spec="1.0+" codebase="http://localhost:80" href="test.jnlp"> <!-- URL to the site containing the jnlp application. It should match the value used on export. Href, the name of this file --> <information> <!-- user readable name of the application --> <title>CR-IT System Platform</title> <!-- vendor name --> <vendor></vendor> <!-- vendor homepage --> <homepage href="My company website" /> <!-- product description --> <description></description> <icon kind="splash" href="splash.gif"/> </information> <!--request all permissions from the application. This does not change--> <security> <all-permissions></all-permissions> </security> <!-- The name of the main class to execute. This does not change--> <!--<application-desc main-class="org.eclipse.equinox.launcher.WebStartMain" />--> <application-desc main-class="com.atlascopco.webstart.WebStartLauncher "> <argument>-nosplash</argument> </application-desc> <resources> <!-- Reference to the launcher jar. The version segment must be updated to the version being used--> <!--<jar href="plugins/org.eclipse.equinox.launcher_1.3.200.v20160318-1642.jar"/>--> <jar href="plugins/webstart.jar"/> <!-- Reference to all the plugins and features constituting the application --> <!-- Here we are referring to the wrapper feature since it transitively refers to all the other plug-ins necessary --> <extension name="Wrapper feature" href="features/CR_IT_Client_Feature_1.0.0.new.jnlp"/> <!-- Information usually specified in the config.ini--> <property name="jnlp.osgi.bundles" value="org.eclipse.core.runtime@4:start, org.eclipse.equinox.common@3:start, org.eclipse.equinox.ds@2:start,org. eclipse.equinox.simpleconfigurator@1:start"/> <!-- The id of the product to run, like found in the overview page of the product editor --> <property name="jnlp.eclipse.product" value="CR-IT_client.product"/> <property name="jnlp.osgi.useReliableFiles" value="read,write" /> <property name="jnlp.osgi.parentClassloader" value="current"/> <property name="jnlp.eclipse.security" value="osgi" /> </resources> <!-- Indicate on a platform basis which JRE to use --> <resources os="Windows"> <j2se version="1.7" /> </resources> </jnlp>
I found a solution, too. Apparently properties aren't blocked if they have the prefix "jnlp". So an easy way to come around is to add the prefix to all the properties that are used. Of course the eclipse framework will not find these properties because of the prefix, but if one deploys his own launcher class that simply reads all "jnlp" properties and just resets them without the prefix, everything works fine. Adding your own launcher is quite easy, as it is possible to just forward the start to the equinox WebStartMain.
I added my own launcher to a new plugin which I put into the feature of which my product consists and made a reference to the jar in the jnlp file in addition to the reference to the equinox launcher (second line is new):
<jar href="plugins/org.eclipse.equinox.launcher_1.2.0.v20101119.jar"/>
<jar href="plugins/com.tp.webstart_1.0.0.jar"/>
Properties have to be changed from
<property
name="eclipse.product"
value="com.tp.someProduct"/>
to
<property
name="jnlp.eclipse.product"
value="com.tp.someProduct"/>
At last, I changed the class that is launched in the application-desc section:
<application-desc main-class="com.tp.webstart.WebStartLauncher">
.
The WebstartLauncher class is as simle as follows:
import java.util.Properties; import java.util.Set; import org.eclipse.equinox.launcher.WebStartMain; public class WebStartLauncher { /** * @param args */ public static void main(String[] args) { Properties properties = System.getProperties(); // copy properties to avoid ConcurrentModificationException Properties copiedProperties = new Properties(); copiedProperties.putAll(properties); Set<Object> keys = copiedProperties.keySet(); for (Object key : keys) { if (key instanceof String) { String keyString = (String) key; if (keyString.startsWith("jnlp.")) { // re set all properties starting with the jnlp-prefix // and set them without the prefix String property = System.getProperty(keyString); String replacedKeyString = keyString.replaceFirst("jnlp.", ""); System.setProperty(replacedKeyString, property); } } } WebStartMain.main(args); }
That should do it, at least it worked for me.
I hope this helps anyone that is having the same headaches I had the last days.