Você está na página 1de 13

Guide for writing a tcserver plugin

Temenos S.A.
26.06.2004

This document remains the property of TEMENOS. TEMENOS is not responsible for any abuse by third
parties, nor for any alteration or corruption in transmission, nor for any damage or loss caused by any virus or
other defect.

1
Table of contents

Guide for writing a plugin ..............................................................................3


What is a plugin ........................................................................................3
Why being plug- in oriented ......................................................................3
The TCServer API ....................................................................................4
AbstractListener..................................................................................4
AbstractAdapter..................................................................................5
My First plugin (listener) ..........................................................................6
Synchronous processing : ...................................................................6
Asynchronous processing :.................................................................7
My First plugin (adapter) ..........................................................................8
Packaging a plugin (listener sample)........................................................8
Compiling the sample .........................................................................8
Packaging..........................................................................................10
Tracing functionality in a plugin ............................................................11
Conclusion..............................................................................................13

2
Guide for writing a plugin

What is a plugin
A plug- in a small unit of code, which is independent from the core of the TCServer,
but is recognised by this last. There is 3 types of plug- ins : listener, adapter and
formatter. A Listener is listening to the external world. For example, a TCP Listener
will listen on a TCP port; an MQ Listener will logically listen on a MQSeries
Queue. The listener is responsible to GET a message, and to SEND a response. An
adapter is the unit of code which will PROCESS the message. For example, the OFS
adapter will manage to send the message to T24 via OFS and retrieve the response.
The request is coming from the Listener, and the response will be picked by the
listener to be sent further. A formatter is supposed to change the message. Formatters
are attached to the Adapter (request and response formatters).

Why being plug-in oriented


By default, the TCServer itself doesnt make anything. When starting the TCServer,
the first action is to load the different available plug- ins. Here, the load is a pure
technical one. This has nothing to do with the activation. Even if you havent
mentioned any TCP listener in your configuration file, you will see the TCServer
loading it. You could remove the file tcplistener.jar so the TCServer wont discover it
anymore. The main reason to be plug- in oriented is certainly because is allows :
- to extend / upgrade the TCServer functionalities without touching at the core
- customers to define what the TCServer does (interfaces)
- to be more secure in a fact that you can remove the functionalities you wont
activate

3
The TCServer API
The TCServer API is contained in the package com.temenos.tocf.tcs.API.

In that package, two classes are available :


AbstractListener and AbstractAdapter. (AbstractFormatter will be available in future
version)

AbstractListener
This class is the class you will have to extend if you want to write a new Listener.
Here is the list of the different methods available :

This method ask the TCServer to process your request in a synchronous way
(blocking). The adapter defined in the configuration file will pick the message and
return the response.
public byte[] process(byte[] bRequest) {}

The two following methods are posting a message to the TCServer and returns a
unique ID (bytes[]). There a fully asynchronous. Once the response will be processed,
the method messageReady() will be invoked. The parameter Tag is ANY value
wich will be returned unchanged with the response. The optional parameter Id allows
to force the unique Id. This is important to make sure that this Id is unique, and in
most cases, there wont be necessary to pass that parameter.
public byte[] processAsync(byte[] bRequest, String Tag) {}
public byte[] processAsync(byte[] bId, byte[] bRequest, String Tag) {}

This method is called from the TCServer whenever a message has been processed.
The requested will match the one you received back from the processAssync()
method. The bResponse is the response itself, and the Tag is nothing else than the
value you passed in the processAssync. The TimeStamps object will be described
later.
public void messageReady(byte[] requestId, byte[] bResponse, String sTag,
TimeStamps times){};

This method returns the name you gave to your listener in the configuration file
(tcserver.xml)
public String getName (){}

The getParam() returns the value of a Tag specified in your listener definition in the
tcserver.xml file (eg if you have such a param in the configuration file :
<MYPARAM>myValue</MYPARAM>, then getParam(MYPARAM) will return
myValue).
public String getParam(String sParam){}

This method will be called from the TCServer core whenever you need to stop the
listener.
public abstract void stopIt();

4
The TCServer core will wait until isStopped return true to assume the Listener is
stopped.
public abstract boolean isStopped();

This method returns the name of the associated adapter. Remember that all listener
have to have a adapter associated (to process the message).
public String getAdapterId(){}

The following methods allows you to benefits from the tracing facilities of the
TCServer (see specific chapter)
public void debug(Object o) {}
public void debug(Object o, Throwable t) {}
public void error(Object o) {}
public void error(Object o, Throwable t) {}
public void fatal(Object o) {}
public void fatal(Object o, Throwable t) {}
public void info(Object o) {}
public void info(Object o, Throwable t) {}
public void warn(Object o) {}
public void warn(Object o, Throwable t) {}

AbstractAdapter
This class is the class you will have to extend if you want to write a new Adapter.

This method is the one called by the tcserver core. The request is in byte[] and, unless
some formatters have been defined, the byte[] are kept unchanged regardless what the
charset ofs the platform is. sTag is the value having been passed in a processAsync
call (see previous chapter).
public abstract byte[] process(byte[] bRequest, String sTag);

This method will be called from the TCServer core whenever you need to stop the
adapter.
public abstract void stopIt();

Return the id of the Adapter as defined in the tcserver.xml file.


public String getName ();

Return the parameter as defined in the tcserver.xml file. The parameter is the TAG.
This method is usefull as you don't need to manage a configuration file.
public String getParam(String sParam);

5
My First plugin (listener)

Following, you will find the complete code for a Plugin (type listener) which sends an
enquiry (defined in the configuration file) every x seconds (also defined in the conf
file) :

Synchronous processing :

package com.temenos.sample.listener;

import com.temenos.tocf.tcs.API.*;

public class SampleListener extends AbstractListener {

private boolean _bStop = false;


private boolean _bStopped = false;

/*
* Will be invoked by the core to notify a stop.
*/
public void stopIt() {
this._bStop = true;
}

/*
* Will be invoked by the core to know the status of the listener
*/
public boolean isStopped() {
return this._bStopped;
}

/*
* This listener will be started in a seperate thread.
* the run() method is the entry point.
*/
public void run() {
super.debug("Starting sample listener");
byte[] bRequest = super.getParam("REQUEST").getBytes();
int nFrequence = Integer.parseInt(super.getParam("FREQUENCE"));
super.debug("Parametters : " + new String(bRequest) + "/" + nFrequence);

int nIndex = 0;
while(!_bStop){
nIndex ++;
/*
* Process the request synchronously
*/
byte[] bResponse = super.process(bRequest);
System.out.println(nIndex + " : " + new String(bResponse));
try{
Thread.sleep(nFrequence * 1000);
}catch(InterruptedException ie){
}
}
/*
* Fag it as "stopped" before terminating the thread.
*/
this._bStopped = true;
}
}

6
Asynchronous processing :

package com.temenos.sample.listener;

import com.temenos.tocf.tcs.API.*;

public class SampleListener extends AbstractListener {

private boolean _bStop = false;


private boolean _bStopped = false;

public void messageReady (byte[] responseId, byte[] bResponse, String sTag, TimeStamps times){
System.out.println("Response #" + sTag + " : " + new String(bResponse));
}

/*
* Will be invoked by the core to notify a stop.
*/
public void stopIt() {
this._bStop = true;
}

/*
* Will be invoked by the core to know the status of the listener
*/
public boolean isStopped() {
return this._bStopped;
}

/*
* This listener will be started in a seperate thread.
* the run() method is the entry point.
*/
public void run() {
super.debug("Starting sample listener");
byte[] bRequest = super.getParam("REQUEST").getBytes();
int nFrequence = Integer.parseInt(super.getParam("FREQUENCE"));
super.debug("Parametters : " + new String(bRequest) + "/" + nFrequence);

int nIndex = 0;
while(!_bStop){
nIndex ++;
/*
* Process the request ssynchronously
* Note the the id returned will be passed as
* parametter in the messageReady().
* Whatever string passed as second parametter will be returned unchanged
* in messageready().
*/
byte[] bId = super.processAsync(bRequest, ""+nIndex);
System.out.println("Message #"+nIndex + " posted.");
try{
Thread.sleep(nFrequence * 1000);
}catch(InterruptedException ie){
}
}
/*
* Fag it as "stopped" before terminating the thread.
*/
this._bStopped = true;
}
}

7
My First plugin (adapter)
Following, you will find the complete code for a Plugin (type adapter) which return
whatever has been sent after having waited for few milliseconds(defined in the
configuration file):
package com.temenos.plugin.echoadapter;

public class EchoAdapter extends com.temenos.tocf.tcs.API.AbstractAdapter {

public byte[] process(byte[] bRequest, String sTag) {

long lSleep = 0;
try{
lSleep = Long.parseLong(super.getParam("SLEEPTIME"));
}catch(Exception e){
}

try{
Thread.sleep(lSleep);
}catch(Exception e){
}

return bRequest;
}

public void stopIt() {

Packaging a plugin (listener sample)


Come back to our samplelistener. In fact, the philosophy for an adapter is
EXACTELY the same as the one for a listener. The EchoAdapter is released by
default with the tcserver, and you can have a look at the configuration file
(tcserver.xml) to discover it.

For the current section, we will admit that you copied the code of one of the precedent
sample (samplelistener.java) in a directory
<your_src_dir>/com/temenos/sample/listener
The file name is SampleListener.java (!case sensitive)
You will need to have a jdk (1.3.1 or above) installed.

Compiling the sample


First, create a directory <your_src_dir>/classes
Then, compile the class by typing :
javac -d classes -classpath <path_to_tcserver>/lib/tcserver.jar
com/temenos/sample/listener/*

In your classes directory, you should now have


/com/temenos/sample/SampleListener.class
Creating a plugin.desc

8
Then, you will need to create a small file called plugin.desc. Put this file in the
classes directory.

Edit this file so it looks like this :


plugin-id : samplelistener
plugin-type : listener
plugin-class : com.temenos.sample.listener.SampleListener
plugin-description : Sample listener
plugin-configuration : *REQUEST; FREQUENCE

plugin- id : The id which identify the plugin (this is the type in


tcserver.xml)
plugin- type : Either listener, adapter or formatter
plugin-class : The class, with the full package, without .class
plugin-description : Any description
plugin-configuration : List of the parameters you want to use in the tcserver.xml.

Note that if you want to create a block of parameter like this

<MYTAG>
<MYSUBTAG>Hello</MYSUBTAG>
</MYTAG>

you will write : MYTAG/MYSUBTAG.

The parameters are separated by semi-columns (;).

If you prefix one parameter by a star (*), the value of this parameter will be shown
in the TCMonitor when you ask for the Listener list. (Only valid for listener plugins).

9
Packaging
To package the plugin, use the jar program (part of the jdk)
Type :
jar -cvf samplelistener.jar -C <your_src_dir>/classes .
it should create a file samplelistener.jar in your current directory.

Deploying a plugin
Copy the newly created file (samplelistener.jar) in the ext directory of your tcserver.
Then, edit the file tcserver.xml like this (in the block <LISTENERS>):

<LISTENERS>
. . .
<LISTENER id="sample" type="samplelistener" active="true">
<ADAPTERID>T24</ADAPTERID>
<REQUEST>sample_request</REQUEST>
<FREQUENCE>10</FREQUENCE>
</LISTENER>
. . .
</LISTENERS>

Restart your tcserver. You will see, every 10 seconds, a trace in the console like this :

Your listener is running !

10
Try to play with it by changing the parameters in tcserver.xml (eg, putting a real OFS
syntax)

Tracing functionality in a plugin

The class AbstractListener offers all necessary trace functionality, so you dont have
to worry about it.

# samplelistener
###################
log4j.category.samplelistener=INFO, samplelistener
log4j.appender.samplelistener.layout=org.apache.log4j.PatternLayout
log4j.appender.samplelistener.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n
#log4j.appender.samplelistener=org.apache.log4j.ConsoleAppender
log4j.appender.samplelistener=org.apache.log4j.RollingFileAppender
log4j.appender.samplelistener.File=<log.directory>/samplelistener.log
log4j.appender.samplelistener.MaxFileSize=512KB
log4j.appender.samplelistener.MaxBackupIndex=999

The tcserver is using log4j as tracing mechanism. Any plugin can benefits from this
facility. The unique configuration file for log4j is tcslog.properties. This file is in the
/conf directory of the tcserver. If you followed the procedures of the preceding
chapters, you should find a paragraph in tcslog.properties looking like this :

Lets have a look at it in details.

This whole paragraph is yours !. By default, the trace level is INFO, and everything is
traced in a file in <log.directory>. The file name is samplelistener.log. <log.directory>
is a tag resolved at run time which points to the <path_to_tcserver>/log. Feel fre to
change it ! You can give any path. The fourth line is remed-out. This is one of the
alternative of the tracing. The log4j.appender points to a class which will react in a
specific way. By default, you have the RollingFileAppender and the
ConsoleAppender (screen). The RollingFileAppender is related to the File,
MaxFileSize and MaxBackupIndex. The ConsoleAppende doesnt need any specific
parameter. So, if you wish to trace on the console, just rem-out everything for the
RollingFileAppender, and unrem-out the ConsoleAppender like this :

# samplelistener
###################
log4j.category.samplelistener=INFO, samplelistener
log4j.appender.samplelistener.layout=org.apache.log4j.PatternLayout
log4j.appender.samplelistener.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n
log4j.appender.samplelistener=org.apache.log4j.ConsoleAppender
#log4j.appender.samplelistener=org.apache.log4j.RollingFileAppender
#log4j.appender.samplelistener.File=<log.directory>/samplelistener.log
#log4j.appender.samplelistener.MaxFileSize=512KB
#log4j.appender.samplelistener.MaxBackupIndex=999

11
Log4j offers plenty of facilities. You could write your own appender, conversion
pattern, for more information, please refers to one of the multiple web site like this
one : http://logging.apache.org/log4j/docs/

The AbstractListener class offers the following methods for you to be able to trace :

void debug (Object o);


void debug (Object o, Throwable t);
void error(Object o);
void error(Object o, Throwable t);
void fatal(Object o);
void fatal(Object o, Throwable t);
void info(Object o);
void info(Object o, Throwable t);
void warn(Object o);
void warn(Object o, Throwable t);

In the samples, you can read :


super.debug("Starting sample listener");

So after having started the tcserver (and the listener !), lets look at the log directory.
You will find a file called samplelistener.log. If you look at its contents, you will
discover that this file is empty. This is because the log level by default is INFO. We
wrote debug. DEBUG is lower than INFO in the tracing mechanism. Here is
the hierarchy :
ALL > FATAL > ERROR > WARN > INFO > DEBUG > NONE.

So lets change the debug level in the file tcslog.properties. Change it to this :

log4j.category.samplelistener=DEBUG, samplelistener

And restart the tcserver.

Now, if you look at the samplelistener.log, you will discover this :

2004-06-26 10:36:48,294 [Thread-13] DEBUG samplelistener - Starting sample listener


2004-06-26 10:36:48,294 [Thread-13] DEBUG samplelistener - Parametters : sample_request/10

12
Conclusion

Since the release 1.3.x of the tcserver, all listeners are plugins. The tcplistener,
ssllistener, mqlistener, batchfilelistener, .. are build on top of the AbstractListener.

When you write your own plugin, this is extremely important to test, test and test
again. Remember that your code will be running in the same java virtual machine than
the tcserver. Writing a System.exit(0) in your code will stop the whole tcserver !

Your plugin is running in a dedicated java thread. You could rename it at your
convenience. If your plugin receive a stopIt() call, this is important to react, free any
resources, and make sure that it will return true to the isStopped(). The core tcserver
has a default value of 2 minutes for waiting that a listener is stopped. Afterwards, it
will give- up waiting and

13

Você também pode gostar