JavaFX for GNU/Linux has arrived

Finally, the time has come: JavaFX is now supported on both GNU/Linux and Solaris.

It’s not really advertised, though, so h Here’s how to get it:

  • Go to the JavaFX website.
  • Click the Download now button. Yes, the one that reads JavaFX 1.1 SDK.
  • Click the JavaFX 1.1.1 1.2 SDK option, and click Download.
  • You’ll be prompted to download javafx_sdk-1_2-linux-i586.sh. Save it somewhere convenient.
  • Make the downloaded file executable with chmod + x
  • Run the shell script with ./javafx_sdk-1_2-linux-i586.sh
  • Page through the annoying legal stuff by pressing Space repeatedly. At the end, type yes.
  • You now have a javafx-sdk1.2 directory that you can play with.

Enjoy!

Oh, and in case you have some JavaFX code from pre-1.2 versions, here’s how to migrate it.

Update: There is also a new Eclipse plugin. Binaries only, the source will have to wait until it gets transferred to eclipse.org.

Advertisements

JavaFX plugin for Eclipse patched

A while ago I wrote about how the JavaFX Eclipse plugin has some shortcomings. Luckily, the plugin is released under an Open Source license (BSD). Therefore, the source is available, and anyone can fix problems and supply patches.

So I decided to do just that, and checked out the code from the Subversion repository. I followed the steps described in the Wiki to get the project compiled.

The first thing I ran into, is that the default target didn’t exist. That was easy enough to fix.

Next, it bothered me that I needed to provide several properties on the command line. For instance I needed to specify -DeclipseDir=/opt/eclipse every time. So I patched the build to get this location from the environment variable ECLIPSE_HOME which I set in my .profile.

The same goes for the location of the JavaFX SDK. I introduced a JAVAFX_HOME environment variable to store that location. With these three modifications I could finally issue a build with just a simple ant.

With the build working it was time to tackle one of the problems I encountered during my usage of the plug-in. I figured it would be easy to fix the issue where compilation errors use up three lines in the Problems view, so that’s where I started. Based on information in the book Eclipse, Building Commercial-Quality Plug-ins, I knew I had to look for IMarker. There was only one such place in the code, so the problem was easily fixed. Progress at last!

I took a look at the other issues that were reported against the plug-in. There might be easier ones than the ones I experienced 😉 Indeed, someone noticed that the JavaFX perspective missed an icon. At first I couldn’t reproduce it, but that was because I was starting the plug-in from Eclipse. The official distribution did show the problem. Luckily, the bug reporter also found the cause: the icon used wasn’t part of the jar. A simple addition to build.properties fixed that.

Five patches already! I was feeling pretty good about myself 🙂

Next, someone wanted help with import statements. That was a lot trickier, but probably also a lot more valuable. Having looked at the IMarker code before, I naturally wanted to add a marker resolution.

This turned out to be a lot more work than I anticipated, but I managed to get something working. There were some glitches, and it probably needed a lot more testing for corner cases, but I could add a missing import statement based on the class name. Because I felt that this code wasn’t ready for prime time yet, I didn’t supply a patch, though.

This patching frenzy took place during the holidays. I got no response from Sun during that time, but I guess that was to be expected, given the time of year. So I decided to wait until some time into the new year to see what would happen.

Monday January 5 went by without news, but this morning I started to receive a stream of email notifications about issue tracker updates. Several of my patches were being accepted, and then I even received notification that I was given commit access! Such are the wonders of Open Source…

JavaFX plugin for Eclipse

Being an happy Eclipse user, I’ve always felt sort of a second-rate citizen in the JavaFX world. I get it that Sun wants to promote their own IDE. But let’s face it, there are a lot of us Eclipseans (is that even a word?) out there. Today, my luck has changed with the release of the JavaFX Plugin for Eclipse. Thanks to Jim Weaver for pointing that out to me. BTW, anybody interested in JavaFX should subscribe to his blog.

The first thing I notice, is that, again, there is no support for GNU/Linux. Well, I’m getting used to that by now. I downloaded the Mac version, and it seems to work on my Ubuntu box. So I naturally took it for a spin right away. Here are my first impressions.

Wizards

The plugin doesn’t provide a New Project wizard. Instead, you need to create a new Java project, and then add the JavaFX nature to it. A bit odd, but OK.

I follow the documentation and add a new script using the New Script wizard. Easy as pie. Then I’m supposed to drag a Stage onto the script. The Insert Template: Stage dialog doesn’t work: it just keeps popping back up over and over again. It doesn’t show any errors, but it also doesn’t insert any code. Maybe this is because I’m running on an unsupported platform, I don’t know.

Editor

Anyway, who needs these UI builders anyway 😉 Let’s type in some code myself. The plugin provides basic syntax highlighting, which is good. Other than that, it doesn’t seem to provide much value. Error markers in the gutter don’t show the error messages when you hover over them, as the JDT does. The error messages in the Problems view take up three lines, so that I can see only a few of them at once.

Problems view

Speaking of errors, whenever I insert some non-ASCII symbol, like the é in my name, the plugin reports a mysterious error: Sorry, but the character ''. Right.

Also, there is no Code Completion (or I haven’t been able to find it). For someone just learning the language, as I am, this is a serious drawback. And some Quick Fixes are sorely missed as well.

Running a program

Running a program works using the expected Run As > JavaFX Application menu. The Run Configurations dialog looks like it is not a result of a collaboration between developers and designers:
Run Configurations

What is cool, is the Profile drop down list. It allows you to select the platform on which to run. You can emulate a mobile device, or run on the desktop as an application, as an applet, or with Web Start.

What is not so cool, is that you cannot select a working directory. This means you cannot test real-life deployments all that well. Nor can you specify Virtual Machine arguments. So for memory intensive applications, you’d have to revert to the command line or some build script.

Conclusion

I’m very happy that Sun is finally welcoming Eclipse users into the JavaFX world. But it seems that this plugin is indeed an early release, as there are many rough edges and missing features. Having said that, something is better than nothing. And the BSD license is certainly appreciated.

Running a JavaFX script from an OSGi bundle

Two technologies that have been on my radar for a while are JavaFX, Sun’s entry in the RIA race, and OSGi, the Dynamic Module System for Java. In this tutorial, I will combine the two by running a JavaFX script from an OSGi bundle. You will need Eclipse and Java 6. [That’s right: a JavaFX tutorial that doesn’t want you to use NetBeans!]

Although JavaFX is still in the beta stage (despite being announced at JavaOne last year), and is very much in flux, it makes for an interesting UI technology. I wouldn’t want to write production ready applications in it yet, but maybe that will change in the not-too-distant future.

OSGi, on the other hand, is very much a mature technology. It is widely used, for instance for the plug-ins that make up Eclipse. In fact, Eclipse Equinox is now the reference implementation for OSGi. BTW, the OSGi term for plug-in is bundle, and I will use the two interchangeably.

Wrapping the JavaFX libraries in an OSGI bundle

Everything in OSGi happens inside a bundle, so the first step to running a JavaFX script from an OSGi bundle, is to create a bundle that holds the JavaFX jars. You will need to download the latest JavaFX distribution and unzip it somewhere.

Then, in Eclipse, select File|New|Project..., so that the New Project wizard appears. In the first step, select from the Plug-in Development category the Plug-in from existing JAR archives, and click Next. In the second step, click the Add External button and add all the jars from the JavaFX distribution’s lib directory. In the third step, enter JavaFX for the Project name, and click an OSGi framework under Target platform. Select standard for the OSGi framework, and click Finish. After a while, the plug-in project appears.

     

Next, open META-INF/MANIFEST.MF, select the MANIFEST.MF tab, and paste the following line into it:

Bundle-RequiredExecutionEnvironment: JavaSE-1.6

Now right-click on JRE System Library in the Package Explorer, and select Properties. For System library, select Execution environment, and from the combo box next to it, select JavaSE-1.6. Click OK.

 

Creating an OSGi bundle that will run a JavaFX script

You will now use the bundle you just created by a new bundle, the one running the JavaFX script. Again, select File|New|Project..., but this time, select Plug-in Project from the Plug-in Development category. In the next step, enter Run JavaFX for the Project Name, select the standard OSGi framework as the Target platform (same as above), and click Next. In the next step, just click Finish to create the project.

 

In the Manifest Editor, select the Dependencies tab. Click the Add button under Required Plug-ins, select JavaFX (1.0.0) from the list, and click the Save button in the toolbar.

   

Creating the JavaFX script

Create a new directory named script, and create a new file named HelloWorld.fx in it. Paste the following code into it:

import javafx.application.Frame;
import javafx.application.Stage;
import javafx.scene.paint.Color;
import javafx.scene.text.*;

Frame {
  title: "Hello World!"
  width: 550
  height: 200
  visible: true
  stage: Stage {
    content: Text {
      font: Font {
        name: "Sans Serif"
        style: FontStyle.BOLD
        size: 24
      }
      x: 20
      y: 40
      stroke: Color.BLUE
      fill: Color.BLUE
      content: "Hello from JavaFX Compiled Script"
    }
  }
}

   

Next, right-click the script directory, and select Build path|Use as Source Folder.

Running the script

To actually run the JavaFX script, we will use JSR-223: Scripting for the Java Platform. [That’s why I made you select JavaSE-1.6 as the bundle execution environment.]

In the Run JavaFX project, open the src directory, the run_javafx package, and then the Activator class. [A bundle’s activator allows you to do stuff when your bundle starts or stops.] In the start() method, add the following code:

final ScriptEngine engine = new ScriptEngineManager()
    .getEngineByExtension("fx");
final String scriptName = "HelloWorld.fx";
final InputStream stream = Thread.currentThread()
    .getContextClassLoader()
    .getResourceAsStream(scriptName);
engine.eval(new InputStreamReader(stream));

Use Eclipse’s Quick Fix to add the required import statements for ScriptEngine, ScriptEngineManager, InputStream, and InputStreamReader.

To run the bundle from Eclipse, select the MANIFEST.MF file, select the Overview tab, and click the Run button at the top.

In the Console, you will see the osgi> prompt, followed by a lot of error output. If you scroll through the output, you will see

org.osgi.framework.BundleException: Exception in
    run_javafx.Activator.start() of bundle Run_JavaFX.
[...]
Caused by: java.lang.NullPointerException
	at run_javafx.Activator.start(Activator.java:24)
[...]

Type exit + Enter in the Console to shut down the plug-in.

Finding the script engine

The NullPointerException comes from the ScriptEngine for JavaFX that could not be found. We can fix this as follows: create a new folder named services under META-INF, and copy the javax.script.ScriptEngineFactory file from the JavaFX project to it. See the Service Provider section in the Jar File Specification for an explanation.

 

Now when you run the plug-in, you will get

org.osgi.framework.BundleException: Exception in
    run_javafx.Activator.start() of bundle Run_JavaFX.
[...]
Caused by: javax.script.ScriptException: compilation failed
	at com.sun.tools.javafx.script.JavaFXScriptEngineImpl.parse(JavaFXScriptEngineImpl.java:254)
	at com.sun.tools.javafx.script.JavaFXScriptEngineImpl.eval(JavaFXScriptEngineImpl.java:144)
	at com.sun.tools.javafx.script.JavaFXScriptEngineImpl.eval(JavaFXScriptEngineImpl.java:135)
	at com.sun.tools.javafx.script.JavaFXScriptEngineImpl.eval(JavaFXScriptEngineImpl.java:140)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:232)
	at run_javafx.Activator.start(Activator.java:24)
[...]

There is nothing wrong with the JavaFX script, though. You can test this yourself by running the command line tools (javafxc and javafx) against it.

Fixing the class path

The problem is in the JavaFXScriptEngineImpl class. It passes the class path to the JavaFXScriptCompiler. But this class path is not the actual class path that is used by the class loader, it is taken from the java.class.path system property. You can override this by either setting the com.sun.tools.javafx.script.classpath system property, or by setting the classpath attribute on the ScriptContext.

I will take that last approach. Just before the engine.eval(...) line, add the following:

engine.getContext().setAttribute("classpath", 
    getJavafxClassPath(), ScriptContext.ENGINE_SCOPE);

Implementing the getJavafxClassPath() method is a bit tricky:

private String getJavafxClassPath() {
  String result = FX.class.getProtectionDomain()
      .getCodeSource().getLocation().toExternalForm();
  final int index = result.indexOf(":/");
  if (index >= 0) {
    result = result.substring(index + 1);
  }
  return result;
}

Now finally, when you run the plug-in, it will show the Hello world window: