Java Scripting: Half the Size, Half the Time

by Owen Densmore


Recently I needed to create a megabyte file full of random bytes in order to test network bandwidth with an uncompressible file.  I decided to try using Java, it was simple and had a reasonable random number generator.  So here's the resulting script:



        #!/bin/sh
# testbandwidth host login passwd
host=$1; login=$2; pass=$3

echo "Building mbyte file"
cd /tmp
cat <<EOF> test.java
import java.util.*;
class test {
public static void main (String args[]) {
try {
Random r = new Random();
byte[] data = new byte [1024*1024];
r.nextBytes(data);
System.out.write(data,0,data.length);
} catch (Exception e) {
System.out.println(e);
}
}
}
EOF
javac test.java
java test>mbyte

echo "Upload Test"
ftp -i -n -v $host << EOF
user $login@$host $pass
put mbyte
EOF

echo "Download Test"
ftp -i -n -v $host << EOF
user $login@$host $pass
get mbyte
EOF


Well, that's sorta nifty, but boy is the java a verbose hunk of the code!  Lets enumerate some of the irritations:





  • Have to create the temporary .java and .class files somewhere (here we used /tmp) rather than have it simply execute the commands in place.


  • I've got to make a class and a static void Main method in the class, the Java cliché for building an application.


  • Then it all gets wrapped with a try/catch construct due to possible I/O errors.


  • Testing is tedious, requiring compilation and running rather than more immediate feedback.


  • The flow of the Unix script is broken up .. its hard to tell, for example, what the point of it all is!





Well, I often use

BeanShell

while hacking because its so easy to test a piece of code w/o the compile/run steps.  (See

this article
) I just keep a shell running and cut & paste code pieces from my project.  So being somewhat comfortable with BeanShell, I decided to replace the Java part of the above script w/ the BeanShell equivalent.



        cat<<EOF>/tmp/temp.bsh
r = new java.util.Random();
data = new byte [1024*1024];
r.nextBytes(data);
System.out.write(data,0,data.length);
EOF
java bsh.Interpreter /tmp/temp.bsh > mbyte


So we've replaced 17 lines of Java code with 7 lines almost identical code, but without the verbosity.  Very readable and appropriate, and quite readable.  (Note that we still had to create a temporary file due to BeanShell not coming with a "wrapper" shell script that would handle stdin as program text.  Minor.)  The treat for me was the ability to use the standard, well documented (JavaDoc) classes easily from scripts.  Note that I did not bother with an import statement, I fully specified the Random class.  Due to "loose typing" allowed by BeanShell, I could avoid the equivalent



        java.util.Random r = new java.util.Random();


..which seemed to warrant the use of the import statement.




Wanting to fuss with this a bit more, I rewrote this all in

PNuts
, a Java Shell written with a slightly different set of goals (see

this article
).  It uses incremental compilation for speed, and has a Java-like syntax but with several differences.  For example, rather than Java's



        import java.util.*



form, PNuts uses a procedure form:



        import("java.util.*")







So the PNuts form of the Java code is:



        pnuts<<EOF>mbyte
r = class java.util.Random()
data = byte [1024*1024]
r.nextBytes(data)
class java.lang.System::out.write(data,0,data.length)
EOF


Slightly shorter due to being able to use a "here file" for stdin.




There have been several articles on Java scripting languages,

this one

includes these two and several others.  And

this article

collects all the languages that run on top of the Java VM.





Have you had good luck w/ these or other Java scripting languages? Jython seems interesting, for example.


5 Comments

anonymous2
2004-01-15 00:48:54
Get rid of sh
What about writing the whole thing in a scripting language like groovy. Writing to a source file then compiling and executing it seems like a pain.


You can use a java FTP library to do the ftp. If you want to call a command line tool, I'm working on shell integration for groovy.

sanchonevesgraca
2004-01-15 02:14:09
Relative value of scripting Java
Scripting Java is a light way of constructing Java classes that can be used from an interactive environment. This might be useful for the ocasional usage of a Java library but care should be taken not to extend this approach to larger problems. Unless there is a clear client-service contract between the script and the class, and the class has been thoroughly tested outside the scripted environment, the scripting is likely to create more problems than solutions:


- Development of the Java class becomes intertwined with the development of the script, whereas Java development is much different from script writing. To use Java well, it is necessary to master main(String[]) for starters, then move on to junit and ant;


- Compreheension of the script rapidly deteriorates, and so does the compreheension of the Java classes;


- Collaborative development becomes almost impossible: the Java community will likely not help out with a class written inside a script;


- The class(es) cannot easily be reused by other clients;


It pays to follow the development conventions of a community, and to understand its culture. There should be a separation between the client (script) and the service (Java program). This applies to all languages, not just Java.


Where there is some real value is in approaches that make a programming language other than Java interact with a JVM (e.g., Jython, Mathematica with J/Link).

anonymous2
2004-01-15 04:49:20
why java
unix: dd if=/dev/random of=file count=1024 bs=1024
perl: perl -e 'print map { pack( "c",rand(255 ) } ( 1..1024*1024 ) '
anonymous2
2004-01-15 15:02:30
Judoscript
This would be about as small in Judoscript (http://www.judoscript.com/index.html). Groovy would also be a nice choice.
anonymous2
2004-01-16 13:09:14
why java
dang, you beat me to it.