Monday Jul 30, 2007

ANTLRWorks and fun with grammars

If you are a programming languages enthusiast, you'll probably like this. I downloaded ANTLR Parser Generator. In addition to ANTLR, I downloaded the following:
  • ANTLRWorks - a grammar development environment for ANTLRv3.
  • Java 1.5 ANTLR Grammar It is fun to navigate/debug/view grammars and parse trees. Parse tree of a simple Java class looks as follows:

Saturday Jul 14, 2007

Week-end fun with the java compiler source code

I downloaded java compiler (javac) source code from the JDK 7 site. I did not download entire JDK – I just downloaded compiler-7-ea-src-b15-05_jul_2007.zip I've installed JDK 6 and NetBeans 5.0

I extracted the source zip file into c:\\javac directory. From NetBeans IDE, File->Open Project menu, I chose c:\\javac\\compiler directory. Then, I build the project – I scrolled the build output log to the end and I saw:

Building jar: C:\\javac\\compiler\\dist\\lib\\javac.jar

build-bin.javac:

Copying 1 file to C:\\javac\\compiler\\dist\\bin

build:

BUILD SUCCESSFUL (total time: 8 seconds)

So, I tried to run the newly compiled java compiler. I attempted to compile a simple “Hello World” program. I got the following error:

C:\\javac\\compiler\\dist\\lib>java -jar javac.jar Hello.java

Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/javac/Main

What happened? I looked at the build log again. I missed the following lines – because I had seen only at the end!!

Copying 7 files to C:\\javac\\compiler\\build\\bootclasses

recompiling compiler with itself

javac: invalid flag: C:\\javac\\compiler\\build\\classes

Usage: javac <options> <source files>

use -help for a list of possible options

Java Result: 2

Copying 7 files to C:\\javac\\compiler\\build\\classes

Copying 1 file to C:\\javac\\compiler\\build\\classes\\com\\sun\\tools\\javac\\resources

Building jar: C:\\javac\\compiler\\dist\\lib\\javac.jar

build-bin.javac:

Copying 1 file to C:\\javac\\compiler\\dist\\bin

build:

BUILD SUCCESSFUL (total time: 8 seconds)

Looks like there is a build error. The compiler in built in two steps:

  1. The sources are built with javac in JDK 6 (on which my NetBeans IDE ran)

  2. Then, compiler sources are built again – but this time with the new compiler binary generated by step (1).

Looks we got error in the step (2) [see above: recompiling compiler with itself] . I searched the ant script used to build for “recompiling compiler with itself”. The following is the fragment after that:

<echo message="recompiling compiler with itself"/>

<pathconvert pathsep=" " property="src.javac.files">

<path>

<fileset dir="${src.classes}">

<patternset refid="src.javac"/>

</fileset>

</path>

</pathconvert>

<java fork="true" classpath="${build.bootclasses}" classname="com.sun.tools.javac.Main">

<arg value="-sourcepath"/>

<arg value=""/>

<arg value="-d"/>

<arg file="${build.classes}"/>

<arg value="-g:source,lines"/>

<arg line="${src.javac.files}"/>

</java>

The problem seems to be with “java” command above. Empty string is set as value for -sourcepath option. I changed that to the following:

<arg value="-sourcepath"/>

<arg value="${src.classes}"/>

When I re-built the compiler after the above change, there were no errors – yes, I scrolled the build output to check it :-) And newly compiled javac could compile “Hello World” program.

Now, I wanted to make some to “interesting” but simple change to the compiler source. From a “doc” page, I came to know that there is a hidden javac option called “-printflat”. It appears that with -printflat option javac prints source code after doing transformations for generic types, inner classes, enhanced for-loops, assertions etc. It would be great to visualize the kind of transformations done by javac. So, I wanted to make “hidden” option available. I searched for “printflat” in the project. I got three hits:

  1. JavaCompiler.java

  2. RecognizedOptions.java

  3. java.properties

As usual, I am impatient – wanted to enable printflat option always [regardless of what the command line is]. So, I changed the following line in JavaCompiler.java

printFlat = options.get("-printflat") != null;

to

printFlat = true; // options.get("-printflat") != null;

so that the secret option is enabled always. After rebuilding the compiler, I tried compiling my “Hello World” program. Surprise! I got the following error:

C:\\javac\\compiler\\dist\\lib>java -jar javac.jar Hello.java

Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/javac/Main

When I checked “javac.jar” by “jar tvf javac.jar”, I saw only “.java” files instead of “.class” files! Remember I mentioned that javac is recompiled by itself (step (2) above)? Apparently with “-printflat” option, javac just write transformed files but does not generate .class files! Because I had hardcoded printflat to be true always, during the second bootstrap compilation javac did not generate .class files. Looks like my lazy way does not work! I need to find how to really change the code to accept printflat command line option explicitly. I cut the story shot and just summarize the changes I made:

  1. added a enum value to com.sun.tools.javac.main.OptionName – PRINTFLAT("-printflat");

  2. In com.sun.tools.javac.main.RecognizedOptions class, I added PRINTFLAT to “static Set<OptionName> javacOptions” initialization value.

  3. In public static Option[] getAll(final OptionHelper helper) method of RecognizedOptions class, I added “new HiddenOption(PRINTFLAT)” as an element in the returned Option[].

I managed to compile and run the compiler after the above changes! Now when I can pass “printflat” option!! I compiled the following simple Book.java:


class Book {
  private String name;
  public Book(String name) {
     this.name = name;
  }

  class Order {
     private int quantity;
     public Order(int quantity) {
        this.quantity = quantity;
     }
  }
}

with the following command:

c:\\javac\\compiler\\dist\\lib\\>java -jar javac.jar -printflat c:\\Book.java

Now, I can see the generated Book.java and Book$Order.java in the current directory where java compiler was run:


class Book {
    private String name;
    
    public Book(String name) {
        super();
        this.name = name;
    }
    {
    }
}

class Book$Order {
    /\*synthetic\*/ final Book this$0;
    private int quantity;
    
    public Book$Order(/\*synthetic\*/ final Book this$0, int quantity) {
        this.this$0 = this$0;
        super();
        this.quantity = quantity;
    }
}

Wow! I can see how java compiler generates a hidden synthetic parameter for the outer class object and so on. Note that the java compiler does not overwrite your original source files. You need to run the compiler in a different directory – compiler generates new files [which is good, you won't accidentally overwrite your original code with generics, inner classes and so on].

Now, you can experiment with constructs like asserts, inner class methods accessing outer's private methods/fields, anonymous/local classes, local class accessing final parameters/locals of enclosing method, generics, enhanced for-loop and so on and see how java compiler transforms those constructs to generate good-old “flat” classes without these features. Have fun!!

Thursday Jul 12, 2007

Hacking serviceability code in hotspot JVM

Jim Holmlund (blog?) compiled this very nice summary of serviceability related code in hotspot JVM -- http://openjdk.java.net/groups/serviceability/.

Monday Jun 25, 2007

JavaScript, JSON and JavaFX Script

JavaFX Script, as you may know already, is a declarative and statically typed scripting language. It has first-class functions, declarative syntax, list-comprehensions, and incremental dependency-based evaluation.

JavaFX Script syntax includes object literals - a declarative syntax to construct objects. If you know JavaScript, you may know about JavaScript Object Literals and it's subset called JSON - which is a lightweight data-interchange format (considered to be an alternative for XML in certain use-cases). There are some parallels between JavaScript object literal syntax and that of the JavaFX Script. Of course there are differences. The following is an attempt to summarize the differences.


Types

JavaFX Script is statically typed. But, user may omit types in many places. JavaFX can infer types from the context. While defining object literals, the type of the object is specified. For example:


class Person {
  attribute name: String;
  attribute children: Person\*;
}

var chris = Person {
             name: "Chris"
             children:
             [Person {
                 name: "Dee"
             },
             Person {
                 name: "Candice"
             }]
       };

But except for the "top most" object, we can omit types elsewhere and JavaFX will infer types. For example, the above may also be written as shown below:


class Person {
  attribute name: String;
  attribute children: Person\*;
}

var chris = Person {
             name: "Chris"
             children:
             [ Person {
                 name: "Dee"
             },
             Person {
                 name: "Candice"
             }]
       };

JavaScript is dynamically typed. So, we don't and can't specify the type of the object. [And yes, I do know about JavaScript 2.0 - which is optionally typed. But, I am talking about the current implementations]. We write the above object in JavaScript as


var chris =  {
             name: "Chris",
             children:
             [ {
                 name: "Dee"
             },
              {
                 name: "Candice"
             }]
       };


No comma between property values

JavaFX object literal examples do not include comma between property specifications. For example,


class Person {
  attribute name: String;
  attribute children: Person\*;
}

var chris = Person {
             name: "Chris"
             children:
             [Person {
                 name: "Dee"
             },
             Person {
                 name: "Candice"
             }]
       };

Please note that there is comma between elements of the array but there is no comma between properties (between name and children in above). But, JavaScript object literals (and JSON) have comma between properties as well. But, JavaFX implementation seems to accept comma. So, the following

var chris = Person {
             name: "Chris", // <-- comma here is fine!
             children:
             [Person {
                 name: "Dee"
             },
             Person {
                 name: "Candice"
             }]
       };


Local variables within literal

JavaFX allows local variables in object literal. We can write something like:


class Person {
  attribute name: String;
  attribute likes: String;
}

var v = Person {
    // n is local to this literal
    var n = "sundar"
    name: n,
    likes: "Java"
  };

In JavaScript, we can not use local variables within literal definition. If we want such variables, we may do something like this:


var obj = (function() {
  // n is local in function
  var n = "sundar";
  return {
    name: n, 
    likes: "Java"
  }
})();

i.e., we define an anonymous function surrounding the object literal and call it to get the object.


Arrays are flat

In JavaFX, arrays are flat.


var v = ["Jan", ["Feb", "Mar"]]; 

// the above is same as ..
// var v = ["Jan", "Feb", "Mar"]; 

In JavaScript (and in JSON), arrays can be nested.


Object literals for Java objects

JavaFX allows Java objects to be created with object literal syntax. For example:


import javax.swing.JFrame;
import javax.swing.JButton;

var f = new JFrame { title: "hello world" };
var b = new JButton { label: "ok" };

f.add(b, "Center");
f.pack();
f.setVisible(true);

Mozilla Rhino implementation of JavaScript (which is included in Sun's JDK 6) allows accesing Java classes. But, JSON-like initialization is not supported for Java objects. Java bean conventions are supported. So, it is possible to use field access syntax for getXXX()/setXXX() method calls. We may write the above as


importClass(javax.swing.JFrame);
importClass(javax.swing.JButton);

var f = new JFrame();
// Java bean convention
f.title = "hello world";

var b = new JButton();
b.label = "ok" ;

f.add(b, "Center");
f.pack();

// bean convention again
f.visible = true;

Is it possible at all to have JSON-like syntax to create Java objects? Yes, it is! We can use JSAdapter. We can define the following two JavaScript functions using JSAdapter.



function junwrap(o) {
  var origObj = "__wrapped__";
  if (o instanceof Array) {
    var res = new Array(o.length);
    for (var e in o) {
      res[e] = junwrap(o[e]);
    }
    return res;
  }

  if ((typeof(o) == 'function' ||
      typeof(o) == 'object') &&
      origObj in o) {
    return o[origObj];
  } else {
    return o;
  }
}


function jimport(ctr, name) {
  var origObj = "__wrapped__";
  var obj = new ctr();

  this[name] = function(initObj) {    
    var res = new JSAdapter() {
      __has__ : function(name) {
        return (name in obj) || (name == origObj);
      },
      __get__ : function(name) {
        if (name == origObj) {
          return obj;
        } else {
          var v = obj[name];
          if (typeof(v) == 'function') {        
            return function() {
              var args = new Array(arguments.length);
              for (var i = 0; i < arguments.length; i++) {
                args[i] = junwrap(arguments[i]);
              }
              return v.apply(obj, args);
            }
          } else {
            return v;
          }
        }
      },
      __put__: function (name, value) {        
        if (name != 'origObj') {
          value = junwrap(value);
          obj[name] = value;
        }
      }
    }

    for (var f in initObj) {
      res[f] = initObj[f];
    }
    return res;
  }
}

With the above functions, we can write


jimport(javax.swing.JFrame, "Frame");
jimport(javax.swing.JButton, "Button");

var f = new Frame() { title: "hello world"; };
var b = new Button() { label: "ok" };

f.add(b, "Center");
f.pack();

f.visible = true;

Note that this JSON-like Java object initialization may be used in the server side JavaScript as well. For example, we may create a java.util.Date object as


jimport(java.util.Date, "JDate");

var d = new JDate() { 
  date : 1, 
  month: 0, // 0 is January!
  year : 17 // offset from year 1900
};

Two server side use-cases with the Phobos framework include:

Typically, we may create these POJO class instances and persist/marshall for subsequent use. These POJO classes follow Java bean conventions. So, it is easy to use JSON-like object creation with these classes.

Monday Jun 11, 2007

JRuby 1.0 released, jsr-223 engine updated!

JRuby 1.0 has been released. The jsr-223 script engine for JRuby had an issue because of a recent change in JRuby parse API during 1.0.0RC3. Thanks to the java.net user "bongobongo" for reporting this issue along with the patch. I've included this fix and regenerated binaries and changed the engine to use JRuby 1.0 version -- as usual, you can find the sources and binaries at @ scripting.dev.java.net

Friday Jun 01, 2007

Scripting updates...

It has been a while. I've not updated on scripting.dev.java.net project and related activities. Here it is ...

You probably know this already, but just in case you missed: JavaFX Script has jsr-223 script engine for it (included in javafxrt.jar). See also:

Friday May 25, 2007

A project idea for OpenJDK...

You probably checked out the OpenJDK project and even built it on your favorite platform. And you are wondering how can you do a small, but interesting project with OpenJDK. In Nov 2006, I mentioned about HotSpot Serviceability Agent (SA) which is a set of APIs and tools for debugging HotSpot Virtual Machine processes and core dumps. You may want to look at HotSpot Serviceability page and HotSpot SA sources in the hotspot/agent/ directory and the subdirectories.

One of the components of HotSpot SA is (pure Java) disassemblers for SPARC and x86 processors. These are used to view HotSpot compiled code, HotSpot interpreter code (recall that hotspot Java bytecode interpreter is generated at the start of the virtual machine) as well as the compiled C/C++ code of the virtual machine. You may want to refer to the asm and subdirectories. But, there is no disassembler yet for AMD64.

Maxwell Assembler Framework has assemblers and disassemblers for SPARC, PowerPC, AMD64 and IA32. From the project web page:

The architecture of our system is largely based on the Klein assembler system, which has been developed in the Klein project. Its main idea is to generate assembler methods that are very well tested against existing textual assemblers.

How about using the Maxwell framework with HotSpot SA? It will get us AMD64 disassembler and we can replace the existing disassemblers for SPARC and x86 as well! I think this is a small enough, but interesting project to work on.

Tuesday May 22, 2007

Troubleshooting BOF (JavaOne 2007) slides

We received few comments/emails asking for the slides of troubleshooting tools BOF (JavaOne 2007). Alan Bateman has uploaded the slides (PDF) of the troubleshooting tools BOF.

Wednesday May 16, 2007

Programmatically dumping heap from Java applications

In the troubleshooting BOF, we demonstrated how to use the jmap -dump option to dump heap dump of a running application and showed how to browse/analyze the resulting binary heap dump using the jhat tool.

One of the questions was how to programmatically dump the heap from applications. For example, you may want to dump multiple heap snapshots from your application at various points in time and analyze those off line using jhat. Yes, you can dump heap from your application -- but you have to do a bit of programming as shown below:


import javax.management.MBeanServer;
import java.lang.management.ManagementFactory;
import com.sun.management.HotSpotDiagnosticMXBean;

public class HeapDumper {
    // This is the name of the HotSpot Diagnostic MBean
    private static final String HOTSPOT_BEAN_NAME =
         "com.sun.management:type=HotSpotDiagnostic";

    // field to store the hotspot diagnostic MBean 
    private static volatile HotSpotDiagnosticMXBean hotspotMBean;

    /\*\*
     \* Call this method from your application whenever you 
     \* want to dump the heap snapshot into a file.
     \*
     \* @param fileName name of the heap dump file
     \* @param live flag that tells whether to dump
     \*             only the live objects
     \*/
    static void dumpHeap(String fileName, boolean live) {
        // initialize hotspot diagnostic MBean
        initHotspotMBean();
        try {
            hotspotMBean.dumpHeap(fileName, live);
        } catch (RuntimeException re) {
            throw re;
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }

    // initialize the hotspot diagnostic MBean field
    private static void initHotspotMBean() {
        if (hotspotMBean == null) {
            synchronized (HeapDumper.class) {
                if (hotspotMBean == null) {
                    hotspotMBean = getHotspotMBean();
                }
            }
        }
    }

    // get the hotspot diagnostic MBean from the
    // platform MBean server
    private static HotSpotDiagnosticMXBean getHotspotMBean() {
        try {
            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
            HotSpotDiagnosticMXBean bean = 
                ManagementFactory.newPlatformMXBeanProxy(server,
                HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class);
            return bean;
        } catch (RuntimeException re) {
            throw re;
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }

    public static void main(String[] args) {
        // default heap dump file name
        String fileName = "heap.bin";
        // by default dump only the live objects
        boolean live = true;

        // simple command line options
        switch (args.length) {
            case 2:
                live = args[1].equals("true");
            case 1:
                fileName = args[0];
        }

        // dump the heap
        dumpHeap(fileName, live);
    }
}

By including the above class in your application, you can call HeapDumper.dumpHeap whenever you want to dump the heap as shown in the sample main.

Important note: while you can dump multiple heap snapshots from your application, you can not correlate the objects from multiple dumps. jmap tool uses object addresses as object identifiers - which vary between garbage collections [recall that GC may move objects which changes the object addresses]. But, you can correlate by aggregate stat such as histogram etc.

Tuesday May 15, 2007

JavaOne'07 -- my summay.

After 19 hours of flight, I finally reached Chennai from SFO (on Sunday morning). I'm still going through the timezone change. I wish for a "Star Trek" like transport :-)

This JavaOne turned to be a "device" JavaOne for me -- I attended talks on SunSPOT, Java ME, Blu-ray, OCAP etc. In some sense, it is device JavaOne anyway -- after all one of the big announcements is about JavaFX mobile. I wanted to attend, but missed the talk on "x86 (JPC?) Java emulator".

Random bits from this year's JavaOne:

  • Our troubleshooting BOF went well. As usual there were many questions to the point that they would hardly let me finish jhat demo :-).
  • I was at the performance and diagnostics POD for some time - mostly demonstrating jconsole, jhat to few folks.
  • I felt that there was more crowd this time. JavaOne is getting bigger and bigger. Long queues everywhere ...
  • On Friday, I had a chat with Fat Cat Air. The chat was mostly about the flight that he is building and not about "tiered compilation" :-)
  • I had to travel to L.A for a day. I stayed with my friend Gurumoorthy over the week end. Now, I've a new friend "Akhilan" (Gurumoorthy's son).
  • I had to explain quite a few folks how I work at Chennai when there is no Sun office at Chennai. Yes, I work from home. If you are curious, you may want to check out OpenWork.
That's all....

Friday May 11, 2007

JavaOne'07 Thur (May 10)

I attended only two sessions:
  • TV sessions kick off -- introducing to many Java TV related technologies. One problem with the TV domain is that there are loo...ots of acronyms! One feels lost in the words ... For example, GEM stands for "Globally Executable MHP" and "MHP" stands for Multimedia Home Platform and so on. Add to that the telecommunication/MPEG related jargons. You may want to check out a few sites that I find interesting. Sumit Malik (of Sony) showed very interesting demos on Blu-Ray.
  • I attended the talk on OCAP. Too many APIs :-)
One important aspect of JavaOne is about meeting people as much as attending sessions/BOFs. I met and had nice chat with Matthias Ernst. And of course many of the Sun folks as well. I got the CD for blu-ray development - there is a competition to be won (52 inch LCD HDTV!) :-) :-)

Thursday May 10, 2007

JavaOne'07 Wed (May 9)

I attended the following sessions/BOFs (in no specific order):
  • Building PhoneME project and applications on it. The speakers (Stuart Marks and Hinkmond Wong) demonstrated how to SVN checkout, build the platform - both Phone ME feature (CLDC) and Phone ME advanced (CDC). A sample protocol handler (called "upcase" protocol) was added to the platform and the platform was built. Also, the speakers showed how to build CLDC/CDC apps using NetBeans IDE. Stuart Marks made the IDE to use the Phone ME feature build rather than the bundled wireless toolkit version of CLDC [He didn't tell how to do so. You may want to watch out for Terrence Barr's blog.
  • Vincent Hardy's talk on using JSR 226, 287 and 290 (SVG/XHTML/CSS/ECMAScript) on phones. It was interesting talk. I knew a bit about SVG format - but I learned about how to use it on Java ME platform.
  • JavaFX talk by Chris Oliver. Seeing is believing -- you got to see the stuff - you may want to download and try it out!.
  • I attended the session on developing flashy graphics for Java ME platform -- it was mostly the "common sense" stuff ((like don't call System.gc() explicitly, use double-buffering etc). But, sometimes it is worthwhile reminding the "obvious".
  • I attended the Java SE performance BOF - it was an interactive Q & A session. The "performance gurus" of Sun answered the questions. Most questions were about GC - as one would expect in such sessions :-)

Wednesday May 09, 2007

JavaOne'07 Tuesday (May 8)

Here is what I did on the first day of JavaOne 2007.
  • I attended the keynote session - main messages are:
    • "JavaFX script" language - a dynamic, statically typed language for GUI/Java2D/Swing type applications (can be used for general purpose as well). It was formerly called F3. In future, there will be an authoring tool that emits JavaFX script.
    • JavaFX/Mobile - complete software platform for mobible - sort of like "Java OS" for mobile phones. You have Java SE, yes - you read it right, Java SE for mobile phones! And JavaFX script wil run on this platform too.
    • OpenJDK
    • NetBeans 6.0
    I attended the following talks:
    • Language oriented programming - this was very nice presentation on DSLs (Domain Specific Languages). Very nice examples for internal DSLs (where you stay within the general purpose language) in Groovy, Java and JRuby - then followed by brief description of external DSLs (do it in the hard way - create your own lexer, parser) and tools for the same. Interesting talk!
    • Then, I attended the talk on SunSPOT. The talk was around constructing virtual reality/game/3D stuff using SunSPOT devices and desktop. SunSPOT runs Squawk - VM that runs on the bare ARM-9 hardware and provides low-level operating system support, as well as application isolation (isolates). Over the week end, I played on Wii console [which my friend bought recently]. After attending this session on SunSPOT, I appreciate how difficult it is to create such a system! Cool stuff!
    At 8.00 PM, Alan, Mandy and I presented the usual JDK troubleshooting tools BOF. There were lots of questions. We wanted it to be interactive - it was so interactive that I could barely complete the demo on jhat tool :-) If you are keen on improving heap dumps, you may want to join and contribute http://heap-snapshot.dev.java.net project. One important suggestion was to create a web page of tools and products that import hprof heap dump format files. After the talk, we discussed on importing the heap dump to a database and allowing SQL queries -- so that we can handle very large heap dumps. We will have to revisit this. But, now that we have Open JDK, you can contribute with new ideas and implementations/improvements!

Thursday May 03, 2007

Meet you at BOF - 2816 JavaOne 2007

As usual, there is troubleshooting BOF this year as well (2816 - Tuesday 8.00 PM). Alan Bateman, Mandy Chung and yours truely will present. Meet you all there!

Wednesday Apr 18, 2007

Desktop scripting applications with NetBeans 5.5

How about developing desktop Java applications using scripting, XML and database with NetBeans? This afternoon I played with scripting using NetBeans 5.5. Before proceeding further, I will describe the devepment environment:

In addition, I've CVS checked out the following java.net projects:

I started with a simple Java program project. Added a script file with the name "hello.js" to the project:

I added the following code using the JavaScript editor:

JavaScript editor supports syntax highlighting etc. The "importPackage" built-in function imports a Java package to script."importClass" imports a specific Java class. Everything above is straight forward -- except may be the listener for the button. JavaScript engine takes care of wrapping the supplied JavaScript function to ActionListener interface. Also, JavaScript engines supports JavaBean convention so that we can write f.visible = true instead of f.setVisible(true).

I added the following code to the main class:


package helloscript;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Main {
    public static void main(String[] args) throws Exception {
        // create manager
        ScriptEngineManager m = new ScriptEngineManager();
        // create javascript script engine
        ScriptEngine js = m.getEngineByName("javascript");
        // evaluate "hello.js"
        InputStream strm = Main.class.getResourceAsStream("/hello.js");
        Reader r = new InputStreamReader(strm);
        js.eval(r);
    }   
}

Note that NetBeans copies "hello.js" to build/classes directory and packages it into dist/HelloScript.jar as well. So, the above getResourceAsStream works as expected. When running the project, I got this:

Now, how about throwing some database access and XML? I'm too lazy to use JDBC API directly. I wanted to try out the persistence API. So, I followed the steps below to generate entity classes from the sample database [shipped with NetBeans enterprise pack? I've no idea, as long as it works... :-) ]. You probably know this already: You do not need to use Java EE to use the persistence API. You can use it within Java SE

Password is also "app". Don't forget to choose "Remember password during this session" option!

I added all tables from the sample db and I just selected package name to be "helloscript".

Created "persistence unit" as suggested!

Now, I need to add Java code to fetch all "Customer" instances from DB. So, I added the following to Main.java:



package helloscript;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Main {
    public static void main(String[] args) throws Exception {
        // create JavaScript engine
        ScriptEngineManager m = new ScriptEngineManager();
        ScriptEngine js = m.getEngineByName("javascript");
        
        // Create Entity manager factory - "HelloScriptPU"
        // is the name given when creating persistence unit
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("HelloScriptPU");
        // create Entity manager
        EntityManager em = emf.createEntityManager();

        // select all Customer instances
        Query q = em.createQuery("SELECT c FROM Customer c");

        // get the result list (of Customers)
        List l = q.getResultList();

        // expose the Customer list to script
        // as a global variable by the name "customers"
        js.put("customers", l);

        // now evaluate script -- the script may use
        // "customers" variable        
        InputStream strm = Main.class.getResourceAsStream("/hello.js");
        Reader r = new InputStreamReader(strm);
        js.eval(r);
    }   
}

Now, I added logic to display the customer list in the JavaScript code:

Again, I've used JavaBean convention support to access Customer name and email -- so that I wrote c.name and c.email instead of calling c.getName() and c.getEmail() on the entity instances. I used JEditorPane to display the generated HTML table inside the JFrame. When I ran the above code. I got the following error:


Exception in thread "main" Local Exception Stack: 
Exception [TOPLINK-4003] (Oracle TopLink Essentials - 2006.8 (Build 060830)): oracle.toplink.essentials.exceptions.DatabaseException
Exception Description: Configuration error.  Class [org.apache.derby.jdbc.ClientDriver] not found.
        at oracle.toplink.essentials.exceptions.DatabaseException.configurationErrorClassNotFound(DatabaseException.java:86)
        at oracle.toplink.essentials.sessions.DefaultConnector.loadDriver(DefaultConnector.java:168)
        at oracle.toplink.essentials.sessions.DefaultConnector.connect(DefaultConnector.java:83)
        at oracle.toplink.essentials.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:170)
        at oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:537)
        at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:180)
        at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:230)
        at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:78)
        at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:113)
        at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:107)
        at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:76)
        at helloscript.Main.main(Main.java:20)
Java Result: 1

Seems like persistence runtime did not find the driver classes. I added derbyclient.jar from $JDK/db/lib directory to the project's "Libraries".

After that, it ran as expected!

But, I mentioned XML. Where is it? Well, I generated (X)HTML for table :-) How about using E4X? (easier interface to work with XML). Although Mozilla Rhino JavaScript supports E4X, the bundled version in JDK 6 does not support E4X. Rhino's E4X implementation depends on Apache XML Beans. We do have a jsr-223 script engine for "full" Rhino with E4X support in the http://scripting.dev.java.net project. I added js-engine.jar from this project, js.jar [Rhino jar - either download it from Mozilla site or from CVS workspace of scripting project] and xmlbeans.jar [which I got from the Phobos project $PHOBOS/phobos/dist/lib/xmlbeans.jar] to the project:

Then, I modified the "hello.js" script to use E4X:

Note that the HTML table generation does not involve strings. I use E4X to generate it -- I've expressions inside { } for the 'dynamic' portions of the (X)HTML. Also, in the Java code, I made a small change:


        ScriptEngine js = m.getEngineByName("rhino-nonjdk");

Note that I used "rhino-jdk" as the engine name instead of "javascript" so that the manager would choose the jsr-223 engine that is bundled with JDK 6. Without this, it would choose the not bundled jsr-223 engine in rt.jar. With the change above, E4X works! I learned a bit about NetBeans 5.5 JavaScript support, persistence API and E4X. Hmm..., some day I need to try out the bleeding edge stuff in NetBeans 6...

About

sundararajan

Search

Archives
« June 2016
SunMonTueWedThuFriSat
   
1
2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
22
23
24
25
26
27
28
29
30
  
       
Today
Bookmarks
Links

No bookmarks in folder

Blogroll

No bookmarks in folder

News

No bookmarks in folder