Skip to main content

Running in the Family

Posted by editor on September 21, 2006 at 8:29 AM PDT


Sooner or later, everything will be callable from Java

A few years back, I needed to call AppleScript from a Java program -- really, what I needed was to send Apple Events -- but with no way to do it programmatically, I was forced to do a Runtime.exec() invocation of osascript. Yuck.

Fortunately, Thomas Künneth's jasconn project uses JDK 6's scripting language support, as defined by JSR-223, to offer a Java-friendly binding to AppleScript. It only works with the pre-release JDK 6 available from the Apple Developer Connection (NDA genuflection required) and of course is only for Macs, but I thought I'd give it a spin yesterday.

It's a pleasure to report that jasconn worked well. What I did was to take an AppleScript I use to set my iChat status as the number of e-mails in my O'Reilly INBOX, so co-workers can see how many blog requests, article proposals, and news blurbs I have yet to dig through before I'm able to take on anything new. Here's the script:

global messageCount
tell application "Mail"
        set oReillyAccount to account named "O'Reilly"
        set oReillyBox to mailbox "INBOX" of oReillyAccount
        set oReillyMessages to messages of oReillyBox
        (* set oReillyCount to length of oReillyMessages *)
        (* only count non-deleted messages *)
        set messageCount to 0
        repeat with aMessage in oReillyMessages
                if (deleted status of aMessage is not true) then
                        set messageCount to (messageCount + 1)
                end if
        end repeat
end tell

tell application "iChat"
        set status message to "O'R Inbox at " & messageCount
end tell

Normally, this sits in my ~/Library/Scripts, waiting for me to invoke it from the optional script menu. For kicks, I decided to wire it up to a trivial Swing GUI:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import de.thomaskuenneth.jasconn.*;
import javax.script.*;

public class JASConnTest extends JFrame implements ActionListener {

    JButton button;
    ScriptEngine engine;
    String script;

    public JASConnTest() {
        super ("JASConn Test");
        getContentPane().setLayout (new FlowLayout());
        button = new JButton ("Update iChat");
        button.addActionListener (this);
        getContentPane().add (button);
        try {
            setUpScriptEngine();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void setUpScriptEngine() throws IOException {
        // get jasconn
        ScriptEngineManager sem = new ScriptEngineManager();
        engine = sem.getEngineByName ("jasconn");
        if (engine == null)
            throw new RuntimeException ("couldn't find jasconn engine");
        // read script into a string
        char[] buffy = new char[1000];
        StringBuffer sb = new StringBuffer();
        BufferedReader reader =
            new BufferedReader (new FileReader ("OReillyInboxAt.applescript"));
        int bytesRead = 0;
        while ( (bytesRead = reader.read (buffy)) > 0) {
            sb.append (buffy, 0, bytesRead);
        }
        script = sb.toString();
    }

    public static void main (String[] arrrImAPirate) {
        Frame f = new JASConnTest();
        f.pack();
        f.setVisible(true);
    }

    public void actionPerformed (ActionEvent e) {
        if (e.getSource() == button) {
            try {
                engine.eval (script);
            } catch (ScriptException  se) {
                se.printStackTrace();
            }
        }
    }
}

Notice how the script has an .applescript extension, indicating that it has been saved as plain-text. I'm not sure whether compiled .scpt files would work. Also notice that this reads the entire script into a String and caches it. That's one option with using ScriptEngine.eval(); another is to give it a Reader, presumably pointed to the flat file. Call it a premature optimization, but reading the whole script in and keeping it in memory is a huge performance boost over letting the native script menu read, parse, and execute the script each time.

Anyways, compile and run with the full long path (you have to point to /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Commands to do this, as anyone who's juggled Java versions on Mac OS X knows. Here's the resulting GUI:

jasconn-test-frame.png

And when I click the button, here's the result in iChat:

jasconn-ichat-status.png

This is one of those unanticipated bonuses of JSR-223. It's not about whether other languages are "better" or "worse" than Java, but what they can do. AppleScript is a profoundly nifty way of interacting with native applications on the system, and jasconn exposes them to Java. Nobody planned that when they wrote the JSR-223 draft, any more than they anticipated, say, websites that would let you upload and run server-side JavaScript with Rhino. But that's what this feature enables. And a lot of people are going to find cool things to do with it.

So, would you like to bring your favorite language to Java? I'm glad you asked...

In today's Feature Article, Thomas shows you the nuts-and-bolts of
Making Scripting Languages JSR-223-Aware, in which he writes:

Establishing a basic link between Java and existing scripting languages using JSR 223 is quite easy. The number of interfaces you need to implement is fairly small. Additionally, Sun provides useful helper classes that you can take advantage of in your implementation.

Read on for the details of making scripting languages callable from Java.


In Java Today,

Artima takes note of JSR 306 in the discussion New JSR Aims To Change How Java Standards are Defined. "The recently submitted JSR 306, 'Towards a New Version of the JCP,' aims to refine how the Java Community Process (JCP) creates and manages Java standards. Artima spoke with Onno Kluyt, chair of the JCP, about the proposed changes. [...] The expert group for JSR 306 consists of JCP executive committee member companies and individuals. Artima spoke with Sun's JCP Chair Onno Kluyt, and JCP program manager Heather VanCura, about the proposed changes."

Last week's 10th Jini Community Meeting was a big success, and those who didn't attend can start catching up with some of the materials on the jini.org wiki. The 10th JCM Live page is being left as an informal collection of conference blogs, photos, and more. The 10th JCM Sessions page lists all the sessions and lightning talks from the meeting, and many of them already link to PDF slides and/or QuickTime video of the talks.

"Concurrent or multi-threaded software is not a new technology but its importance has been accelerating. This is primarily due to the low cost of multi-core CPUs that are becoming common in even the most basic machines." But how do you take advantage of concurrency? Nathan Tippy's article Discover the Elegant Simplicity of JSR 166 offers an introduction to a handful of the features provided by the java.util.concurrent packages.


Joshua Marinacci takes the wraps off a major SwingX feature in today's Weblogs. Not that it's completely ready, but better to release early than later (or not at all). In Introducing Painters, he writes: "One of the temptations of design is to not show your work until it's ready. Not until every edge is smoothed and every bolt is tightened should the anyone be allowed to see it."

Alexander Potochkin would like to help you create
A well-behaved GlassPane, a blog in which he offers advice for
"fixing common mouseEvents problems for the custom GlassPanes implementations"

Finally, Kirill Grouchnikov is
Experimenting with internal frames and presents "an experimental feature added to the internal frame title panes. What do you think?


Following up on his blog announcement (see above), Josh Marinacci puts the call out for feedback in the Forum message
Introducing Painters:
"I've just posted my first blog discussing the past few months work on painters. In this thread I'd like to discuss where we should take the Painters API and what improvements we need to get there. In particular: what standard painters do we need, how do we serialize painters with external references (like images), how should we encourage and distribute painters, what would the ideal builder tool look like, [and] how do we reconcile filter effects and shape effects?"

robross wants to know
How can I convert a Java Image to a native format?:
"I'm working on passing a Java Image to a JNI method on Mac OS X so I can draw that image in the Status Bar and menu items. In the JNI code on the Mac, I can work with various types of data such as GIF, JPEG, TIFF, etc. If I can convert the Java image into one of those formats, I will be able to work with it. So, how do I get access to the data bytes in an Image so I can pass, say a byte[] to the JNI method, and have that data be interpreted properly as one of the above image types?"


In today's java.net
News Headlines
:

Registered users can submit news items for the href="http://today.java.net/today/news/">java.net News Page using our
news submission
form
. All submissions go through an editorial review before being
posted to the site. You can also subscribe to the href="http://today.java.net/pub/q/news_rss?x-ver=1.0">java.net News RSS
feed.


Current and upcoming Java
Events
:

Registered users can submit event listings for the href="http://www.java.net/events">java.net Events Page using our href="http://today.java.net/cs/user/create/e">events submission form.
All submissions go through an editorial review before being posted to the
site.


Archives and Subscriptions: This blog is delivered weekdays as
the Java
Today RSS feed
. Also, once this page is no longer featured as the
front page of java.net it will be
archived along with other past issues in the href="http://today.java.net/today/archive/">java.net Archive.

Sooner or later, everything will be callable from Java