7u10: JavaFX packaging tools update
- by igor
Last weeks were very busy here in Oracle. JavaOne 2012 is next week. Come to see us there!  
  Meanwhile i'd like to quickly update you on recent developments in the area of packaging tools. This is an area of ongoing development for the team, and we are  continuing to refine and improve both the tools and the process. Thanks to everyone who shared experiences and suggestions with us. We are listening and fixed many of reported issues. Please keep them coming as comments on the blog or (even better) file issues directly to the JIRA. 
  
In this post i'll focus on several new packaging features added in JDK 7 update 10: 
   
    Self-Contained Applications: Select Java Runtime to bundle 
    Self-Contained Applications: Create Package without Java Runtime 
    Self-Contained Applications: Package non-JavaFX application 
    Option to disable proxy setup in the JavaFX launcher 
    Ability to specify codebase for WebStart application 
    Option to update existing jar file 
    Self-Contained Applications: Specify application icon 
    Self-Contained Applications: Pass parameters on the command line 
   
  
All these features and number of other important bug fixes are available in the developer preview builds of JDK 7 update 10 (build 8 or later). Please give them a try and share your feedback! 
  Self-Contained Applications: Select Java Runtime to bundle 
  
Packager tools in 7u6 assume current JDK (based on java.home property) is the source for embedded runtime. This is useful simplification for many scenarios but there are cases where ability to specify what to embed explicitly is handy. For example IDE may be using fixed JDK to build the project and this is 
not the version you want to bundle into your application. 
To make it more flexible we now allow to specify location of base JDK 
explicitly. It is optional and if you do not specify it then current JDK will be used (i.e. this change is fully backward compatible). 
New 'basedir' attribute was added to <fx:platform> tag. Its value 
is location of JDK to be used. It is ok to point to either JRE inside 
the JDK or JDK top level folder. However, it must be JDK and not JRE as we need 
other JDK tools for proper packaging and it must be recent version of 
JDK that is bundled with JavaFX (i.e. Java 7 update 6 or later). 
Here are examples (<fx:platform> is part of <fx:deploy> task):  
     <fx:platform basedir="${java.home}"/>  
   <fx:platform basedir="c:\tools\jdk7"/> 
Hint: this feature enables you to use packaging tools from JDK 7 update 
10 (and benefit from bug fixes and other features described below) to create application package with bundled FCS version of JRE 7 update 6.
  
    
  
  
  
  
  
  
  
  Self-Contained Applications: Create Package without Java Runtime 
This may sound a bit puzzling at first glance. Package without embedded Java Runtime is not really self-contained and obviously will not help with: 
   
    Deployment on fresh systems. JRE need to be installed separately (and this step will require admin permissions). 
    Possible compatibility issues due to updates of system runtime. 
  
However, these packages are much much smaller in size. If download size 
matters and you are confident that user have recommended system JRE 
installed then this may be good option to consider if you want to improve user experience for install and launch.  
Technically, this is implemented as an extension of previous feature. 
Pass empty string as value for 'basedir' attribute and this will be 
treated as request to not bundle Java runtime, e.g. 
  
  
  
  
  
  
  
  
  
  <fx:platform basedir=""/> 
  Self-Contained Applications: Package non-JavaFX application
One of popular questions people ask about self-contained applications - 
can i package my Java application as self-contained application? Absolutely. 
This is true even for tools shipped with JDK 7 update 6. Simply follow steps for creating
 package for Swing application with integrated JavaFX content and they will work even if your application does not use JavaFX. What's wrong with it? Well, there are few caveats: 
   
    bundle size is larger because JavaFX is bundled whilst it is not really needed 
    main application jar needs to be packaged to comply to JavaFX packaging requirements(and this may be not trivial to achieve in your existing build scripts) 
    javafx application launcher may not work well with startup logic of your application (for example launcher will initialize networking stack and this may void custom networking settings in your application code) 
   
  
In JDK 7 update 6 <fx:deploy> was updated to accept arbitrary 
executable jar as an input. Self-contained application package will be created preserving input jar as-is, i.e. no JavaFX launcher will be embedded. This does not help with first point above but resolves other two.  
  More formally following assertions must be 
true for packaging to succeed:  
   
    application can be launched as "java -jar YourApp.jar" from the command line  
    mainClass attribute of <fx:application> refers to application main class 
    <fx:resources> lists all resources needed for the application 
   
  
To give you an example lets assume we need to create a bundle for application consisting of 3 jars:
    dist/javamain.jar
    dist/lib/somelib.jar    dist/morelibs/anotherlib.jar 
  
where javamain.jar has manifest with      Main-Class: app.Main     Class-Path: lib/somelib.jar morelibs/anotherlib.jar 
Here is sample ant code to package it:
 
    
  <target name="package-bundle"> 
      <taskdef resource="com/sun/javafx/tools/ant/antlib.xml"  
                uri="javafx:com.sun.javafx.tools.ant"    
                classpath="${javafx.tools.ant.jar}"/> 
      <fx:deploy nativeBundles="all"  
                   width="100" height="100" 
                   outdir="native-packages/" outfile="MyJavaApp">  
            <info title="Sample project" vendor="Me"  
                     description="Test built from Java executable jar"/>  
            <fx:application id="myapp" version="1.0"  
                  mainClass="app.Main" name="MyJavaApp"/>  
            <fx:resources>  
               <fx:fileset dir="dist">  
                  <include name="javamain.jar"/>  
                  <include name="lib/somelib.jar"/>  
                  <include name="morelibs/anotherlib.jar"/>  
               </fx:fileset>  
            </fx:resources> 
      </fx:deploy>  
</target> 
  Option to disable proxy setup in the JavaFX launcher
Since JavaFX 2.2 (part of JDK 7u6) properly packaged JavaFX applications  have proxy settings initialized according to Java Runtime configuration settings.  
This is handy for most of the application accessing network with one 
exception. If your application explicitly sets networking
 properties (e.g. socksProxyHost) then they must be set before
 networking stack is initialized. Proxy detection will initialize 
networking stack and therefore your custom settings will be ignored. 
One way to disable proxy setup by the embedded JavaFX launcher is to pass
 "-Djavafx.autoproxy.disable=true" on the command line. This 
is good for troubleshooting (proxy detection may cause significant 
startup time increases if network is misconfigured) but not really user friendly. 
Now proxy setup will be disabled if manifest of main application jar has "JavaFX-Feature-Proxy" entry with value "None". Here is simple example of adding this entry using <fx:jar> task: 
  <fx:jar destfile="dist/sampleapp.jar"> 
     <fx:application refid="myapp"/> 
     <fx:resources refid="myresources"/> 
     <fileset dir="build/classes"/> 
     <manifest>  
            <attribute name="JavaFX-Feature-Proxy" value="None"/>  
     </manifest>      
</fx:jar> 
  Ability to specify codebase for WebStart application 
  
JavaFX applications do not need to specify codebase (i.e. absolute location where application code will be deployed) for most of real world deployment scenarios. This is convenient as application does not need to be modified when it is moved from development to deployment environment. 
However, some developers want to ensure copies of their application JNLP
 file will redirect to master location. This is where codebase is 
needed. To avoid need to edit JNLP file manually <fx:deploy> task now accepts optional codebase attribute. If 
attribute is not specified packager will generate same no-codebase files
 as before. 
If codebase value is explicitly specified then generated JNLP files 
(including JNLP
 content embedded into web page) will use it.  Here is an example:   
  <fx:deploy width="600" height="400"  
                  outdir="Samples"  
                  codebase="http://localhost/codebaseTest"  
                  outfile="TestApp">  
        .... 
</fx:deploy> 
  Option to update existing jar file
JavaFX packaging procedures are optimized for new application that can use ant or command line javafxpackager utility. This may lead to some redundant steps when you add it to your existing build process.  
One typical situation is that you might already have a build procedure that produces executable jar file with custom manifest. To properly package it as JavaFX executable jar you would need to unpack
 it and then use javafxpackager or <fx:jar> to create jar again (and you need to make sure you pass all important details from your custom manifest). 
We added option to pass jar file as an input to javafxpackager and <fx:jar>. This simplifies integration of JavaFX packaging tools into 
existing build  process as postprocessing step. By the way, we are looking for ways to simplify this further. Please share your suggestions! 
On the technical side this works as follows. Both <fx:jar> and 
javafxpackager will attempt to update existing jar file if this is the 
only input file. Update process will add JavaFX launcher classes and update the jar manifest with JavaFX attributes. Your custom attributes will be preserved. Update could be performed in place or result may be saved to a different file. 
Main-Class and Class-Path elements (if present) of manifest of input jar file will be used for JavaFX application  unless they are explicitly overriden in the packaging command you use. E.g. attribute mainClass of <fx:application> (or -appclass in the javafxpackager case) overrides existing Main-Class in the jar manifest. Note that class specified in the Main-Class attribute could either extend JavaFX Application or provide static main() method. 
Here are examples of updating jar file using javafxpackager: 
   
    Create new JavaFX executable jar as a copy of given jar file javafxpackager -createjar -srcdir dist -srcfiles fish_proto.jar -outdir dist -outfile fish.jar  
    Update existing jar file to be JavaFX executable jar and use test.Fish as main application class javafxpackager -createjar -srcdir dist -appclass test.Fish -srcfiles fish.jar -outdir dist -outfile fish.jar  
     And here is example of using <fx:jar> to create new JavaFX executable jar from the existing fish_proto.jar: 
  <fx:jar destfile="dist/fish.jar">  
     <fileset dir="dist">  
        <include name="fish_proto.jar"/>  
     </fileset>  
 </fx:jar>  
 
  Self-Contained Applications: Specify application icon 
  
The only way to specify application icon for self-contained application using tools in JDK 7 update 6 is to use drop-in resources. 
Now this bug is resolved and you can also specify icon using 
<fx:icon> tag. Here is an example:  
  <fx:deploy ...> 
     <fx:info> 
         <fx:icon href="default.png"/> 
     </fx:info> 
     ... 
</fx:deploy>
Few things to keep in mind:
  
  
  
  
  
  
  
  
  
  
  
    
   
    Only default kind of icon is applicable to self-contained applications (as of now) 
    Icon should follow platform specific rules for sizes and image format (e.g. .ico on Windows and .icns on Mac) 
   
  Self-Contained Applications: Pass parameters on the command line 
  
JavaFX applications support two types of application parameters: named and unnamed (see the API for Application.Parameters). 
Static named parameters can be added to the application package using 
<fx:param> and unnamed parameters can be added using 
<fx:argument>. They are applicable to all execution modes including standalone applications. 
It is also possible to pass parameters to a JavaFX application from a Web page that hosts it, using <fx:htmlParam>.  Prior to JavaFX 2.2, this was only supported for embedded applications. 
Starting from JavaFX 2.2, <fx:htmlParam> is applicable to Web 
Start applications also. See JavaFX
 deployment guide for more details on this. 
However, there was no way to pass dynamic parameters to the 
self-contained application. This has been improved and now native 
launchers will  delegate parameters from command line to the application code. I.e. to 
pass parameter to the application you simply need to run it as "myapp.exe somevalue" and then use getParameters().getUnnamed().get(0) to get "somevalue".