Schedule, Execute, E-Mail, SSH, SCP
By James Jianbo Huang October 2001 UPDATED: Jan 2003 printer-friendly versionAbstract
The schedule
statement schedules one-time or repetitive jobs to run
at intervals or at specific moments for any kind of actions. The job also has
a built-in HTTP server as a HTML-based control panel, activated when a port
number is specified. The code in the job can take and interpret commands from
the control panel and/or generate custom information for display. Executables
are run with the exec
command with all kinds of input/output and
piping options, including taking input from the script itself or sending
output back to the script for processing; working directory and environment
variables can be set. The mail::send
statement sends messages in text,
HTML or both with or without attachment to multiple "to", "cc" and "bcc"
recipients. The texts can be in different character sets. SCP and SSH are
used to securely transfer files between remote hosts as well as issue commands
on the remote machines. All these applications can be highly useful for
scheduled jobs to automate tasks.
The schedule
statement schedules jobs to run in the future.
Any actions can be specified, such as database operations, run Java or
native executables, sending e-mails, etc. It has a number of modes:
one-time or repetitive, absolute or non-absolute, and starting at a
specific time or after a delay. A HTTP interface is integrated and
started when a port number is provided, so that the job can be
monitored or controlled via a browser or any HTTP client program.
schedule
[ absolute
]
[ ( starting
| after
) time_or_delay
[ repeating
period ] block
[ listen on
[ title
html_title ] control_block ]
Schedules can not be embedded. A program can have one schedule running at
a time. Each schedule is run by a timer called $$timer
. It can be
accessed in the scheduler code, which has these members: time
for
the current event being handled, period
for the current period,
htmlOut
is the HTML output stream and cmd
is the command
sent by the control panel client (most likely a brower) -- the last two are
valid only in the control block.
To abort a schedule job, run break schedule;
.
The following program emulates a count-down process, where 4 one-time events
are run one second apart.
Listing 1. countdown.judo -- one-time event |
1: time = date(2001,10,12,19,4,57);
2: schedule starting time { println $$timer.time, ": Three!"; }
3: ++time.second;
4: schedule starting time { println $$timer.time, ": Two!"; }
5: ++time.second;
6: schedule starting time { println $$timer.time, ": One!"; }
7: ++time.second;
8: schedule starting time { println $$timer.time, ": LAUNCH!"; }
|
This is a simple repetitive motion:
Listing 2. heart_beat.judo -- not-so-accurate repetitive events |
1: beats_per_minute = 80;
2:
3: schedule repeat 60000 / beats_per_minute
4: {
5: println 'puh ... at ', $$timer.time;
6: }
|
Next, we emulate a coocoo clock that every hour it plays so many "Cukoo"
sound. Lines 1 through 4 gets the time for the next hour. Line 7 gets
the time for this event, and its hour attribute is used for the number
of "Cucoo" sound.
Listing 3. coocoo_clock.judo -- accurate repetitive events |
1: $start = date();
2: ++$start.hour;
3: $start.minute = 0;
4: $start.second = 0;
5: schedule absolute starting $start repeat 3600000
6: {
7: local time = $$timer.time;
8: for $i from 1 to time.hour { print 'Cukoo...'; }
9: println;
10: }
|
Scheduled jobs should run quickly, that is, they should not run longer
than the scheduled periods. If they do sometimes and mess up the
operation, practical synchronization mechanism should be put in place.
For instance, suppose every 5 minutes the job checks the database for
unprocessed order data. If it founds some, process them. Sometimes
e-commerce site may take so many orders in a short period of time,
that within that 5-minute period they can not be all processed. What
you can do is, for instance, use a temporary database table; when
start processing, set a flag there, and reset it when done; if this
flag is set, other jobs will simply bypass. The crux of this solution
is, use an operation that is always short than the period to enforce
the synchronization.
By issuing a listen on
clause with a port number, you have the
scheduled job start a single-thread HTTP server. A title can be specified
for the HTML output. If not, the default title is "JudoScript Scheduler
Control Panel".
Listing 4. changing_time.judo |
1: history = linkedList{};
2:
3: schedule repeat 2000
4: {
5: history.add($$timer.time);
6: if $history.length() > 10 { history.remove(0); }
7: }
8: listen on 3333 title '<h1>Changing Time</h1>'
9: {
10: println <$$timer.htmlOut> '<h3>Latest Events</h3>';
11: for x in history backward { println <$$timer.htmlOut> x, '<br>'; }
12: }
|
The job itself does nothing but keeping the execution time in a list for the
last 10 events (line 6). Its control panel server listens on port 3333. The
control panel is typically run from a browser. The title, "Changing Time", is
issued on line 8. The screen is standard above the horizontal line. If and
only if both boxes are checked will the job be stopped and closed. Anything
user type in to the edit box is sent to the server and becomes the content of
$$timer.cmd
. What it means is totally up to your interpretation, such
as a mini command system. In the control panel code, we used $$timer.htmlOut
to write out custom content that shows below the horizontal line (lines 10 and 11).
Review Questions
- How to schedule a one-time event? How about repetitive events?
- How to schedule events that happen precisely (up to JVM precision)
every 5 minutes?
- How to obtain the time for the current event and the period
for this job?
- Specified a
listen on 4444
for a scheduled job with an
empty control block. When connected to it via a browser, what
will you see?
- Think of a scheduled job with the control panel, and devise an
interactive mechanism that takes the command from the control
panel in the brower and acts upon it.
»»» Top | This Section «««
You can send e-mails directly from JudoScript. To use the e-mail feature, you
need to have the javax.mail
packages in the class path. It can
be obtained from various places, such as the "j2ee.jar" file in the J2EE
installation. Before sending any messages, you must first connect to a
mail server by calling the system function:
mail::connect( server [ , username [ , password ] ] );
mail::disconnect();
The server may include a port number, separated by a colon. Once
connected, you can easily send one, two, fitfy or a million e-mails from
a simple JudoScript script; spamming is never easier. Well, if one does want to
spam, there are zillions of ways anyway.
The syntax for sending mail is:
mail::send
[ charset ]
( ( from
| to
| cc
| bcc
| attach
| subject
| body
| htmlBody
) :
content
)+
As you see, text and/or HTML messages can be sent at the same time.
You can specify character sets for addresses, subject and bodies.
If charset is set to mail::send
, both the text and HTML bodies will use it.
A charset can have "charest=". The following two examples are equivalent:
mail::send 'iso-2022-jp' ...
mail::send 'charset=iso-2022-jp' ...
Alternatively, you can call the system function setCharset()
to set
the language character set for the whole language environment. The
mail::send
command uses that if no charset is explicitly
specified in itself. This global character set may affect text encoding used
in other places.
Files can be attached; messages can be sent to a list of "to", "cc" and/or
"bcc" recipients; within each list, recipients are separated by commas. Each
clause can appear at most once. For the message bodies, the here-doc is a big
convenience. Here is an example:
mail::send
from: 'syang@exotic.nat'
to: 'foodback@judoscript.com, syang56@yahoo.cum'
subject: 'bug report'
body: [[*
Hi there,
JudoScript is cool. I'm doing a lot and will do a lot more
with it.
I think I've found a bug. I have a program, 'tvcontrol.judo';
there is a function like this:
function switchTV $on {
if $on { turnOnTV(); } else { turnOffTV(); }
}
however, when it is called with $on=3, it turns off my VCR!
I believe this is a bug in JudoScript that, when the value
is not 0 or 1, it emits erroneous radio shock waves that
affect other appliances than the intended one. Please take
a look. Thank you!
Best regards,
-- Steve Young
*]];
The following example sends out trial software to newly registered users,
whose information is stored in a database. For each user with status
"NEW", a zip file and a "readme.txt" file are sent, and his/her status
is changed to "TRIAL VERSION" in the database. This program is likely
executed by a scheduled job that runs at midnight or later.
db::connect 'jdbc:oracle:thin:@localhost:1521:userdb', 'onlyme', 'uggess';
db::query u:
select email, lastname, solute from usertbl where status='NEW';
db::prepare: update userdb set status='TRIAL VERSION' where email=?;
while u.next() {
sendSoftware(u.email, u.lastname, u.solute);
executeUpdate with @1 = u.email;
}
db::disconnect;
function sendSoftware email, lname, solute
{
mail::send
from: 'info@judoscript.com'
to: email
subject: 'The software. Thank you!'
attach: 'readme.txt, software.zip'
body: [[*
Dear (* solute *) (* lname *),
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 (* solute *) (* lname *),
<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=www.judoscript.com>www.judoscript.com</a>
for the latest news and information. Thank you!
<p>Sincerely,
<p>JudoScript
</body></html>
*]]
;
}
Review Questions
- How to connect to a mail server?
- Can you send an e-mail message in both text and HTML?
- Can you have multiple "to" clauses? How to specify multiple recipients?
- How to attach 3 files to a message?
»»» Top | This Section «««
The SSH and SCP features uses ISNetworks' distribution of MindTerm package,
a GPL'ed open-source pure Java SSH/SCP bundle. It is a GUI program that
you can use daily; its SCP screen looks like a FTP GUI client. Very handy!
Download it from ISNetworks.
Make sure the version is "version 1.2.1 SCP release 3" or up. Unpack and put
the class jar file into your classpath, and run
%java mindbright.application.MindTerm
If it is the first time use, it prompts you for host, user and password,
and generates necessary keys automatically. You should run it to establish
such environment before using JudoScript's SSH/SCP features. By the way, the nice
SCP screen is available on its "File" menu, not so obvious to the first-time
users.
Once the jar file is in the classpath and you have set up the environment,
please refer to the language spec for
how to use. It is rather straightforward.
»»» Top | This Section «««
Running scheduled jobs is an important application of scripting languages.
The schedule
command allows to schedule one-time jobs or repetitive
ones, running at intervals or at specific moments. The actions for the job
can be any valid JudoScript statements and commands except for another schedule,
that is, no embedded schedules. The internal variable, $$timer
, has
members like time
and period
for code to access. A JudoScript
scheduled job has a built-in HTTP server for control panel. All you have to
do is specify the listen on
with a port number, and use a browser
to see the current status. The control panel allows administrators to stop
the job, or send a command string to it, which becomes $$timer.cmd
in the script that you can respond to. With $$timer.htmlOut
, you
can generate more information to the control panel.
Scheduled jobs typically check database or some files for changes and
respond by processing the data, running other applications, handling files
and archives and sending results either via remote calls to systems or
e-mails to humans. JudoScript has flexible JDBC scripting, running executables,
invoking Java programs and sending e-mails. So practically you rarelly
have to leave JudoScript.
The exec
command can run executables as flexible as any shells or
Windows consoles with input/output redirections, merging program output
and error, and piping output to other executables; what is more, the
command line can even take input from the script, or pipe the output back
to the script for processing. A command line can be indicated to take from
the system input; if it is not indicated and the program reads system input,
an EOF is sent immediately so it does not hang the script.
E-mails can be sent directly via the mail::send
command; the message
can be in text, HTML or both. File attachment is supported, so are multiple
recipients for "to", "cc" and "bcc". Prior to sending e-mails, a mail
server must be connected via mail::connect()
system call. The
Java extension packages of javax.mail
must be present.
»»» Top | This Section «««
- countdown.judo -- one-time event
- heart_beat.judo -- not-so-accurate repetitive events
- coocoo_clock.judo -- accurate repetitive events
- changing_time.judo