Managing constantly-changing JNLP dependencies? - java

We use JNLP to deploy our Swing application to all of our users. With JNLP, you have to reference specific names/versions of any JAR dependencies, such as widget-lib-1.4.7.jar.
We have just introduced a new project that will compile as a reusable JAR, but that will be changing rapidly (every few days or so), and so the version number will change frequently. Our Swing app will depend on this new project once its completed.
Unless we change our setup, we'll have to update the JNLP and republish it every time we publish a new version of this new dependency, which, like I said, will be very frequent.
Is there any way to call Ivy from inside a JNLP, or some way of telling the JNLP to include the contents of a directory (and then have a separate process that always makes sure the latest version of the JAR is in that directory), or something we can do so that we don't have to constantly change the JNLP?
Thanks in advance!

If your JNLP is updated frequently (or needs any other per-user parameters, like upload keys), don't use a static file. Instead, create a template JNLP file with JSP, Velocity, Freemarker, or a similar template engine and fill in the JNLP's fields dynamically, such as from a database.

I'm not sure if this addresses your need, but you could use a second .jnlp for your frequently changing library. Your main application's .jnlp would refer to that .jnlp with an <extension> element.
Your main application's .jnlp would contain this:
<resources>
<j2se version="1.7+"/>
<jar href="MyApp.jar" main="true"/>
<extension name="WidgetLib" href="WidgetLib.jnlp"/>
</resources>
And WidgetLib.jnlp would look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<jnlp href="WidgetLib.jnlp"
version="1.4.7"
codebase="http://www.company.com/myapp/">
<information>
<title>Widget Library</title>
<vendor>My Company</vendor>
<description>Latest version of Widget Library</description>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<jar href="widget-lib-1.4.7.jar"/>
</resources>
<component-desc/>
</jnlp>

Related

JNLP syntax for a local executable JAR in the same location

I've seen similar questions asked on SO before, but all of them have codebase/href values pointing to things like http://localhost:8000/test and file://D:/MyProject/Foo.jnlp instead of supporting a completely arbitrary "run out of the same local directory" behavior. People have mentioned that some combination of empty and/or missing attributes are supposed to work in recent JREs, but I can't find any combination of syntax that will work. (Normally I'd just go look through the launcher source, but can't for javaws.)
Collectively, we have a lot of experience with the Java language, but we haven't needed to use javaws before, and Oracle's documentation is... frustrating. What we've come up with, anonymized to protect the innocent:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="9+" version="x.y.z" codebase="???" href="test.jnlp">
<information>
<title>Our Stuff Name</title>
<offline-allowed/>
</information>
<resources>
<java version="9+" java-vm-args="-X:foo"/>
<java version="1.8*" java-vm-args="-X:bar"/>
<jar href="OurStuff.jar" main="true"/>
</resources>
<!-- this is apparently required for local operation even if
the JAR has a manifest with the same main() class -->
<application-desc main-class="com.example.OurStuff"/>
<security>
<all-permissions/>
</security>
</jnlp>
The JNLP file is included as JNLP-INF/APPLICATION.JNLP before signing the JAR file. (The signing and verifying go okay, and running the signed JAR by hand using a java .... -jar OurStuff.jar command line works, but of course isn't available to Windows users.)
But we don't have enough experience among us to get the codebase/href attributes right. What we've tried:
Any codebase attribute trying to refer to the current working directory, like "file://." and similar hacks, all fail with parse errors. This makes total sense. We tried that only out of desperation.
No codebase, no href in the <jnlp> element at all: "The field href has an invalid value in the signed launch file: OurStuff.jar"
No codebase, <jnlp href="test.jnlp">: "The field href has an invalid value in the signed launch file: test.jnlp"
It apparently is supposed to be able to handle only having a location URL in one place, but can't handle not having any. Grrrr.
We tried turning on tracing and cranked the trace level to high. Then it gets frustrating, because at the top of the trace file, javaws had this to say:
basic: Running JVMParams: [JVMParameters: isSecure: true, args:]
-> [JVMParameters: isSecure: true, args:]
basic: XMLParser with _source:
<?xml version="1.0" encoding="utf-8"?>
..... our entire JNLP file verbatim including comments ......
basic: Error parsing test.jnlp. Try to parse again with codebase from LAP
java.net.MalformedURLException: no protocol:
at java.base/java.net.URL.<init>(URL.java:627)
.... internals stack trace .....
Okay, fine, it needs a well-formed URL in an href. But later in the same trace, we see this:
temp: returning LaunchDesc from XMLFormat.parse():
<jnlp spec="9+" codebase="file:/C:/building/OurStuff/branchname/" version="x.y.x" href="file:/C:/building/OurStuff/branchname/test.jnlp">
<information>
<title>Our Stuff Name</title>
<vendor></vendor>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<update check="timeout" policy="always"/>
<resources>
<java version="9+"/>
<java version="1.8*"/>
<jar href="file:/C:/building/OurStuff/branchname/OurStuff.jar" download="eager" main="true"/>
</resources>
<application-desc type="Java" main-class="com.example.OurStuff"/>
</jnlp>
The codebase attribute, both of the href attributes, all of the missing/optional attributes, have all been worked out correctly! Even entire elements we left out in order to get default behavior! We were in the C:\building\OurStuff\branchname directory at the time! Yay! We thought! Except no! After a couple hundred more lines of correctly testing the signed jar's modification time, copying pieces around in its cache behind the scenes, and matching up the <java/> elements with the locally-installed JREs, it decided to ignore everything it had discovered, but instead printed out the original error and exited.
What do we need to put in the JNLP file to tell javaws "go ahead and use the results from 'codebase from LAP'", whatever LAP means? Or is there some other combination of codebase and href attributes that it will simply look in the same directory as the JNLP file, wherever that happens to be?

How to use variables in JNLP arguments

Having the following sample jnlp:
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="$$codebase" href="$$name">
<information>
<title>Some Example</title>
<vendor>Some Sample Vendor</vendor>
<homepage href="http://www.somesamplevendorhomepage.com"/>
<description>Some Sample Description</description>
<icon kind="splash" href="link_to_some_splash.jpg"/>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<update check="always" policy="always"/>
<application-desc main-class="com.some.sample.Main">
<argument>--URL=SAMPLE_DB_NAME=http://localhost:<db_port>/webapplication/creds/auth</argument>
<argument>--UserTimeout=350</argument>
</application-desc>
<resources>
<j2se version="1.7+" />
<jar href="com.some.sample_1.0.0.jar"/>
.
.
.
</resources>
</jnlp>
(please ignore formatting or other inconsistencies - the only part that matters is the argument part)
Having the variable db_port within the argument tag, is there a way to pass a value to this variable when executing the jnlp with javaws?
For example: javaws /path/to/sample.jnlp 31022
EDIT:
JNLP downloads the JARs to the cache folder located (on Windows) under AppData\LocalLow\Sun\Java\Deployment\cache.
Is there a way to use the download JARs (my app has multiple JAR files) in order to have a way to execute the app providing the argument directly to the downloaded JAR?
For example:
jar -jar app.jar --URL=SAMPLE_DB_NAME=http://localhost:<db_port>/webapplication/creds/auth
PS: I understand that the files that are stored in the cache folder have a computed generated name and they are without the .jar extension.
However from the Java Control Panel GUI or from CMD/PS with "javaws -viewer" I was able to determine the file used as jnlp and launch it. I was wondering if there is a way to use some of the JARs to launch the app or maybe create a "parent" one in order to be able to pass arguments to it.
The documentation seems to be intentionally lacking on this topic, but the documentation suggests the preferred method to pass command line parameters to the javaws executable is through ‑userConfig flag.
e.g.
javaws /path/to/sample.jnlp -userConfig port 31022
The documentation doesn't provide examples for this. I even searched GitHub for javaws userConfig and only got a handful of results, so this seems to be a very rarely used feature.
Since your question specifically asks about a <port> variable contained within another variable, that is not something directly supported. You would instead need to find a way to wildcard or paramaterize the <port> using an additional variable and some search/replace inside the main class, assuming you have access to the source. If you don't have access to the source, you will be stuck writing the JNLP by hand, which can have additional work required if it's a signed file.

With Java 7 Update 45, the System Properties no Longer Set from JNLP Tag "Property"

We run the application from the attached JNLP. On the Java console, we have output the system properties with D. The properties from our JNLP files are not set any more. This is the first Java version that we get this sort of problems with. Everything was working fine up to and including 7 Update 40.
We have all the jars signed but there are no security attributes in their manifests.
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://10.0.10.230/webstart/app" href="desktop.jnlp">
<information>
<title>MyApp Desktop</title>
<vendor>MyApp GmbH</vendor>
<homepage href="http://www.myres-edv.de"/>
<description>MyApp Desktop</description>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.5+" initial-heap-size="512M" max-heap-size="1024M" javaws-vm-args="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8200"/>
<property name="org.omg.CORBA.ORBInitialHost" value="10.0.10.230"/>
<property name="org.omg.CORBA.ORBServerHost" value="10.0.10.230" />
<property name="sun.net.spi.nameservice.provider.1" value="dns,sun" />
<property name="MyApp.baktswritedos" value="true"/>
<property name="MyApp.nocomm" value="true"/>
<property name="MyApp.la.erfassungdos" value="true"/>
<property name="com.sun.corba.ee.transport.ORBTCPConnectTimeouts" value="500:30000:40:30000" />
<property name="deployment.trace.level" value="all" />
<jar href="myresjar/ejb/myres/myres_ejb_client.jar" main="true" download="eager"/>
<jar href="myresjar/ejb/myres/myres_ejb.jar" download="eager"/>
<extension name="jars" href="commonejbjars.jnlp"/>
<extension name="jars" href="jr.jnlp"/>
<extension name="jars" href="commonjars.jnlp"/>
<extension name="jars" href="commonjh.jnlp"/>
<nativelib href="myresjar/ejb/myres/myres_dll.jar"/>
</resources>
<resources os="Windows">
<nativelib href="myresjar/myres/native-dlls.jar" download="eager"/>
</resources>
<application-desc main-class="de.myapp.gui.desktop.mainframe.DesktopMainFrame">
<argument>-serverIP=10.0.0.230</argument>
<argument>-initNewDayAction=true</argument>
</application-desc>
</jnlp>
We experienced the same Problem with Java 7 Update 45 (1.7.0_45). The JNLP Spec gave a hint for a work-around:
Properties set in the jnlp file will normally be set by Java Web Start after the VM is started but before the application is invoked. Some properties are considered "secure" properties and can be passed as -Dkey=value arguments on the java invocation command line.
The following properties, as well as properties beginning with either "javaws." or "jnlp.", are considered "secure" and will be passed to the VM in this way:
...
While "insecure" properties stopped working, we realized that "secure" properties would still be set correctly.
Maybe the mechanism that sets properties after the VM is started but before the application is invoked, got broken with this Java update, or maybe this was an intentional but undocumented change.
The work-around now depends on the type of system properties:
For system properties that affect Java behavior or libraries, we changed our code to call System.setProperty() at the application start instead of setting them in the JNLP.
For properties that we use to configure the application from the JNLP file, we added the jnlp. prefix so that they are passed correctly again.
<property name="myconfig" value="DE" />
to
<property name="jnlp.myconfig" value="DE" />
Edit: According to OpenJDK Bug JDK-8023821, the change was intentional:
Starting from 7u45 launch descriptor (JNLP file) need to be signed in order to set insecure system properties. So it is expected behaviour in 7u45...
(from a comment)
Instructions for signing a JNLP.
We got bit badly by this same issue. We ended up going the route of including the JNLP file in the signed jar, but that presented some tricky build issues for us, because we had previously built one set of JARS and used multiple JNLP files to support different environments (QA, Production, Demo, etc), passing the environment details through to the app via a system property. We did try to make use of a JNLP template file as discussed here, http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/signedJNLP.html, but we kept getting errors related to verifying the JNLP file and gave up due to time constraints. It's possible we were just doing something wrong, but the error messages did not make it at all clear what part of the JNLP file didn't match the template. Additionally, there is this somewhat unhelpful note in the link above that says: "Elements or attributes that may compromise security will be locked out from this feature." I could find no documented examples of such elements or attributes.
Had the same problem and solved it by signing the jnlp file. Your main jar should contain a copy of the jnlp file renamed as APPLICATION.JNLP and placed under JNLP-INF folder.(the name of the folder and jnlp file must be uppercase)
I set as:
<jnlp>
...
<application-desc main-class="Main">
<argument>param1=value1</argument>
</application-desc>
</jnlp>
Ps. Just be aware that passing values using tag you are passing application parameters and not JVM parameter. Your application should catch this parameter in your method main(String args[])
Just spent 2 days trying to fix this problem, trying to sign jars and other files...and then I found the solution which seems to be very simple and is working fine:
I *put a jndi.properties-file with the following content in my JRE-home-director*y (jre7/lib):
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
I had this problem when updating from Java 1.6 to Java 1.7(51)...

JNLP does not auto updating JAR file

I am working in a such environment, where we have to update client jar in every 2 months maximum. So, as a solution I am suggesting to use JNLP by using this approach we do not have to worry that every user is using the latest release or not. As, There are more then 100 clients per department.
But the problem is JNLP isn't upgrade the new jar file in the following is the my.jnlp file
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://192.168.1.26:8080/" href="Test.jnlp">
<information>
<title>HC</title>
<vendor>DRL</vendor>
<homepage href="http://192.168.1.26:8080/" />
<description>DRL</description>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.6+" />
<jar href="JnlpTest.jar" download="eager" />
</resources>
<application-desc
name="HC-DRL"
main-class="com.drl.simap.client.module.ui.Splash" />
</jnlp>
My working environment:
Tomcat-6.0 server and following tutorial
here
If you download the jnlp spec and look at chapter 6, there is a whole section about caching: "6 Downloading and Caching of Resources"
You can try to add a version number to your jar file and then use the jnlp jar version attribute.
If you currently don't do that, the spec states the following:
An entry downloaded using the basic download protocol must be located
in the cache based on the URL. The time stamp obtained from the HTTP
GET request in the Last-Modified header field of the reply should be
stored along with the downloaded resource. The time stamp is used to
determine if the copy on the server is newer.
The JNLP Client cannot assume that the HTTP GET request will return
the same JAR file for each request. The JNLP Client must periodically
check the Web server to see if an updated version is available. This
check is recommended to be performed before an application is
launched, but the exact algorithm used by a JNLP Client depends on the
particular implementation. For example, if a JNLP Client is offline,
the check is not required to be performed.
The above caching rules also apply to extension descriptors downloaded
using the extension download protocol where the version attribute is
not specified.

JNLP File Association: How do I open the file which was double-clicked on?

I've got the following JNLP:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc//DTD JNLP Descriptor 6.0.10//EN" "http://java.sun.com/dtd/JNLP-6.0.10.dtd">
<jnlp spec="6.0.10" version="1.63" codebase="http://foo.example.com/msi" href="Foo.jnlp">
<information>
<title>Foo</title>
<vendor> Foo Systems, Inc.</vendor>
<homepage href="http://Foo.com"/>
<description>Foo Viewer/Editor Application</description>
<icon href="splash.gif" width="425" height="102" kind="splash"/>
<icon href="Foo.gif" width="64" height="64"/>
<offline-allowed/>
<shortcut>
<desktop/>
<menu submenu="Foo Systems, Inc."/>
</shortcut>
<association mime-type="application-x/wlog" extensions="wlog"/>
<association mime-type="application-x/mplot" extensions="mplot"/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.6+" initial-heap-size="32m" max-heap-size="255m"/>
<jar href="jars_deployment/TimingFramework-1.0.jar"/>
<jar href="jars_deployment/iText-2.1.5.jar"/>
<jar href="jars_deployment/jai_codec.jar"/>
<jar href="Foo.jar"/>
<jar href="jars_deployment/TimingFramework-1.0.jar"/>
<jar href="jars_deployment/iText-2.1.5.jar"/>
<jar href="jars_deployment/jai_codec.jar"/>
<jar href="jars_deployment/jsch-20090402.jar"/>
<property name="apple.laf.useScreenMenuBar" value="true"/>
<property name="apple.awt.graphics.UseQuartz" value="false"/>
<property name="com.apple.mrj.application.apple.menu.about.name" value="Foo"/>
<property name="java.util.logging.config.file" value="/Users/Shared/logging.properties"/>
</resources>
<application-desc main-class="com.prosc.msi.editor.ui.test.Sandbox"/>
</jnlp>
Most everything is working. When I double-click a .wlog file, it opens up my application. However, it doesn't open the correct file. I read somewhere that JNLP was supposed to pass parameters to the main method indicating which file caused the app to be launched, but this is not happening (on OS X 10.6). I get an empty array to my application's main method.
Probably unrelated, my splash screen doesn't work :(
Any pointers on getting this working?
In a bundled application on Mac OS X, you can implement com.apple.eawt.ApplicationListener, as shown in the Mac OS X Reference Library example, OSXAdapter:
The sample also supports document handing from the Finder by implementing the handleOpenFile() method and registering for supported file types in its Info.plist file.
Addendum: com.apple.eawt.ApplicationListener is deprecated; instead consider com.apple.eawt.Application, which provides getApplication().setOpenFileHandler().
About the splash window
I think the app is just missing the right path to your images.
In this case, like you mention the codebase:
<jnlp spec="6.0.10" version="1.63" codebase="http://foo.example.com/msi" href="Foo.jnlp"> and like you said in the image:
<icon href="splash.gif" width="425" height="102" kind="splash"/>
then, your images have to be in http://foo.example.com/msi/splash.gif
You might want be sure images are in that place.... is what I'm thinking could be the cause.
About the file association.
I'm working right now in the same, and it was seeming to be working while adding a Service from the JNLP API SingleInstanceService. This service is used to register the application like a singleton instance. So, any time your application is lauched, it could retreive the parameters which were used to call you app. In this case, you can use it to see the name of the file that was double clicked on.
http://download.oracle.com/javase/6/docs/technotes/guides/javaws/developersguide/examples.html#SingleInstanceService
In page above you can find an example and a breaf explanation about that service.
The problem that I found with that, is that I could not see the file name the first time that you run the app.
I mean, this service should register the app the first time, and after this time, you will be seeing the parameters used to launch the app. So, with this service if you opened the first time your app through a double click on your associated file, you will miss the parameters, until the next double click on it. Your app now will not open another instance again, just will pass the parameters to the instantiated application.
So, I found another solution for this.
http://www.knowledgesutra.com/discuss/tpclso-implement-single-instance-application-java.om
The boy in the page above, used a jar file from inside the Java installation to see the VM instance running that was invoked to see the parameters of the launch of your app. It has the code and the jar used to do that in this same page.
Now I'm able to see the line that was calling the app, like this:
com.sun.javaws.Main -open C:\\JNLP example\\applet-cartoon\\drawingPack\\drawing_monitor\\ejemplo.ply C:\Users\IsraelAltamira\AppData\Local\Temp\javaws23
where ejemplo.ply is the file extension that I used in the jnlp descriptor.
And well, Im working in OS X 10.6.4 now, and it seems to work, but at this moment the web start is not doing me the file association, and is not doing the shortcuts to the installed app... but maybe this last solution works for both systems (at least it work from my fake hyperlink, like the line above to open the file).

Categories

Resources