Escolar Documentos
Profissional Documentos
Cultura Documentos
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
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).
3
The TCServer API
The TCServer API is contained in the package com.temenos.tocf.tcs.API.
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 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.*;
/*
* 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 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;
long lSleep = 0;
try{
lSleep = Long.parseLong(super.getParam("SLEEPTIME"));
}catch(Exception e){
}
try{
Thread.sleep(lSleep);
}catch(Exception e){
}
return bRequest;
}
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.
8
Then, you will need to create a small file called plugin.desc. Put this file in the
classes directory.
<MYTAG>
<MYSUBTAG>Hello</MYSUBTAG>
</MYTAG>
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 :
10
Try to play with it by changing the parameters in tcserver.xml (eg, putting a real OFS
syntax)
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 :
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 :
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
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