Tuesday Feb 14, 2012

Comparing JVMs on ARM/Linux

For quite some time, Java Standard Edition releases have included both client and server bytecode compilers (referred to as c1 and c2 respectively), whereas Java SE-Embedded binaries only contained the client c1 compiler.  The rationale for excluding c2 stems from the fact that (1) eliminating optional components saves space, where in the embedded world, space is at a premium, and (2) embedded platforms were not given serious consideration for handling server-like workloads.  But all that is about to change.  In anticipation of the ARM processor's legitimate entrance into the server market (see Calxeda), Oracle has, with the latest update of Java SE-Embedded (7u2), made the c2 compiler available for ARMv7/Linux platforms, further enhancing performance for a large class of traditional server applications. 

These two compilers go about their business in different ways.  Of the two, c1 is a lighter optimizing compiler, but has faster start up.  It delivers excellent performance and as the default bytecode compiler, works extremely well in almost all situations.  Compared to c1, c2 is the more aggressive optimizer and is suited for long-lived java processes.  Although slower at start up, it can be shown to achieve better performance over time.  As a case in point, take a look at the graph that follows.

One of the most popular Java-based applications, Apache Tomcat, was installed on an ARMv7/Linux device.   The chart shows the relative performance, as defined by mean HTTP request time, of the Tomcat server run with the c1 client compiler (red line) and the c2 server compiler (blue line).  The HTTP request load was generated by an external system on a dedicated network utilizing the ab (Apache Bench) program.  The closer the response time is to zero the better, you can see that for the initial run of 25,000 HTTP requests, the c1 compiler produces faster average response times than c2.  It takes time for the c2 compiler to "warm up", but once the threshold of 50,000 or so requests is met, the c2 compiler performance is superior to c1.  At 250,000 HTTP requests, mean response time for the c2-based Tomcat server instance is 14% faster than its c1 counterpart.

It is important to realize that c2 assumes, and indeed requires more resources (i.e. memory).  Our sample device with 1GB RAM, was more than adequate for these rounds of tests.  Of course your mileage may vary, but if you have the right hardware and the right workload, give c2 a further look.

While discussing these results with a few of my compadres, it was suggested that OpenJDK and some of its variants be included in on this comparison.  The following chart shows mean http request times for 6 different configurations:

  1. Java SE Embedded 7u2 c1 Client Compiler
  2. Java SE Embedded 7u2 c2 Server Compiler
  3. OpenJDK Zero VM (build 20.0-b12, mixed mode) OpenJDK 1.6.0_24-b24 (IcedTea6 1.12pre)
  4. JamVM (build 1.6.0-devel, inline-threaded interpreter with stack-caching) OpenJDK 1.6.0_24-b24 (IcedTea6 1.12pre)
  5. CACAO (build 1.1.0pre2, compiled mode) OpenJDK 1.6.0_24-b24 (IcedTea6 1.12pre)
  6. Interpreter only: OpenJDK Zero VM (build 20.0-b12, interpreted mode) OpenJDK 1.6.0_24-b24 (IcedTea6 1.12pre)

Results remain pretty much unchanged, so only the first 4 runs (25K-100K requests) are shown.  As can be seen, The Java SE-E VMs are on the order of 3-5x faster than their OpenJDK counterparts irrespective of the bytecode compiler chosen.  One additional promising VM called shark was not included in these tests because, although it built from source successfully, it failed to run Apache Tomcat.  In defense of shark, the ARM version may still be in development (i.e. non-stable) mode.

Creating a really fast virtual machine is hard work and takes a lot of time to perfect.  Considering the resources expended by Oracle (and formerly Sun), it is no surprise that the commercial Java SE VMs are excellent performers.  But the extent to which they outperform their OpenJDK counterparts is surprising.  It would be no shock if someone in the know could demonstrate better OpenJDK results.  But herein lies one considerable problem:  it is an exercise in patience and perseverance just to locate and build a proper OpenJDK platform suitable for a particular CPU/Linux configuration.  No offense would be taken if corrections were presented, and a straightforward mechanism to support these OpenJDK builds were provided.

Tuesday Jan 03, 2012

Tomcat Micro Cluster

The term Micro Server has been bandied about recently as a means to provide a certain class of server functionality. As embedded systems continue their inexorable drive towards better performance, and standard hardware/software architectures become ubiquitous, the notion of using low-cost, low-power, small-footprint devices as servers becomes quite realistic.  Just as data center managers have utilized multitudes of affordable rack mount servers to provide scalability, why not duplicate that effort with these off-the-shelf devices?

The video that follows takes the Micro Server to its next logical evolution: The Micro Cluster.  Built from commodity hardware (and by commodity I mean The Home Depot), the cluster board has a rack mount form factor that can house 12 Plug Computers.  As the Java SE HotSpot Virtual Machine is available for the Plug Computer (ArmV5/Linux), we'll utilize Apache Tomcat to demonstrate a Tomcat Micro Cluster.  Over time, as the individual compute nodes increase in performance and capacity, this should become even more compelling.

Monday Oct 24, 2011

Java ONE 2011 Hands on Lab for Java SE Embedded

Now that the dust has settled, sincere thanks go out to my compadres (you know who you are) for helping make The Java One 2011 Java SE Embedded Hands on Lab such a success.  In fact it was so well received, our peers in Asia are already planning on replicating the effort for JavaOne Tokyo in April 2012.  In addition to the Tokyo event,  we hope to provide future opportunities for this venue elsewhere.  In the interim, we'd seriously consider hosting this lab, albeit on a smaller scale (Java One had 105 networked devices and workstations), for interested customers.  To give you a feel for the lab contents, here's a synopsis:

Java One 2011 Hands on Lab 24642: Java SE Embedded Development Made Easy

This Hands-on Lab aims to show that developers already familiar with the Java develop/debug/deploy lifecycle can apply those same skills to develop Java applications, using Java SE Embedded, on embedded devices.  Each participant in the lab will:

  • Have their own individual embedded device to gain valuable hands on experience
  • Turn their embedded device into a Java Servlet container
  • Learn how to deploy embedded Java applications, developed with the NetBeans IDE, onto their device
  • Learn how embedded Java applications can be remotely debugged from their desktop NetBeans IDE
  • Learn how to remotely monitor and manage embedded Java applications from their desktop
If the logistics for setting up a lab prove to be a bit too much, as an alternative, we've given quite a few live presentations/demonstrations with similar flair.  So please, by all means, contact me at james.connors@oracle.com, if you're interested in learning more.  For those of you who run developer user groups, most notably Java User Groups, and are looking for a speaker at your next meeting, please consider us.  We will not disappoint.


Friday Aug 19, 2011

Serial Port Communication for Java SE Embedded

The need to communicate with devices connected to serial ports is a common application requirement.  Falling outside the purview of the Java SE platform, serial and parallel port communication has been addressed with a project called RXTX.  (In the past, you may have known this as javacomm).  With RXTX,  Java developers access serial ports through the RXTXcomm.jar file.  Alongside this jar file, an underlying native layer must be provided to interface with the operating system's UART ports.  For the usual suspects (Windows, Linux/x86, MacOS, Solaris/Sparc), pre-compiled binaries are readily available.  To host this on an alternative platform, some (hopefully minimal) amount of work is required.

Here's hoping the following notes/observations might aid in helping you to build RXTX for an embedded device utilizing one of our Java SE Embedded binaries.  The device used for this particular implementation is my current favorite: the Plug Computer.

Notes on Getting RX/TX 2.1-7-r2 Working on a Plug Computer

1. At this early juncture with Java 7, be wary of mixing Java 7 with code from older versions of Java. The class files generated by the JDK7 javac compiler contain an updated version byte with a value that results in older (Java 6 and before) JVMs refusing to load these classes.

2. The RXTX download location http://rxtx.qbang.org/wiki/index.php/Download has binaries for many platforms including Arm variants, but none that worked for the Plug Computer, so one had to be built from source.

3. Using the native GCC for the Plug Computer and the RXTX source, binaries (native shared objects) were compiled for the armv5tel-unknown-linux-gnu platform.

4. The RXTX "stable" source code found at the aforementioned site is based on version rxtx 2.1-7r2.  This code appears to be pretty long in the tooth, in that it has no knowledge of Java 6.  Some changes need to be made to accommodate a JDK 6 environment.  Without these modifications, RXTX will not build with JDK6

SUGGESTED FIX, most elegant, not recommended:
Edit the configure.in file in the source directory and look for the following:

    case $JAVA_VERSION in
    1.2*|1.3*|1.4*|1.5*)

and change the second line to:

    1.2*|1.3*|1.4*|1.5*|1.6*)

Upon modification, the autogen.sh script found in the rxtx source directory must be re-run to recreate the ./configure script.  Unfortunately, this requires loading the autoconf, automake and libtool packages (plus dependencies) and ended up resulting in libtool incompatibilies when running the resultant ./configure script.

RECOMMENDED FIX:
Instead, edit ./configure and search for the occurrences (there are more than one) of

    case $JAVA_VERSION in
    1.2*|1.3*|1.4*|1.5*)

and change the second line to:

    1.2*|1.3*|1.4*|1.5*|1.6*)

Run './configure', then 'make' to generate the RXTXcomm.jar and platform specific .so shared object libraries.

5. You may also notice in the output of the make, that there were compilation errors for source files which failed to find the meaning of "UTS_RELEASE".  This results in some of the shared object files not being created.  These pertain to the non-serial aspects of RXTX.  As we were only interested in librxtxSerial.so, this was no problem for us.

6. Once built, move the following files into the following directories:

    # cd rxtx-2.1-7-r2/
    # cp RXTXcomm.jar $JAVA_HOME/lib/ext
    # cd armv5tel-unknown-linux-gnu/.libs/
    # cp librxtxSerial-2.1-7.so $JAVA_HOME/lib/arm
    # cd $JAVA_HOME/lib/arm
    # ln -s librxtxSerial-2.1-7.so librxtxSerial.so

Now Java applications which utilize RXTX should run without any java command-line additions.

The RXTXcomm.jar file can be downloaded here.  To spare you the effort, a few pre-built versions of  librxtxSerial-2.1-7.so are provided at this location:

If you've gone through this exercise on any additional architectures, send them my way and I'll post them here.

Tuesday Jun 21, 2011

Observations in Migrating from JavaFX Script to JavaFX 2.0

Observations in Migrating from JavaFX Script to JavaFX 2.0

Introduction

Having been available for a few years now, there is a decent body of work written for JavaFX using the JavaFX Script language. With the general availability announcement of JavaFX 2.0 Beta, the natural question arises about converting the legacy code over to the new JavaFX 2.0 platform. This article reflects on some of the observations encountered while porting source code over from JavaFX Script to the new JavaFX API paradigm.

The Application

The program chosen for migration is an implementation of the Sudoku game and serves as a reference application for the book JavaFX – Developing Rich Internet Applications. The design of the program can be divided into two major components: (1) A user interface (ideally suited for JavaFX design) and (2) the puzzle generator. For the context of this article, our primary interest lies in the user interface. The puzzle generator code was lifted from a sourceforge.net project and is written entirely in Java. Regardless which version of the UI we choose (JavaFX Script vs. JavaFX 2.0), no code changes were required for the puzzle generator code.

The original user interface for the JavaFX Sudoku application was written exclusively in JavaFX Script, and as such is a suitable candidate to convert over to the new JavaFX 2.0 model. However, a few notable points are worth mentioning about this program. First off, it was written in the JavaFX 1.1 timeframe, where certain capabilities of the JavaFX framework were as of yet unavailable. Citing two examples, this program creates many of its own UI controls from scratch because the built-in controls were yet to be introduced. In addition, layout of graphical nodes is done in a very manual manner, again because much of the automatic layout capabilities were in flux at the time. It is worth considering that this program was written at a time when most of us were just coming up to speed on this technology. One would think that having the opportunity to recreate this application anew, it would look a lot different from the current version.

Comparing the Size of the Source Code

An attempt was made to convert each of the original UI JavaFX Script source files (suffixed with .fx) over to a Java counterpart. Due to language feature differences, there are a small number of source files which only exist in one version or the other. The table below summarizes the size of each of the source files.

JavaFX Script source file

Number of Lines

Number of Character

JavaFX 2.0 Java source file

Number of Lines

Number of Characters




ArrowKey.java

6

72

Board.fx

221

6831

Board.java

205

6508

BoardNode.fx

446

16054

BoardNode.java

723

29356

ChooseNumberNode.fx

168

5267

ChooseNumberNode.java

302

10235

CloseButtonNode.fx

115

3408

CloseButton.java

99

2883




ParentWithKeyTraversal.java

111

3276




FunctionPtr.java

6

80




Globals.java

20

554

Grouping.fx

8

140




HowToPlayNode.fx

121

3632

HowToPlayNode.java

136

4849

IconButtonNode.fx

196

5748

IconButtonNode.java

183

5865

Main.fx

98

3466

Main.java

64

2118

SliderNode.fx

288

10349

SliderNode.java

350

13048

Space.fx

78

1696

Space.java

106

2095

SpaceNode.fx

227

6703

SpaceNode.java

220

6861

TraversalHelper.fx

111

3095




Total

2,077

79,127


2531

87,800

A few notes about this table are in order:

  • The number of lines in each file was determined by running the Unix ‘wc –l’ command over each file.
  • The number of characters in each file was determined by running the Unix ‘ls –l’ command over each file.
  • The examination of the code could certainly be much more rigorous. No standard formatting was performed on these files.  All comments however were deleted.

There was a certain expectation that the new Java version would require more lines of code than the original JavaFX script version. As evidenced by a count of the total number of lines, the Java version has about 22% more lines than its FX Script counterpart.

Furthermore, there was an additional expectation that the Java version would be more verbose in terms of the total number of characters.  In fact the preceding data shows that on average the Java source files contain fewer characters per line than the FX files.  But that's not the whole story.  Upon further examination, the FX Script source files had a disproportionate number of blank characters.  Why?  Because of the nature of how one develops JavaFX Script code.  The object literal dominates FX Script code.  Its not uncommon to see object literals indented halfway across the page, consuming lots of meaningless space characters.

RAM consumption

Not the most scientific analysis, memory usage for the application was examined on a Windows Vista system by running the Windows Task Manager and viewing how much memory was being consumed by the Sudoku version in question. Roughly speaking, the FX script version, after startup, had a RAM footprint of about 90MB and remained pretty much the same size. The Java version started out at about 55MB and maintained that size throughout its execution.

What About Binding?

Arguably, the most striking observation about the conversion from JavaFX Script to JavaFX 2.0 concerned the need for data synchronization, or lack thereof. In JavaFX Script, the primary means to synchronize data is via the bind expression (using the “bind” keyword), and perhaps to a lesser extent it’s “on replace” cousin. The bind keyword does not exist in Java, so for JavaFX 2.0 a Data Binding API has been introduced as a replacement.

To give a feel for the difference between the two versions of the Sudoku program, the table that follows indicates how many binds were required for each source file. For JavaFX Script files, this was ascertained by simply counting the number of occurrences of the bind keyword. As can be seen, binding had been used frequently in the JavaFX Script version (and does not take into consideration an additional half dozen or so “on replace” triggers). The JavaFX 2.0 program achieves the same functionality as the original JavaFX Script version, yet the equivalent of binding was only needed twice throughout the Java version of the source code.

JavaFX Script source file

Number of Binds

JavaFX Next Java source file

Number of “Binds”



ArrowKey.java

0

Board.fx

1

Board.java

0

BoardNode.fx

7

BoardNode.java

0

ChooseNumberNode.fx

11

ChooseNumberNode.java

0

CloseButtonNode.fx

6

CloseButton.java

0



CustomNodeWithKeyTraversal.java

0



FunctionPtr.java

0



Globals.java

0

Grouping.fx

0



HowToPlayNode.fx

7

HowToPlayNode.java

0

IconButtonNode.fx

9

IconButtonNode.java

0

Main.fx

1

Main.java

0

Main_Mobile.fx

1



SliderNode.fx

6

SliderNode.java

1

Space.fx

0

Space.java

0

SpaceNode.fx

9

SpaceNode.java

1

TraversalHelper.fx

0



Total

58


2

Conclusions

As the JavaFX 2.0 technology is so new, and experience with the platform is the same, it is possible and indeed probable that some of the observations noted in the preceding article may not apply across other attempts at migrating applications. That being said, this first experience indicates that the migrated Java code will likely be larger, though not extensively so, than the original Java FX Script source. Furthermore, although very important, it appears that the requirements for data synchronization via binding, may be significantly less with the new platform.

Wednesday Jun 01, 2011

Java SE Embedded Development Made Easy

Slowly but surely this old dog (who can learn new tricks, but at a snail's pace) came to the realization that although still quite relevant, a whole generation of people prefer not to read lengthy writings, but would rather digest information in small pieces using new media formats.  Thus the rationale for the following blog...

Certainly no thespian when it comes to public speaking, I will say this:  based upon my experience demonstrating Java SE on embedded devices, people have definitely expressed genuine interest.  Maybe it was the cool device (i.e. Plug Computer) which was used, or maybe this combination of hardware and software inspired the audience to think of the possibilities presented by this new platform.  Either way, I thought it might make sense to capture a shortened presentation/demonstration session.  Following is a 30 minute session broken down into two 15 minute videos (because YouTube only allows videos of 15 minutes or less for mere mortals). They aim to demonstrate how developers already familiar with the Java SE development paradigm can leverage that knowledge to seamlessly develop on very capable embedded processors.  Happy viewing!


Thursday May 26, 2011

The Shackles are Off

Today marks an important milestone for JavaFX 2.0.  Prior to this date, only a select few partners had early access privilege to the technology, and for good reason.  During that early access period, the API was in a very fluid state, and from personal experience I can tell you that changes to the JavaFX 2.0 API were done almost on a build-by-build basis.  The announcement of a public beta not only makes the software available worldwide, but also signals that the JavaFX 2.0 API is on much more solid footing.

So check out the javafx.com website for the latest JavaFX 2.0 information.   Three software downloads are now available:

  1. JavaFX 2.0 Beta SDK - the JavaFX functionality needed to develop directly via the command line or with other tools
  2. JavaFX 2.0 Beta Runtime - the runtime environment required for running JavaFX 2.0 applications 
  3. JavaFX 2.0 Beta Plugin for NetBeans IDE 7.0 -  for building, previewing, and debugging JavaFX applications in NetBeans 7.

Tuesday Mar 15, 2011

The Unofficial Java SE Embedded SDK

Developing applications for embedded platforms gets simpler all the time, thanks in part to the tremendous advances in microprocessor design and software tools.  And in particular, with the availability of Java SE compatible Virtual Machines for the popular embedded platforms, development has never been more straightforward.

The real beauty behind Java SE Embedded development lies in the fact that you can use your favorite IDE (Eclipse, NetBeans, JDeveloper ...) to create, test and debug code in the identical fashion in which you'd develop a standard desktop or server application.  When the time comes to try it out on a Java SE Embedded capable device, it's just a matter of shipping the bytecodes over to the device and letting it run.  There is no need for complicated emulators, toolchains and cross-compilers.  The exact same bytecodes that ran on your PC, run unmodified on the embedded device.

In fact, because all versions of Java SE (embedded or not) share a considerable amount of common code, we have plenty of anecdotal evidence which supports the notion that behavior -- correct or incorrect -- manifests itself identically across platforms.  We refer specifically here to bugs.  Now no one wants bugs, but believe it or not, our customers like the fact that behavior is consistent across platforms whether it's right or not. "Bug for bug compatibility" has actually become a strong selling point!

Having espoused the virtues of transparently developing off device, many still wish to test and debug on-device regularly as part of their development cycle.  If you're the touchy/feely type, there are ample examples of affordable and supported off-the-shelf devices that could fit the bill for an Unofficial Java SE Embedded SDK.  One such platform is the Plug Computer.

The reference platform for the Plug Computer is supplied by Marvell Technology Group. Manufacturers then license the technology from Marvell to create their own specific implementations.  Two such vendors are GlobalScale and Ionics.  These are incredibly capable devices that include Arm processors in the 1.2GHz to 2.0GHz range, and sport 512MB of RAM and flash.  There are a host of external port and interface options including USB, µUSB, SATA, GBE, SD, WiFi, ZigBee, Z-Wave and soon HDMI.  Additionally, several Linux distros are available for these systems too.  The typical cost for a base model is $99, and perhaps the most disruptive aspect of these systems, they consume on average about 5 watts of power.

Alongside developing in the traditional manner, the ability to step through and examine state on these devices via remote debugging comes as a standard feature with the Java SE-E VM.  Furthermore, you can use the JConsole application from your desktop to remotely monitor performance and resource consumption on the device.

So what would a bill of materials look like for The Unofficial Java SE Embedded SDK?  Pretty simple actually:

That's about it.  Of course, for higher level functionality, you can add additional packages.  For example, Apache runs beautifully here.  Could anyone imagine a large number of these devices acting as a parallel web server?

Thursday Dec 16, 2010

Java SE Embedded Refreshed

As embedded processor designs continue their inexorable drive towards ever increasing capability, the natural desire to utilize more robust software platforms, previously reserved for powerful desktop computers and servers, follows suit.  Recognizing this trend, a version of the Java Standard Edition platform, called Java SE Embedded, has been developed to address this growing market.  In addition to bringing all of the benefits of the ubiquitous Java Standard Edition to the most popular embedded processors, static footprint and memory optimizations have been realized.  To get a feel for some of the space savings, check out this article.

Partly due to the turmoil surrounding the Oracle acquisition of Sun, a refresh of the Java SE Embedded binaries took longer than anticipated.  The new versions are now available for download with these supported configurations.  During that time frame, Java SE-E engineers were able take care of some internal housekeeping which should help for better synchronization of future releases of Java SE with Java SE-E.  In the past, Java SE-E engineers would take a snapshot of the Java Standard Edition code and incorporate their modifications to create a new release, forking from the standard edition source,.  Now, the Java SE-E code is part of the overall Java SE project, such that future Java SE enhancements and bug fixes should now be automatically incorporated into the Java SE-E code base.

The refreshed Java SE-E binaries are based on the Java SE 6 Update 21, and represent substantial security, performance and quality enhancements.  Benchmark tests show that, for example, simply replacing the previous versions of the Java SE-E virtual machines with the latest binaries produces on average about 20% performance gain for the same hardware/OS combination.  Having recently introduced a Just-In-Time (or JIT) compiler to the Android Dalvik Virtual Machine, we thought it would be an interesting exercise to compare performance of Java SE-E to Android on identical hardware.  For a full explanation of the results and methodology, check out Bob Vandette's blog on this topic.  To cut to the chase, for the selected benchmarks, Java SE-E outperforms Android by a factor of two. 

Improving virtual machine performance is a tedious process that takes time.  The bottom line is this:  Java SE Virtual Machine engineers have been at this for a very long time, and have had the benefit of fifteen years of scrutiny from the computer science community.  It will take considerable time and effort for Android to come close to this capability.  In the interim, the Java Virtual Machine performance and quality improvement marches on.

   Next up: Take a look at these pictures.  Based upon Marvell's Plug Computer design, these amazing devices pack a 1+GHz Arm processor with 512MB RAM and consume a minuscule 5 watts of power. They run Java SE-E beautifully.  Combined with an IDE like NetBeans, this makes for an ideal, although unofficial, Java SE Embedded Development Kit.

Sunday Nov 28, 2010

Why I like the New JavaFX

I have a vested interest in seeing the original JavaFX Script based platform prosper. As an early adopter of this technology, a good portion of my life these past few years has been spent developing, blogging and even co-authoring a book on the subject. So when the inevitable demise of JavaFX Script was formally announced, those of us intimately involved did not take it lightly.

Perhaps not unlike yourselves, I’ve viewed the plans to morph JavaFX into a Java API with a bit of skepticism. The new resulting coding paradigm is unquestionably less stylish than its predecessor and can be downright verbose. But the new way grows on you. Having the privilege to experiment with early versions, I’ve come to like the new platform. In fact I like it a lot. Here’s why I think the new JavaFX platform is more attractive:

The community has spoken and it doesn’t feel the need for yet another scripting language. The attempt to lure graphics designers into the Java camp by offering a simplified Rich Internet Application environment never really panned out. Why? First, there already exists a wealth of mature, established RIA scripting alternatives. These address much of what designers need and JavaFX Script is not sufficiently different enough. Second, the clamor to provide RIA capabilities in Java comes from the Java community proper, not the graphics artists. These developers have a lot invested in Java and are not interested in learning a new language. What they want is a Java API with RIA capabilities. By making JavaFX a first class citizen of the Java platform, it goes a long way towards meeting these desires.

The JavaFX API is a more universal solution. By building an API in Java, the opportunity for developers of other dynamic languages (like JRuby and JavaScript) to access JavaFX has been made much easier. Moreover, as the trend to host other languages atop the Java Virtual Machine accelerates, these too will profit from this move.

No more mapping between JavaFX Script and Java. A derivative of Java, one of the touted advantages of JavaFX Script is its ability to seamlessly integrate and leverage the wealth of Java code written already. Indeed a very important benefit, Java/JavaFX Script integration is mostly straightforward; however there are subtle differences between both languages that the developer must take into consideration. Mapping primitive Java data types to JavaFX basic types can be an issue. The original JavaFX classes can only extend Java classes that contain a default (no arguments) constructor. Features familiar to Java programmers, like multidimensional arrays, generics, annotations, and multi-threading have no real equivalent in JavaFX Script. Bringing the JavaFX class libraries directly onto the Java platform eliminates all of these concerns. If you want to use some external Java code, just use it.

Superior Development Environment. Attempting to debug JavaFX Script within an Integrated Development Environment is at best a tricky endeavor and at worst a waste of time. Additionally only NetBeans, and to a lesser extent Eclipse, are the only viable JavaFX Script capable IDEs. As the new JavaFX platform is entirely based on Java, not only is debugging support first rate, the option of choosing other Java IDEs opens up considerably.

The new JavaFX results in, for lack of a better term, more predictability. One of the primary JavaFX Script mechanisms used to define and place graphical assets (Nodes) into the scenegraph is the object literal notation. Being static in nature, the notion of a sequential flow of events inside an object literal may not make much sense. To compensate, JavaFX Script introduces the powerful concept of binding. Without question, binding is very elegant, but it comes with a price. It is not uncommon to see liberal and arguably unnecessary use of binding throughout JavaFX script code.

One can argue that bringing JavaFX to Java should lessen, but certainly not eliminate, the need for binding. Rather than defining objects inside a static initializer, JavaFX API objects are created and defined sequentially by constructor and method calls respectively. By defining objects in an order that makes sense, there is potential to eliminate a certain class of dependencies that were previously resolved with binding.

Improved performance. Although by default the JavaFX compiler generates Java bytes codes from JavaFX Script source, there is a command-line option which can be invoked to save the intermediate Java code that is produced as part of the process. A brief perusal of this source shows that even the most humble of JavaFX Script constructs churns out a lot of complicated Java code. Eliminating this overhead is bound to improve performance in many instances. Furthermore, significant optimizations to memory and static footprint as well as startup time are underway. Finally a new lightweight, fast graphics subsystem, dubbed project prism, will obviate the need to utilize older Java graphics windowing systems.

It’s not how you feel, it’s how you look. A superficial difference, but nonetheless one that should not be underestimated, lies in what your code looks like. In JavaFX Script, graphical Nodes are typically placed in the scenegraph via the definition of object literals. Even the least sophisticated of object literal scenegraphs can be grouped and nested several levels deep, each nesting moving the source code further to the right. Some JavaFX Script code is so indented it leaves little room to write anything of consequence without having to split a line of code into two or more lines.

It didn’t take very long to come up with these talking points. No doubt, as development progresses and more folks jump on board, additional benefits will become apparent.

Friday Feb 19, 2010

NetBeans with Subversion, SSH and Windows

Having spent too much time wrestling with the various components required to get NetBeans to access a subversion repository via ssh, I thought it might make sense to jot down a few notes in an effort to save others from such hardships.

NetBeans does have built-in support for CVS, Mercurial and Subversion, but that doesn't mean that these source code revision systems work in a turnkey fashion.  In particular, subversion, especially with Windows, does require some work.

1. To start:
Get the latest JDK.  At the time of this writing it was JDK 6 update 18
Get the latest version of NetBeans,  in this case, NetBeans 6.8.  Install it referencing the latest JDK and furthermore, once inside NetBeans, utilize the update manager to make sure all of your modules are the latest and greatest.

2. Upon starting NetBeans, the menu running along the top of the window has a "Team" entry.  Click on Team and follow Subversion->Checkout (No, you won't be able to check anything out yet). This will bring up an error window which requires you to install a subversion client.

Selecting the default action, which installs a subversion plugin for NetBeans, didn't result in much success. Instead choose the second option: "Install Subversion Commandline Client".  The recommended download for the client points to CollabNet, which is an excellent choice.  Unfortunately the version referred to (v 1.5.5 for Windows) may ultimately prove problematic if you're communicating with a subversion repository that's based on a later version. For this exercise, CollabNet Subversion Command-Line Client v1.6.9 (for Windows) was downloaded and installed.

3. Once Subversion is installed, clicking on Team->Subversion->Checkout again will hopefully bring up a second window which requires you fill in two textfields: (1) A repository URL and (2) a tunnel command.  Let's focus on the tunnel command first.  For windows this requires the equivalent of the Unix/Linux ssh command.  To get this functionality download and install a version of the PuTTY software package.

4. Unlike the Collabnet Subversion Client, PuTTY installation does not put the executables of this package into your PATH.  Make sure to add the PuTTY path (typically C:\\Program Files\\PuTTY) to your PATH.

5. You'll need to edit a subversion configuration file to specify the tunnel command as follows:

C:\\>cd %APPDATA%\\Subversion
C:\\>edit config 

Look for the comment that starts like this:

#ssh = $SVN_SSH ssh

Uncomment it and make it look like the statement below.  The plink.exe executable is part of the PuTTY software bundle:

ssh = $SVN_SSH plink.exe -l user -pw password 

Where user is your remote user name and password is your user's password. You can also use private key authentication if you're uncomfortable with putting your password in the clear, which might look something like:

ssh = $SVN_SSH plink.exe -l user -i C:\\my_private_key.ppk

6. Prior to trying out Netbeans, first connect to your subversion repository via ssh as follows:

C:\\> plink.exe user@host

Prior to running this command, the NetBeans attempt to access the subversion repository hangs, apparently looking for a host fingerprint cache entry.  The plink.exe command above accomplishes its creation, once the correct password is entered.  In addition, it assures that SSH is correctly set up on your Subversion repository server.

7. Returning to the Team->Subversion->Checkout selection from the main NetBeans window, now it's time to fill in the two textfields.  The first entry should look something like this:

svn+ssh://host/subversion_repository_path

for example:

svn+ssh://127.0.0.1/home/svn/myProject

Next should come the tunnel command which should be similar to the entry placed in the %APPDATA%\\Subversion\\config file, namely

plink -l user -pw password

Where, again, user is your remote user name and password is this user's password.

8. With information correctly filled in, and assuming your subversion server is correctly configured, you should be able to begin utilizing subversion through ssh with NetBeans.  For further information, check out:

Good Luck!



Wednesday Feb 10, 2010

JavaFX, Sockets and Threading: Lessons Learned

When contemplating how machine-dependent applications might communicate with Java/JavaFX, JNI or the Java Native Interface, having been created for just such a task, would likely be the first mechanism that comes to mind.  Although JNI works just fine thank you, a group of us ultimately decided against using it for a small project because, among others:

  • Errors in your JNI implementation can corrupt the Java Virtual Machine in very strange ways, leading to difficult diagnosis.
  • JNI can be time consuming and tedious, especially if there's a varied amount of interchange between the Native and Java platforms.
  • For each OS/Platform supported, a separate JNI implementation would need to be created and maintained.

Instead we opted for something a bit more mundane, namely sockets.  The socket programming paradigm has been around a long time, is well understood and spans a multitude of hardware/software platforms.   Rather than spending time defining JNI interfaces, just open up a socket between applications and send messages back and forth, defining your own message protocol.  Following are some reflections on using sockets with JavaFX and Java.  For the sake of simplicity, we'll skip the native stuff and focus on how sockets can be incorporated into a JavaFX application in a thread safe manner.

Sockets and Threading

Socket programming, especially in Java, lends itself to utilizing threads.  Because a socket read() will block waiting for input, a common practice is to place the read loop in a background thread enabling you to continue processing while waiting for input at the same time.  And if you're doing this work entirely in Java, you'll find that both ends of the socket connection -- the "server" side and the "client" side -- share a great deal of common code.  Recognizing this, an abstract class called GenericSocket.java was created which is responsible for housing the common functionality shared by "server" and "client" sockets including the setup of a reader thread to handle socket reads asynchronously.

For this simple example, two implementations of the abstract GenericSocket class, one called SocketServer.java, the other called SocketClient.java have been supplied.  The primary difference between these two classes lies in the type of socket they use.  SocketServer.java uses java.net.ServerSocket,  while SocketClient.java uses java.net.Socket.  The respective implementations contain the details required to set up and tear down these slightly different socket types.

Dissecting the Java Socket Framework

If you want to utilize the provided Java socket framework with JavaFX, you need to understand this very important fact:  JavaFX is not thread safe and all JavaFX manipulation should be run on the JavaFX processing thread.1 If you allow a JavaFX application to interact with a thread other than the main processing thread, unpredictable errors will occur.  Recall that the GenericSocket class created a reader thread to handle socket reads.  In order to avoid non-main-thread-processing and its pitfalls with our socket classes, a few modifications must take place.

[1] Stolen from JavaFX: Developing Rich Internet Applications - Thanks Jim Clarke

Step 1: Identify Resources Off the Main Thread

The first step to operating in a thread safe manner is to identify those resources in your Java code, residing off the main thread, that might need to be accessed by JavaFX.  For our example, we define two abstract methods, the first, onMessage(), is called whenever a line of text is read from the socket.  The GenericSocket.java code will make a call to this method upon encountering socket input. Let's take a look at the SocketReaderThread code inside GenericSocket, to get a feel for what's going on.

    class SocketReaderThread extends Thread {

        @Override
        public void run() {
            String line;
            waitForReady();
            /\*
             \* Read from from input stream one line at a time
             \*/
            try {
                if (input != null) {
                    while ((line = input.readLine()) != null) {
                        if (debugFlagIsSet(DEBUG_IO)) {
                            System.out.println("recv> " + line);
                        }
                        /\*
                         \* The onMessage() method has to be implemented by
                         \* a sublclass.  If used in conjunction with JavaFX,
                         \* use Entry.deferAction() to force this method to run
                         \* on the main thread.
                         \*/
                        onMessage(line);
                    }
                }
            } catch (Exception e) {
                if (debugFlagIsSet(DEBUG_EXCEPTIONS)) {
                    e.printStackTrace();
                }
            } finally {
                notifyTerminate();
            }
        }

Because onMessage() is called off the main thread and inside SocketReaderThread, the comment states that some additional work, which we'll explain soon, must take place to assure main thread processing.

Our second method, onClosedStatus(), is called whenever the status of the socket changes (either opened or closed for whatever reason).  This abstract routine is called in different places within GenericSocket.java -- sometimes on the main thread, sometimes not.  To assure thread safety, we'll employ the same technique as with onMessage().

Step 2: Create a Java Interface with your Identified Methods

Once identified, these method signatures have to be declared inside a Java interface.  For example, our socket framework includes a SocketListener.java interface file which looks like this:

   package genericsocket;

   public interface SocketListener {
       public void onMessage(String line);
       public void onClosedStatus(Boolean isClosed);
   }
Step 3: Create Your Java Class, Implementing Your Defined Interface

With our SocketListener interface defined, let's take a step-by-step look at how the SocketServer class is implemented inside SocketServer.java.  One of the first requirements is to import a special Java class which will allow us to do main thread processing, achieved as follows:

   import com.sun.javafx.runtime.Entry;

Next, comes the declaration of SocketServer.  Notice that in addition to extending the abstract GenericSocket class it also must implement our SocketListener interface too:

   public class SocketServer extends GenericSocket implements SocketListener {

Inside the SocketServer definition, a variable called fxListener of type SocketListener is declared:

       private SocketListener fxListener;

The constructor for SocketServer must include a reference to fxListener.  The other arguments are used to specify a port number and some debug flags.

       public SocketServer(SocketListener fxListener,
                int port, int debugFlags) {
            super(port, debugFlags);
            this.fxListener = fxListener;
       }

Next, let's examine the implementation of the two methods which are declared in the SocketListener interface.  The first, onMessage(), looks like this:

       /\*\*
        \* Called whenever a message is read from the socket.  In
        \* JavaFX, this method must be run on the main thread and
        \* is accomplished by the Entry.deferAction() call.  Failure to do so
        \* \*will\* result in strange errors and exceptions.
        \* @param line Line of text read from the socket.
        \*/
       @Override
       public void onMessage(final String line) {
           Entry.deferAction(new Runnable() {

               @Override
               public void run() {
                   fxListener.onMessage(line);
               }
           });
       }

As the comment points out, the Entry.deferAction() call enables fxListener.onMessage() to be executed on the main thread.  It takes as an argument an instance of the Runnable class and, within its run() method, makes a call to fxListener.onMessage().  Another important point to notice is that onMessage()'s String argument  must be declared as final.

Along the same line, the onClosedStatus() method is implemented as follows:

       /\*\*
        \* Called whenever the open/closed status of the Socket
        \* changes.  In JavaFX, this method must be run on the main thread and
        \* is accomplished by the Entry.deferAction() call.  Failure to do so
        \* will\* result in strange errors and exceptions.
        \* @param isClosed true if the socket is closed
        \*/
       @Override
       public void onClosedStatus(final Boolean isClosed) {
           Entry.deferAction(new Runnable() {

               @Override
               public void run() {
                   fxListener.onClosedStatus(isClosed);
               }
           });
       }

Another Runnable is scheduled via Entry.deferAction() to run fxlistener.onClosedStatus() on the main thread. Again, onClosedStatus()'s Boolean argument must also be defined as final.

Accessing the Framework within JavaFX

With this work behind us, now we can integrate the framework into JavaFX.  But before elaborating on the details, lets show screenshots of two simple JavaFX applications, SocketServer and SocketClient which, when run together, can send and receive text messages to one another over a socket.

These JavaFX programs were developed in NetBeans and utilize the recently announced NetBeans JavaFX Composer tool.  You can click on the images to execute these programs via Java WebStart.  Note: depending upon your platform, your system may ask for permission prior to allowing these applications to network.  Source for the JavaFX applications and the socket framework in the form of NetBeans projects can be downloaded here.

Step 4: Integrating into JavaFX

To access the socket framework within JavaFX, you must implement the SocketListener class that was created for this project.  To give you a feel for how this is done with our JavaFX SocketServer application, here are some code excerpts from the project's Main.fx file, in particular the definition of our ServerSocketListener class:

public class ServerSocketListener extends SocketListener {
    public override function onMessage(line: String) {
        insert line into recvListView.items;
    }
    public override function onClosedStatus(isClosed : java.lang.Boolean) {
        socketClosed = isClosed;
        tryingToConnect = false;
        if (autoConnectCheckbox.selected) {
            connectButtonAction();
        }
    }
}

Sparing all of the gory details, the onMessage() method will place the line of text read from the socket in to a JavaFX ListView control which is displayed in the program user interface.  The onClosedStatus() method primarily updates the local socketClosed variable and attempts to reconnect the socket if the autoconnect option has been selected.

To demonstrate how the socket is created, we examine the connectButtonAction() function:

var socketServer : SocketServer;

...

public function connectButtonAction (): Void {
     if (not tryingToConnect) {
            if (socketClosed) {
                socketServer = new
                    SocketServer(ServerSocketListener{},
                    java.lang.Integer.parseInt(portTextbox.text),
                    javafx.util.Bits.bitOr(GenericSocket.DEBUG_STATUS,
                                           GenericSocket.DEBUG_IO));
                tryingToConnect = true;
                socketServer.connect();
            }
        }
    }
 
  
 
  

Whenever the user clicks on the "Connect" button, the connectButtonAction() function will be called.  On invocation, if the socket isn't already open, it will create a new SocketServer instance.  Recognize also that the SocketServer constructor includes an instance of the ServerSocketListener class which was defined above.

To round this out, when the user clicks on the "Disconnect" button, the disconnectButtonAction() function is called.  When invoked, it tears down the SocketServer instance.

   function disconnectButtonAction (): Void {
        tryingToConnect = false;
        socketServer.shutdown();
   }

Conclusion

Admittedly, there's a fair amount to digest here.  Hopefully, by carefully reviewing the steps and looking at the complete code listing, this can serve as a template if you wish to accomplish something similar in JavaFX.


Thursday Dec 31, 2009

GlassFish on a Handheld

Until now, the idea of running something akin to a Java EE application server on a small handeld device would have been greeted with ridicule.  Suddenly that notion doesn't seem so ridiculous when considering the recent technology that's been made available. In particular, the following software advances make this pipe dream more of a reality:

  • Java Standard Edition for Embedded Devices: A series of Java virtual machines are available from Sun for many of the popular embedded hardware/OS platforms. They are not only Java SE compatible, but have been space optimized from a static footprint and RAM perspective to perform in embedded environments.  To give you an idea of some of those optimizations, read this.
  • Java Enterprise Edition 6 Platform Specification and the Web Profile:  The Java EE 6 specification allows for the creation of a subset of the component technologies, called "profiles".  The first of these has been dubbed the Web Profile and contains the common technologies required to create small to medium web applications.  Rather than having to use a full blown Java EE application server in all its glory, you can take advantage of a significantly smaller, less complex framework.
  • Embedded GlassFish: This capability, which is now part of GlassFish v3, enables you to run GlassFish inside your Java application, as opposed to the other way around. Simply put, there is no need install GlassFish or create GlassFish domains in this scenario.  Instead, you include an instance of glassfish-embedded-web.jar in your classpath, make a few GlassFish Embedded API calls from your standard Java application, and voila! you've got a web application up and running.

The Hardware

Rather than opting for one of the many embedded development platforms around (because I'm cheap), I instead decided to investigate what was available from a handheld perspective and see if that environment could be adapted to suit my needs.  After some searching, it looked like the Nokia N810 just might fit the bill.  Courtesy of my buddy Eric Bruno, here's a picture of the N810:

To get a feel for this very capable device, check out Eric's Article. What most interested me was that (1) it has 128MB RAM, (2)  a 400MHz Arm v6 processor, (3) runs a common embedded version of Linux (maemo), (4) has a version of Java SE Embedded (from Sun) which runs fine on this platform and (5) can be had for a relatively affordable price on eBay.

The Operating System

The Nokia N810 is powered by the maemo distribution, an open source platform with a thriving community of developers.  Knowing full well that any attempt to get a web application up and running on this device would stretch its resources to the limit, it was necessary to reclaim as much RAM as possible before starting out.  Here's a description of some of the kludgery involved:

  1. You'll need to download and install some additional applications which can be retrieved from the N810's Application Manager program.  They include: rootsh to enable root access to the device and openssh-client and openssh-server to remotely access the device.
  2. A quick and dirty way to reclaim RAM is to shut down the X-server and kill all of the windowing applications that run in parallel. There are certainly more elegant ways to do this, but in addition to being cheap, I'm lazy too.  What you quickly find out is that any attempt to manually kill off some of these processes results in a reboot of the tablet.  Why? Because by default, the N810 includes a watchdog process that monitors the state of the system.  If it detects any irregularities, it forces a restart.
  3. You can get around this problem by putting the device into what is called "R&D" mode.  This is achieved by downloading the "flasher" utility from maemo.org and establishing a USB connection between the N810 and your host computer.  Directions for this process can be found here.
  4. Once established, you can invoke the following flasher command:  flasher3.5 --set-rd-flags=no-lifeguard-reset. If this was done successfully, you'll notice that a wrench appears on the tablet screen when it is rebooted.
  5. Once in R&D mode you'll have to remotely ssh into the device via the WiFi connection. The following script called set-headless.sh has been provided to kill off the windowing system.  After executing this script, the N810 in effect becomes a headless device.  The only way to communicate with it is through the network.

The Environment

Here's what was required to get the web application up and running:

  1. Ssh into the device.
  2. Download an evaluation copy of Java SE Embedded (ARMv6 Linux - Headless).  For this example the download file was gunzip'ed and untar'ed into the N810 device's /usr directory resulting in a new /usr/ejre1.6.0_10 directory.
  3. Download a copy of glassfish-embedded-web-3.0.jar and place this file in the /usr/ejre1.6.0_10/lib directory.
  4. Modify your PATH variable to include /usr/ejre1.6.0_10/bin and set your JAVA_HOME variable to /usr/ejre1.6.0_10
  5. Create a temporary directory, for this example we'll create a /root/tmp directory.
  6. Compile the following Java source file, Embedded.java,  on a JDK equipped system, which is a slightly hacked version of the original provided by Alexis Moussine-Pouchkine.
  7. Create a glassfish directory under /root/tmp/ and place the compiled Embedded.class file there
  8. Download the sample hello web application, hello.war, and place it in the /root/tmp directory.
  9. Reclaim as much RAM as possible by running the set-headless.sh script
  10. Run the web application from inside the /root/tmp directory via the the following command-line invocation:
     # java -cp /usr/ejre1.6.0_10/lib/glassfish-embedded-web-3.0.jar:. glassfish/Embedded hello.war 600

As the N810 cannot match even the most modest of laptops in terms of performance, be prepared to wait around a little before the application is ready.  Check this output to see what is printed out to the console during invocation.

For this run the, N810 was assigned a WiFi IP address of 192.168.1.102, thus the browser is pointed to that address with port 8888.  Here's what comes up:

And Interacting with the web app produces this:

So this is obviously not ready for prime time, but it does open up a whole lot more possibilities in the near future.

Happy New Year! 

Wednesday Nov 04, 2009

Consumer Electronics: Your Utility Company's Best Friend

If you're reading this article, the chances are real good that your home is full of electronic gadgets.  Moreover many are permanently plugged into wall sockets.   Having recently purchased a P3 International P4460 Kill A Watt EZ power meter, I've been running around getting a feel for how much energy some of these common components use.

For this first table, I wanted to see how much energy was being consumed by audio/visual components that were plugged into the wall, but not powered on.  Indeed some of these numbers are eye-opening:

 Device  Watts consumed (powered off)
Visio 22" LCD HDTV (circa 2007)  1.58
Visio 32" LCD HDTV (circa 2009)  1.18
25" RCA Tube TV (circa 1990)  4.17
Marantz AV Surround Reveiver SR7200  2.79
Marantz CD Changer CC9100  1.43
Marantz DVD Player DV6200  3.60
Boston Micro90pv II Subwoofer 14.53
Microsoft Xbox 360  3.64
Nintendo Wii  2.70
Sony PlayStation 2  0.67
Scientific Atlanta Explorer 4250HD set top 17.27
Scientific Atlanta Explorer 8300HD DVR set top 20.00

The granularity of the P4460 is hundredths of kilowatt-hours, which means that in order to get a decent reading on a low-power device, you've got to leave it attached for a while.  No doubt some of these measurements could be more accurate, but I think you get the point.  Of note:

  1. The 4 components that comprise the audio system consume over 22 watts all day, every day 24x7.
  2. As set top boxes gain more functionality (e.g. DVR), they suck up even more power.   At this rate, you'd think the power utility would subsidize the cable companies to get as many of these things installed as possible.
  3. All told, the devices in the preceding table consume an amount of energy similar to a 75 watt incandescent light bulb being left on all the time.

For the most part, these components are non-critical, and one could argue that some (e.g  the stereo) should be connected to a power strip with an on/off button. This should not pose much of an inconvenience.  However, it's a completely different story when it comes to the video components.  When powered cycled, set top boxes take forever to reach full functionality as they reboot over the cable network.  And televisions, if left untethered to electric power for too long, go through this whole channel search sequence when they're powered up.  In short, when it comes to video, you're currently stuck with paying the hidden price of "convenience".

For the computer nerd in us, here's a table comprising some of the computer/network-related components that are left on 24x7.

Device
 Watts Consumed
Belkin Wireless G Router
 5.09
Motorola SBV5120 SURFboard Cable Modem
 5.40
Netgear ProSafe 16 port 10/100 Switch (FS116)
 8.33
HP Photosmart c6280 printer (circa 2008) (networked)
 4.78
HP Laserjet 4P (circa 1994)
 5.32
Canon ImageCLASS MF4270 all-in-one laser printer (networked) (circa 2009)
 3.60
Fit-PC Slim with external USB hard disk (network file server)
 7.50

A decade ago, devices like those listed above were virtually non-existent in the home.  So what's the cost of being Internet ready anytime, anywhere?  About 40 watts all day and all night. Some final points:

  1. In general, carefully consider keeping around older gadgets.  The circa 1990s devices definitely use more energy than their newer, more functional counterparts.
  2. Notice no computers are included.  You know you have more than one, some (present company included) have way more than one.  Let's hope you're turning these off or at least putting them to sleep at night!

Tuesday Sep 08, 2009

Java RTS 2.2 Early Access 2 Released

Sun recently announced the availability of a second edition of its Java Real-Time System (Java RTS) version 2.2 Early Access.  In a previous blog post, many of the important new features of this release were highlighted.  But I felt compelled to jot down a few additional words, not only because there's a newer version of the software to evaluate, but because there's one interesting component that deserves a little more exposure.

I spent some time today speaking with my compadre, Eric Bruno, author of Real-Time Java Programming: With Java RTS.  He clued me in on the fact that our engineers have performed the daunting task of backporting the JDK 7 client compiler onto Java RTS 2.2.  The engineering team is particularly proud of this feat, and ought to be.  It not only enhances Java RTS performance, it also enables them to better stay in lock step with the latest client hotspot VM developments, something the latest Java SE 6 releases may not entirely do.  For some insight into the engineering trade-offs associated creating this latest version of Java RTS, check out Roland Westerlin's entry.

You can find further information about Java RTS here.  And you can download a version of the software for evaluation here.

Cheers.

About

Jim Connors

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today