DJAVA

Package au.gov.aao.drama

A package which provides a JAVA Interface to the AAO's DRAMA API, allowing DRAMA tasks and GUI's to be implementing in JAVA.

See:
          Description

Interface Summary
Arg.StructList This inteface is used by the Arg.List() method to print a single line when listing an SDS structure.
DramaPath.DisconnectHandler This interface is to be used by objects which are specified with with DramaPath.SetDisconnect.
DramaTask.Action This interface is be used by objects which implement DRAMA Obey message handlers.
DramaTask.ErsHandler An inteface to be implemented by objects which output ERS messages.
DramaTask.KickableAction This interface is be used by objects which implement DRAMA Obey message handlers.
DramaTask.KickHandler This interface is be used by objects which implement DRAMA Kick message handlers.
DramaTask.MsgHandler An inteface to be implemented by objects which output MsgOut messages.
 

Class Summary
Arg This class implements an interface to the AAO's DRAMA SDS Library Java equivalent to the Arg library interface to SDS.
DramaErs The DramaErs class is used to access the DRAMA ERS library.
DramaMonitor This class implements parameter monitoring in a DRAMA task written in Java - allowing a JAVA DRAMA task to set up DRAMA parameter monitoring in other DRAMA tasks.
DramaMonitor.MonResponse Used to handle DramaMonitor responses.
DramaPath This class implements an interface to sending DRAMA messages.
DramaPath.Buffers A helper class for defining buffer sizes for use with DramaPath objects.
DramaPath.RescheduleHandler A class which handles rescheduling of a DRAMA Action using the DramaPath class to messages to other DRAMA tasks.
DramaPath.ResponseHandler A class which handles responding to DRAMA messages initiated using a DramaPath object.
DramaSem A multiple entry semaphore which is used to protect DRAMA's internal structures from multithread access from JAVA.
DramaStatus The DramaStatus class is used to access DRAMA status codes.
DramaTask This class implements an AAO DRAMA task in Java.
DramaTask.ErsMessage A Class used to represent a DRAMA ERS message report.
DramaTask.TaskInfo A class used with the DramaTask.Tasks() function, to return the details of currently known DRAMA tasks.
Sdp This class implements an interface to the DRAMA C language SDP library, used to create DRAMA parameters.
Sdp.Sds This class is used to access the value Sdp parameter using SdsID and Arg class methods.
SdsID This class implements an interface to the AAO's DRAMA SDS Library Java.
 

Exception Summary
DramaException Objects of this class are thrown when exceptions occur in DRAMA software.
 

Error Summary
DramaError Objects of this class are used to convert a checked DramaException to an unchecked expection.
 

Package au.gov.aao.drama Description

A package which provides a JAVA Interface to the AAO's DRAMA API, allowing DRAMA tasks and GUI's to be implementing in JAVA.

Topics

DRAMA and JAVA

It is assumed here that you have some knowledge of the concepts of DRAMA. See The DRAMA Web Page for more information on DRAMA itself.

The DJAVA DRAMA package is a Java interface to the AAO's DRAMA API. The DRAMA API allows the implementation of a distributed set of portable message sending and and receiving tasks

The DJAVA component of DRAMA has two significant uses, which overlap. First, it allows you to implement a DRAMA task using Java. Such a task has DRAMA actions implemented as Java objects and can have DRAMA parameters. Here DJAVA is providing an alternative interface for writing DRAMA tasks. Such a task can implement DRAMA actions, send messages to other tasks etc., all the normal things which may be done by a DRAMA task. This provides a strongly O-O approach to implementing DRAMA tasks.

The second use of DJAVA is to implement user interfaces to DRAMA systems. Here DJAVA is an alternative to the use of Tcl/Tk, X windows, Perl, etc. for the implementation of DRAMA user interface tasks. Since Java provides one of the best set of GUI widgets sets available, you can quickly write high quality user interfaces using DJAVA.

DJAVA cannot be used to implement applets. This is because DJAVA requires a Java native languge interface (JNI) library which links to the core DRAMA libraries. As a result, you can only run DJAVA programs on machines which hava DRAMA installed, as well as having DJAVA built.

Introduction to DJAVA

The DramaTask class is used to create and run a DRAMA task. You can use the DramaTask.Add(or this alternative) method to add DRAMA actions to this task. You create classes which implement the actions - such action implementation classes must implement the DramaTask.Action or DramaTask.Kickable Action interfaces.

After adding actions and parameters, setting up a user interface etc, you should invoke the DramaTask.RunDrama method to process DRAMA messages. For simple DRAMA Java programs without a GUI, this method is normally called in the main thread of the program. If you are implementing a GUI, then you will have to call DramaTask.RunDrama in a different Java thread from the thread which implements the GUI.

When you wish to shutdown your DRAMA task, you should call DramaTask.CloseTask, the return value of which can be passed to System.exit() to provide the program exit status. (Unlike C++'s destructors, Java's rough equivalent, the finialize method, cannot ensure DRAMA is shutdown correctly, hence the need for the close call. See this Sun tip for more information). This should be done in the same thread as called RunDrama().

DramaTask also methods equivlant to standard DRAMA C interface operations, such as PutObeyHandler(), GetEntReason() etc. For example, PutObeyHandler() allows you to specify a different object with the DramaTask.Action interface for the next stage of an action. There are also methods which allow a GUI to redirect DRAMA'sMsgOut (informational) and Ers (error) messages such that they may be directed to windows.

Below is a simple example of a simple DRAMA task implemented in Java.
class main {
    // Static main - invoked when program starts up.
    public static void main(String[] args) throws DramaException {

        // Make this program a DRAMA task named "TICKER"
        DramaTask task = new DramaTask("TICKER");

        // Add a couple of actions to the task.
        task.Add("TICK",new MyAction());
        task.Add("EXIT",new ExitAction());

        // Process DRAMA messages.
        task.RunDrama();

        // Tidy up.
        System.exit(task.CloseTask());
        // Should not get here, but ensure we don't try to use this again
        task = null;
    }
}

// A class which implements a Kickable DRAMA action.
class MyAction implements DramaTask.KickableAction {
    // Invoked for Obey messages.
    public void Obey(DramaTask t) throws DramaException  {
        // Output an informational message.
        t.MsgOut("Obey routine hit");
        // Make action reschedule (does this indefintenly)
        t.PutRequestWait(10);
    }
    // Invoked for kick messages
    public void Kick(DramaTask t) throws DramaException {
        t.MsgOut("Kick routine hit");
        // Make the action end
        t.PutRequestEnd();
    }
}
// A class which implements a DRAMA action (not kickable)
class ExitAction implements DramaTask.Action {
    // Invoked for Obey messages.
    public void Obey(DramaTask t) throws DramaException  {
        t.MsgOut("EXIT action invoked");
        // Make the task exit - DramaTask.RunDrama will now return.
        t.PutRequestExit();
    }
}

The DJAVA Classes

The class DramaTask implements the basic DRAMA task from a JAVA program. It provides access most DRAMA functions.

Objects of class DramaException are thrown when errors occur in the DRAMA calls (replacing DRAMA's use of inherited status). A DramaException object is created with a detail string and a DRAMA Status code (using the class DramaStatus class) and these are displayed when the exception is converted to a string. The detail string is used to add some context to the error, normally indicating the underlying DRAMA call which failed. The DramaException class is a checked exception, so your methods always have to handle or throw this exception. You can convert such an exception to an unchecked exception using the DramaError class

The SdsID class provides access to DRAMA's SDS library. Similarly, the Arg class provides access to the SDS ARG routines.

The Sdp class provides methods to create and access DRAMA parameters.

The DramaErs class provides an interface to DRAMA's ERS library.

The DramaStatus provides an interface to DRAMA's Status Codes.

To send messages to other DRAMA tasks you use the DramaPath class. For example, to create such an object refering to a specific task on a specified Node, use
 target = DramaPath(DramaTask, "TICKER", "aat40.aao.gov.au");
You can then use this object to send DRAMA messages, e.g.
target.GetPath()
target.Obey("TICK");
For more details, see the DramaPath class description.

Having used DramaPath to get a path to a task, you can use the DramaMonitor to wrap up parameter monitoring operations.

The DramaSem class is used to control access to DRAMA from multiple Java threads (Java uses threads extensively, particularly in GUI applcations). This class implements a special semphore scheme. The explict use of this class is not normally required by DJAVA application programmers (except in one case, described in the description of the DramaPath class), but its use may be required if you are implementing your own classes which use the Java Native language Interface (JNI) to access DRAMA from C/C++. Before any such method is invoked, you should call the Take() method of this class and then call the Release() method after you return. This will ensure that mutliple threads do not attempt to access DRAMA's internal structures at the same time. Note that you must call the Release() method once for each call to the Take() method, otherwise your task will probably hang due to a deadlock. Take() may be invoked recursively without problems.

To ensure the Release() method is invoked, you should handle exceptions appropriately, eg.
DramaSem.Take()
try {
   // Do real work here which might throw exception
}
finally {
    DramaSem.Release();
}
This will prevent a deadlock occuring due to the throwing of an exception after the semaphore has been taken.

The code between the Take() and Release() calls should take as little time as possible as DRAMA is not able to process messages whilst the semaphore is taken.

Example Code

A number of examples are provided. The sdstest and argtest examples are simple test programs used to test out the SdsID and Arg classes.

A version of DRAMA's traditional ticker and tocker examples are available. Here, ticker implements a DRAMA task named TICKER which implements the actions TICK and EXIT. tocker implements a DRAMA task which sends the TICK action to TICKER. These examples can be used with the standard DRAMA versions of these examples as well as each other.

The most complete example is the MonitorGui example, which implements a user interface in DRAMA, which sends messages to the ticker program. Features including the automatic loading of the program, parameter monitoring, disconnection notification etc. At this point MonitorGui is a somewhat complicated by also being a test program for DJAVA. Currently it is written using AWT rather the Swing.

DRAMA Status codes

The DramaStatus class is used to access DRAMA Status codes from DRAMA. In addition, the messgen utility can generate JAVA classes contining the status code values. See the -j and -J options.

Additionally, all the normal DRAMA Status codes are released in a JAVA accessible form as part of this package. The following error code files are released:
arg_err.java
Error codes set by the Arg library.
dcpp_err.java
Error codes set by the DCPP functions in the DUL library.
djava_err.java
Error codes set by DJAVA itself.
dtcl_err.java
Error codes set by DTCL. Not available with TCL was not enabled when building DJAVA.
dul_err.java
Error codes set by the DUL library.
imp_err.java
Error codes set by the IMP library.
sds_err.java
Error codes set by the SDS library.
Dits_Err.java
Error codes et by the DITS library.
Ers_Err.java
Error codes set by the ERS library.
Git_Err.java
Error codes set by the DUL library.
To use any of these, you need to import them into your application. E.g.
import au.gov.aao.drama.dul_err;
The error codes are fields within the class. E.g., dul_err.FILEOPENERR is how you access the value of the DUL Error code known in C as DUL__FILEOPENERR.

Thread issues - Interactions with Swing

Application developers must be aware that responses to DRAMA messages often happen in a different thread then the operation which started the message. In particular, this applies to Swing applications, where one thread is used to run Swing and another to run DRAMA. DRAMA messages are often sent from the Swing thread (in response to things such as button presses) with any reply handled by the DRAMA thread. Threads may also be used by various classes and you should think about possible interactions.

Of particular concern is that a Swing GUI object normally can only be updated from within the Swing thread. Please see this page for full details on Swing and threads, but note that in DJAVA we have no choice but to use threads in such applications.

In summary, in Swing applcations, you must use SwingUtilities.invokeLater() to update your GUI from any method which may be invoked in the DRAMA thread. The following is an example of how to do this (this was taken from Sun's JAVA web pages and uses an anonymous class which implements the Runnable interface),

void showHelloThereDialog() throws Exception {
    Runnable showModalDialog = new Runnable() {
        public void run() {
            JOptionPane.showMessageDialog(myMainFrame,
                                          "Hello There");
        }
    };
    SwingUtilities.invokeAndWait(showModalDialog);
}
You should consider using this approach in a Swing and DRAMA application for any method implementing the standard DRAMA callbacks. E.g, the appropiate methods in classes which implement the following interfaces

You should also be aware that when a DRAMA action handler returns, the underlying SDS ID available from DramaTask.GetArgument() becomes invalid and may be reassigned. You must not keep references to this item which may be used after the handler returns. As a result you must not use a reference to this value in the class used by SwingUtilities.invokeLater(). If you wish to keep it about, create a deep copy of the item.

Building and Running DJAVA applications

In order to execute DJAVA programs, you need to ensure the correct version of JAVA is in your source path (the correct version is one compatible with the version DJAVA was built against, e.g., the same version, but sometimes a later version of JAVA is ok). For example, on a Solairs system you would normally need to have /usr/java/bin in your path. To check if you have java in your path correctly, try the command java -h which shold output help on the Java command.

On Mac OS X you should set you CLASSPATH environment variable to locate the standard JAVA classes. You may want the default directory included when developing. E.g, prior to starting DRAMA do
setenv  CLASSPATH ".:/System/Library/Java'

Assuming DJAVA has been installed as part of DRAMA (see below), then you then need to execute your start DRAMA startup sequence (the dramastart command). The dramastart command will automatically add the correct DJAVA directories to the LD_LIBRARY_PATH and CLASSPATH environment variables.

You should now be able to build DJAVA programs, for example, to build ticker.java, enter javac ticker.

You run JAVA programs with the java command. But to run your programs, you (may) need to ensure the directory where you built you class is part of the classpath either by putting it in the CLASSPATH environment variable value or by specifying it on the command line. For example, if ticker.class is in my default directroy, the following should work
java -classpath .:$CLASSPATH ticker
The classpath has been a point of much confusion with JAVA and I admit to being unsure if I have specified the above details completely correctly (through the above does work).

Creation of proper packages etc. for release are outside the scope of this document, but the DJAVA source structure and DRAMA's dmakefile may help you here.

Acquiring and Building DJAVA

Currently, DJAVA has only been tested with JAVA 1.2, JAVA 1.3 and JAVA 1.4. (note, JAVA 1.2 is also known as JAVA 2.0, a point of some confusion which I have not been able to clear up to my satisfaction). DJAVA will not work with versions of JAVA older then 1.2, as many usefull features were not present and there were a log of bugs. It is just too hard to make it work with JAVA 1.x releases. But, it appears that you can build DJAVA with JAVA 1.2 and it will continue to work with JAVA 1.3 without rebuilding being required. DJAVA has been building under Solaris 2.6 and later, Redhat Linux 5.1 and later and Mac OS X 10.2 (which requires that you install the developer tools and the latest version of the JAVA runtime).

DJAVA is currently distributed in the standard DRAMA release (from DRAMA version 1.3b6). It is built automatically if the macro "HasJava" is defined as YES in the DRAMA configuration files. You may also need to set the "JavaBase" macro to the location of Java (e.g. /usr/java). (This was added from DRAMA version 1.5.1). These are done by adding the following lines to your ~drama/local/drama_local.cf file (creating the file if it does not yet exist)
#undef HasJava
#define HasJava YES
#undef JavaBase
#define JavaBase /usr/java
By default, DJAVA will be built for Solaris and Mac OS X. In both cases Java is presumed to be in the standard location. You can change the verson of Java used by changing the defintion of JavaBase (from DRAMA version 1.5.1. In older versions you must edit drama_source/djava/dmakefile to make this change).

You can obtain DRAMA from our FTP site. See Installing and building DRAMA for details on building DRAMA. But, you must have a C++ compiler and tell DRAMA you have it. The later is done by adding the following lines to your ~drama/local/drama_local.cf file.
#undef HasCPlusPlus
#define HasCPlusPlus YES
(This is not required for Mac Os X and Linux where the presence of GNU C++ is presumed).

The GNU C++ compiler is quite sufficent and is all I have tested at this stage. If you are selected GCC as your C compiler when building DRAMA then adding the above lines will enable GNU C++. If you are using a different C compiler, then you may or may not find that the above is all you need to do. Please see the DRAMA installation pages for more information

Final Note

Not all DRAMA C level API calls are currently available in DJAVA. It is believed that the set of methods most likely to be required are available, please contact contact tjf@aaoepp.aao.gov.au if you need a Java equivalent of a DRAMA C API which does not appear to exist.

Please feel free to contact tjf@aaoepp.aao.gov.au if you have problems with it or feel the implementation could be improved.


DJAVA

Click here for the DRAMA home page and here for the AAO home page.

For more information, contact tjf@aaoepp.aao.gov.au.