Developing your System

This section details the elements necessary for developing Tymeac Systems in your installation.

It's really very simple. It's the first time through here that's a little confusing.

Tymeac development comprises four elements:

  1. The Processing Application Class that executes the application code.
  2. The Queue in which the Processing Application Class resides.
  3. The Function in which the Queue resides.
  4. The Client that calls the Tymeac Server.

... and four related subjects:

  1. System Wide Variables
  2. Testing.
  3. The user exit structure.
  4. The overall structure.

For an overview of how the Client and Server interact, see here.

divider.gif (931 bytes)

A Tymeac Function is basically a list of Tymeac Queues.

 

TyF.gif (2230 bytes)

 

A Tymeac Queue contains a list of waiting requests, called Wait Lists, the Threads of execution that make Tymeac a multi-threading container and the Processing Application Class that contains the user code.

 

QWLT3.gif (4584 bytes)

 

A Processing Application Class is the code you write to process the specifics of the application. A Tymeac Queue Thread uses reflection to invoke the main() method of your class.

This is the decoupling that is so important in good application design. Multi-threading is very difficult since not only does the developer have to write the application logic, the developer also has to write the threading logic (wait(), notify(), synchronize() etc.)

You supply the application logic in a Processing Application Class. Tymeac handles the threading logic.

divider.gif (931 bytes)

Preface

A Client wants to execute a method on the Server and it wants the method to use current data. Therefore, the Client passes the current data (what we call "input") to the code. The Client wants two things from the Server:

  1. A response that says the Server worked perfectly.
  2. The result of the application method working on the current data, what we call "returned data".

Let's say the Server calculates Celsius based on Fahrenheit. The Client passes a Fahrenheit number "input" to the Server and the Server returns a Celsius number "returned data" to the Client. Additionally, Tymeac includes a String indicating how the Tymeac Server performed (not the underlying application.)

The Client can wait for the process to complete, a Synchronous Request.

The Client may not wait for the process to complete. This is an Asynchronous Request, also called autonomous processing. In such a case, how would the Client ever know what happened and where would the "returned data" go? The Server code could transmit it to the Client in the network. Unfortunately, this would make the application code very complex.

Tymeac's answer to overly complex applications is to separate the do-the-work from the what-now. The application method (do-the-work) calculates the Celsius number, wraps it in an Object and returns the Object to the Server. The Server returns the Object to the Client for a Synchronous Request.

For the Asynchronous Request the Server may (this is optional) put the returned Object in a Queue called the Output Agent Queue. An Output Agent Queue is just like any other Tymeac Queue. It has Wait Lists, threads and another Processing Application Class that you write. This is where you may put the what-now code.

For example, when you wish the Client to receive the "returned data" on the network you would do the following:

First you must write two Processing Application Classes:

  1. DoTempConv -- Converts Fahrenheit.to Celsius.
  2. SendToNetwork -- Sends the Converted Object to the user.

Then you define

  • a Tymeac Function called "Convert" that contains a normal Tymeac Queue called "FtoC" (short for Fahrenheit to Celsius) and Output Agent Queue called "PutOnNet".

                                             TyFdemo.gif (2501 bytes)

  • a Tymeac Queue called "FtoC" that uses a Processing Application Class called "DoTempConv".

                                        QWLT2demo.gif (4685 bytes)

  • a Tymeac Output Agent Queue called "PutOnNet" that uses a Processing Application Class called "SendToNetwork".

                                                        QWLT3demo.gif (4794 bytes)

Now at execution time:

  • The Client does an Asynchronous Request to the Tymeac Server passing the Fahrenheit number "input"

  • The Tymeac Server puts the "input" into Queue "Convert". A Queue Thread associated with this Queue picks up the "input" and using Java Reflection invokes the main() method of Class "DoTempConv".

  • The "DoTempConv" Class returns an Object "Converted" to the Queue Thread.

  • The Queue Thread puts the "Converted" object, which is now a new "input", into Queue "PutOnNet". An Output Agent Thread associated with this Queue picks up the new "input" and using Java Reflection invokes the main() method of Class "SendToNetwork".

  • The "SendToNetwork" Class passes the "Converted" object to the network.

 

Pic2.gif (6522 bytes)

 

Now if that was all there was to Tymeac, then it would be a very nice backend process manager. But there is more. Tymeac is also a Request Broker. Your Tymeac Functions may contain multiple Tymeac Queues.

What if your "input" Fahrenheit number also needs converting to a second or third scale? No problem. You simple write the Processing Application Class to do this conversion. Define Tymeac Queues as above. Add the new Queues to the Tymeac Function. Now when you execute this Tymeac Function, you get back all the conversions in one Object array.

The details begin with the Processing Application Class.


Processing Application Class (or base Class)

If this is your first time through here, we suggest you take a quick tour of this material without all the detail.

Tymeac utilizes two types of applications:

  1. A normal application
    This application receives input from a Client and may return an object.
    The returned object may pass back to the calling Client or, when an asynchronous request,
    the returned object may be passed on to an Output Agent application.
  1. An Output Agent application
    This optional application receives the returned object(s) from the normal application(s) for asynchronous requests.

    That is just so confusing, but wait, examples are forthcoming.

Your Processing Application Class (base Class) must have a public static main() method that accepts an Object array.

public static Object main(Object[] args) {}
public static void     main(Object[] args) {} (has no returned data)

The Queue Thread uses a java.lang.reflect.Method invoke() for your base Class passing an Object array (Object args[]) ):

  1. The first Object (arg[0])  is either
    1. the optional input data from the Tymeac Client contained in the Tymeac parameter,
      Normal Processing ApplicationClass, or
         
    2. an Object array when this is an Output Agent Processing Application Class. The Object array is the array of all the return Objects from the normal Processing Application Classes. (See here.)

  2. The second Object (arg[1]) is a reference (TymeacInterface) to the Tymeac Server. You may use this reference for recursion processing or pass it along to another Class.

For examples see the Demo Classes we supply in the sample directory. A snippet of the code is presented in the following documents.

Demo1.java -- is a normal Processing Application Class. It receives input data from a Tymeac Client.

DemoAgent1.java -- is an Output Agent Processing Application Class. It receives an Object array of the return Objects of the normal Processing Application Classes.

DemoRecur.java -- is an example of recursion processing. It uses the second argument (arg[1]) to call the Tymeac Server.

The main() method Return Type may be an Object, void, another class or primitive. Tymeac passes the return value back to the Synchronous Request in an Object array or on to the Output Agent in an Object array. Therefore, it is up to the receiving module to interpret this Object. (For maximum flexibility, we recommend using a return type of Object and casting any return class to Object, or, wrapping a primitive in an object and casting it to Object.)

The first object in the returned Object array is the result of Tymeac Processing.
This is always a String.
For a Synchronous Request:
   Tymeac SR(0000)

  • Tymeac is the prefix.
  • SR stands for Synchronous Request.
  • (nnnn) Return code, should be 0000. When the number in parentheses is not zero, then check the return code document for the failure reason.

The other objects in the returned Object array are the result of YOUR processing. YOUR objects may be any object that implements the interface serializable.

For an Asynchronous Request there is only one String object in the returned Object array:
   Tymeac AR(0000)[session id, request id]

  • Tymeac is the prefix.
  • AR stands for Asynchronous Request.
  • (nnnn) Return code, should be 0000. When the number in parentheses is not zero, then check the return code document for the failure reason.
  • The data in brackets are:
    • Session Id -- The System time in milliseconds since 1970. MilliTime also appears on the start up and shut down messages  It is the way to identify this session of Tymeac. When you wish to inquire about the status of an asynchronous request, this Id is necessary, see the Request Status Class.
    • Request Id -- A unique number assigned to every request starting at one (1). When you wish to inquire about the status or to cancel an asynchronous request, this Id is necessary, see the Request Status Class.

For a Shut down Request there is only one String object in the returned Object array:
   Tymeac SD(0000)

  • Tymeac is the prefix.
  • SD stands for Shut Down.
  • (nnnn) Return code, should be 0000. When the number in parentheses is not zero, then check the return code document for the reason.

The public is so that Tymeac may find your base Class. The static is so that no instance of your base Class is necessary, eliminating constructors (called a Class Method).

Since this main() is static other method references by code in main() must also be static. However, there is no restriction on new instances of other Classes (composition). his means that the main() method can be a base for the rest of your functionality including loading other Classes, using a transport mechanism (like RMI or CORBA) or Servlets.

The Queue Thread invokes your base Class with a:
Object  return_data = ...invoke()...

The Output Agent Queue Thread invokes your Class with an:
...invoke()...  ( no return value specified.)


Additional Subjects:

Canceling a working request
Yes, it is possible, see here.

Access
Tymeac needs access to your Processing Application Class therefore, Tymeac must be able to load that class into the Java Virtual Machine. Two option are available:

  1. Using the Java Class Path:
    Tymeac uses a custom Class Loader with the method, findSystemClass(), for your base Class. The base Class is the Class you define in the Tymeac Queue. Therefore, your base Class must be a local Class (on the CLASSPATH,  -cp or codebase).

  2. Using URL's:
    Tymeac uses a URLClassLoader with the list of URL's specified along with the class name. See the class naming and URL document for details of how to specify a URL list.

Security
Tymeac handles Security Exceptions in that it sets all Queue Threads as unavailable for requests (status: disabled). Therefore, you must address all security issues before starting Tymeac Server.

You should catch exceptions.
The Tymeac Queue Thread invokes your base Class in a "try" block. Exceptions for this reflect.Method are caught, including, "Throwable". Tymeac processes a caught exception by logging a message, sending a notification, and disabling the thread. If this is the action you wish to take, then rethrow the exception. See also the return codes for Queue Threads.

When should you rethrow the exception? Anytime the situation requires manual intervention, that is, it's broken beyond what error recovery code can handle. An example is a corrupt file or database, a programming error or any critical resource that is not available.

Once you rethrow the exception, the thread is marked "disabled". Once all threads are "disabled" the Queue is no longer functional. The Tymeac Monitor sends a notification when all threads are disabled.

If the exception was due to a programming error, then you may fix the logic, recompile the module, use the New Copy to get a new copy of the Class and enable the Queue Threads with the enable button on the Queue Threads Display/Alter.

If you can fix the problem without taking down the Server then you may enable the Queue Threads as above.

Re-loading Classes
During testing it is common that the base Class you develop may need adjusting. It is not necessary to shut down and restart Tymeac every time a change is necessary. The Tymeac Class, TyNewCopy, is available to re-load the base class or load an alternate base Class during execution.

N.B. -- Classes already loaded by the Virtual Machine through a classpath cannot be unloaded (at this time.) Therefore, if you need changes to the base class, then you must use a URL to load the class. This also holds true for any classes your base class loads. See the class naming and URL document.

Long running processes pose a potential problem. 
Tymeac is a process NOW system. The structure is to accept a work request, process that request as quickly as possible and fetch the next request. There is no facility within Tymeac to process the request at a later time. However, there are numerous middleware, message-queuing systems on the market. The scope of these systems is that one sends a message (this could be the parameters for Tymeac) to a message queue with instructions to deliver the message to another message queue at a later time.

Tymeac keeps track of the time the Queue Thread is executing within the reflection invoked base class and may flag the Queue Thread as possibly stalled. The result of this is that the Queue Thread's status becomes 'cancelled' or 'disabled'. When all Queue Threads within a Queue have either of these status codes, the Queue cannot accept any more requests (Scheduling failure).

If the processing is just slow, then the potential for a problem is small. However, if this is truly a long running process then one may use the Queue timeout value to increase the time Tymeac allows the reflection invoked code to execute before flagging it as possibly stalled.

This flagging has no affect on the executing Processing Application Class. It simply changes the Queue Thread's status code. If the Processing Application Class finishes processing, the Queue Thread resets the status code.

Compiling:
The Tymeac Classes (TymeacInterface, TymeacParm, etc.) are in package com.tymeac.base, in the directory, <TymeacHome>/Classes. Import the package com.tymeac.base in the user classes that require access to the Tymeac Classes and include the proper directory for the compiler.

"Sharing" conflicts:
Since your Processing Application Class runs as a Java Thread, there may be many threads of execution using this same code. Java provides two ways for preserving integrity on shared objects. These are:

  1. the synchronized modifier on the method definition
        public synchronized void yourMethod() {}
  2. and the synchronized statement
        synchronized (object) {}

When locking spans multiple methods, then the second way is preferable. However, confusion sometimes arises over how one may get a reference to a shared object (the (object) in the synchronized statement.)

The simplest way is to lock on a Class object (e.g. synchronized (MyClass.class) {}).

Another is to use a Singleton Class (i.e. There are numerous examples of this technique in the Sun archives, developerWorks.com and JavaWorld.com.)

One common way is to use a public Class with static fields. See the User Exit structure, below.

Not only does "synchronized" lock out other threads, it reads/writes the thread's variables from/to main memory.

In Java, main memory is where all variables live. (See the Java Memory Model, Chapter 17 of the Java Language Specification) Each thread has a copy of  the variables it uses. When a thread writes a value to a variable, it is the thread's copy of the variable that gets modified. Eventually, Java writes the value to main memory.

Therefore, if another thread looks at a variable, it may see the value of the main memory variable before Java updates the main memory.

The solution is to synchronize.

"Java Synchronized" is only one way of working in a multi-threaded environment. This is the simplest method, often called the "single threaded" approach -- only one thread may access the resource at a time. Inter-process communication using:

  • shared memory,
  • private semaphores,
  • locks with a:
    • DBMS,
    • Queuing Facility, or
    • JavaSpaces
  • and any propriety software products provide many more.

However, one must remember that Tymeac controls the threads -- instantiation, termination, wait(), notify(), etc. Although you may pass a thread-object reference (java.lang.Thread.currentThread() ) to a private product, there is a potential for conflict if that product uses wait(), notify() or other methods from java.lang.Object or Thread.

  • Tymeac may believe a stall condition is present in the Processing Application Class when that application waits for an excessive amount of time.
  • When using the Queue Thread alteration GUI or the New Copy GUI, one may purge threads that have a reference stored in a private Vector. Although Tymeac believes the thread is gone, the thread may resume execution and results are unpredictable.
  • Since only Tymeac controls the threads, private techniques for flushing, resetting and restarting threads in private resources are not available.

RunTime Information
Tymeac maintains information about the currently executing Tymeac Server. This information is available to any Processing Application Class or User Exit.

The Singleton
Tymeac maintains a user singleton class into which you may put any objects for use by your runtime classes for sharing between threads.

ShutDown
There are two implementation methods for shut down:

  1. public String shutRequest(); -- This is the old version and is the same as the second with a boolean false.

  2. public String shutRequest(boolean kill); -- This version supports forcing termination in the case when there are unresponsive Queue Threads. For all normal shut down requests, you should set the boolean to false or simply use version 1. If normal shutdown cannot progress and you need the Server down quickly, then set the boolean to true.

Queues

A Queue constructs with the Queue Maintenance Class, TyQueMaint.

All three parts of a Queue work together; Threads, Wait Lists, and your Processing Application Class.

After you write the Processing Application Class, above, you define the environment in which it is to execute, the Queue.

The client request goes into a Queue's Wait List. A Queue Thread picks up the request, invokes your Processing Application Class, saves the return Object from your Class and repeats that cycle until there are no more requests.

For a Synchronous Request, the array of return Objects is passed back to the client.

For an Asynchronous Request, the array of return Objects may go into an Output Agent Queue's Wait List. An Agent Queue Thread picks up the request, invokes your Processing Application Class and repeats that cycle until there are no more requests.

How many threads in the Queue and the number of Wait Lists are determined by processing requirements. The Queue Maintenance Class, TyQueMaint, discusses these.

Functions

A Function constructs with the Function Maintenance Class, TyFuncMaint.

After you define the Queue, above, the component part of a request, you set up the way by which Queues tie together, the Function.

The client requests a Function. The Function contains Queues. Each Queue contains your Processing Application Class.

Each Function has one or more Queues associated with it. For example, refer to the Tymeac Demonstration System:

Class, Demo1, is a Processing Application Class.
Queue, AAAA, is a Queue that uses Demo1.
Function, Function_2, is a Function that uses Queue AAAA.

Class, Demo2, is a Processing Application Class.
Queue, BBBB, is a Queue that uses Demo2.
Function, Function_3, is a Function that uses Queues AAAA and BBBB.

Tymeac supports two types of requests: Synchronous and Asynchronous.

A Synchronous Request schedules the Queues in the Function, waits until all Queue's finish processing and returns the "return Objects" of all the Processing Application Classes to the client in an array.

An Asynchronous Request schedules the Queues in the Function and returns control to the client.

As part of an Asynchronous Request, it is often useful to do something with the "return Objects" of all the Processing Application Classes. This is the purpose of the Output Agent Queue.

As part of the definition of a Function is the option of an Output Agent Queue. When the last Queue Thread finishes processing the request (the order of which is irrelevant):

  • it builds an array of all the of the "return Objects" of all the Queues in the Function that is latter passed to the Processing Application Class as the first Object (arg[0])
  • it schedules the Output Agent Queue.

For an overview of  Tymeac processing, with drawings, see the Tymeac Overview.

Tymeac Client

The client access to the Tymeac Server is with the parameter the client passes to the Tymeac Server and the communication code.

The parameter is Class TymeacParm. The input Object (passed to all Processing Application Classes), is optional.

The communication code is the variable. We supply a framework Class, TySvrComm. However, you may develop any Class you wish. Processing before and after this class is purely application oriented.

We supply several demonstration classes that are Tymeac Clients: [prefix com.tymeac.demo..]

  • DemoClientBase -- base from which other classes inherit.
  • DemoClient_1 - _8
  • TyDemoT1, TyDemoT3
  • DemoRecur -- This is the recursion example. It is a Processing Application Class that also becomes a client.

Identification
There may be times when your Processing Application Class, executing in the Tymeac Server, needs to know the identification of the Tymeac Client requesting the service Outside of CallBack.

Although there is an rmi Server method, getClientHost(), this method generally is unacceptable and Tymeac Server does not use this method.

  • The method only returns the TCP EndPoint address of the host on which the client resides, not the actual client identification and this method is only available to pure Java (not RMI-IIOP or other plug-in) implementations.
  • Using a physical address to identify a client is usually not a good idea. The network may change, machines come and go. This is "hard wiring". When the location changes, then an administrator must alter all tables. Using a "soft wiring" method means the client can take its identification with it when it moves.

Secondly, the RMI Runtime keeps track of the identification of Clients that have unmarshalled this Server's RemoteObject. (This has to do with the Distributed Garbage Collector.) However, API access to this data is not available.

Therefore, it is the responsibility of the Client to include a unique identifier for use by the Processing Application Class within the input Object it passes to the Tymeac Server. This coding is totally dependent on each application.

Idle Period
There may be times when you would like to know when no Tymeac Clients exist. (See the SDK documentation /guide/rmi/spec/rmi/ (Garbage Collection of Remote Objects.) This involves implementing the Unreferenced Interface (one method, Unreferenced()) in the Tymeac Server.

  1. The unreferenced() method is only called when ALL clients no longer hold a reference to the remote object or when the lease time expires (java.rmi.dgc.leaseValue.)
  2. The Registries (RMI/JNDI) are clients. When Tymeac Server registers with one of these, then the unreferenced() method may never be called.
  3. Since this is the purview of the Distributed Garbage Collector, each operating system may implement this differently.

We do not implement the Unreferenced Interface.

For the activatable Tymeac Server, we keep track of the idle period, that is - the time when no Client has called the Server. (see Configuration File Maintenance and User Variables Class) When this idle period reaches a threshold, the application may take some action (such as deactivating, etc.)  In this way, we are not dependent on any implementations of DGC and we have much more flexibility.

System Variables

Tymeac reads system variables at start up from the TymeacUserVariables class for stand alone mode or the Tymeac Configuration File for DBMS start up. This is where you put the monitor interval, etc.

Testing

Becoming familiar with how Tymeac works is preliminary in any testing environment. We provide a page on how to alter the Demonstration System Classes and a page on abnormal conditions that may arise.

The easiest way to test a Class is without the Tymeac threading environment. We supply a source Class, DemoTesting.java. This Class:

  • loads the required Class, Class.forName("name of the Class to load"),
  • finds the method signature, "main(Object[])", and
  • invokes the found "main" method.

This is similar to the way Tymeac invokes your Processing Application Class. Therefore, if it runs here, it should run there.

Two directories are necessary to use this Class:

  1. <home>\com\tymeac\serveruser  -- for the Processing Application Class
  2. <home>\com\tymeac\demo  --  for the DemoTesting Class.

divider.gif (931 bytes)

Having tested the Class in a stand-alone environment, it is time to test the Class in the Tymeac threading environment.

Testing a Class usually requires setting up a Queue and a Function just for testing.

It is easier to test a single Class when there is only one Queue in the Function. It is easier to isolate threads when there is only one thread in the Queue. Therefore, define a Queue, TyQueMaint, with one (1) thread and the name of your Processing Application Class. Define a Function, TyFuncMaint, with the name of this single Queue.

Write a Tymeac Client Class that passes the input Object to the Tymeac Server as a Synchronous Request, TymeacParm, with a time out value high enough to allow stepping through the application.

  • Start the RMI Registry.
  • Start TymeacServer.
  • Set a trap for your application.
  • Run the application.

See also the section on naming threads found in the Maintenance Class for Queues and in the section on Thread Names.

This same process works for the Output Agent Processing Application Class.

Just set up a normal Queue and pass simulated data to this application, with a Synchronous Request, as it would be if from other applications. When the application works properly, then set up an Output Agent Queue as part of a Function.

When there is more than one thread in the Queue, knowing which thread is going to process a request is sometimes possible.

Thread numbering starts at zero (0). Tymeac thread selection always starts at zero(0). Therefore, if three threads are "waiting for work", TyQueThd, Tymeac selects thread number zero (0), first. If all threads are "inactive" or "never used", Tymeac activates thread number zero (0), first.

As mentioned, above, the New Copy Class is available so that you do not have to shut down and start up Tymeac Server every time you recompile your Class.

divider.gif (931 bytes)

Now that all is working well, what happens when this newly developed system is under a load? That is, many clients requesting service at the same time. Are there any "sharing" conflicts, resource limitations, etc? We supply an "under load" system, the T3 series. [You may wish to clone this series, renaming the classes to your own standards.]

TyDemoT3 is made up of   five classes. The only one you must change is TyDemoT3Thread. The other classes may remain without change. Alter TyDemoT3Thread Constructor to use your TymeacParm information. Alter TyDemoT3Thread.run() to perform the sequence of events necessary for your testing.

Now you may put as heavy a load on your code as necessary.

User Exits

As with other general purpose tools, Tymeac cannot supply all the functionality one may wish to have. Therefore, Tymeac provides exits or hooks into which you may add your own functionality. See the section on user exits.  See also the section on start up functions.

These exits are established either in the Tymeac Configuration File or in the TymeacUserVariables Class.

Overall Structure

  • We provide guidance in the form of patterns that appear frequently within Tymeac.
  • We provide an exposition on RMI communications for use with Tymeac.
  • The computer memory requirements are difficult for any system. We provide a discussion on how Tymeac uses storage.
  • We have a discussion on network load balancing.

 

 

© 1998 - 2004 Cooperative Software Systems, Inc.  All rights reserved.