The com.hume.DMH Java Package


Hume Integration has created a Java package for integrating Java and web-based applications into a distributed system using the Distributed Message Hub (DMH) message system.   The Java package consists of classes to use the DMH message system, a class to use text formatted as lists, and a class that provides interval timing.   High-level methods are provided for sending and receiving messages, with either send-and-reply synchronous-style interactions, or higher performance asynchronous-style interactions.    Message exchanges are typically directed to application servers such as the Hume Integration Datahub, or the dmh_SQLsrv persistent database interface.  The DMH message system is remarkably easy to use because the messages are typically SQL, Tcl, or VFEI text that is directly interpreted by the receiver.   The package also includes DMH server capabilities.

Feature Summary


User Guide

The package distribution includes the following notable items.  Only the DMH.jar file is needed in a runtime environment.  The interface definition files are provided for the convenience of the developer.  They are usually loaded into an integrated development environment to provide class information.
 
The distribution is designed for the portable Java virtual machine platform, version 6.0 (JDK 1.6) and later.   The class library interoperates with recent versions of the Tcl/Tk DMH software running on any platform.
 

Installation

The DMH Java software is distributed as three archive files:
DMH.jar
The Java classes for the com.hume.DMH package. The jar file is typically added to your Java class path.
DMHApplet.zip
Example Swing and Swingx Applets, coded for package DMHApplet and containing pathnames of the form DMHApplet/*.*. This archive also contains the DMH.jar file.  Example HTML documents are included to activate the Applets.
humeDocs.zip
Javadoc documentation which includes the DMH package.  This is an important separate download for a developer who is using an IDE such as Eclipse.  The DMH.jar file should be associated with the humeDocs.zip archive or the extracted contents as its javadoc location.
If you received the DMH software on CDROM, the  files are located in the subdirectory LAN_IMAGE. Installation consists of unzipping these archive files into directories of your choice.

The demonstration applets included with this DMH package, are coded with the package name "DMHApplet". For the simplest web deployment, a directory of this name, DMHApplet, is created from the root directory of your web server, and the files are installed in that directory. For development, see your Java documentation about adding the directory and the DMH.jar file to your CLASSPATH, or loading it into your integrated development environment.

There are alternatives for web server deployment.  It is possible to create jar file archives that contain the class files and your application files.  The startup of your application is sped up if the jar file is pre-installed at the client.  When you use jar files, you need to specify the name of the jar file as one of the options to the HTML markups that identify your Applet.

Development

In your java source code, you will usually include the statement, "import com.hume.DMH.*" near the top of your file. This statement makes the package classes available without full package name references.

Your application will typically use one instance of the DmhClient class or the DmhServer class.  You can declare the instance as part of your application class, and then make it public or pass references to your window and dialog classes.   A single instance of the class can be used for sending and receiving with multiple mailboxes simultaneously.  More than one instance of the DmhClient class is used if you wish to communicate directly with multiple DMH servers.  

If you are not familiar with the DMH message system, you may want to read the mbx Tcl command document which is usually installed at \usr\local\htm85\mann\mbx.html.  If your application acts a DMH message system client, during initialization it attaches to a running DMH server.  Once you are connected to the DMH system, you can exchange messages with other attached processes.

To initialize a DmhClient instance, you only need to know the hostname where the DMH server is running, and the DMH Groupname that has been assigned to the server.   If you click on the Windows "Programs"/"Hume Datahub SDK 8.5"/"Datahub" program item, or start a Datahub process on your POSIX system ("datahub eof &"), you will start a DMH server running on your host, with the default DMH groupname of "mbx".

The usual DMH client application design, and the one that provides the best performance,  is to connect to the DMH server during initialization, and to use this connection during the life of the application.  The init( ) method is used to connect to the server.  The server's hostname and groupname are provided as arguments to the init( ) method.  If the application disconnects from the server, the init( ) command can be used again to restore the connection.

So in your application class you might have code that looks like:
 

import com.hume.DMH.*;   // Hume Integration DMH message system

// class declaration
public class MyApp extends JApplet implements DmhLostServerItf, ... {
    // ...
    public static DmhClient dmh = null;

    // ...
    public void init() {
        // ...
        // construct a single class instance if needed
        if(dmh == null) { dmh = new DmhClient(); }
        // connect to the DMH server on the web server host
        // if not already connected
        if( dmh.getState() == 0) {
            String serverhost;
            try {
                // throws exception if called from static main
                java.net.URL thisURL = getCodeBase();
                serverhost =thisURL.getHost();
             } catch (Exception e) { ; }
            if ( serverhost == null || serverhost.equals(""))  {
                serverhost = dmh.getHostname();
                }
            System.out.println("Connecting to the DMH Server, host=" + serverhost + "group=mbx");
            try {
                dmh.init(serverhost, "mbx");
            } catch (Exception e) {
                String msg="Communication to the application server failed.  Try reloading this web page later.";
                JOptionPane.showMessageDialog(null,
                  msg, "DMH Server Not Online", JOptionPane.WARNING_MESSAGE);
                //setContentPane(offline_panel());
                return;
            }
         }
        // ...
    }

    public void dmhLostServer(DmhClientItf dmh) {
        String msg="Communication to the DMH server has been lost.  The system has probably been shutdown";
       msg = msg + " Reload this web page to try reconnecting.";
        JOptionPane.showMessageDialog(null,
                msg, "Communication Lost", JOptionPane.WARNING_MESSAGE);
    // now disable transaction buttons...
    }
 

Error Handling

A long running program such as a user interface or automation application needs to handle intermittent errors with network outages or server shutdowns.  There are two styles of handling errors; you can mix both styles in your application as you see fit.

The first style of error handling is to avoid them by disabling buttons and window controls that make use of DMH features when there is not a server connection.  You write the statements that enable your buttons after a successful init( ) call, and you write statements that disable the buttons in your dmhLostServer( ) event handler.  During initialization, before you have a connection, call a procedure that you have written to disable the buttons.  Also during initialization, call the init( ) method.  The init( ) method is a synchronous call that does not return until you have setup a connection to the DMH server, or have failed.  When the init( ) call succeeds, call a procedure that you have written to enable your buttons.

The second style of error handling is to add explicit error trapping to your procedures.   The methods that involve network communication can throw exceptions which can be caught with a try{ } and catch( ) statement.

Here is a summary of the kinds of errors that the DMH control will report.  When you make a method call that requires a DMH server connection, and you do not have one, an Exception will be thrown with the text "No DMH server connection".  If you use an improper mailbox name such as one with whitespace in it, an Exception will be thrown with the text, "mailbox name must contain only letters, digits, -, _, ., !, :, or @".   These are the two main errors when calling most of the methods.   Most of the DMH  method calls are then processed asynchronously.  In other words, your method call returns, and the message communication you initiated happens as events are processed.  An error that occurs during event processing results in the dmhLostServer( ) callback being processed.  You do not need to write a dmhLostServer( ) callback handler,  but you probably should to communicate to the users of your program if an error occurs.  You can place logic in your dmhLostServer( )  handler to initiate recovery and resume logic, exit the program, etc.  The init( ) can result in a wider variety of exception returns - see the reference pages.
 

Sending and Receiving - Basics

The programming model of the DMH message system is that you send a plain text message to a destination mailbox.  When sending the message, you can optionally specify the name of a second mailbox for the recipient to send a reply message to.  Usually you send a message to an application logic server such as a Datahub.  The message is usually SQL,  Tcl, or VFEI code that the recipient executes.  If the sender has designated a reply mailbox, the result of executing the command is sent to the reply mailbox.

You can send messages without asking for replies using the put( ) method .  For example,  suppose you are integrating a barcode reader.  When data is read from the barcode reader device, your code is supposed to update a record in a Datahub table.  You will send messages without asking for reply messages - if there is a system shutdown or communication failure, your application will know from the DmhLostServer( ) callback.  This is more efficient than asking for a reply message at every barcode read.  When you send a message without waiting for a reply, it is referred to as an asynchronous send.

Often, you will want to send a message to obtain reply data.  The most convenient method to use is the doXact( ) method.  This method will take care of specifying and using a unique mailbox for your reply message, and it will take care of managing a timer in case a reply message is not forthcoming.  Suppose you want to query a database table, and the DB variable is assigned the mailbox name of the dmh_SQLsrv process.   The online documentation shows that the SQL standard "select" command sends multiple reply messages, but the "telect" command sends a single reply message with all of the requested data formatted as a Tcl list.  The doXact( ) method is designed for a single reply message, so your code looks like:

String reply;
String msg;
msg = "telect device_id from barcode_config where display='" + new hostname() +" '");
reply = dmh.doXact(DB, msg);
if (reply.equals("TIMEOUT")) {
    // timeout or error
    return;
}
// Parse the result- a Tcl List
// element(6) = rows of data, then (0) = first row, then (0) = first item in row
String device_id = TclList.listElement(selection, 6, 0, 0);
 
 

Sending and Receiving - Advanced

If your application needs to receive unsolicited messages from other processes, you use the whenMsg( ) method to setup asynchronous receiving.  When an unsolicited message is received, your specified DmhReceiveItf handler is called.    By convention you should use mailbox names for receiving that end in _SQL if SQL messages are expected, _VFEI if VFEI messages are expected, and _RPC if Tcl messages are expected.   There is no limit to the number of mailboxes that you use for receiving, but the design convention is that you use unique names based on the server function(s) provided.  There should be only one receiving process per mailbox name in a DMH group.  You may wish to create a unique mailbox name for receiving by basing the name on your hostname - see the getHostname( ) method.

The disarm( ) method can be used to unregister an existing whenMsg setup, or all whenMsg setups.

The whenMsg( ) method  functions to receive only one message.  If whenMsgAgain( ) is executed from your receiving event handler, then the logic is re-armed to receive the next message.  So the combination of whenMsg( ) and whenMsgAgain( ) are used for ongoing asynchronous receiving.

Lets revisit the doXact( ) method.  In some situations, you may want higher performance by sending messages and collecting the replies asynchronously, instead of waiting for each reply before sending the next message.  You do this by setting up one or more reply mailboxes and arming them for receiving using the whenMsg( )  method.  Instead of using doXact( ) use the putr( ) command and specify the reply mailbox argument.  Typically a high  performance application will create a small number of unique mailbox names for replies, and re-use them.  If you are creating unique mailboxes for each reply message, use the close( ) method when you are done with each one, to recover resource usage.

Your application should not "live" inside of your message receive handling code.  Be sure to return in due course.  Avoid performing long running computations.

Tcl Lists

The Hume Java package also includes the class TclList, which is able to split text that is formatted as a Tcl list into string elements.  The class has the ability to create Tcl lists that are constructed from multiple list append calls.  The method names and functions are based on corresponding commands found in Tcl.  This class is useful to work with the String values that are returned from SQL table selections from the Hume Datahub or from the dmh_SQLsrv persistent database server.  Also, there is the class TclListModel which behaves like the TclList class and also implements the ListModel and ComboBoxModel interfaces in order to support displaying list data in Swing widgets.  

The class StringList  is a revision of the TclList class made more convenient for use by not throwing exceptions except when attempting construction from improper text. The class does not offer the static list parsing methods that TclList does.

ListBuilder class is for creating text structured as lists where whitespace, and {braces} are used to delimit list elements.   This class has less overhead than TclList or StringList for constructing lists and it does not throw Exceptions.

VFEI Text

The Hume Java package includes the class Vfei2Map which is used to parse text that is formatted according to the SEMATECH VFEI 2.2 (or 2.1)  specification.  VFEI is a self-describing, name-equals-value text format that is used for equipment integration in the Semiconductor industry.  The parser creates or updates entries in the caller's java.util.Hashtable (or other class implementing the Map interface).  The item name String is used as the table entry key, and the entry value is the value String.  A demonstration program, Vfei2MapTest, is provided.  The program is run at the console by entering, "java com.hume.DMH.Vfei2MapTest".  The program parses console input, or file input.  See the source for details.
 

International Character Sets

Java is an excellent choice for International applications because double byte characters are used consistently.  Multibyte UTF-8 character sequences are used by Tcl and DMH to represent International characters.  Conversion between these two formats happens transparently as you send and receive messages.  You should stick with ASCII characters for mailbox names and datahub table names, but feel free to use International text in your message data.

When declaring database tables to hold International text, base the VARCHAR( ) sizes on UTF-8 byte counts, not on the number of characters.  In the most conservative case,  you need to allow 3 bytes per displayed character.

To be successful with International applications you need to make sure that you have installed fonts and chosen fonts in your application that are capable of displaying the characters you require.

Termination

When your application is shutting down, you should call the disconnect( ) method to disconnect gracefully from the DMH server.  Practically speaking the DMH server routinely takes care of situations where clients leave ungracefully, but proper software manners are encouraged.

 

Miscellaneous Notes

An actual network connection is not attempted until init() is called.

You will not usually have more than one connection to a particular DMH server.  It is typical to have only one DMH connection per application process.  It is possible to use multiple controls, each connected to a different DMH Group.

There should be only one reader per mailbox name in a given DMH group.

The  DmhClient class is able to use and resolve DMH groupname aliases as described in the online Tcl documentation.  Groupname aliases are resolved at the DMH server and not at the client.

Mailbox Naming rules:



DmhClient Class Reference

 DmhClient "Properties"
Property Access Description
String getClientID() The DMH server assigns a unique string to each client for identification purposes.  This value is a readonly runtime value providing the server's ID string or an empty string if a connection has not been established. 
int getDefaultTimeout( )
int setDefaultTimeout(int)
The default timeout interval for send and reply transactions, or timed receive invocations.   In seconds - the default value is 30.  Settable range: 1 - 86399.
String getDescription( )
void setDescription(String)
One of the features of the Tcl/Tk DMH Status Window is to provide an action for identifying connected clients.  The default description provided for a Java DMH client is similar to "<hostname>: Java DMH client".  Using the setDescription( ) method, you are able to provide your own description string for your Java application.
String getGroupname( ) Returns the DMH Groupname value which was passed to the DmhClient init() method.
String getHostname(); Returns the TCP/IP hostname of the computer that the control is executing on.  The name is guaranteed to be stripped of domain information.  We have seen that the Microsoft Java VM provides the useless result "localhost" when running in an Applet.
String getMhGroup() The MhGroup property is a readonly runtime value indicating the hostname:port  of the DMH server when connected, else an empty string.  Hostname is the server's idea of his hostname which may be different from the hostname that was specified at the client.
String getProduct()  If this interface is implemented for another product, a different Product() string should be returned in case the using software needs to know the difference. The Hume DMH software returns a two element list with "DMH" as the first element, and a Copyright message as the second element.
int getState( )
 
 
 
 
 
 
 

 

The state property is a read-only value available at runtime.  The value can be read to determine if a healthy communication connection exists, etc.    Applications will ordinarily use event methods and not poll the state property value.  The transient and error states do not last long, so testing for the values 0 or 7 is the most common scenario. 
  0       disconnected
  4       hostname is being resolved
  6       connection setup in progress 
  7       healthy connection exists
  8       connection close in progress
  9       a communication error has occurred  
 
519       DMH protocol setup in progress (519 = &H100 Or 7)
int getTraceBits( )
int setTraceBits(int)
The TraceBits property controls output of diagnostic data to the Trace event.  This value is used as a bitfield with the bit values controlling the following categories of output:

01 data reads
02 data writes
04 message receiving
08 message sending
16 logic tracing
32 background errors

String getVersion( ) Returns a two element list consisting of the DMH protocol version, and the library component configuration management Id string. Current software returns the "1.1" to  as the first element to indicate compatibility with DMH protocol version 1.1.


 
DmhClient Callback Events
Event Callback  and Set Method Description


All callback methods - NOTES
 
 
 
 
 

 

You write your own callback class or classes, and you declare that a class implements the callback interface.  It is possible to implement any or all of the interfaces in one class,  or multiple classes.

// Demonstration of repeated receiving
class WheneverReceive implements DmhReceiveItf {
    public void  dmhReceive(
       DmhClientItf dmh,    // the DMH connection
       String msg,          // the message
       String destBoxName,  // destination mailbox 
       String replyBoxName) // reply mailbox name 
        throws Exception {

      dmh.whenMsgAgain();  // rearm for next message

      // process the received message
      //DMHApplet.theApp.OutputAppend(
      //    "dmhReceive() called: dest=" +
      //  destBoxName + " replyBox=" + replyBoxName +
      //  " msg=" + msg);
      }
}

Then, you register instances of your class(es) to receive the event with the DmhClient:

WheneverReceive wr=new WheneverReceive();
dmh.whenMsg("CLIENTDEMO", wr);

When the event happens, your callback function is called.  A reference to the DmhClient is provided as an argument, in case you are using the same callback with multiple instances of the DmhClient class. 

When registering the LostServer or Trace callbacks, the previous value is returned.  This lets you chain, or swap and restore callbacks. 

public interface
DmhLostServerItf {
  public void dmhLostServer(
    DmhClientItf dmh);
  }

// DmhClient set method
DmhLostServerItf setLostServer(DmhLostServerItf handler);

The LostServer event happens when the DMH connection has been closed from any circumstance such as remote closure, communication failure, error, or invocation of the Disconnect method.  This event is similar to the Tcl lostserver procedure invocation.  The event may happen more than once if multiple errors are being processed.

public interface DmhReceiveItf {
  public void dmhReceive(
    DmhClientItf dmh,
    String data, 
    String destinationBox, 
    String replyMailbox) 
     throws Exception;
}
The Receive callback is executed when a message has arrived.  You can register different callback objects for each destination mailbox using the whenMsg method, described in the next table. 

The destinationBox parameter is a mailbox name that your application has specified when initiating receiving.  If the sender of the message indicated a reply mailbox, it is passed as the replyMailbox.  If no reply mailbox has been specified, the replyMailbox argument is an empty string.  The data argument is the text of the sent message.  The DmhClient  logic protects you from receiving another message for the DestinationMailbox, and re-entering your handler logic until you have returned from the current callback execution. 

public interface 
DmhTraceItf {
  public void dmhTrace(
    DmhClientItf dmh, 
    String traceMessage);
    }

// DmhClient set method
DMHTraceItf setTrace(DMHTraceItf handler)

This event provides diagnostic and debug information per the TraceBits property setting.  Your application needs to avoid creating new DMH activity in the Trace event callback, that in return causes Trace events.  A cycle of positive feedback is possible which will cause a software fission reaction.

DmhClient Methods
METHOD DESCRIPTION

All methods - NOTES
If the method throws Exceptions, it is generally true that if the method is called when there is not a connection to the DMH server, an Exception will be raised.   In this situation, the text of the Exception is "No DMH server connection".
void close(String boxname) throws Exception; Stop using a mailbox - Disarm receiving if listening, Flush if not empty,  and remove from existence if it exists.  The Tcl version of this call, differs because it will not flush existing messages.
int[] count(String boxname) throws Exception;
Returns an array of three numbers, the total count of messages that have been sent to the mailbox, the total count of messages that have been consumed from the mailbox, and last, the current count of pending messages.  A pending message is one that exists in the queue associated with the mailbox, and has not been consumed by reading or flushing.
public void disarm(String boxname) throws Exception;
public void disarm() throws Exception;
Un-register the listener from a specified  mailbox.  This call may be used to cancel an earlier whenMsg( ) call. 

If called with no arguments, all whenMsg( ) receiving registrations are canceled. 

void disconnect(); The counterpart of init( ); disconnects from the DMH server.  The call also cancels all receiving.  Has no effect if not connected.
DmhClient() The class constructor takes no arguments.
String doXact(String destbox, String msg) throws Exception;

String doXact(String destbox, String msg, int seconds_timeout) throws Exception;

String doXact(String destbox, String msg, String replybox) throws Exception;

String doXact(String destbox, String msg, String replybox, int seconds_timeout) throws Exception;

 

Performs a complete send and reply transaction with timeout management.  Creates and manages a unique reply mailbox for the send and reply transaction if the replybox argument is defaulted.  If the timeout is not specified, the DefaultTimeout value is used.  The usual reply is the text of the reply message. The String literal TIMEOUT is returned in case of failure.

If you specify a ReplyMailbox, you need to insure that the name you specify is only used by your application.  It is usual to create a unique reply mailbox name, perhaps based on the hostname, assign it to a variable, and use it repeatedly.

If you are not connected, the call fails immediately with an Exception. 

void flush(String boxname) throws Exception;
Empty a mailbox of any pending messages.  A pending message is one that has been sent to the mailbox but has not been consumed.  In other words, a pending message is waiting in a queue associated with the  mailbox name.  Messages are consumed by reading or flushing.
int groupnamePort(String Groupname)
Used to determine the TCP/IP port number that is used by the DMH server to listen for client connections.  The method is equivalent to the mh_name_to_socket Tcl procedure.  Most applications will not have a use for this method since the server socket port is managed by the DMH software. 
String init(String hostname, String groupname) throws Exception;

String init(String hostname, int port) throws Exception;

 

Performs the initial connection to the DMH message server. The connection will be setup or an exception result will be obtained before returning.

If the connection to the DMH server is ever lost, the LostServer( ) event is fired.

 

void put(String mailbox, String message) throws Exception; The put( ) method sends a message to a mailbox with no reply mailbox indicated. 

The doublebyte String characters are converted to UTF-8 encoding, so that you can safely send  International characters.

Sending to the mailbox name "TRACE" sends the message to the DMH Server Trace Facility.

void putr(String destbox, String replybox, String message) throws Exception; Sends a message to a mailbox with a reply mailbox indicated.   By convention, when a reply mailbox is indicated for a command message sent to a Datahub mailbox or equipment interface mailbox, the command is processed, and a reply message is sent to the reply mailbox. 

Sending to the mailbox name "TRACE" sends the message to the DMH Server Trace Facility.

String serverStatus() throws Exception;
 
 
 
 
 

 

Returns a Tcl list containing the information presented in the Tcl DMH status window.  The information can be parsed by the application to determine  status information on every mailbox that is currently in use.  This command may be useful for debugging, and is not used by ordinary applications.

The first element of the list is a list of 5 elements:
{ hostname:port messagesReceived messagesSent messagesQueued tcl_version }

Subsequent elements in the list are lists of four or five elements:
{ mailboxName countIn countOut countPending [readerHandle] }

Additional elements may exist in the list if there are DMH clients that are not currently waiting to receive messages.  These elements are formatted as:
{{{no whenmsg pending}} - - - readerHandle}

String timedReceive(String boxname, int secondsTimeout) throws Exception; Waits for a message to be received in the specified mailbox.  If the call succeeds,  the return value is the message data.  If the call fails, the return value is the literal string "TIMEOUT". 

If you are not connected, the call fails immediately with an Exception.

void whenMsg(String boxname, DmhReceiveItf handler) throws Exception;
Register for receiving the next available message directed to the specified mailbox.  Calling whenMsgAgain( ) in your DmhReceive( ) event handling code re-arms the receive registration for the next message.
void whenMsgAgain() throws Exception; The whenMsg( ) method functions as a one-shot.  In other words, receiving is stopped after receiving one message.  Calling the whenMsgAgain method from the receive handler re-registers to receive the next message.
String[][] whenMsgDump(); The whenMsgDump method returns an array of string pairs (String [N][2]).  Each pair consists of [][0] a mailbox name, and [][1] the result of executing the toString( ) method of the DmhReceiveItf object.  This command may be useful for debugging, and is not used by ordinary applications.
  String reply[][];
  try {
      reply = dmh.whenMsgDump();
      OutputAppend("whenMsgDump:");
      for(int i=0; i< reply.length; i++) {
          OutputAppend("box=" + reply[i][0] +
            "  obj=" + reply[i][1]);
      }
  } catch (Exception e) { 
      OutputAppend( "Exception:" + e);
  } 


DmhServer Class Reference

The DmhServer class implements both the DmhClientItf interface and the DmhServerItf interface.   All of the reference material for the DmhClient Class, above, is relevant, with the understanding that the "connection" between the client and server is directly made without network communication.  The initialization methods, init( ), create an instance of a server socket on your TCP/IP host that other DMH clients can connect to and exchange DMH messages.  The client connection may be made from any supported platform and language environment including the C++, Java, Tcl/Tk, and the Visual Basic OCX.  The DmhServer reference, below, only highlights the additions and changes to the DmhClient reference material, above.
 
 DmhServer  Additional "Properties"
Property Access Description
public void addAlias(String  groupname);

public String [] getAliases();

A DMH mailbox name can have an optional DMH group name specification, for example, HUB@TESTFLOOR.  The software recognizes and removes group names that map to the actual DMH group served by the DmhServer instance.  This feature can be exploited to provide the concept of multiple virtual DMH groups in a single physical server.  A typical user will not need to use these methods.  The present Java server version does not provide gateway forwarding across groups as the Tcl server does.  So the alias definitions should all resolve to the server's own group.
public String getDescription( )
public void setDescription(String)
After the init( ) call is made, the default description for the server is set to a string like "(DMH Server MhGroup) (java port)".  To customize the identity description, the setDescription( ) call should be used after the init( ) call is made.  The description is seen from the DMH Status window of Tcl/Tk clients by using the "Identity" action.

 
 DmhServer  Additional Callback Events
Event Callback  and Set Method Description
public interface DmhLostClientItf {
    public void dmhLostClient(
              DmhServerItf server, String clientID, boolean superseded);
    }

public DmhLostClientItf 
setLostClient(DmhLostClientItf dlc);

The LostClient event happens when the DMH connection to a client has been closed from any circumstance such as remote closure, communication failure, error, or invocation of the clientDisconnect() method.  The clientID string can be used in conjunction with the serverStatus() result to determine which mailboxes were in use.
public interface DmhReceiveItf {
  public void dmhReceive(
    DmhClientItf dmh,
    String data, 
    String destinationBox, 
    String replyMailbox) 
     throws Exception;
}

public DmhReceiveItf 
setTraceMsg(DmhReceiveItf traceReceive);

The TRACE message event happens when messages are sent to the TRACE mailbox.  The default handler is System.out.println( ) with timestamp decoration.  You can replace the handling of TRACE messages in your application.  Do not perform time-consuming manipulation in your TRACE message handling logic.

 
 DmhServer  Additional & Revised Methods
METHOD DESCRIPTION
public void clientDisconnect(String clientID); Close a client's DMH connection to the server.
public String clientIdentify(String clientID) Ask the client to provide his hostname, command line, and DISPLAY name as a String result.
public void clientPing(String clientID); Exercise the network connection to a client which causes an error and connection close if the client is no longer present. 
public void clientTerminate(String clientID); Tell the client to exit, which is honored by Tcl & Java clients,  and by VB clients if the developer codes the Shutdown() callback. 
void close(String boxname) throws Exception; Equivalent to the client version of close() - called to stop using a mailbox - Disarm receiving if listening, Flush if not empty,  and remove from existence if it exists. 
DmhServer() The class constructor does not require any arguments.
public String init(String groupname) throws Exception;

public String init(int port) throws Exception;

String init(String hostname, String groupname) throws Exception;

String init(String hostname, int port) throws Exception

Begin functioning on a TCP/IP port as a DMH server.  The DMH group may be specified as a name, or as a socket port.  The default group name for clients has been "mbx" which is mapped to the port number 5328.  The mapping of a group name can be determined using the DmhClient method groupnamePort().  You can optionally specify which of your network interfaces to serve on.  The name "localhost" will make the server visible to other processes on the same computer who also specify the hostname "localhost", and leave the server invisible on the network. 

If you have more than one network interface on your computer, you may specify the one to serve on.  If you do not specify a hostname or dotted IP address, you get default behavior.  It seems that default behavior will always make your server visible on the "localhost" and on the default hostname interface.  On some platforms, default behavior will also make your server visible on all enabled network interfaces.  You can determine your default hostname by executing the command "hostname" at the prompt of a command shell window.

public String lastRead(String boxname); To support debugging, the DMH server keeps a copy of the last message sent to each mailbox.  In the Tcl versions, the global array  mh_last_read is used.  You can know what mailboxes are in use from the serverStatus() call.  A typical user will not need this method.
public static void main(String argv[]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
For simple use and testing, there is a static main method which allows the com.hume.DmhServer class to be run as a standalone application.  The optional command line arguments are of the form [groupName [TraceBits]].  The server listens to mailbox "DMH" for the following command messages:
 
addAlias <groupname>
Equivalent to the Java method of the same name.
echo [<arg>]*
Echoes the message text to the reply mailbox.
exit
Does a shutdown and calls System.exit(0).
getAliases
Equivalent to the Java method of the same name.
getClientID [<boxname>]
Returns the client ID of the DMH client who is waiting to receive on a specified boxname.  If no boxname is specified, the result is for the client who is receiving the reply message.
lastRead <boxname>
Equivalent to the Java method of the same name.
mh_msgs <boxname>
Equivalent to the Java getMhMsgs() method.
set tracebits [<n>]
Used to set or query the TraceBits property. The TraceBits should be set to 0 in a production system since tracing activity has a huge detrimental impact on server performance.
shutdown
Equivalent to the Java method of the same name.  Since the application has no other threads running, the process exits.
An example command to invoke the server is:
set CLASSPATH=c:\hume;
"c:\Program Files\Java\jdk1.6.0_20\bin\java.exe" com.hume.DMH.DmhServer mbx 0
public String getMhMsgs(String boxname);
 
 
 
 
 
The Datahub Tcl server makes it seem like there is a global array mh_msgs which has all of the queued DMH messages.  The array does not physically exist - the read accesses are trapped and the queue data is converted to variable form on demand.  There is risk of the user causing huge amounts of additional memory use by viewing a message queue that has a lot pending message data.   This is a documented feature, and an acceptable design, because computing history has shown that what we consider huge today is ordinary and reasonable in a few years.  The Java server supports the equivalent feature, which is used for debugging and diagnosis.  The String result is a formatted list of pairs, where each pair is a list of the message body and the reply mailbox.  If there is  no reply mailbox, the second element of the pair is an empty list. For example:

 "{{hello world message} MY_REPLYBOX} {{sent w/o replybox} {}}"

public void shutdown(); Shutdown the server and close all existing client connections.

 


TclList, StringList, and ListBuilder Class Reference

Detailed javadoc API information for these classes is now being built from the com.hume.DMH package source code.   See the Hume website java directory to browse the latest javadocs.  Datahub SDK customers should download the humeDocs.zip archive for in-context viewing and prompting within Eclipse or NetBeans.

The TclList class provides methods to parse or construct text Strings that are formatted per the list conventions of the Tcl programming environment.  Tcl uses braces to delimit white space, and backslash character sequences are also possible.  Most of the methods listed in the table below throw ListFormatExceptions because not all strings are valid Tcl lists.  The class also implements java.io.Serializable and java.lang.Cloneable.  The class and methods are safe for use from multiple threads. 
 
TclList Public Methods
METHOD DESCRIPTION
TclList(String s)
TclList()
The constructors.  To work with String text that is formatted as a Tcl list, pass the text as the constructor argument.  For creating a new empty Tcl list, use the empty constructor.  A new empty list can also be constructed by passing a null or empty string constructor argument.
String join() Used to obtain the text of the constructed Tcl list.
void lappend(String element) throws ListFormatException
void lappend(String e1, String e2) throws ListFormatException
void lappend(String e1, String e2, String e3) throws ListFormatException
void lappend(String e1, String e2, String e3, String e4) throws ListFormatException
List append - adds one to four string elements at the end of the list. 
String lindex(int n) throws ListFormatException Obtain the string element at the specified index.  Indexing starts with 0.  An empty string is returned if the index is out of range.
static String lindex(String s, int n) throws ListFormatException Use this method to grab elements in a list without constructing a TclList object.  The method caches a parsed representation of the last String argument, so successive calls to lindex on the same string are processed rapidly.
void linsert(String e, int index) throws ListFormatException List insert - add an element at index N, sliding existing elements +1.
static String listElement(String s, int index1) throws ListFormatException

static String listElement(String s, int index1, int index2) throws ListFormatException

static String listElement(String s, int index1, int index2, int index3) throws ListFormatException

These are convenience methods to parse elements in a list without constructing a TclList object.  If a single index is specified, the method is identical to the static lindex( ) method.  Additional indexes may be specified to parse lists that are nested inside of lists.  If a specified index is out of bounds, an empty string is returned.   Similar methods are provided with the DMH Active-X control, and the DMH C++ client software.
int length() throws ListFormatException
int llength() throws ListFormatException
Returns the number of elements in the list - the list length.
void remove(int index) throws ListFormatException Removes a single element at a given index, shortening the list.  The index must be in the range of 0 to llength( )-1.
void remove(int indexes[]) throws ListFormatException Removes multiple elements at specified indexes, shortening the list.
void replace(int index, String element) throws ListFormatException Replaces a single element at a given index.
String[] split() throws Exception
static String [] split(String s) throws ListFormatException
Returns a string array representing the elements of the list. There is also a static version for parsing a list without creating a TclList instance.
String toString() Returns the result of join( ).  This method causes operations like string concatenation to work with TclList objects.

 
 


TclListModel Class Reference

The TclListModel class provides the list data manipulation of the TclList class, and also implements the ListModel and ComboBoxModel interfaces that are needed to support Swing listbox and combobox display widgets.  The class also implements java.io.Serializable and java.lang.Cloneable.  The class and methods are safe for use from multiple threads.
 
 
TclListModel Public Methods
METHOD DESCRIPTION
TclListModel(String s)
TclListModel()
The constructors.  To work with String text that is formatted as a Tcl list, pass the text as the constructor argument.  For creating a new empty Tcl list, use the empty constructor.  A new empty list can also be constructed by passing a null or empty string constructor argument.
void addListDataListener(ListDataListener l) Supports the ListModel interface.
Object getElementAt(int i) Similar to lindex( ).  Returns null if the list is invalid.  Supports the ListModel interface.
Object getSelectedItem() Supports the ComboBoxModel interface.
int getSize() Similar to llength().  Returns -1 if the list is invalid.  Supports the ListModel interface.
String join() Used to obtain the text of the constructed Tcl list.
void lappend(String element) throws Exception List append - adds a string element at the end of the list. 
String lindex(int n) throws Exception Obtain the string element at the specified index.  Indexing starts with 0.  An empty string is returned if the index is out of range.
void linsert(String e, int index) throws Exception List insert - add an element at index N, sliding existing elements +1.
int llength() throws Exception Returns the number of elements in the list - the list length.
Object remove(int index)  Removes a single element at a given index, shortening the list.  The index must be in the range of 0 to llength( )-1.
void removeListDataListener(ListDataListener l Supports the ListModel interface.
void replace(int index, String element) throws Exception Replaces a single element at a given index.
void setSelectedItem() Supports the ComboBoxModel interface.
String[] split() throws Exception Returns a string array representing the elements of the list.
String toString() Returns the result of join( ).  This method causes operations like string concatenation to work with TclList objects.



HisTimer Class Reference

The HisTimer class has the ability to call a timeout method on your object after a specified time interval.  The timer starts running when it is instantiated and is discarded after one use.
 
HisTimer Callback Events
Event Callback Description
package com.hume.DMH;

public interface HisTimeoutItf {
   public void hisTimeout(Object obj) throws Exception;
   }

This is the callback interface that a timer uses to notify you that your interval has expired.  The Object argument references the timer so you can see which timer has expired.  We let you throw exceptions so you do not have to code everything in try blocks.
HisTimer Methods
Method Description
public HisTimer(long millisecs, HisTimeoutItf target); The constructor.


Vfei2Map Class Reference

The Vfei2Map class is used to parse text that is formatted according to the SEMATECH VFEI Specification #95113016A-TR.
 
Vfei2Map Methods
Method Description
public static int parse(String VFEItext, java.util.Map NameValues) throws Exception The parse method is static which means that no instances of the class are needed to call the method. 

The Map interface is implemented by the java.util.Hashtable class, and instances of this class are usually passed as the second argument. 

The return value is the count of new entries that were added to the Map table.  Usually, the caller empties the table before calling the method, in which case the count indicates the number of (name, value) pairs parsed from the string.

Backslashes can be used to escape imbedded quotes.  Other backslash escape sequences are left in the value strings as they are found.  Otherwise, the parsing is the same as the Hume developed Tcl vfei_2_array command.

The method can throw Exceptions for input text that is not proper VFEI.  No Exception is thrown for blank text.

See the com.hume.DMH.Vfei2MapTest.java file for example code that uses this class.


License Terms

Subject to Change Without Notice

The Hume DMH Java software is licensed for development and runtime use at no additional charge for computers that are licensed for development or runtime use of the Hume Integration Datahub SDK.  Hume Integration is also pleased to offer separate runtime licenses for using the Java software on systems that are not licensed for the Datahub SDK.  Runtime usage of the DMH client software can be licensed separately from the Datahub SDK runtime license at a lower cost.  Contact Hume Integration directly for current terms.


Document Version

The API was refactored in January 2006 for better conformance to Java community naming conventions.

Date of last revision: $Date: 2017/08/10 18:22:09 $