P3 A new story begins

Aller au contenu | Aller au menu | Aller à la recherche

dimanche 29 janvier 2012

How to build and package JavaFX 2 Application with Maven

I hate Ant, and I can't begin to work on a project that require using it.

So like many people I want to build my brand new JavaFX 2 applications with the best toolchain available for Java : Maven.

I planned to create a custom maven-plugin to do the job, but by using existing ones we can do it. Some things must be improved but the essential works.

The results is a zip file containing all dependencies (jar) with a jnlp file used to launch the application online or offline.

A demo application is currently visible on the JRebirth website. I used the html template generated by the javafxpackager tool.

Here you have the pom.xml file of the JavaFX application.

You can browse the svn source repository to show more information about the demo project at source.jrebirth.org:

The Pom that rules the maven Build

pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  2. <modelVersion>4.0.0</modelVersion>
  3. <groupId>org.jrebirth.presentation</groupId>
  4. <artifactId>javafx2</artifactId>
  5. <version>1.0.0-SNAPSHOT</version>
  6. <name>JavaFX 2.0 Presentation</name>
  7. <url>http://www.jrebirth.org</url>
  8. <description>Interactive Presentation of JavaFX2 capabilities</de
  9. <!-- not used yet -->
  10. <properties>
  11. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12. </properties>
  13.  
  14. <build>
  15. <!-- Include FXML resources -->
  16. <resources>
  17. <resource>
  18. <filtering>false</filtering>
  19. <directory>${basedir}/src/main/java</directory>
  20. <includes>
  21. <include>**/*.fxml</include>
  22. </includes>
  23. </resource>
  24. <resource>
  25. <filtering>false</filtering>
  26. <directory>${basedir}/src/main/resources</directory>
  27. <includes>
  28. <include>**/*.*</include>
  29. </includes>
  30. </resource>
  31. </resources>
  32.  
  33. <plugins>
  34. <plugin>
  35. <groupId>org.apache.maven.plugins</groupId>
  36. <artifactId>maven-compiler-plugin</artifactId>
  37. <version>2.3.2</version>
  38. <configuration>
  39. <source>1.7</source>
  40. <target>1.7</target>
  41. <encoding>UTF-8</encoding><!-- try to force encoding -->
  42. </configuration>
  43. </plugin>
  44.  
  45. <plugin>
  46. <groupId>org.apache.maven.plugins</groupId>
  47. <artifactId>maven-jar-plugin</artifactId>
  48. <version>2.3.2</version>
  49. <configuration>
  50. <archive>
  51. <manifestEntries>
  52. <JavaFX-Version>2.0</JavaFX-Version>
  53. <Main-Class>org.jrebirth.presentation.Presentation</Main-Class>
  54. <implementation-vendor>seb</implementation-vendor>
  55. <implementation-title>${project.name}</implementation-title>
  56. <implementation-version>1.0</implementation-version>
  57. <JavaFX-Application-Class>org.jrebirth.presentation.Presentation</JavaFX-Application-Class>
  58. <JavaFX-Class-Path>presentation-0.4.0-SNAPSHOT.jar
  59. jaxb-api-2.2.1.jar stax-api-1.0-2.jar activation-1.1.jar
  60. jaxb-impl-2.2.1.jar core-0.4.0-SNAPSHOT.jar
  61. </JavaFX-Class-Path>
  62. </manifestEntries>
  63. <manifest>
  64. <addClasspath>true</addClasspath>
  65. </manifest>
  66. </archive>
  67. </configuration>
  68. </plugin>
  69. <plugin>
  70. <groupId>org.codehaus.mojo.webstart</groupId>
  71. <artifactId>webstart-maven-plugin</artifactId>
  72. <version>1.0-beta-2</version>
  73. <executions>
  74. <execution>
  75. <phase>package</phase>
  76. <goals>
  77. <goal>jnlp</goal> <!-- use jnlp, jnlp-inline or jnlp-single as appropriate -->
  78. </goals>
  79. </execution>
  80. </executions>
  81. <configuration>
  82. <!--outputDirectory>
  83. </outputDirectory --> <!-- not required?? -->
  84.  
  85. <!-- Set to true to exclude all transitive dependencies. Default is false. -->
  86. <excludeTransitive>false</excludeTransitive>
  87.  
  88. <!-- The path where the libraries are stored within the jnlp structure. not required. by default the libraries are within the working directory -->
  89. <!-- <libPath>
  90. lib</libPath> -->
  91. <!-- [optional] transitive dependencies filter - if omitted, all transitive dependencies are included -->
  92. <!-- <dependencies>
  93. Note that only groupId and artifactId must be specified here. because of a limitation of the Include/ExcludesArtifactFilter <includes> <include>org.jrebirth:presentation</include>
  94. <include>org.jrebirth:core</include> </includes> excludes> <exclude></exclude> <excludes </dependencies> -->
  95. <!--resourcesDirectory>
  96. ${project.basedir}/src/main/jnlp/resources</resourcesDirectory --> <!-- default value -->
  97.  
  98. <!-- JNLP generation -->
  99. <jnlp>
  100. <!-- default values -->
  101. <!--inputTemplateResourcePath>
  102. ${project.basedir}</inputTemplateResourcePath -->
  103. <!--inputTemplate>
  104. src/main/jnlp/template.vm</inputTemplate --> <!-- relative to inputTemplateResourcePath -->
  105. <outputFile>Prez.jnlp</outputFile> <!-- defaults to launch.jnlp -->
  106. <!-- used to automatically identify the jar containing the main class. -->
  107. <!-- this is perhaps going to change -->
  108. <mainClass>org.jrebirth.presentation.Presentation</mainClass>
  109. </jnlp>
  110.  
  111. <!-- SIGNING -->
  112. <!-- defining this will automatically sign the jar and its dependencies, if necessary -->
  113. <sign>
  114. <keystore>${basedir}/jrebirth.jks</keystore><!-- Used a pre-generated keystore -->
  115. <keypass>gojava</keypass> <!-- we need to override passwords easily from the command line. ${keypass} -->
  116. <storepass>gojava</storepass> <!-- ${storepass} -->
  117. <!--storetype>
  118. fillme</storetype -->
  119. <alias>jrebirth</alias>
  120.  
  121. <!--validity>
  122. fillme</validity -->
  123. <!-- only required for generating the keystore -->
  124. <!--dnameCn>
  125. fillme</dnameCn> <dnameOu>fillme</dnameOu> <dnameO>fillme</dnameO> <dnameL>fillme</dnameL> <dnameSt>fillme</dnameSt> <dnameC>fillme</dnameC -->
  126. <verify>true</verify> <!-- verify that the signing operation succeeded -->
  127. <!-- KEYSTORE MANAGEMENT -->
  128. <!-- <keystoreConfig>
  129. <delete>true</delete> delete the keystore <gen>true</gen> optional shortcut to generate the store. </keystoreConfig> -->
  130. </sign>
  131.  
  132. <!-- BUILDING PROCESS -->
  133. <pack200>false</pack200>
  134. <gzip>false</gzip> <!-- default force when pack200 false, true when pack200 selected ?? -->
  135. <!-- causes a version attribute to be output in each jar resource element, optional, default is false -->
  136. <!-- <outputJarVersions>
  137. true</outputJarVersions> -->
  138. <!--install>
  139. false</install --> <!-- not yet supported -->
  140. <verbose>true</verbose>
  141. </configuration>
  142. </plugin>
  143. </plugins>
  144. </build>
  145.  
  146. <dependencies>
  147. <dependency>
  148. <groupId>org.jrebirth</groupId>
  149. <artifactId>core</artifactId>
  150. <version>0.4.0-SNAPSHOT</version>
  151. </dependency>
  152. <dependency>
  153. <groupId>com.oracle.javafx</groupId>
  154. <artifactId>jfxrt</artifactId>
  155. <scope>provided</scope>
  156. <version>2.0</version>
  157. </dependency>
  158. </dependencies>
  159. </project>

I choose to deploy the jfxrt.jar into my maven repository to have a cross-platform build independantly of JavaFX Runtime installation.

Maven build doesn't require Dlls (or .so files) dependencies, it just need the JavaFX api jar (jfxrt.jar), thus we can manage several javafx versions.

An alternative is to provide the jar with system scope by usin a JAVAFX_HOME environment variable :

  1. <dependency>
  2. <groupId>javafx</groupId>
  3. <artifactId>javafx</artifactId>
  4. <version>2.0.2</version>
  5. <scope>system</scope>
  6. <systemPath>C:/Program Files/oracle/jfx2.0/rt/lib/jfxrt.jar</systemPath><!-- should use environment variable for cross-platform-->
  7. </dependency>

Jnlp Template for JavaFX 2

The jnlp file template that you must use :

It could be improved by adding runtimes for all operating system.

src/main/jnlp/template.vm

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <jnlp spec="1.0+" xmlns:jfx="http://javafx.com" href="Prez.jnlp">
  3. <!-- codebase="http://www.jrebirth.org/prez" for online-->
  4. <information>
  5. <title>${project.name}</title>
  6. <vendor>Sébastien Bordes</vendor>
  7. <homepage href="${project.url}"/>
  8. <description>${project.description}</description>
  9. <!--<description kind="short">
  10. </description>-->
  11. <!--<icon href="icon.png"/>
  12. -->
  13. <offline-allowed/>
  14. </information>
  15.  
  16. <security>
  17. <all-permissions/>
  18. </security>
  19.  
  20. <resources os="Windows" arch="x86">
  21. <jfx:javafx-runtime version="2.0+" href="http://download.oracle.com/otn-pub/java/javafx/javafx-windows-i586__Vlatest.exe "/>
  22. </resources>
  23. <resources os="Windows" arch="x64">
  24. <jfx:javafx-runtime version="2.0+" href="http://download.oracle.com/otn-pub/java/javafx/javafx-windows-x64__Vlatest.exe "/>
  25. </resources>
  26.  
  27. <resources>
  28. <j2se version="1.7+" />
  29. <property name="file.encoding" value="UTF-8"/>
  30. $dependencies
  31. </resources>
  32.  
  33. <applet-desc width="1024" height="768" main-class="com.javafx.main.NoJavaFXFallback" name="${project.name}" />
  34. <jfx:javafx-desc width="1024" height="768" main-class="$mainClass" name="${project.name}" />
  35.  
  36. <update check="background"/>
  37. </jnlp>

Developper launching

I'm using e(fx)clipse to write code.

I launch the application from eclipse IDE, and to do the 'Dlls" trick, I copy the bin folder (that store all Dlls) into the parent folder of the jfxrt.jar stored into my maven repository. It's only used to launch the application from Eclipse. A better way will be to store them into the maven repository but It's quite painful... When you launch the jnlp file, you will use the default JavaFX runtime installed on your platform.

Bin_Trick.png



Continuous Delivery

Then you can add a FTP transfer task into your Continuous Integration (obviously I use jenkins for JRebirth) to allow continuous delivery to your favorite project.

Continuous_Delivery.png

So JavaFX 2 Rocks with Maven, and even with your favorite software factory tools ! (You can have a look at JRebirth contribute page to see which other softwares I use)

Enjoy JavaFX with Maven !!

Wordle: Maven JavaFX2 Tutorial

mercredi 28 décembre 2011

Type Filters for Accelerated JavaFX 2.0 UI development

I was bored by Eclipse who ask me to choose between many API classes when I press crtl+shift+O to Organize Imports.

So I explore the type filters feature of my preferred IDE : Eclipse.

Here you have a screenshot of packages filtered to gain few seconds when you write new class reference into your code.

I filter the awt and swing API, and also the Javafx inner API and other package which hold simlilar class names.

Eclipse Type Filter for JavaFX 2.0

if you want to copy paste packages name :

  • AWT
    • com.sun.awt.*
    • java.awt.*
  • Swing
    • javax.swing.*
  • Inner JavaFX 2.0 API
    • com.sun.javafx.*
    • com.sun.prism.*
  • For Line class
    • javax.sound.sampled.*
  • For Duration class
    • javax.xml.datatype.*

Be careful some classes will be inaccessible.