Groovy: A Powerful Scripting Language for Java Developers on System i
May 16, 2007 Mike Brown
When programmers are put in a situation to develop and deploy applications for a new environment, they tend to look for familiar tools to use. An example might be a text editor that is similar to something that has been used in the past. Another example might be the command line environment (sometimes referred to as a “shell”) such as Bash in the Unix/Linux world. IBM provides QShell on the System i as a basic command line environment. However, if you are accustomed to the Unix/Linux world, a lot of utilities that you may be used to may be missing. IBM also provides an excellent Java environment on the System i. If you are familiar with Java, its vast library of utility classes, and its large number of third party libraries, wouldn’t it be great to use Java as a scripting language? What if this scripting language didn’t have to be compiled, had a simpler syntax, and could interact with all the Java classes you already know? What if this scripting language could give you access to the System i resources? There is such a scripting language, and it is called Groovy. A Good Fit According to the Groovy Web site: “Groovy is an agile dynamic language for the Java Platform with many features that are inspired by languages like Python, Ruby and Smalltalk, making modern programming features available to Java developers with almost-zero learning curve.” Python and Ruby are, no doubt, the more popular dynamic languages today. However, if you are a Java developer looking for a dynamic language, I recommend looking at Groovy. Here are some reasons:
Whether you are just automating some tasks with Groovy scripts or manipulating System i resources, you have everything you need to start using Groovy on the System i. Java 1.4, which Groovy requires, is available through licensed product 5722-JV1 on V5R1 and later. The IBM Toolbox for Java provides access to System i data and resources to Java applications, which means you can also access them from Groovy. Installing Groovy on the System i Download the binary distribution for the current version, which is 1.0 at this time, from the Groovy Web site (see the Related Resources section below for more stuff). Copy the groovy-1.0.zip to the IFS.You will need to extract the contents of the zip file. Assuming the zip file is located in the IFS directory /home/user, the following QShell commands will extract the contents to /QOpenSys/groovy-1.0: mkdir /QOpenSys/groovy-1.0 cd /QOpenSys/groovy-1.0 jar xf /home/user/groovy-1.0.zip You will need to define two environment variables (see Getting Started with Qshell Scripts from a 2002 edition of this newsletter for more information on doing this in your profile script) and update your PATH. Here are the relevant lines from my .profile script: GROOVY_HOME=/QOpenSys/groovy-1.0 JAVA_HOME=/QIBM/ProdData/Java400/jdk15 PATH=$PATH:$JAVA_HOME/bin:$GROOVY_HOME/bin export GROOVY_HOME JAVA_HOME PATH Testing the Installation When you have installed Groovy and set the appropriate environment variables, do a quick test to make sure everything is setup properly. Since I’m sure you will be writing a lot of Groovy scripts, run the following Qshell commands to create a directory in your home directory to hold those scripts: mkdir ~/gscripts cd ~/gscripts Note that the “~” character is a replacement for your user home directory. You can verify the location of this directory by using the following command: echo ~. Using your editor of choice, create a text file in this directory called time.groovy, containing the following line: println "The current time is: ${new Date()}" Since you have added /QOpenSys/groovy-1.0/bin to your path with the, you can execute the script from any IFS directory with the following Qshell command: groovy ~/gscripts/time.groovy The response will be similar to the following: The current time is: Wed May 09 06:32:18 CDT 2007 If you had any errors, check the contents of the groovy script and the statements in your .profile. Example Script to Delete Temporary Files I use Emacs as a text editor on my PC, which creates backup files with a particular pattern. Other tools may also leave backup or temporary files on your computer. The following is a sample Groovy script that will delete files that match particular patterns. It also counts the number of files that meet the patterns and totals the size of those files. Create a new text file in ~/gscripts called deltemp.groovy containing the following source code: def emacsBak = ~/.*~$/ def emacsTemp = ~/^#.*#$/ def patterns = [emacsBak, emacsTemp] def process def count = 0 def bytes = 0 process = {aFile -> //println "Dir ${aFile.canonicalPath}"; aFile.eachDir( process ); for (pattern in patterns) { //println "Looking for: ${pattern}" aFile.eachFileMatch (pattern) { println "Delete File: " + it; bytes += it.length(); count++; //it.delete(); } } } def usage = { println "Usage: groovy deltemp.groovy As is, this script will not delete anything since the it.delete() statement is commented out. Groovy uses the same comment syntax as Java. If you want to see the all the directories and files that the script is looking at, uncomment the first two println statements in the process closure. This script uses regular expressions (see the Resources section) to define the pattern for a temp file to delete. You can add different patterns and add that pattern to the patterns list. Without going into any detail, I want to point out a couple of features of Groovy that make this script so compact. First, the process defined in the example is something called a closure. A closure is basically one or more statements enclosed in curly braces. Think of it as a method in a class, but you don’t have to define the class and method. Closures can be passed as parameters as in the statement: aFile.eachDir( process ). You might be wondering where this eachDir method came from. It is not part of the File class provided in the java.io package. Groovy adds a lot of “helper” methods to standard classes to make our jobs easier. This method takes a closure as a parameter and will invoke that closure with a File parameter for each directory of the given directory (represented by aFile in our script). Just as a teaser, there are similar “enhancements” to make dealing with XML files, SQL processing, etc. for the Groovy language. Getting Active Job Information Now that you have Groovy installed and verified the installation, let’s consider a script that retrieves information about active jobs on the System i for a specified user. This script will use the IBM Toolbox for Java to retrieve that information. In your ~/gscripts directory, create a new script called jobs.groovy with the following text. import com.ibm.as400.access.* def usage = { println "Usage: groovy jobs.groovy Before you can run this script, you need to let Groovy know about the Toolbox jar file. The default configuration for Groovy specifies that jar files found in ~/.groovy/lib will be loaded automatically. Instead of copying the file, make a symbolic link. The following command should be on one line. ln -s /QIBM/ProdData/OS400/jt400/lib/jt400Native.jar jt400Navtive.jar This script uses Toolbox classes and standard Java classes to get the work done while using very little of Groovy’s features. It is worth noting that the script will have an implicit “args” array that holds command line options, just like the main method of a Java class. Execute the script and supply a system user name (yours or QTCP perhaps, which will probably give you a long list) as follows: groovy jobs.groovy [username] The following is a sample of the output with the user name masked to protect the guilty! Name: QPADEV0001, Number: 018735, User: **, CPU Used: 112 Date entered: Fri May 11 07:50:17 EDT 2007, Status: *ACTIVE, Type: I Func Name: STRQSH, Func Type: C Name: QZSHSH, Number: 018736, User: **, CPU Used: 31 Date entered: Fri May 11 07:52:39 EDT 2007, Status: *ACTIVE, Type: B Func Name: QZSHSH, Func Type: P Name: QP0ZSPWP, Number: 018765, User: **, CPU Used: 1975 Date entered: Fri May 11 08:39:52 EDT 2007, Status: *ACTIVE, Type: B Func Name: GroovyStar, Func Type: J A function type of “J” means it is a Java program. Improving Performance Once you get a script written and tested, you can improve the performance by compiling the Groovy code to Java class files. After you do this, you can run the script as you would any Java application. The following command compiles the jobs.groovy script. Several class files are produced: one for the script and one for each closure in the script. groovyc jobs.groovy To execute the jobs class, you must include /QOpenSys/groovy/embeddable/groovy-all-1.0.jar in your class path along with any other libraries your class depend on (e.g., jt400Native.jar). Create a shell script called rg.sh to make running compiled Groovy scripts easier. The following will give you a starting point. The text below should be all on one line and you will need to replace [userhome] with your home directory. java -classpath .:/QOpenSys/groovy/embeddable/groovy-all-1.0.jar: Execute your new Java application with this command: ./rg.sh jobs [username] Create Powerful Scripts in a Familiar Environment Now you can create powerful scripts on the System i using any of the standard Java classes, any third party library (e.g., the Toolbox, the Spring framework, etc.) and the enhancements that Groovy itself provides. I encourage you to try it for yourself and automate those mundane, repetitive tasks with Groovy scripts! Mike Brown is the founder of comIT, LLC, a consulting company that provides architecture, project management, and development services. Mike’s experience ranges from compiler development to Department of Defense contract work to commercial IT systems. He can be reached at mbrown@comITServices.com. RELATED RESOURCES IBM’s Toolbox for Java Is Getting Better Every Day Getting Started with Qshell Scripts Java Specification Request (JSR) 241
|