This article is old and is being consolidated into
the book.
Please refer to the corresponding chapter(s) therein. If the chapters or
sections are not completed yet, you can use this article. Refer to the
examples as they are tested against the latest code.
AbstractJudoScript is a powerful tool for J2EE developers, thanks to its superb Java scripting capability,
enterprise computing and general features. This article demonstrates some of them with a
list of JudoScript's J2EE use cases, which you can adapt to use in your cases.
It may grow to include more cases over time.
JudoScript code is supposed to be obvious to Java programmers.
In the example source code, we put a special comment that starts with
//{{NOTE}} to indicate it is a JudoScript usage note.
Otherwise, it is a valid comment for the program itself.
JudoScript is the first JDBC scripting language. You can easily execute SQL statements in various modes,
such as directly, preparedly or in batches. It is simply easier to write the SQL and bind parameters.
We give two practical examples that are easy for you to adapt and use in your work.
In Oracle, stored procedure source code is stored in a table.
For user procedures, they can be obtained through view user_source.
Each line of source code is stored as a row, each row contains the procedure name, type, line number and code itself.
connect oraCon to 'jdbc:oracle:thin:@dbserver:1521:mysid',
'dbuser', 'dbpass';
executeQuery qry using oraCon:
select distinct type, name, line, text
from user_source
order by name, type, line
;
name = null;
while qry.next() {
if name != qry.name { // beginning of a new procedure
if name != null { // last procedure ..
prinltn nl; // print a new line
}
name = qry.name;
prinltn name, ':';
}
flush ' ', qry.text; // print the code --
//{{NOTE}} Oracle keeps a new-line at the end of text.
//{{NOTE}} So use flush instead of println.
}
oraCon.disconnect();
One thing worth noting: the connection is named with oraCon, and
the executeQuery statement has a using oraCon clause.
Named connections allow multiple connections to different (kinds of) databases simultaneously.
Let us enhance the script so it can print out source for specific procedures specified on the command-line.
In JudoScript, command-line parameters are stored in a pre-defined constant array, #args.
More over, we want to save individual procedures into their own .proc files.
// construct a where clause
whereClause = '';
if #args.length > 0 {
whereClause = 'where name in (';
for i=0; i<#args.length; ++i {
if i>0 { whereClause @= ', '; } //{{NOTE}} @ is string concat op.
whereClause @= "'" @ #args[i].toUpper() @ "'";
}
whereClause @= ')';
}
connect oraCon to 'jdbc:oracle:thin:@dbserver:1521:mysid',
'dbuser', 'dbpass';
executeQuery qry using oraCon:
select distinct type, name, line, text
from user_source
order by name, type, line
(* whereClause *)
;
//{{NOTE}} can contain dynamic text for the SQL statement.
name = null;
file = null;
while qry.next() {
if name != qry.name { // beginning of a new procedure
name = qry.name;
if file != null {
flush ;
file.close(); // close the previous file
}
// open a new file for the object
file = openTextFile(name @ '.' @ qry.type, 'w');
}
print qry.text; //{{NOTE}} write the code into the file
}
if file != null { // for the last file.
flush ;
file.close();
}
oraCon.disconnect();
const #custName = 'com.example.ejb.customer.CustomerManagerHome';
ctx = weblogicContext('t3://jhuang:7301','weblogic','system32');
custMgr = ctx.lookup(#custName)
.cast(#custName) //{{NOTE}} Why must cast? See below.
.create();
custs = custMgr.findCustomersByFirstName('James'); // returns java.util.List
//{{NOTE}} Java collection data structures can be iterated
//{{NOTE}} the same way as JudoScript arrays, like so:
for x in custs {
println x.getFirstName(), ' ', x.getLastName();
}
The .cast() in most cases are required and should be interesting to Java programmers.
The reason is a limitation (actually, a feature) in Java reflection API.
As we know, when using RMI and EJB, you define (remote) interfaces, and rmic or ejbc will generate
stubs and skeletons, which are normally not public but do implement those interfaces.
JudoScript uses Java reflection to find all the classes extended and interfaces implemented by the stub class;
in this case, it will only fail because the stub is not public.
Thus, you have to explicitly call the .cast(className) which is a JudoScript-built-in method for
Java objects (the other JudoScript-built-in mehtod for Java objects is .instanceof(className)).
JudoScript has rich support for O.S. and file system operations.
We can use them to compile Java and package jar files for EJBs.
This step-by-step process is easy and straightforward.
Suppose we have such a directory structure for the source code:
and we intend to make two jar files: ~/dist/ecom.jar for non-EJB classes and
~/dist/ejbs.jar for EJBs.
In the process, we use ~/temp/classes/ to store compiled class files.
src_dir = '~/dev/';
tmp_dir = '~/temp/classes/';
dist_dir = '~/dist/';
rmdir tmp_dir force; // clear first
mkdir tmp_dir; // create the dir to store class files.
// Step 1. Compile Java files
// first, construct the Java source file list
list '*' except '*/META-INF*' in src_dir dirOnly recursive;
//{{NOTE}} list returns paths in $$fs_result (array).
java_files = $$fs_result.toCsv(' ', lambda x { return x @ '/*.java'; });
//{{NOTE}} lambda is an anonymous function.
//{{NOTE}} JudoScript functions may take function references as parameters.
//{{NOTE}} Classic example is a compartor function for array sorting.
exec <> [[*
javac -classpath ${CLASSPATH}${:}${MY_CP}
-d (* tmp_dir *)
(* java_files *)
*]];
//{{NOTE}} a) <> forces this exec to be synchronous.
//{{NOTE}} <x> returns the exit value in x; exec is synchronous.
//{{NOTE}} b) a command-line can span many lines
//{{NOTE}} c) ${} expands variable values or environment variables
//{{NOTE}} if name-sake variable does not exist.
//{{NOTE}} ${:} is for platform path separator,
//{{NOTE}} ${/} is for platform file name separator, and
//{{NOTE}} ${~} denotes the home directory.
//{{NOTE}} d) (* *) encloses expressions.
// Step 2. Create the jar files
// create jar for non-EJB classes
copy 'com/*.class' except '*/ejb/*' in tmp_dir recursive
into dist_dir @ 'ecom.jar';
//{{NOTE}} 'into' puts into archives.
//{{NOTE}} 'to' puts into a directory or a target file.
// create jar for EJB classes:
jar = createJar(dist_dir @ 'ejbs.jar');
copy 'com/*/ejb/*.class' in tmp_dir recursive into jar;
copy 'META-INF/*' in src_dir @ 'ejb' recursive into jar;
jar.close();
//{{NOTE}} Need to open a jar object to do multiple copies.
The following script subscribes to a JMS topic named
"weblogic.examples.jms.exampleTopic" running on a Weblogic server and
prints out text messages received until user types a line of "q" on the keyboard:
//{{NOTE}} JudoScript can extend Java classes/interfaces with "Java extension class".
//{{NOTE}} (JudoScript also has its own support of classes.)
//{{NOTE}} Note the Java method signatures are always public,
//{{NOTE}} but the method body is JudoScript code!
class TextListener extendsjava javax.jms.MessageListener
{
void onMessage(javax.jms.Message msg) {
if msg.instanceof('javax.jms.TextMessage') {
println 'Got message: ', msg.cast('javax.jms.TextMessage').getText();
} else {
println 'Got wrong type message: ', msg.getClass().getName();
}
}
}
ctx = weblogicContext('t3://localhost:7001', 'weblogic', 'system32');
tconFactory = ctx.lookup('javax.jms.TopicConnectionFactory');
tcon = tconFactory.createTopicConnection();
tsession = tcon.createTopicSession(false, javax.jms.Session::AUTO_ACKNOWLEDGE);
topic = ctx.lookup('weblogic.examples.jms.exampleTopic');
tsubscriber = tsession.createSubscriber(topic);
tlistener = new TextListener;
tsubscriber.setMessageListener(tlistener);
tcon.start();
while {
line = readLine();
if line == 'q' { break; }
}
JudoScript is easy to integrate with Java software. It has an easy-to-use engine API,
and also supports Bean Scripting Framework (BSF).
In theory, it can be used in JSPs by setting language to "judoscript", and can easily be extended for
JSP Expression Language (EL). This may be done in the near future.
JudoScript does have a server-side scripting feature now, called JudoScript Server Page (JUSP).
It works almost the same way as JSPs, using special tags like <%> and <%=> to quote scriptlets.
In the JUSP pages, you can do anything that JudoScript can do as long as security allows.
Each page has a number of predefined objects such as request, response,
session, etc. You must install its servlet, com.judoscript.jusp.JuspServlet,
in order to use this feature. (This may likely be deprecated in favor of using JudoScript within standard JSP.)
Strictly speaking, spamming is not a feature of J2EE. Just kidding. But it is easy to spam
with javax.mail, and with JudoScript, boy, it is almost tempting!
connectMailServer 'mail_server', 'mail_login', 'mail_password';
sendMail
from: 'info@judoscript.com'
to: 'slee@example.com'
subject: 'The software. Thank you!'
attach: 'readme.txt, software.zip'
body: [[*
Dear Mr. Lee,
Thank you very much for your interest in this software.
Attached is a zip file for the software and a readme
text file. Follow the instructions therein for
installation and using. Enjoy!
Please visit www.judoscript.com for the latest news
and information. Thank you!
Sincerely,
JudoScript
*]]
htmlBody: [[*
<html><body>
<p>Dear Mr. <b>Lee</b>,
<p>Thank you very much for your interest in <i>this software</i>.
Attached is a <u>zip file</u> for the software and a <u>readme
text</u> file. Follow the instructions therein for installation
and using. Enjoy!
<p>Please visit <a href=http://www.judoscript.com>www.judoscript.com</a>
for the latest news and information. Thank you!
<p>Sincerely,
<p>JudoScript
</body></html>
*]]
;
disconnectMailServer();
All clauses in this sendMail command can take expressions, so
you can hook up with database, Excel spreadsheet (via ActiveX scripting), XML, ...
what have you, and do a lot of damage to the network bandwidth.
(Disclaimer: JudoScript is not responsible for any spams if it is used for spamming;
it is the killer that kills, not the gun.)