Originally published on: Fri, 14 Aug 2009 02:38:36 +0000
Like a fair number of other developers, I am trying to acclimate myself to programming in one or more dialects of Lisp. I've recently begun to toy with Clojure, a modern Lisp that runs on the Java Virtual Machine.
Before really engaging in some sort of all-out project in Clojure, I thought that I could ease my way into the language by attempting to use it as an embedded scripting language for a simple Java application. I looked through some of the online documentation on Java/Clojure interoperability. The task didn't seem to be too much to attempt in a short amount of time.
I decided to first create a small Java program that performs a simple task in a controlled loop. This program took shape as a small screen-capture utility.
ScrCapture.java
The above program iterates ten times, incrementing a counter from zero to nine inclusively. The entire screen dimensions are retrieved. Then, the entire screen is captured into a file with the iteration number in the file. A beeping sound is generated followed by a ten second delay before iterating through the loop again.
If you execute the above program, you should see the following output: java ScrCapture Captured as capture_0.jpg Captured as capture_1.jpg Captured as capture_2.jpg Captured as capture_3.jpg Captured as capture_4.jpg Captured as capture_5.jpg Captured as capture_6.jpg Captured as capture_7.jpg Captured as capture_8.jpg Captured as capture_9.jpg I wanted to move all of the different elements of the above ... the number of iterations, the sound, the delay, the image filename, the image dimensions ... into an external Clojure script.
The resulting Java program is as follows:
ScreenScript.java
One of the first things I'd like to note is that I included a package definition in ScreenScript.java. I didn't have a formal package name for ScrCapture.java and all worked well. I ran into some issues in Clojure with the . special form.
I tried to use the . special form to invoke static methods I'd provided in the ScreenScript class from the Clojure script. An example would be this call to the sleep method I provided:
(. com.mailsend_online.ScreenScript sleep 2000 )
Until I placed the ScreenScript class in a formal package, Clojure had real issues finding the class. I tried various classpath changes to no avail.
Onward...
One goal in writing ScreenScript was to provide a series of static methods available for use by the Clojure script. I provided the methods screenWidth(), screenHeight(),captureRectangle,sleep(),and beep(). The Clojure script would mimic the main loop from the ScrCapture.java.
Although I had intended to create a loop in Clojure to perform all of the screen capture operations, I found that I really need practice with Clojure's flow-control facilities. This is one of the areas of Lisp where I hope to grasp the beauty of recursion to control iterations. I made a few small attempts to no avail, so I ended up keeping a for-loop in the ScreenScript program.
To compile the above program, make sure that clojure-1.0.0.jar is in your classpath.
ScreenScript first loads the Clojure script specified on the command-line. The method RT.loadResourceScript() loads the specified script and also initializes the Clojure runtime environment.
After the script is loaded, two Var objects are initialized ( captureLoop and maxIterations ) so that I can invoke their like-named functions in the specified Clojure script.
The code invokes maxIterations first to determine the number of times to loop. This is one area of the code that I'd like to change so that it will, in a future incarnation, leverage Clojure's flow-control.
In the loop body, the Clojure method capture-loop is invoked.
Please consider the following Clojure script that is used in conjunction with ScreenScript:
cap.clj
The call to max-iterations in the above script yields a value of ten. I don't yet know how to simply make a symbol that I can read, so I left this mechanism in the form of a function.
The capture-loop function accepts on parameter named i. The calling Java program passes in the iteration number ( relative to zero ). The capture-loop function uses i to form up the name of the output file.
Note that in the Clojure script above, we only capture a 400 by 200 pixel section of the screen, we use a different file naming convention option for shorter names, we only delay 2 seconds between each iteration, and we output a different message that does not contain the generated filename.
The output from the above might look like this:
java com.mailsend_online.ScreenScript cap.clj Capture number 0 Capture number 1 Capture number 2 Capture number 3 Capture number 4 Capture number 5 Capture number 6 Capture number 7 Capture number 8 Capture number 9
If we wanted to completely replicate the functionality of ScrCapture.java, we could make calls to screenWidth and screenHeight so that we capture all of the screen and could change all of the Clojure code to parallel the parameters used in the original program.
The primary goals I had were to learn how to call a Clojure function from within Java and also to learn how to call a Java method from within Clojure. The resulting Clojure host isn't quite perfect yet, but I'll be exercising Java/Clojure interoperability again in the near future.
Unless otherwise noted, all code and text entries are Copyright ©2009 by James K. Lawless
Save to del.icio.us
Save to StumbleUpon
Digg it
Save to Reddit
Share on Facebook
Share on Twitter
More bookmarks
Subscribe!
Auto Save Clipboard Images Redux
Extending SpiderMonkey JavaScript on Windows
Rhino JavaScript to EXE with launch4j
Compiling Rhino JavaScript to Java
Directory Traversal in Rhino JavaScript
A Command-Line MP3 Player for Windows
Auto Save Images from the Clipboard
Java in a Windows EXE with launch4j
An Interview with Tom Zimmer: Forth System Developer
Setting Windows Console Text Colors in C
Changing the C64 Text Color in C
An Interview with the Author of the French Silk Assembler
Embedding JavaScript in a Batch File
BPL: Batch Programming Language Interpreter
Checking Shift States with DEBUG
Screen Capture from Multiple Monitors in Java
MicroISV on a Shoestring
DadHacker
The Bottom Feeder
Writin' That Code!
The Recursive ISV
The Thomsen Blog
Prototypically Speaking
The Reinvigorated Programmer