In this chapter:

Book: The Judo Language 0.9

Chapter 4. Running Judo and Logging

By James Jianbo Huang


non-printer version
Synopsis: This chapter details the running of the Judo language. Judo can be run in various modes, including standalone, as a server and as an embedded language engine in Java software.

 
Start-Up Environment

To run Judo, you need Java and Judo software installed. The command line to run is judo. It normally runs a script file, but can run a short program specified on the command line itself, or compile a script without executing.

To run a script, this is the general format:

java [ java-options ] judo [ judo-option ] script_name [ script-parameters ]

Judo script file names normally end with .judo, although it can be anything; included file names normally end with .judi.

The script file and its included files, if any, are located in this order:

  1. the specified path
  2. directories listed in a system propertied called JUDOPATH
  3. ~/.judobase
  4. c:/judobase on Windows or /usr/judobase otherwise
  5. the CLASSPATH for the current JVM (can be turned off with -Dnocp Java option.)

Item 3 and 4 allow users to store common programs in a common place. JUDOPATH uses the same format as Java CLASSPATH except that ZIP or JAR files are not supported. It is optional, and is defined as a JVM system property (the -D option). JVM CLASSPATH is searched last, and Judo scripts can reside within zip or jar files. This can be turned off if the JVM system property nocp is specified.

Judo runtime options

  • -c: to compile the script only to check for the syntax.
  • -q: quite mode, run the script without displaying the copyright notice.
  • -x: to execute the code specified on the command line. Everything on the command line is concatenated, and an extra ; is appended. For instance, the following are some sample command lines:
    java judo -x "println #versionInfo"
    java judo -x "println (1234).fmtRoman('M')"
    java judo -x "println (1234).fmtHex()"
    java judo -x "println 0x4D2"
    java judo -x "println 49.95 * 1.0825"
    

Script parameters and options
Any parameters on the command line following the script name are passed in to the script; they are accessible in the program by the predefined constant array, #cmd_args. Judo supports a simple yet useful parameter format: if specified parameter is like -name:value, it is deemed as an option; the value can be omitted which will be defaulted to true. These options are accessible in the program by the predefined constant #options, which is an OrderedMap. The option values are generally strings; but if multiple occurrences of a same option are specified, the value for that option is an array. The rest of the parameters are accessed as constant array #args. If not options are specified, then #args is the same as #cmd_args.

Listing 4.1 cmdline.judo
print '#cmd_args: ';
for x in #cmd_args {
  print x, ' ';
}
print nl, '    #args: ';
for x in #args {
  print x, ' ';
}
println nl, ' #options: ';
for x in #options.keys() {
  println '           ', x, '=', #options[x];
}

Let's run with this command line:

java judo -q cmdline.judo uvw -aa:1 -bb -aa:2 xyz

The result is:

#cmd_args: uvw -aa:1 -bb -aa:2 xyz
    #args: uvw xyz
 #options:
           aa=[1,2]
           bb=true

In this example, the aa option has two values, stored in an array. The bb is specified without value, and is assumed true.


 
Classpath

When Judo starts, the JVM has an initial classpath called system classpath. Judo also allows additional user classpaths. This is done through the predefined constant, #classpath object.

To add a user classpath component, which can be either a file system directory name or a zip or jar file, use the add() method of #classpath, which can add individual class path name or an array of them. When Judo tries to load a Java class or a resource, the classpaths are searched first; if the class or resource is not found, Judo tries the system classpath. The following program demonstrates how to use this object:

Listing 4.2 add_classpath.judo
println '---- Just system classpath ----', nl, #classpath;

#classpath.add('c:/temp');
println '---- Added user classpaths ----', nl, #classpath;

a = new java::alfa;
println nl, a;

The toString() method of #classpath prints out the complete classpath at the time of execution, where user classpaths are displayed first. The alfa is a test class put in the c:\test. You can inspect classpath components stored in #classpath like this:

Listing 4.3 list_classpath.judo
#classpath.add('c:/temp');

println '---- User classpath components ----';
for x in #classpath.userClasspaths {
  println x;
}

println nl, '---- System classpath components ----';
for x in #classpath.systemClasspaths {
  println x;
}

To add an array of class path names, such the jar or zip files under some lib directory, do this:

Listing 4.4 add_libjar_2cp.judo
/*
 * To add all the jar/zip files in ${deploy}/lib and ${thirdparty}/lib
 * into the (user) classpath.
 */
arr = [];
listFiles <arr> '*.jar, *.zip' in '${deploy}/lib';
listFiles <arr> '*.jar, *.zip' in '${thirdparty}/lib';

#classpath.add(arr);

Java Class Constants

Java classes can be loaded into constants in Judo. Keep in mind that user classpaths are added at runtime, where constants are set at compile time. So the following code would fail:

#classpath.add('c:/temp');

const #CDimension = java::java.awt.Dimension; // OK

const #CAlfa = java::alfa; // fails, even though alfa.class in in c:/temp!

Java classes in the system classpath are ok.



 
System Properties and Environment Variables

As you may well know, when you run any Java software, the JVM contains a set of system properties. In the class java.lang.System, its static method getProperties() returns a java.util.Properties, which is essentially a name-value pair map, that includes all the system properties. You can specify runtime attributes on the command-line like this:

java -Dabc=1 -Dxyz=aaa judo sysprops.judo

User defined properties are also part of the java.util.Properties returned by System.getProperties() method. The JVM predefines a list of system properties that describes various aspects of the JVM, system and runtime information. The following table lists what is defined in Java version 1.4:

Table 4.1 Predefined System Properties in Java 1.4
KeyDescription of Associated Value
java.versionJava Runtime Environment version
java.vendorJava Runtime Environment vendor
java.vendor.urlJava vendor URL
java.homeJava installation directory
java.vm.specification.versionJava Virtual Machine specification version
java.vm.specification.vendorJava Virtual Machine specification vendor
java.vm.specification.nameJava Virtual Machine specification name
java.vm.version JavaVirtual Machine implementation version
java.vm.vendor JavaVirtual Machine implementation vendor
java.vm.name JavaVirtual Machine implementation name
java.specification.versionJava Runtime Environment specification version
java.specification.vendorJava Runtime Environment specification vendor
java.specification.nameJava Runtime Environment specification name
java.class.versionJava class format version number
java.class.pathJava class path
java.library.pathList of paths to search when loading libraries
java.io.tmpdirDefault temp file path
java.compilerName of JIT compiler to use
java.ext.dirsPath of extension directory or directories
os.nameOperating system name
os.archOperating system architecture
os.versionOperating system version
file.separatorFile separator ("/" on UNIX)
path.separatorPath separator (":" on UNIX)
line.separatorLine separator ("\n" on UNIX)
user.nameUser's account name
user.homeUser's home directory
user.dirUser's current working directory

Judo's built-in constant, #sysprops, refers to the system properties.

JVM system properties are different from environment variables. The environment variables are for the operating system process that runs the current JVM. In Judo, there are two system functions, getenvs() and getenv(name). Alternatively, you can use the ${name} notation in place of getenv(name); ${name} can appear within string literals as well; see String and Character for details. Let's look at an example.

Listing 4.5 sysprops.judo
// Print out system class path:
cp = systemProperty('java.class.path').csv(${:});
for x in cp { // print class path nicely.
  if loopIndex() == 0 {
    println 'Java class path: ', x;
  } else {
    println '                 ', x;
  }
}

// Print out a few pieces of system information:
println 'OS Name:    ', osName();
println 'isMac:      ', isMac();
println 'isWindows:  ', isWindows();
println 'isHP:       ', isHP();
println 'isLinux:    ', isLinux();
println 'isSunOS:    ', isSunOS();
println 'javaVendor: ', javaVendor();
println;
println 'fileSep:    ', ${/};
println 'pathSep:    ', ${:};
println 'homeDir:    ', ${~};
println 'curDir:     ', ${.};
println "cd '/'";
cd '/';   // change curDir().
println 'curDir:     ', ${.};
println 'userName:   ', #user;

// Print out all the system properties:
println nl, '=======================',
        nl, ' All system properties',
        nl, '=======================';
for k in #sysprops {
  println k:>26, ' = ', #sysprops.(k);
}

// Print out all the environment variables of this JVM process:
println nl, '==========================',
        nl, ' All environment variables',
        nl, '==========================';
envvars = getenvs();
for k in envvars {
  println k:>26, ' = ', envvars.(k);
}

In this program, it first prints out the JVM's class path; then it prints out some system information. The osName(), javaVendor() and the isXXX() functions are all Judo system functions that obtain information from the system properties. Finally, it prints out all the system properties and environment variables.


 
Include Other Scripts

Judo programs can include other scripts with the !include clause like this:

!include 'common.judi'

By convention, scripts intended to be included have their file names end with .judi. The included files texturally become a part of the current script. Usually included files are used for libraries of functions, user-defined classes, constants, and sometimes global variables or initialization/clearn-up code. Generally, it is not a good idea to put a lot of executable code in included files because this may lead to subtle bugs that are hard to figure out. This is a style issue.

Conditional include
Files can be conditionally included. The complete syntax for !include is as follows:

Include ::= !include ( if Expr | ifexists | ( ifdef | ifndef ) CONST_NAME )? STRING_LITERAL

Between !include and the file path, you can specify a condition; if the condition is an expression, it must be a constant expression. Only when the condition is true will the file be included. The conditions can be the existence or otherwises of a constant, the existence of the included file itself, or a boolean expression. The following shows some examples of conditional include:

!include if ${LOCALE}==null     'messages_en.judi'
!include if ${LOCALE}=='en'     'messages_en.judi'
!include if ${LOCALE}=='es'     'messages_es.judi'
!include if ${LOCALE}=='sim_cn' 'messages_cn_s.judi'
!include if ${LOCALE}=='tra_cn' 'messages_cn_t.judi'


!include ifexists 'init.judi'

!include ifdef #debug 'debuglib.judi'

The syntax of ${LOCALE} accesses the environment variable at runtime. For more details, see String and Character.

Environment variables in include file path
The ${} syntax can also be embedded in string literals. In the case of !include, ${}'s are only interpreted as environment variables. So you can include files like this:

!include '${ENVROOT}/bonanza/common.judi'

 
Pragma

Pragmas are instructions inside program source files to modify the behavior of Judo language system at different levels, such as parsing, script internal states and runtime characteristics. Pragmas take this general syntax:

pragma ::= !pragma PRAGMA_NAME = LITERAL

where the PRAGMA_NAME is a dot (.) separated name, exactly like a qualified Java class name. Each pragma follows its own rules and has its own use, which will be discussed in various parts of this book.

Collectively, !include, !pragma and any other mechanisms in Judo that starts with an exclamation mark (!) are called language directives, which is a not-so-useful concept.


 
Make Scripts Executable

Judo scripts can be made executable on both Windows and Unix platforms. Let's see how they can be done on Windows and Unix.

Make Scripts Executable on Windows

On Windows, we create a simple batch file to run Judo:

Listing 4.6 judo.bat
java judo -q %1 %2 %3 %4 %5 %6 %7 %8 %9

This script assumes that all the necessary Java software libraries, including judo.jar, are in the CLASSPATH environment variable. Then, you can run Judo scripts like this:

judo myscript.judo param1 param2

Next, use the Windows Explorer to associate this batch file to files with extensions of .judo, .jud, .judi and any extensions you like to use for Judo scripts. To do this, first start Windows Explorer and navigate to a file of one of those extensions; right-click on that, and choose "Open With" and then "Choose Program". The "Open With" dialog box shows up; check the box of "Always use this program to open these files"; click on the "Other" button, navigate to the judo.bat you have created, and finish. Next time, you can run a Judo script by either double-clicking on a Judo script in the Windows Explorer, or directly type the script name in a console window (DOS box).


Make Scripts Executable on Unix

It is easy to create an executable script on Unix to run Judo:

Listing 4.7 /usr/local/bin/judo
java judo $*

Certainly, don't forget to chmod it to be executable. So you can run Judo on the command line like this:

judo myscript.jdo param1 param2

To make the Judo scripts auto-run, put the following as the first line in the script:

#!/usr/bin/env judo

And don't forget to chmod the Judo script to be executable. It seems that the following should also work:

#!/usr/local/bin/judo

but there are reports that the first approach works better in most shells, and this is not Judo-specific.



 
Logging

Internally, the Judo engine logs various messages. These messages are classified as trace, debug, info, warning, error and fatal; they are collectively called logging levels. A program can programmatically change the logging level via !pragma mechanism.

Judo Logging Sources and Logging Pragma

Judo has these logging sources within the language engine:

Table 4.2 Judo Logging Sources
Logger NameDescription
judoThe general logger for the whole language engine.
judo.userThe user log writable via the print <log> statement.
judo.jdbcThe JDBC logger. This logger is set to java.sql.DriverManager via a call to its setLogWriter() method.
judo.hibernateThe Judo logger for its Hibernate scripting events.
judo.scheduleThe logger for the schedule statement.

When the language engine starts, all the loggers are initialized to a same logging level, depending on the configuration. Logging levels for any of these sources can be modified via the logging pragma like this:

!pragma logger.judo = 'warn'
!pragma logger.judo.user = 'trace'
!pragma logger.judo.jdbc = 'debug'
!pragma logger.judo.hibernate = 'info'

The logging levels have priorities, from lowest to highest in this order: trace, debug, info, warn, error and fatal. The lower the priority, the more verbose. For instance, if a logger is set to warn level, then all warning, error and fatal messages will be logged. You can also specify an all level, which equates to trace. You can also set an off level to turn off logging altogether.

A special case is to set the logging level for judo.user; you can use logger without suffix to represent judo.user:

!pragma logger = 'trace'

Non-Judo Logging Sources

There may be Java software packages used with your Judo programs. A classical example is Hibernate. These packages often log various messages from different parts.

Logging is a basic part of any software package. Java software can choose their own way of logging, such as writing to System.err or System.out, a file, operating system system logs or even databases. In modern Java, there are a few common choices, notably the JDK 1.4 logging API and the Apache Log4J logging framework. In addition, there is a light-weight wrapper API called Apache commons-logging package that provides a common API to various logging implementations. This is what is used by Judo, Hibernate and many other open source and commercial software products and projects. We need to discuss this package in a little more detail.

Apache commons-logging package

As just mentioned, the Apache commons-logging package is a wrapper on top of various logging APIs. It is closely modeled after Log4J, and provides a SimpleLog of its own in case no other logging implementation is present. By default commons-logging picks a logger with this discovery strategy:

  1. use Log4J if it is available in the classpath. Otherwise,
  2. use the JDK 1.4 logging API if the system is running on JDK 1.4. Otherwise,
  3. use the org.apache.commons.logging.impl.SimpleLog.

If the non-Judo software package does use commons-logging API, you can set the logging level for them as well: simply append the logger name to logger. in the pragma:

!pragma logger.org.hibernate = 'warn'
!pragma logger.org.hibernate.SQL = 'warn'

Logging with Log4J and JDK 1.4 Logging API

The commons-logging API has no special requirements for configuration; the logging configuration must be provided for the used logging mechanism. For instance, Log4J takes a log4j.properties file in the root of the classpath (among other means), and JDK 1.4 logging API reads a logging.properties at start, also from the root of the classpath.

Judo installation provides a default log4j.properties and logging.properties. They are not in the classpath automatically. Take a look at them if you intend to use, and edit them based on your needs, such as setting the logging levels, logging destinations and/or mechanism. The details of these two logging APIs are beyond the scope of this book, and you can find a lot of resources on them both online and in books.



 
Program Documentation

Judo has a special mechanism for structured documentation of programs, the usage block at the beginning of scripts. Its contents are key-value pairs, where the values are any literals. There are three particular keys, minArgs, args and desc. The key minArgs must take an integer number; if it is specified and the number of arguments is less than that, Judo prints out args and desc. The args can be any format and does not serve any other particular purposes other than displaying. The following is an example:

Listing 4.8 usage.judo
usage {
  desc    = [[*
                This program displays a text file of any encoding in a simple Java GUI.
                It is easy to use. Simply provide a text file name and optionally an
                encoding name; the default is your current Java default encoding.
            *]];
  minArgs = 1;
  args    = 'file [encoding]';
  author  = 'James Huang';
  created = '2002-11-14';
  lastMod = '2004-06-28';
}

When run it without any parameters, it prints out the help message like this:

% java judo usage.judo

Usage: java judo usage.judo file [encoding]

This program displays a text file of any encoding in a simple Java GUI.
It is easy to use. Simply provide a text file name and optionally an
encoding name; the default is your current Java default encoding.

The special options, -? and --helper, tell the Judo engine to print out the same help message and exist the script.

The usage block can appear only once in a script. If the script includes other scripts, only the main script's usage is used.
 
back to top
 


Copyright c 2001-2021 JudoScript.COM. All Rights Reserved.