[[jposiso]]

== jPOS approach to ISO-8583

This chapter describes how jPOS handles ISO-8583 messages. 

=== ISOMsg &amp; Co.

jPOS' internal representation of an ISO-8583 message is usually an ISOMsg
object (or an ISOMsg's subclass). 

The ISOMsg class uses the *Composite pattern* (see  
Design Patterns, elements of Reusable Object-Oriented Software
by Gamma, Helm, Johnson and Vlissides). 

ISOMsg, ISOField, ISOBitMapField, ISOBinaryField and any custom field type
that you may implement are subclasses of ISOComponent.  Let's have a look at
ISOComponent's methods: 


[source,java]
----
    public abstract class ISOComponent implements Cloneable {
        public void set (ISOComponent c) throws ISOException;
        public void unset (int fldno) throws ISOException;
        public ISOComponent getComposite();
        public Object getKey() throws ISOException;
        public Object getValue() throws ISOException;
        public byte[] getBytes() throws ISOException;
        public int getMaxField();
        public Hashtable getChildren();
        public abstract void setFieldNumber (int fieldNumber);
        public abstract void setValue(Object obj) throws ISOException;
        public abstract byte[] pack() throws ISOException;
        public abstract int unpack(byte[] b) throws ISOException;
        public abstract void dump (PrintStream p, String indent);
        public abstract void pack (OutputStream out) throws IOException, ISOException;
        public abstract void unpack (InputStream in) throws IOException, ISOException;
    }
----


This approach has proven to be really useful and maps quite well to the
ISO-8583 message structure.  

There are many situations where some methods are not applicable (i.e.,
getChildren() has no meaning in a leaf field, same goes for methods such as
getMaxField()), but as a general rule, using the same super-class for ISOMsg
and ISOFields has proven to be a good thing. You can easily assign an ISOMsg as
a field of an outer ISOMsg. 

The following diagram shows how some ISOComponents interact with each other. 

image:images/isomsg.jpg[width="400px",alt="ISOMsg",align="center"] 

The following code can be used to create an internal representation of our 0800
message (described in <<iso8583,An ISO-8583 primer>>).  

[source,java]
----

   import org.jpos.iso.*;

   ISOMsg m = new ISOMsg();
   m.set (new ISOField (0, "0800"));
   m.set (new ISOField (3, "000000"));
   m.set (new ISOField (11, "000001"));
   m.set (new ISOField (41, "29110001"));
   m.set (new ISOField (60, "jPOS 6"));
   m.set (new ISOField (70, "301"));
  
----

We are just calling +ISOComponent.set (ISOComponent)+ method. 

In order to reduce typing and improve code readability, ISOMsg provides some
handy methods such as  

[source,java]
----
ISOMsg.setMTI (String)
----

 and 

[source,java]
----
ISOMsg.set (int fieldNumber, String fieldValue)
----

implemented like this: 

[source,java]
----

    public void set (int fldno, String value) throws ISOException {
        set (new ISOField (fldno, value));
    }
    public void setMTI (String mti) throws ISOException {
	if (isInner())
	    throw new ISOException ("can't setMTI on inner message");
	set (new ISOField (0, mti));
    }
  
----

So the previous example can be written like this: 

[source,java]
----

    ISOMsg m = new ISOMsg();
    m.setMTI ("0800");
    m.set (3, "000000");
    m.set (11, "000001");
    m.set (41, "29110001");
    m.set (60, "jPOS 6");
    m.set (70, "301");
----


[TIP]
=====

ISOMsg is one of the most used classes in typical ISO-8583-based jPOS applications. 
While you can subclass it, you probably won't have to. If there's a single class in 
all jPOS that you want to study in great detail, this is it.

We recommend you to have a look at its
link:http://jpos.org/doc/javadoc/org/jpos/iso/ISOMsg.html[API documentation ] 
and play with its helper methods such as clone, merge, unset, etc. 

=====

=== Packing and unpacking

ISOComponents have two useful methods called: 

[source,java]
----

    public abstract byte[] pack() throws ISOException;
    public abstract int unpack(byte[] b) throws ISOException;
  
----

+pack+ returns a +byte[]+ containing the binary representation of a given 
component (can be just a field or the whole ISOMsg);  
+unpack+ does the opposite and also returns the number of consumed 
bytes. 

jPOS uses a *Peer pattern* that allows a given ISOComponent to be packed and unpacked 
by a peer class, _plugged_ at runtime. 

You use

[source,java]
----

    public void setPackager (ISOPackager p);
   
----

in order to assign a packager to a given +ISOMsg+, e.g.:

[source,java]
----

   ISOPackager customPackager = MyCustomPackager ();
   ISOMsg m = new ISOMsg();
   m.setMTI ("0800");
   m.set (3, "000000");
   m.set (11, "000001");
   m.set (41, "29110001");
   m.set (60, "jPOS 6");
   m.set (70, "301");
   m.setPackager (customPackager);
   byte[] binaryImage = m.pack();
  
----

In order to unpack this +binaryImage+ you may write code like this: 

[source,java]
----

   ISOPackager customPackager = MyCustomPackager ();
   ISOMsg m = new ISOMsg();
   m.setPackager (customPackager);
   m.unpack (binaryImage);
  
----

It is very easy to create protocol converters using jPOS, e.g.: 

[source,java]
----

   ISOPackager packagerA = MyCustomPackagerA ();
   ISOPackager packagerB = MyCustomPackagerB ();
   ISOMsg m = new ISOMsg();
   m.setPackager (packagerA);
   m.unpack (binaryImage);
   m.setPackager (packagerB);
   byte[] convertedBinaryImage = m.pack();
  
----
 

+ISOMsg.pack()+ delegates message packing/unpacking operations 
to its underlying "peer" ISOPackager. The code looks like this: 

[source,java]
----

    public byte[] pack() throws ISOException {
        synchronized (this) {
            recalcBitMap();
            return packager.pack(this);
        }
    }
  
----

+packager.pack(ISOComponent)+ also delegates its packing/unpacking duties to an 
underlying +ISOFieldPackager+. There are +ISOFieldPackager+ implementations for many 
different ways of representing a field. It is very easy to create your own, if required. 

The following code is used by an +ISOFieldPackager+ implementation to pack and unpack 
fixed-length alphanumeric fields: 

[source,java]
----

    public byte[] pack (ISOComponent c) throws ISOException {
        String s = (String) c.getValue();
        if (s.length() > getLength())
            s = s.substring(0, getLength());
        return (ISOUtil.strpad (s, getLength())).getBytes();
    }
    public int unpack (ISOComponent c, byte[] b, int offset)
        throws ISOException
    {
        c.setValue(new String(b, offset, getLength()));
        return getLength();
    }
  
----

jPOS comes with many +ISOFieldPackager+ implementations so you'll probably 
never have to write your own. Names chosen are somewhat cryptic, though.


[NOTE]
======
Many people are using them for their own custom packagers so we'll probably 
have to live with those names for a while. 

======

As a general rule, all +ISOFieldPackagers+ live under package +org.jpos.iso+ 
and start with the name *+IF+* which stands for "ISO Field", but that's just
an arbitrary naming convention. You can name and place your own ISOFieldPackager
implementations at your will.

So we have things like this: 

.ISOFieldPackagers
[cols="2,4", options="header"]
|===============
|Name|Purpose
|IF_CHAR|Fixed length alphanumeric (ASCII)
|IFE_CHAR|Fixed length alphanumeric (EBCDIC)
|IFA_NUMERIC|Fixed length numeric (ASCII)
|IFE_NUMERIC|Fixed length numeric (EBCDIC)
|IFB_NUMERIC|Fixed length numeric (BCD)
|IFB_LLNUM|Variable length numeric (BCD, maxlength=99) 
|IFB_LLLNUM|Variable length numeric (BCD, maxlength=999)
|IFB_LLLLNUM|Variable length numeric (BCD, maxlength=9999)
|...|...
|...|...
|===============


=== Creating custom packagers

jPOS provides the ability to create customized packagers for different kind of
ISO-8583 implementations. Over the last few years, several developers have
contributed their customized ISOPackagers and ISOFieldPackagers, so chances are
good that you can find an implementation suitable for you, or something very
close to what you need as part of jPOS distribution. 


[TIP]
====
Before writing your own packager, have a look at the classes under
+jpos/src/main/java/org/jpos/iso/packager+ directory.
====


Writing a packager is very easy. There's a support class called ISOBasePackager
that you can easily extend, e.g.: 

----

public class ISO93APackager extends ISOBasePackager {
    protected ISOFieldPackager fld[] = {
    /*000*/ new IFA_NUMERIC (  4, "Message Type Indicator"),
    /*001*/ new IFA_BITMAP  ( 16, "Bitmap"),
    /*002*/ new IFA_LLNUM   ( 19, "Primary Account number"),
    /*003*/ new IFA_NUMERIC (  6, "Processing Code"),
    /*004*/ new IFA_NUMERIC ( 12, "Amount, Transaction"),
    /*005*/ new IFA_NUMERIC ( 12, "Amount, Reconciliation"),
    ...
    ...
    ...
    public ISO93APackager() {
        super();
        setFieldPackager(fld);
    }
}
 
----


So the programmer's task (BTW, an easy but boring one) is to verify that  every
single field in your packager configuration matches your interchange
specifications. 

An ISOPackager is not required to extend the supporting class ISOBasePackager,
but we've found it quite convenient for most situations. 


[TIP]
====

while you write your own packager implementation, we recommend you to write a
unit test for it. Have a look at the +jpos/src/test/java/org/jpos/iso/...+ directory
to find some sample unit tests that can be used as a starting point.
 
====

After adding several packagers to our repository, jPOS developer Eoin Flood
came up with a good idea: a _GenericPackager_  that one could configure by
means of an XML file. The GenericPackager configuration looks like this: 

----

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE isopackager PUBLIC
        "-//jPOS/jPOS Generic Packager DTD 1.0//EN"
        "http://jpos.org/dtd/generic-packager-1.0.dtd">

<!-- ISO 8583:1993 (ASCII) field descriptions for GenericPackager -->

<isopackager>
  <isofield
      id="0"
      length="4"
      name="Message Type Indicator"
      class="org.jpos.iso.IFA_NUMERIC"/>
  <isofield
      id="1"
      length="16"
      name="Bitmap"
      class="org.jpos.iso.IFA_BITMAP"/>
  <isofield
      id="2"
      length="19"
      name="Primary Account number"
      class="org.jpos.iso.IFA_LLNUM"/>
  <isofield
      id="3"
      length="6"
      name="Processing Code"
      class="org.jpos.iso.IFA_NUMERIC"/>
  <isofield
      id="4"
      length="12"
      name="Amount, Transaction"
      class="org.jpos.iso.IFA_NUMERIC"/>
  <isofield
      id="5"
      length="12"
      name="Amount, Reconciliation"
      class="org.jpos.iso.IFA_NUMERIC"/>
  <isofield
      id="6"
      length="12"
      name="Amount, Cardholder billing"
      class="org.jpos.iso.IFA_NUMERIC"/>
      ...
      ...
      ...
</isopackager>
  
 
----

We now have XML configurations for most packagers under the
+org.jpos.iso.packager+ package. They are available in the
+jpos/src/main/resources/packager+ directory. 

[TIP]
=====
If you are to develop a custom packager, we encourage you to use
GenericPackager with a suitable custom configuration file instead. 
It will greately simplify your task. 

If you're using Q2 to configure your packagers, GenericPackager
uses the "packager-config" property in order to determine its 
configuration file. 

The XML based packager configuration can be either placed
in the operating system or inside a jar within the classpath,
GenericPackager has the ability to read it as a resource.
=====

[NOTE]
=====
If you need support for nested messages, you may want to have
a look at +jpos/src/main/resources/org/jpos/iso/packager/genericpackager.dtd+ 
as well as examples such as +jpos/src/dist/cfg/packager/base1.xml+
(see field 127).
=====

=== Managing the wire protocol with ISOChannel

jPOS uses an interface called +ISOChannel+ to encapsulate wire protocol details.  

+ISOChannel+ is used to send and receive +ISOMsg+ objects. It leverages the *peer
pattern*  where its _peer_ is an +ISOPackager+ instance. It has +send+ and +receive+
methods as well as means to +set+ and +get+ a peer packager: 

[source,java]
----

    ...
    public void send (ISOMsg m) throws IOException, ISOException;
    public ISOMsg receive() throws IOException, ISOException;
    public void setPackager(ISOPackager p);
    public ISOPackager getPackager();
    ...
  
----

Although not meaningful under all possible situations, +ISOChannel+ has a few
connection-related methods as well: 

[source,java]
----

    ...
    public void connect () throws IOException;
    public void disconnect () throws IOException;
    public void reconnect() throws IOException;
    public void setUsable(boolean b);
    public boolean isConnected();
    ...
  
----

In order for applications to bind jPOS components at runtime, there's a
Singleton class called +org.jpos.util.NameRegistrar+ where you
can register and get references to Objects. The ISOChannel interface provides
handy methods to access ISOChannels at runtime by their name. 

[source,java]
----
    ...
    public void setName (String name);
    public String getName();
    ...
----


ISOChannel extends ISOSource which reads like this: 

[source,java]
----

    public interface ISOSource {
        public void send (ISOMsg m) 
            throws IOException, ISOException, VetoException;
        public boolean isConnected();
    }
----

Different interchanges use different wire protocols. jPOS encapsulates that
functionality in completely isolated ISOChannel implementations. It comes with
many implementations and it's easy to write your own, perhaps taking advantage
of the +BaseChannel+ as a super class.

.Sample ISOChannel implementations
[cols="2,4", options="header"]
|=============================
|Name|Description
|ASCIIChannel
|4 bytes message length plus ISO-8583 data

|LogChannel
|Can be used to read jPOS's logs and inject messages into other channels
     
|LoopbackChannel
|Every message sent gets received (possibly applying filters).
 Very useful for testing purposes.
     
|PADChannel|
Used to connect to X.25 packet assembler/dissamblers

|XMLChannel
|jPOS Internal XML representation for ISO-8583 messages
|...|...
|...|...
|=============================


[TIP]
====
(see +org.jpos.iso.channel.\*+ for a complete list) 
====

[NOTE]
======
Out of all channel implementations, PADChannel deserves a special note.
Most TCP/IP based ISO-8583 wire protocol implementations use some kind 
of indicator to easily detect message bounderies. Most of them use a
packet length header so the receiving implementation can tell apart
a given ISO-8583 packet from the next one.

On the other hand, implementations that do not use any message boundary
indicator are typically migrations from older packet-based networks such as
X.25 and assume that a given ISO-8583 packet will come in a single TCP/IP
packet, which is *absolutely wrong*. Intermediate networks may split packets
(depending on the MTUs involved) or join packets on retransmissions.

PADChannel use no message boundary indicator, it reads the ISO-8583 message
on-the-fly. It does the right thing. Unfortunately, unless you have another
PADChannel on the other endpoint, you'll probably have to deal with the problem
mentioned in the previous paragraph.

======

.ISOChannel example
====

[source,java]
----

    import org.jpos.iso.*;
    import org.jpos.util.*;
    import org.jpos.iso.channel.*;
    import org.jpos.iso.packager.*;

    public class Test {
        public static void main (String[] args) throws Exception {
            Logger logger = new Logger();
            logger.addListener (new SimpleLogListener (System.out));
            ISOChannel channel = new ASCIIChannel (
                "localhost", 7, new ISO87APackager()
            );
            ((LogSource)channel).setLogger (logger, "test-channel");
            channel.connect ();

            ISOMsg m = new ISOMsg ();
            m.setMTI ("0800");
            m.set (3, "000000");
            m.set (41, "00000001");
            m.set (70, "301");
            channel.send (m);
            ISOMsg r = channel.receive ();
            channel.disconnect ();
        }
    }
  
----
====

[TIP]
====
While we'll see many examples similar to the previous one throughout this
document, where a simple main() method takes care of instantiating and
configuring several jPOS components, later we'll introduce *Q2*, jPOS's
component assembler. We *strongly recommend* to use Q2 to run
jPOS. It will make your life easier.  

Q2 lets you define your jPOS-based application in a very simple, easy to create
and easy to maintain set of XML configuration files. 

We recommend that you wait until we talk about Q2 before diving into coding
your own jPOS-based application. Using code like the previous example is good
to learn jPOS but not to run it in a production environment. 

In addition, you usually don't deal directly with a channel using its +send+
and +receive+ methods. You typically interact with it via a multiplexer (+MUX+)
or a server (+ISOServer+).

====

If you have a look at the ISOChannel implementations (most of them live in
org.jpos.iso.channel package) you'll notice that many of them extend
+org.jpos.iso.BaseChannel+. 

BaseChannel is an abstract class that provides hooks and default
implementations for several methods that are useful when writing custom
channels. While you don't necesarily have to extend BaseChannel to write a
custom channel, you'll probably find it very useful. 

Depending on your wire protocol, you'll probably only need to extend
BaseChannel and just override a few methods, e.g.: 

[source,java]
----

   protected void sendMessageLength(int len) throws IOException;
   protected int getMessageLength() throws IOException, ISOException;
  
----
(see jpos/src/main/java/org/jpos/iso/channel/CSChannel.java for an example).

You may also want to have a look at the LoopbackChannel implementation for an
example of an ISOChannel that doesn't extend BaseChannel. 

[[isofilter]]

==== Filtered Channels

Many ISOChannels implement +FilteredChannel+ which looks like this: 

[source,java]
----

    public interface FilteredChannel extends ISOChannel {
        public void addIncomingFilter (ISOFilter filter);
        public void addOutgoingFilter (ISOFilter filter);
        public void addFilter (ISOFilter filter);
        public void removeFilter (ISOFilter filter);
        public void removeIncomingFilter (ISOFilter filter);
        public void removeOutgoingFilter (ISOFilter filter);
        public Collection getIncomingFilters();
        public Collection getOutgoingFilters();
        public void setIncomingFilters (Collection filters);
        public void setOutgoingFilters (Collection filters);
    }
  
----

The +ISOFilter+ interface is very simple as well: 

[source,java]
----

    public interface ISOFilter {
        public ISOMsg filter (ISOChannel channel, ISOMsg m, LogEvent evt) 
            throws VetoException;
        }
    }
  
----

Whenever you add a filter (be it incoming, outgoing, or both) to a
FilteredChannel, all messages sent or received by that channel are passed
through that filter. 

Filters give you the opportunity to stop a given message from being sent or
received by that channel, by throwing an ISOFilter.VetoException. 

Let's have a look at a very simple filter, DelayFilter: 

[source,java]
----

    public class DelayFilter implements ISOFilter, Configurable {
        long delay;
        public DelayFilter() {
            super();
            delay = 0L;
        }
       /**
        * @param delay desired delay, expressed in milliseconds
        */
        public DelayFilter(long delay) {
            super();
            this.delay = delay;
        }
        public void setConfiguration (Configuration cfg) {
            delay = cfg.getInt ("delay");
        }
        public ISOMsg filter (ISOChannel channel, ISOMsg m, LogEvent evt) 
        {
            evt.addMessage ("<delay-filter delay=\""+delay+"\"/>");
            if (delay > 0L) 
                ISOUtil.sleep(delay);
            return m;
        }
    }
  
----

DelayFilter simply applies a given delay to all traffic being sent or received
by a given channel. It can be used to simulate remote host delays, a good tool
for testing purposes. 

But the filter method has the ability to modify the +ISOMsg+ object or to
just replace it with a new one. A handy +LogEvent+ is provided for log/audit
purposes.

[TIP]
=====
The previous code introduces a few classes and interfaces, namely
+Configuration+, +LogEvent+. We'll talk about these
important parts of jPOS soon.
=====

jPOS comes with many general purpose filters: 

* +MD5Filter+ can be used to authenticate messages; 
* +MacroFilter+ can be used  to expand internal variables and sequencers; and 
* +XSLTFilter+ can be used to apply XSLT Transformations to ISO-8583 messages. 


////
TODO: See the reference section of this document to get detailed information about available filters. 
////

There's a popular filter called +BSHFilter+ that can execute link:http://www.beanshell.org[BeanShell] 
code placed in an external file that can be modified at runtime without restarting
the system, providing an excellent way to make quick changes (which are welcome
during tests and initial rounds of certifications - the BSH code can be easily
migrated to Java later). 

[CAUTION]
=========
We've seen full applications implemented as BSH-based filters.
Those are very difficult to maintain and are significantly slower
than business logic implemented in Java code. We encourage you
to use this handy scripting capability as a tool for hot-fixes
and testing and remember to move the code to Java as soon as
you can.
=========

[[isoserver]]
=== Accepting connections with ISOServer

+ISOServer+ listens in a given port for incoming connections and takes care of
accepting them and passing control to an underlying ISOChannel implementation. 

Once a new connection is accepted and an ISOChannel is created, a
ThreadPool-controlled Thread takes care of receiving messages from it. 
Those messages are passed to an ISORequestListener implementation. 

.ISOServer
====
----

import org.jpos.iso.*;
import org.jpos.util.*;
import org.jpos.iso.channel.*;
import org.jpos.iso.packager.*;

public class Test {
    public static void main (String[] args) throws Exception {
        Logger logger = new Logger ();
        logger.addListener (new SimpleLogListener (System.out));
        ServerChannel channel = new XMLChannel (new XMLPackager());
        ((LogSource)channel).setLogger (logger, "channel");
        ISOServer server = new ISOServer (8000, channel, null);
        server.setLogger (logger, "server");
        new Thread (server).start ();
    }
}
----
====

[TIP]
=====
The third argument of ISOServer's constructor is an optional
ThreadPool. Should you pass a null parameter there, a new ThreadPool
is created for you, which defaults to 100 threads. 
(+new ThreadPool (1,100)+)

Once again, we show this sample code for 
educational purposes. In real life applications, you
want to use Q2's +QServer+ component instead.
=====

In order to test the previous server Test program (which is listening on port
8000), you can use a simple 'telnet' client where you will be able to type an
XML-formatted ISO-8583 message, e.g.: 

----

   $ telnet localhost 8000
   Trying 127.0.0.1...
   Connected to localhost.
   Escape character is '^]'.
  
----

Now if you have a look at your running Test program you'll see something like this: 

[source,xml]
----

    <log realm="server" at="Fri May 17 08:11:34 UYT 2002.824">
        <iso-server>
            listening on port 8000
        </iso-server>
    </log>
  
----

Back on your telnet session, you can type in an 
XML formatted ISO-8583 message like this: 

[source,xml]
----

   <isomsg>
    <field id="0" value="0800"/>
    <field id="3" value="333333"/>
   </isomsg>
 
----

(please note XMLChannel expects <isomsg> as well as </isomsg> to be placed as
the first thing in a line)
  
Your test program will then show: 

[source,xml]
----

    <log realm="server.channel" at="Fri May 17 07:56:58 UYT 2002.407">
     <receive>
      <isomsg direction="incoming">
       <field id="0" value="0800"/>
       <field id="3" value="333333"/>
      </isomsg>
     </receive>
    </log>
----

As stated above, you can add an ISORequestListener to your ISOServer that will
take care of actually processing the incoming messages. So let's modify our
little Test program to answer our messages. Our Test class has to implement
ISORequestListener, e.g.: 

[source,java]
----

public class Test implements ISORequestListener {
    ...
    ...
    public boolean process (ISOSource source, ISOMsg m) {
        try {
            m.setResponseMTI ();
            m.set (39, "00");
            source.send (m);
        } catch (ISOException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }
    ...
    ...
}
----

You have to assign this request listener to your server. You can do  this
assignment with the following instruction: 

[source,java]
----

    server.addISORequestListener (new Test ());
   
----


The full program looks like this: 

[source,java]
----

import java.io.*;
import org.jpos.iso.*;
import org.jpos.util.*;
import org.jpos.iso.channel.*;
import org.jpos.iso.packager.*;

public class Test implements ISORequestListener {
    public Test () {
        super();
    }
    public boolean process (ISOSource source, ISOMsg m) {
        try {
            m.setResponseMTI ();
            m.set (39, "00");
            source.send (m);
        } catch (ISOException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    public static void main (String[] args) throws Exception {
        Logger logger = new Logger ();
        logger.addListener (new SimpleLogListener (System.out));
        ServerChannel channel = new XMLChannel (new XMLPackager());
        ((LogSource)channel).setLogger (logger, "channel");
        ISOServer server = new ISOServer (8000, channel, null);
        server.setLogger (logger, "server");
        server.addISORequestListener (new Test ());
        new Thread (server).start ();
    }
}
----


Now try to telnet to port 8000 and send another XML-formatted ISO-8583 message.
You'll get a response, with a result code "00" (field 39), e.g.: 

----

    (you type)
    <isomsg>
     <field id="0" value="0800"/>
     <field id="3" value="333333"/>
    </isomsg>

    (and you should receive)
    <isomsg direction="outgoing">
      <field id="0" value="0810"/>
      <field id="3" value="333333"/>
      <field id="39" value="00"/>
    </isomsg>
   
----
 
ISOServer uses a ThreadPool in order to be able to accept multiple connections
at the same time. Every socket connection is handled by a single thread.  If
your request listener implementation takes too long to reply, new messages
arriving over that session will have to wait for their response. 

To solve this problem, your ISORequestListener implementation should run in its
own thread pool so that its process(...) method will just queue requests to be
processed by a peer thread. 

[TIP]
=====
Before worrying too much about handling simultaneous transactions, you'll be
happy to know that jPOS has a +TransactionManager+ that deals with that.
We'll cover it very soon, keep reading.
=====

////
TODO: We could add a link to the TransactionManager chapter in the previous tip 
////


ISOServer uses ISOChannel implementations to pull ISOMsgs from the wire.  These
ISOChannels can, of course, have associated filters as described earlier. 

[NOTE]
=====

In modern jPOS applications ISOServer is usually managed by the 
QServer service (see QServer). 
// TODO: Add link to qserver chapter when it becomes available
The ISORequestListener is usually a thin implementation
that forwards the request to the TransactionManager.
// TODO: add link to TransactionManager when it becomes available

 
=====

[[multiplexing_with_mux]]
=== Multiplexing an ISOChannel with a MUX

Imagine an acquirer implementation that receives several requests at a time
from several POS terminals and has to route them to an issuer institution by
means of an ISOChannel. 

While you can establish one socket connection per transaction, it is common use
to setup just one socket connection (handled by an ISOChannel instance) and
multiplex it. 

So a MUX is basically a *channel multiplexer*.  
Once you have instantiated a MUX, you just send a request and wait for the response. 

Originally, the MUX interface look like this: 

[source,java]
----
    public interface MUX {
        public ISOMsg request (ISOMsg m, long timeout) throws ISOException;
        public boolean isConnected();
    }
----
* The +ISOMsg request(ISOMsg, long)+ method queues
  a request to be sent by the underlying ISOChannel(s) and waits for
  the response up to the timeout specified in milliseconds. It either
  returns a response or null.
* +isConnected()+ is self explanatory, it returns
  true if the underlying channel(s) are connected.

[NOTE]
====

MUX is an interface that can have many different implementations.
Depending on the implementation and the configuration the 
value returned by +isConnected()+ might not
be reliable (it could return true even on an unconnected channel).

====

Recently footnote:[jPOS 1.6.1] we've added the ability to asynchronously queue requests, 
the new MUX interface has another +request+ method that returns immediately and calls 
an ISOResponseListener (with an optional handBack Object). 

[source,java]
----
    public interface MUX {
        ...
        ...
        public void request 
            (ISOMsg m, long timeout, ISOResponseListener r, Object handBack)
        throws ISOException;
    }
----
 
[NOTE]
=====

This new asynchronous way of calling the MUX is available in the
+QMUX+ implementation of the +MUX+ interface but it has not been 
back-ported to the +ISOMUX+ implementation which is going to be 
deprecated in future versions of jPOS.
ISOMUX has a +queue+ method that can be used to achieve a similar asynchronous
behavior. 

=====

In order to send responses to the appropriate sending thread, a +MUX+
implementation uses selected fields from the original +ISOMsg+ request
expected to be present in the +ISOMsg+ response. Although not part of the 
+MUX+ interface, implementations such as QMUX (the new one) and ISOMUX 
(the old one) have a protected method called +String getKey(ISOMsg m)+ that 
returns a matching key based on the +ISOMsg+ content. 

QMUX reads an XML file that honors a +<key>nn,nn,nn</key>+ child element
and can be used to easily set the appropriate matching key.

The default implementation uses fields such as 41 (Terminal ID) plus field 11
(Serial Trace Audit Number) to create an unique key. You can override
+getKey()+ in order to use other fields. 


.MUX example
====
[source,java]
----

    ...
    ...
    MUX mux = (MUX) NameRegister.get ("mux.mymultiplexer");
    ...
    ...
  
----


[source,java]
----

    ISOMsg m = new ISOMsg();
    m.setMTI ("0800");
    m.set (11, "000001");
    m.set (41, "00000001");
    ISOMsg response = mux.request (m, 30000);
    if (response != null) {
        // you've got a response
    } else {
        // request has timed out 
        // you may want to reverse or retransmit
    }
  
----

====

When a message arrives to MUX's underlying ISOChannel, the MUX implementation
checks to see if that message's 'key' is registered as a pending request. 

Should that key match a pending request, the response is handed to the waiting
thread. If the key was registered as a request, or the response comes in too
late then that response is (depending on the configuration) ignored, forwarded
to an ISORequestListener or to a well defined Space queue. (see QMUX for
details). 

Under many situations, the same channel that a client application may use to
send requests and wait for responses may also receive requests coming from the
remote server. 

Those _unmatched requests_ coming from the remote server are delegated to an 
+ISORequestListener+ (or a well defined "unhandled" Space queue). 

Let's have a look at the ISORequestListener interface: 

[source,java]
----

    public interface ISORequestListener {
        public boolean process (ISOSource source, ISOMsg m);
    }
  
----

Imagine we want to answer the 0800 echo requests arriving to our MUX. 
We can write the following implementation: 

[source,java]
----

   public class EchoHandler extends Log
        implements ISORequestListener 
   {
        public boolean process (ISOSource source, ISOMsg m) {
            try {
                if ("0800".equals (m.getMTI())) {
                    m.setResponseMTI ();
                    m.set (39, "00");
                    source.send (m);
                }
            } catch (Exception e) {
                warn ("echo-handler", e);
            }
            return true;
        }
   }
----

