Download as pdf or txt
Download as pdf or txt
You are on page 1of 27

jCard Internals

Table of Contents
Copyright notice ......................................................................................................................... v
1. jCard Server ........................................................................................................................... 1
1.1. jCard Server Lifecycle ............................................................................................... 1
1.2. jPOS CMF Server ...................................................................................................... 1
1.3. jPOS XML Server ...................................................................................................... 2
1.4. jCard Request Dispatcher ........................................................................................... 2
1.5. Incoming Handlers ..................................................................................................... 3
2. jCard Transaction Manager ................................................................................................... 5
3. jCard Transaction Manager Participants ............................................................................... 8
3.1. PrepareContext ............................................................................................................ 8
3.2. Open ............................................................................................................................ 9
3.3. Switch ....................................................................................................................... 10
3.4. Balance Inquiry Group ............................................................................................. 12
3.4.1. CheckFields participant ................................................................................. 13
3.4.2. CreateTranLog participant ............................................................................. 16
3.4.3. CheckCard participant ................................................................................... 18
3.4.4. CheckTerminal participant ............................................................................ 19
3.4.5. CheckAcquirer participant ............................................................................. 20
3.4.6. SelectAccount participant .............................................................................. 20
3.4.7. ComputeBalances participant ........................................................................ 21

ii
List of Figures
2.1. Transaction Manager .......................................................................................................... 5
2.2. Transaction Participants ..................................................................................................... 6
3.1. Card / CardHolder / Account Relatioship ........................................................................ 18
3.2. Terminal / Merchant related relationships ........................................................................ 19
3.3. Card / CardHolder / Account Relatioship ........................................................................ 21

iii
List of Tables
3.1. jCard supported transactions ............................................................................................ 11
3.2. CheckFields special constant names ................................................................................ 13

iv
Copyright notice
Copyright © 1998-2015 by Alejandro Revilla d/b/a jPOS Consulting, Company# 212 752 380 016 - Uruguay. All rights
reserved. No part of this book may be reproduced in any form or by any electronic or mechanical means, including
information storage and retrieval systems, without permission in writing from Alejandro Revilla, except by a reviewer who
may quote brief passages in a review.

v
Chapter 1. jCard Server
1.1. jCard Server Lifecycle
The lifecycle of a transaction managed by jCard starts at a server.

jCard can have multiple servers that in turn can operate using different ISO-8583 version/
variants.

There are two classes of servers:

• jCard Native servers that operate using the jPOS CMF [http://jpos.org/doc/jPOS-CMF.pdf]
• Customer specific servers that use other ISO-8583 versions/variants, or even non ISO-8583
based protocols and convert all incoming and outgoing messages to and from the jPOS
CMF

The non jCard servers can operate on the same JVM as jCard (if deployed on the same deploy
directory), or they can run at external JVMs or even external systems and in turn connect to a
native jCard server after the conversion to and from jPOS CMF took place.

We call those customer specific servers (either running on the same JVM or on external JVMs)
Source Stations.

1.2. jPOS CMF Server


The jPOS CMF server (ISO-8583 v2003) is defined in the file modules/jcard/
deploy/50_server.xml and its configuration looks like this:

<server name="jcard-server" class="org.jpos.q2.iso.QServer" logger="Q2">


<attr name="port" type="java.lang.Integer">@iso2003_server_port@</attr>
<channel name="jcard.channel"
class="org.jpos.iso.channel.CSChannel"
packager="org.jpos.iso.packager.GenericPackager" logger="Q2">
<property name="packager-config" value="cfg/iso2003binary.xml" />
<property name="timeout" value="300000" />
</channel>
<request-listener class="org.jpos.jcard.Dispatcher" logger="Q2"
realm="incoming-request-listener">
<property name="prefix" value="org.jpos.jcard.Incoming_" />
<property name="timeout" value="60000" />
<property name="space" value="tspace:default" />
<property name="queue" value="JCARD.TXN" />
</request-listener>
</server>

The previous configuration instantiates a standard jPOS ISOServer that listens on a port
defined in the target file (i.e. devel.properties)

The jPOS-EE build process uses Jakarta Ant’s filters to preprocess properties
defined in the build files (i.e. build.xml, build.properties, devel.properties)
providing property expansion. In the default jCard configuration, the property
iso2003_server_port is defined in devel.properties with a value of 8001.

1
jCard Server

The server uses the jPOS CSChannel and GenericPackager configured for ISO-8583
v2003. It uses a 5 minutes timeout (300000ms) and defines a request listener
org.jpos.jcard.Dispatcher and passes some configuration parameters to it, such as a space,
a transaction manager queue (JCARD.TXN) and a class prefix (org.jpos.jcard.Incoming_).
The Dispatcher completes the class name using the incoming message’s MTI and forwards the
transaction to the appropriate class, i.e:

• Incoming_100
• Incoming_200
• Incoming_220
• …
• …

1.3. jPOS XML Server


The jPOS CMF uses ISO-8583 v2003, but for testing/debugging purposes, jCard also uses
an ISO-8583 v2003 based XML server configured in the file modules/jcard/src/dist/
deploy/50_xml_server.xml.

The configuration looks like this:


<server name="jcard-xml-server" class="org.jpos.q2.iso.QServer" logger="Q2">
<attr name="port" type="java.lang.Integer">@xml_server_port@</attr>
<channel name="jcard.channel"
class="org.jpos.iso.channel.XMLChannel"
packager="org.jpos.iso.packager.XML2003Packager" logger="Q2">
<property name="timeout" value="300000" />
</channel>
<request-listener class="org.jpos.jcard.Dispatcher" logger="Q2"
realm="incoming-request-listener">
<property name="prefix" value="org.jpos.jcard.Incoming_" />
<property name="timeout" value="60000" />
<property name="space" value="tspace:default" />
<property name="queue" value="JCARD.TXN" />
</request-listener>
</server>

The previous configuration instantiates a standard jPOS ISOServer that listens on a port
defined in the target file (i.e. devel.properties).

See jPOS CMF Server for an explanation of how filters work as well as how the
request listener is configured.

This XML server uses jPOS XML representation of ISO-8583 messages (same as shown in the
jPOS logs).

1.4. jCard Request Dispatcher


The jCard Request Dispatcher is an ISORequestListener [http://jpos.org/doc/javadoc/org/
jpos/iso/ISORequestListener.html] that receives all traffic coming on the jCard main servers
(both ISO-8583 v2003 and XML ones) and forwards them to the appropriate handler for the
given MTI.

2
jCard Server

The code is located in modules/jcard/src/main/java/org/jpos/jcard/Dispatcher.java


and its process method looks like this:
public boolean process (ISOSource source, ISOMsg m) {
try {
String mti = m.getMTI();
String className = cfg.get("prefix", "") + mti.substring(1);
Class c = Class.forName(className);
if (c != null) {
ISORequestListener rl = (ISORequestListener) c.newInstance();
if (rl instanceof LogSource)
((LogSource)rl).setLogger
(getLogger(), getRealm()+"-"+mti);
if (rl instanceof Configurable)
((Configurable)rl).setConfiguration (cfg);
return rl.process (source, m);
}
} catch (ClassNotFoundException e) {
warn (e.getClass().getName() + " " + e.getMessage());
} catch (InstantiationException e) {
warn (e);
} catch (IllegalAccessException e) {
warn (e);
} catch (ISOException e) {
warn (e);
}
return false;
}

Please note that we append the MTI to the configured prefix


(org.jpos.jcard.Incoming_ in order to locate the appropriate handler class. The
MTI in jPOS includes the ISO-8583 version number (in this case the number 2
representing ISO-8583 version 2003), so we use the code mti.substring(1) to
pick just the three-letter MTI.

1.5. Incoming Handlers


Once a message reaches one of the jCard’s ISOServers, it gets forwarded to the Request
Dispatcher, which in turn would instantiate an appropriate handler based on the Message’s
MTI.

As a small example, an 800 message (Network Management) would get forwarded to


Incoming_800 which is implemented like this:

public class Incoming_800 extends Log implements ISORequestListener {


public boolean process (ISOSource source, ISOMsg m) {
try {
m.setResponseMTI ();
m.set (39, "0000");
source.send (m);
} catch (Exception e) {
warn (e);
}
return true;
}
}

This is a very simple handler that would just echo back a 810 response.

On the other hand, other messages, such as 100, 200, 220, 304 and 420s are more complex
and handled by the Transaction Manager. The implementation classes inherit from
IncomingSupport and are implemented like this:

3
jCard Server

public class Incoming_100 extends IncomingSupport { }


public class Incoming_200 extends IncomingSupport { }
...
...
public class Incoming_420 extends IncomingSupport { }

IncomingSupport uses code like this in its process method.


public boolean process (ISOSource source, ISOMsg m) {
Context ctx = new Context ();

ctx.put (REQUEST, m);


String txnname = m.getString(0).substring(1);
if (m.hasField(3)) { // processing code
String pcode = m.getString(3);
if (pcode.length() > 2)
txnname = txnname + "." + pcode.substring(0,2);
}
if (m.hasField(24)) {
txnname = txnname + "." + m.getString(24); // function code
if (m.hasField (101))
txnname = txnname + "." + m.getString(101); // file name
}
if (m.hasField(25)) {
txnname = txnname + "." + m.getString(25); // reason code
}
ctx.put (TXNNAME, txnname);
ctx.put (SOURCE, source); // source is Transient
sp.out (queue, ctx, timeout); // hands off to the TransactionManager
return true;
}

This basically:

• Creates a TransactionManager Context [http://jpos.org/doc/javadoc/org/jpos/transaction/


Context.html] (ctx).
• Creates a transaction name variable (TXNNAME) based on the MTI, the first two digits of
processing code (data element 3), and optionally the content of data element 24 (function
code) and data element 25 (reason code). In situations where data element 24 is present, an
optional data element 101 (file name) may be appeneded to the transaction name.
• Puts a reference to the ISOSource [http://jpos.org/doc/javadoc/org/iso/ISOSource.html]
provided by the process method of the ISORequestListener [http://jpos.org/doc/javadoc/
org/jpos/iso/ISORequestListener.html] in the Context under the constant name SOURCE.
• Places the Context in a space under the queue defined in the XML configuration for the
server. This queue has to be the same used by the TransactionManager (in our case,
"JCARD.TXN").

In adition to the queue name, we define a timeout (in millis). The Context is placed in the
Space for a given time; ideally, it should be picked immediately by the TransactionManager.
If the timeout expires, the entry will be lost. Interesting enough, due to the way the
ISO-8583 operates, this is a good thing. If for some reason a transaction doesn’t reach the
TransactionManager in a reasonable short period of time, it would indicate that the system is
experiencing problems (such as a database being down, extremely high load, network issue,
etc.). The best thing is to ignore the aging transactions so that the system recovers faster when
the situation gets resolved. The remote endpoint will retry the transactions and the system will
be back up and running faster than if we try to process transactions that wouldn’t reach the
remote endpoint anyway, because they have been timed out already.

4
Chapter 2. jCard Transaction Manager
jCard uses the jPOS TransactionManager [http://jpos.org/doc/javadoc/org/jpos/
transaction/TransactionManager.html] 1 to implement its business logic using
reusable TransactionParticipant’s [http://jpos.org/doc/javadoc/org/jpos/transaction/
TransactionParticipant.html].

The TransactionManager implements a two-phase commit protocol, where participants get


called usually twice; the first time at prepare time, and then — if all participants agree to
proceed with the transaction — at commit time. If, for some reason, one of the participants
aborts the transaction, then those participants that were previously called (using their prepare
callback method) will get a call to their abort method. There are special type of participants,
the AbortParticipants that get called even if the transaction is going to abort, and the
GroupSelectors that can provide some handy grouping of related participants.

Figure 2.1. Transaction Manager

jCard splits the business logic implementation into small little reusable chunks that we call
participants. A typical transaction would:

• Prepare the context with useful information such as a transaction timestamp


• Perform some initial sanity checks on the message
• Create an Hibernate session and begin a JDBC transaction
• Create a TranLog record in the database with information taken from the request
• Then perform multiple validations on the CardHolder, the Card, the Accounts…
• …and similarly with Balance, Velocity checks, etc.
• At some point the transaction is ready, so it’s logged and the JDBC transaction is committed
• A suitable response gets created and transmitted back to the client

Here is an overly simplified example of the aforementioned steps:


1
Documented in the jPOS Programmer’s Guide on chapter 10, and in the new Programmer’s Guide Draft http://jpos.org/doc/
proguide-draft.pdf on chapter 9 (work in progress, so the numbering may change).

5
jCard Transaction Manager

Figure 2.2. Transaction Participants

The transaction manager configuration is located in modules/jcard/src/dist/


deploy/10_txnmgr.xml.

The configuration starts like this:


<txnmgr class="org.jpos.transaction.TransactionManager" logger="Q2">
<property name="queue" value="JCARD.TXN" />
<property name="sessions" value="2" />
<property name="debug" value="true" />
...

<!-- List of participants and groups of participants -->


<participant class="org.jpos.jcard.PrepareContext" logger="Q2" realm="prepare-context" />
...
<group name="xxx">
<participant ... />
<participant ... />
...
</group>
...
</txnmgr>

This creates a TransactionManager named txnmgr (it doesn’t explicitly define a name
attribute, so the element name is used as the service name) and define the following properties:

• queue: This is the name of the Space [http://jpos.org/doc/javadoc/org/jpos/space/


Space.html] queue used to send transactions to the TransactionManager. We use the
arbitrary name JCARD.TXN but it could have been any other name, as long as the name
matches the queue name defined in the request listeners (see modules/jcard/src/dist/
deploy/50_*_server.xml)
• sessions: The TransactionManager can process multiple simultaneous sessions. We use
a low default value (2) in our tests servers in order to reduce the log size and simplify its
reading. Larger values can be used in production. The optimum value will depend on the
number of processors available.
• debug: if true, the TransactionManager will produce a log ticket after every transaction
with useful information about the transaction and the participants involved, with their timing
and results.

6
jCard Transaction Manager

• participants: Then it follows a list, or chain, of TransactionParticipant's (or named


groups that will process the transaction step by step. In the following chapter we’ll take a
look at some of them.

As we said above, if the TransactionManager definition has its debug property enabled, it
will produce log ticket. Here is a sample of what they look like:
T 2010.589" lifespan="56ms">
<debug>
txnmgr-0:151
prepare: org.jpos.jcard.PrepareContext NO_JOIN
prepare: org.jpos.transaction.Open READONLY NO_JOIN
prepare: org.jpos.jcard.Switch READONLY NO_JOIN
groupSelector: reversal prepareresponse logit close sendresponse
prepare: org.jpos.jcard.CheckFields NO_JOIN
prepare: org.jpos.jcard.CreateTranLog NO_JOIN
prepare: org.jpos.jcard.CheckCard NO_JOIN
prepare: org.jpos.jcard.CheckTerminal NO_JOIN
prepare: org.jpos.jcard.CheckAcquirer NO_JOIN
prepare: org.jpos.jcard.FindOriginal READONLY NO_JOIN
prepare: org.jpos.jcard.Reverse READONLY NO_JOIN
prepare: org.jpos.jcard.PrepareResponse NO_JOIN
prepare: org.jpos.jcard.LogIt READONLY NO_JOIN
prepare: org.jpos.transaction.Close READONLY
prepare: org.jpos.jcard.SendResponse READONLY
prepare: org.jpos.jcard.ProtectDebugInfo READONLY
prepare: org.jpos.transaction.Debug READONLY
commit: org.jpos.transaction.Close
commit: org.jpos.jcard.SendResponse
commit: org.jpos.jcard.ProtectDebugInfo
commit: org.jpos.transaction.Debug
head=152, tail=152, outstanding=0, tps=12, peak=13, avg=9.38, elapsed=56ms
<profiler>
prepare: org.jpos.jcard.PrepareContext [0.0/0.0]
prepare: org.jpos.transaction.Open [0.6/0.6]
prepare: org.jpos.jcard.Switch [0.0/0.6]
prepare: org.jpos.jcard.CheckFields [0.2/0.9]
prepare: org.jpos.jcard.CreateTranLog [1.2/2.1]
prepare: org.jpos.jcard.CheckCard [4.2/6.4]
prepare: org.jpos.jcard.CheckTerminal [0.8/7.2]
prepare: org.jpos.jcard.CheckAcquirer [0.6/7.9]
prepare: org.jpos.jcard.FindOriginal [2.3/10.2]
prepare: org.jpos.jcard.Reverse [29.5/39.7]
prepare: org.jpos.jcard.PrepareResponse [1.7/41.5]
prepare: org.jpos.jcard.LogIt [0.1/41.7]
prepare: org.jpos.transaction.Close [0.0/41.7]
prepare: org.jpos.jcard.SendResponse [0.0/41.7]
prepare: org.jpos.jcard.ProtectDebugInfo [0.0/41.7]
prepare: org.jpos.transaction.Debug [0.0/41.7]
commit: org.jpos.transaction.Close [4.5/46.3]
commit: org.jpos.jcard.SendResponse [0.8/47.1]
commit: org.jpos.jcard.ProtectDebugInfo [0.1/47.3]
commit: org.jpos.transaction.Debug [9.0/56.3]
end [56.9/56.9]
</profiler>
</debug>
</log>

We sometimes call this debug tickets

7
Chapter 3. jCard Transaction Manager
Participants
Once the transaction reaches the top of the Transaction Manager’s queue, it gets processed by
the participants defined in the file modules/jcard/src/dist/deploy/10_txnmgr.xml.

In this chapter we’ll take a look at some of the most significant ones, to have an idea of what
they do and how they work together to accomplish a full transaction. :numbered:

3.1. PrepareContext
The PrepareContext participant is the very first participant in the execution chain. It is
configured in ../deploy/10_txnmgr.xml like this:
<txnmgr ...>
...
<participant class="org.jpos.jcard.PrepareContext" logger="Q2" realm="PrepareContext" />
...
</txnmgr>

PrepareContext (available at modules/jcard/src/main/java/org/jpos/jcard/


PrepareContext.java) prepares the Context (actually an org.jpos.transaction.Context)
with helpful objects required by other participants down the execution chain, such as:

• TIMESTAMP:It is desirable that all participants in a given transaction use exactly the same
timestamp, in order to avoid edge conditions where a transaction starts at a given date (i.e.
23:59:59.99) and finish the next day (i.e.: at 00:00:00.00). These conditions not only happen
at day boundary, they could happen at cutover times, etc.
• TXNMGR: In situations where a transaction is forwarded from one transaction manager
to another one (using the Forward participant), this context variable keeps a list of the
transaction managers involved in a given transaction.

Implementing PrepareContext is trivial, the code looks like this:


public class PrepareContext extends TxnSupport {
TransactionManager txnmgr;

public int prepare (long id, Serializable o) {


Context ctx = (Context) o;
ctx.getProfiler();
if (ctx.get (TIMESTAMP) == null)
ctx.put (TIMESTAMP, new Date());

String name = ctx.getString (TXNMGR);


name = name == null ?
txnmgr.getName() : ", " + txnmgr.getName();
ctx.put (TXNMGR, name);

return PREPARED | NO_JOIN;


}

public void setTransactionManager (TransactionManager txnmgr) {


this.txnmgr = txnmgr;
}

public void commit (long id, Serializable o) { }


public void abort (long id, Serializable o) { }
}

8
jCard Transaction
Manager Participants
The code is straight forward, but it deserves a few comments and clarifications:

• The constants TIMESTAMP and TXNMGR are defined in file modules/jcard/src/main/java/


org/jpos/ee/Constants.java, and taken at runtime from the org.jpos.ee.Constants
interface.
• The method void setTransactionManager (TransactionManager txnmgr) is
not part of the TransactionParticipant [http://jpos.org/doc/javadoc/org/jpos/
transaction/TransactionParticipant.html] interface, but if available, it gets called by
the TransactionManager — providing a reference to itself — at initialization time.
1
PrepareContext uses this technique in order to grab a reference to the transaction manager
so it can properly set the TXNMGR context variable.

3.2. Open
The Open participant creates a new org.jpos.ee.DB object, which in turns holds a live
Hibernate and JDBC session. It stores a reference to the DB object in the context, under the
name DB (defined in the org.jpos.ee.Constants interface). In addition, it begins a Hibernate/
JDBC transaction, and stores it under the name TX.

The configuration looks like this:


...
<participant class="org.jpos.transaction.Open" logger="Q2" realm="open">
<property name="checkpoint" value="open" />
<property name="timeout" value="300" />
</participant>
...

The configuration defines the following properties:

• checkpoint: This participant uses the general purpose jPOS Profiler [http://jpos.org/doc/
javadoc/org/jpos/util/Profiler.html] in order to have realtime, fine grained, information
about the system’s performance. We store a checkpoint called open that will appear at the
end of every transaction (courtesy of the participant Debug that dumps the Context variables
to the jPOS log).
• timeout: This is a timeout passed to Hibernate, which in turn passes it to the underlying
JDBC session. It is expressed in tenths of a second (in this case, 30.0 seconds).

org.jpos.transaction.Open is located in jPOS-EE’s txn module and its implementation uses


the support class org.jpos.transaction.TxnSupport.

TxnSupport provides a standard implementation of the prepare method, which in


turn calls a protected doPrepare method. TxnSupport's prepare method creates
a safety net around doPrepare, taking care of catching and logging possible
exceptions.

1
Duck typing

9
jCard Transaction
Manager Participants

3.3. Switch
Once the Context is prepared, and a Hibernate/JDBC session has been opened, we are
ready to analize the transaction and decide how to route it, using a TransactionManager's
GroupSelector [http://jpos.org/doc/javadoc/org/jpos/transaction/GroupSelector.html].

The participant org.jpos.jcard.Switch implements said GroupSelector. The


implementation is quite straight forward:
public class Switch extends TxnSupport implements GroupSelector {
public int prepare (long id, Serializable context) {
return PREPARED | READONLY | NO_JOIN;
}
public void commit (long id, Serializable ser) { }
public void abort (long id, Serializable ser) { }

public String select (long id, Serializable ser) {


Context ctx = (Context) ser;
String type = (String) ctx.get(TXNNAME);
String groups = null;
if (type != null)
groups = cfg.get(type, null);
if (groups == null)
groups = cfg.get("unknown", "");

// Debug info in context


ctx.put("SWITCH", type + " (" + groups + ")");
return groups;
}
}

Switch extends TxnSupport just to enjoy a couple of helper methods, such as the fact that
it already implements org.jpos.util.Configurable. It does nothing at prepare time, and
returns a PREPARE | READONLY | NO_JOIN value that tells the TransactionManager that:

• The participant is prepared.


• It did not modify the Context, so no need to take a persistent snapshot of it.
• It doesn’t need to be called at prepare or abort time (NO_JOIN modifier)

Then the select method uses the TXNNAME provided by the incoming handlers in order to
figure out which set of groups are going to process this transaction. It keys off the TXNNAME
using configuration properties provided in the transaction manager configuration file
(.../deploy/10_txnmgr.xml) that looks like this:
...
<participant class="org.jpos.jcard.Switch" logger="Q2" realm="Switch">
<property name="100.30"
value="balanceinquiry prepareresponse logit close sendresponse" />
<property name="100.00"
value="authorization prepareresponse logit close sendresponse" />
<property name="100.02"
value="auth-void prepareresponse logit close sendresponse" />
<property name="100.20"
value="refund prepareresponse logit close sendresponse" />
<property name="100.22"
value="refund-void prepareresponse logit close sendresponse" />
...
...
</participant>
...

10
jCard Transaction
Manager Participants
The identifiers that appear in the value attributes of each property are the names
of groups defined in the transaction manager configuration file. For a deeper
explanation, please refer to the previous chapter, and to the Programmer’s Guides
given on that chapter’s footnote.

The configuration is self-explanatory, a balance inquiry transaction (MTI=100, processing


code starts with 30) would run the following groups:

• balanceinquiry: gets the balance for a given card/cardholder/account type


• prepareresponse: prepares a response
• logit: logs the transaction to the database
• close: commits the JDBC transaction, so we can be sure the transaction is logged to
persistent storage
• sendresponse: sends a response back to the originating point

The interesting point about jPOS TransactionManager in general, and jCard’s use
of it in particular, is the fact that the system reuses most of the transaction participant
implementations, and even the groups of participants placed together under a given name (i.e.:
logit, or sendresponse, etc.).

jCard currently supports the following transactions:

Table 3.1. jCard supported transactions


ITC Name Description
100.30 Balance Inquiry Computes the balance available and ledger balance for a given
account identified by the processing code’s account type (third and
forth digits of data element 003)
100.00 Authorization Authorization transaction, targets the cardholder’s account associated
with the account type specified in the processing code.
100.02 Authorization Voids a previously authorized transaction
void
100.20 Refund Initiates a refund transaction
100.22 Refund void Voids a previously authorized refund transaction
200.00 POS Purchase Similar to 100.00 (Authorization), operates on the accounting layer.
200.01 Cash Withdrawal Business logic is similar to POS Purchase, but withdrawals get
a special ITC (internal transaction code) for reporting and risk
management purposes.
200.02 Void Voids a POS Purchase or Cash Withdrawal
200.20 Financial refund ditto
200.21 Deposit Payment/Deposit to account
Returns and deposits use a special account which is not
immediately accessible to cardholders, until an EOD process moves it
to an appropriate and usable account.
200.22 Voids a
previously
processed refund/
deposit

11
jCard Transaction
Manager Participants
ITC Name Description
200.40 Account transfer Used to transfer funds from different accounts of the same cardholder
(i.e.: checking to savings)
220.00.0000 Purchase advice.
A previously
authorized
transaction
(pending layer)
gets confirmed
by a purchase
advice.
220.20.0000 Refund advice Same for refunds
220.00.1000 Force post Records a refund that was not previously authorized by the system.
The value 1000 here represents: "Stand-In processing at the card
issuer’s option".
See jPOS-CMF document, Appendix D, Reason Codes.
220.00.2000 Force post Representment
220.20.1000 Refund/Return
force post
220.20.4500 Chargeback
notification
420.00.0000 Purchase/
Authorization
reversal
420.01.0000 Cash withdrawal
reversal
420.02.0000 Void reversal
420.20.0000 Refund reversal
420.21.0000 Deposit reversal
420.40.0000 Transfer reversal
304.301.CUSTOMER File update Adds a new customer
304.301.MERCHANT File update Adds a new merchant

For a complete list of Message Type Indicators and Processing Codes, refer to the
jPOS-CMF [http://jpos.org/doc/jPOS-CMF.pdf] document.

3.4. Balance Inquiry Group


The Balance Inquiry transaction (itc "100.30") executes the groups:

• balanceinquiry
• prepareresponse
• logit
• close
• sendresponse

and then continues to the participants ProtectDebugInfo and Debug defined after the main
Switch.

12
jCard Transaction
Manager Participants
This section describes the participants used by the balanceinquiry group.

3.4.1. CheckFields participant


Sample configuration
<participant class="org.jpos.jcard.CheckFields"
logger="Q2" realm="CheckRequiredFields">
<property name="mandatory" value="PCODE,7,11,12,13,AMOUNT,PAN,41" />
<property name="optional" value="17,24,32,37,42,43,46,60,63,111" />
</participant>

The class org.jpos.jcard.CheckFields, located in the jcard module, checks for mandatory
and optional fields in the incoming message (available in the Context under the constant name
REQUEST.

In addition to checking field presence by their field number, CheckFields understands several
special names that, when found, are then placed in the Context for the benefit of the following
participants.

Table 3.2. CheckFields special constant names


Constant Name Description
PAN Extracts the PAN from the original message, either from data element 35 on
a swiped transaction, or from data elements 2 and 14. Places the entries PAN
and EXP (expiration) in the Context. Throws an INVALID_CARD business logic
exception (BLException) if a primary account number could not be found in
the request.
PCODE Puts four variables in the context:

• PCODE: full content of data element 3 (6 digits)


• PCODE_TXN_TYPE: transaction type (first two digits of the processing code)
• PCODE_ACCOUNT_TYPE: [source] account type (second group of two digits of
the processing code)
• PCODE_ACCOUNT2_TYPE: destination account type (third group of two digits of
the processing code)

Throws an INVALID_REQUEST BLException on errors.


ORIGINAL_DATA_ELEMENTS Parses field 56 and places the following variables in the Context:

• ORIGINAL_MTI: with the MTI of the original transaction


• ORIGINAL_STAN: with the STAN (field 11) of the original transaction
• ORIGINAL_TIMESTAMP: Timestamp (field 7) of the original transsaction
AMOUNT Picks the transaction amount off field 4 and places the following variables in
the context:

• AMOUNT: a BigDecimal containing the transaction amount. Decimals are


adjusted according to the currency in use
• CURRENCY: ISO-4217 currency code.

Throws INVALID_AMOUNT BLException on errors.


NETWORK_CAPTURE_DATE Parses the capture date and places it in the Context as a java.util.Date
Object under the name NETWORK_CAPTURE_DATE. Throws INVALID_REQUEST on
errors.
ADDITIONAL_AMOUNT Picks additional amount off field 54.

13
jCard Transaction
Manager Participants
Constant Name Description
Field 7 If Field 7 (transmission date) is present in the list of mandatory or optional
fields, a TRANSMISSION_TIMESTAMP Date object is placed in the Context.
Field 12 If Field 12 (local transaction date) is present in the list of mandatory or optional
fields, a LOCAL_TRANSACTION_TIMESTAMP Date object is placed in the Context.
Field 41 If field 41 (Terminal ID) is present in the list of mandatory or optional fields,
its string representation gets placed in the Context under the name TID.
Field 42 If field 42 (Merchant ID) is present in the list of mandatory or optional fields,
its string representation gets placed in the Context under the name MID.

Sample transaction
The Debug participant dumps the context after the transaction has been processed. A typical
Context would look like this:
<log realm="debug" at="Fri Oct 15 18:22:54 UYST 2010.351">
<commit>
<id>148</id>
<context>
<entry key='REQUEST'>
<isomsg direction="incoming">
<!-- org.jpos.iso.packager.GenericPackager[cfg/iso2003binary.xml] -->
<field id="0" value="2100"/>
<field id="2" value="0000000001"/>
<field id="3" value="000000"/>
<field id="4" currency="840" type="amount" value="6.00"/>
<field id="7" value="1015182254"/>
<field id="11" value="000000000144"/>
<field id="12" value="20101015182254"/>
<field id="13" value="001015"/>
<field id="14" value="4912"/>
<field id="17" value="1015"/>
<field id="32" value="000001"/>
<field id="37" value="150622174247"/>
<field id="41" value="29110001 "/>
<field id="42" value="001001"/>
<isomsg id="43">
<!-- org.jpos.iso.packager.GenericSubFieldPackager -->
<field id="2" value="jCard Selftest system"/>
<field id="4" value="Lagos"/>
<field id="5" value="LG "/>
<field id="7" value="NG "/>
</isomsg>
</isomsg>
</entry>
<entry key='TXNNAME'>100.00</entry>
<entry key='SOURCE'>org.jpos.iso.channel.CSChannel@59d6e3d2</entry>
<entry key='PROFILER'>
<profiler>
open [0.7/0.7]
create-tranlog [1.5/2.3]
check-card [5.0/7.3]
check-terminal [0.8/8.1]
check-acquirer [0.7/8.8]
select-account [0.0/8.9]
check-previous-reverse [3.7/12.6]
check-velocity [9.9/22.5]
authorization-start [0.0/22.6]
authorization-pre-lock-journal [1.9/24.5]
authorization-post-lock-journal [2.6/27.1]
authorization-compute-balance [3.6/30.8]
authorization-post-transaction [16.2/47.1]
authorization [0.0/47.1]
create-cache-ledger [26.1/73.2]
create-cache-pending-and-credit [6.8/80.0]
create-cache-pending [7.8/87.9]

14
jCard Transaction
Manager Participants
compute-balances [0.0/87.9]
prepare-response [2.8/90.7]
log-response [0.2/91.0]
close [4.7/95.7]
end [98.1/98.1]
</profiler>
</entry>
<entry key='TIMESTAMP'>Fri Oct 15 18:22:54 UYST 2010</entry>
<entry key='TXNMGR'>txnmgr</entry>
<entry key='DB'>org.jpos.ee.DB@7f4f84d5</entry>
<entry key='SWITCH'>100.00 (authorization prepareresponse logit close sendresponse)</entry>
<entry key='PCODE'>000000</entry>
<entry key='PCODE_TXN_TYPE'>00</entry>
<entry key='PCODE_ACCOUNT_TYPE'>00</entry>
<entry key='PCODE_ACCOUNT2_TYPE'>00</entry>
<entry key='TRANSMISSION_TIMESTAMP'>Fri Oct 15 18:22:54 UYST 2010</entry>
<entry key='LOCAL_TRANSACTION_TIMESTAMP'>Fri Oct 15 18:22:54 UYST 2010</entry>
<entry key='AMOUNT'>6.00</entry>
<entry key='CURRENCY'>840</entry>
<entry key='TID'>29110001 </entry>
<entry key='NETWORK_CAPTURE_DATE'>Fri Oct 15 12:00:00 UYST 2010</entry>
<entry key='MID'>001001</entry>
<entry key='TRANLOG'>org.jpos.ee.TranLog@635e6e9f[id=147]</entry>
<entry key='CAPTURE_DATE'>Fri Oct 15 00:00:00 UYST 2010</entry>
<entry key='CARD'>org.jpos.ee.Card@67360e7[id=4,pan=000000...0001]</entry>
<entry key='CARDHOLDER'>org.jpos.ee.CardHolder@3fea9527[id=2]</entry>
<entry key='ISSUER'>org.jpos.ee.Issuer@64fa32bb[id=1,name=1]</entry>
<entry key='ACQUIRER'>org.jpos.ee.Acquirer@6f3fd5c[id=1,name=1]</entry>
<entry key='ACCOUNT'>org.jpos.gl.FinalAccount@1cb4ccc5[id=1042,code=21.0000000001.00]</entry>
<entry key='LOGEVT'><log realm="" at="Fri Oct 15 18:22:54 UYST 2010.352" lifespan="90ms">
<log>
---- reverse check ----
CriteriaImpl(org.jpos.ee.TranLog:this[][date>=Fri Oct 15 17:22:54 UYST 2010, irc=1816, stan=000000
</log>
</log>
</entry>
<entry key='GLSESSION'>org.jpos.gl.GLSession@3d99fd3f</entry>
<entry key='RC'>0000</entry>
<entry key='APPROVAL_NUMBER'>464166</entry>
<entry key='LEDGER_BALANCE'>8.05</entry>
<entry key='AVAILABLE_BALANCE'>4.00</entry>
<entry key='IRC'>0</entry>
<entry key='RESPONSE'>
<isomsg direction="outgoing">
<!-- org.jpos.iso.packager.GenericPackager[cfg/iso2003binary.xml] -->
<field id="0" value="2110"/>
<field id="2" value="0000000001"/>
<field id="3" value="000000"/>
<field id="4" currency="840" type="amount" value="6.00"/>
<field id="7" value="1015182254"/>
<field id="11" value="000000000144"/>
<field id="12" value="20101015182254"/>
<field id="13" value="001015"/>
<field id="14" value="4912"/>
<field id="17" value="1015"/>
<field id="32" value="000001"/>
<field id="37" value="150622174247"/>
<field id="38" value="464166"/>
<field id="39" value="0000"/>
<field id="41" value="29110001 "/>
<field id="42" value="001001"/>
<isomsg id="43">
<!-- org.jpos.iso.packager.GenericSubFieldPackager -->
<field id="2" value="jCard Selftest system"/>
<field id="4" value="Lagos"/>
<field id="5" value="LG "/>
<field id="7" value="NG "/>
</isomsg>
<field id="54" value="00028402C00000000040000018402C000000000805"/>
<field id="63" value="APROBADO"/>
</isomsg>
</entry>
</context>
</commit>
</log>

15
jCard Transaction
Manager Participants
Some of the variables there, such as MID,
TID, NETWORK_CAPTURE_DATE, PCODE,
PCODE_TXN_TYPE, PCODE_ACCOUNT_TYPE, PCODE_ACCOUNT2_TYPE, etc. are placed by this
CheckFields participant.

3.4.2. CreateTranLog participant


Sample configuration
<participant class="org.jpos.jcard.CreateTranLog"
logger="Q2" realm="create-tranlog">
<property name="capture-date" value="capture-date" />
<property name="checkpoint" value="create-tranlog" />
<property name="node" value="01" />
</participant>

Once the CheckFields participant has performed reasonable sanity checks against the
incoming message, we are ready to create a TranLog record.

The TranLog record is defined in the org.jpos.ee.TranLog entity (see modules/jcard/src/


main/java/org/jpos/ee/TranLog.java and its modules/jcard/src/main/resources/org/
jpos/ee/TranLog.hbm.xml mapping file).

The CreateTranLog participant understands the following configuration parameters:

• capture-date: This is the name of the CaptureDate service (org.jpos.ee.CaptureDate)


defined in the …/deploy/01_capture_date.xml service. It provides a system-wide current
capture date.
• node: In a multi-node jCard deployment, users can configure the transaction managers
to use different node names. This info-only node name gets stored in the tranlog.node
column of the database record (see more about the database record below).
• checkpoint: This property is actually managed by CreateTranLog's super class TxnSupport
which calls checkpoint on the profiler available in the Context. When the Context gets
dumped by the last participant (the Debug participant), the profiler is displayed with useful
information about the time spent by each participant.

Here is a sample output:


<entry key='PROFILER'>
<profiler>
open [0.5/0.5]
create-tranlog [3.7/4.3]
compute-balances [62.0/66.3]
close [25.8/92.2]
end [98.2/98.2]
</profiler>
</entry>

The time is expressed in millis, in this case, the open participant took half a millisecond, and
the create-tranlog participant 3.7ms. The second figure is the running total (in this case, 3.7ms
+0.5ms=4.3ms).

Participants that extend TxnSupport can be configured to create a checkpoint in the


profiler. This is very useful during application tunning.

16
jCard Transaction
Manager Participants
CreateTranLog creates a TranLog record in the database, and populates a set of initial fields
that include:

• Date: it uses the TIMESTAMP Date object available in the Context, courtesy of the
PrepareContext participant.
• LocalTransactionDate: LOCAL_TRANSACTION_TIMESTAMP taken by CheckFields from fields
12 and 13 when available.
• TransmissionDate: TRANSMISSION_TIMESTAMP taken by CheckFields from field 7, usually
available.
• Node: this is the Node name taken from the participant’s configuration property node.
• Itc: the Internal Transaction Code, this is the TXNNAME context variable, placed by the
request listener (IncomingSupport).
• originalItc: On reversals and voids, CheckFields takes the original data elements off the
composite field 56. In particular, originalItc is taken off ORIGINAL_MTI.
• localId: This is the per-instance TransactionManager's id for this transaction. Can be used
to track the transaction in the jPOS logs for debugging purposes.
• Outstanding: This is the number of pending Contexts available in the
TransactionManager's input queue. Usually provides an estimate of the system load. This
value should be really low, ideally 0, at all times.
A higher value here means the system is under heavy load or experiencing a problem and
requires further review.
• Acquirer: taken directly from field 32, if present, otherwise defaults to 000000.
• Mid: Merchant ID, taken directly from field 42, if present.
• Tid: Terminal ID, taken directly from field 41 (usually present).
• Stan: Serial Transaction Audit Number, taken directly from field 11 (usually present).
• ApprovalNumber: taken from field 38, if available.
• ResponseCode: on force-post transactions, field 39 (response code) may be present.
• Currency: The CURRENCY object optionally placed in the Context by CheckFields, taken
from the composite amount field 4.
• Amount: Transaction amount, placed in the Context by CheckFields under the name
AMOUNT.
• AdditionalAmount: If available, placed in the Context by CheckFields under the name
ADDITIONAL_AMOUNT.
• CaptureDate: The system’s capture date, taken from the CaptureDate service.
• FunctionCode: Taken directly from field 24, if present.
• ReasonCode: Taken directly from field 25, if present.
• FileName: on File Update transactions (MTI=304), taken from field 101 (file name), if
present.

After populating the TranLog object with the aforementioned fields, and saving it to the
underlying Hibernate/JDBC session (created by the Open participant), CreateTranLog sets the
following objects in the Context:

• TRANLOG: a reference to the newly created TranLog object


• CAPTURE_DATE: the capture date provided by the CaptureDate service and used by this
transaction

17
jCard Transaction
Manager Participants

3.4.3. CheckCard participant


Sample configuration
<participant class="org.jpos.jcard.CheckCard"
logger="Q2" realm="checkcard">
</participant>

In the jCard system, a Card (org.jpos.ee.Card entity) is just a reference to a


CardHolder (org.jpos.ee.CardHolder) which in turn can hold general ledger accounts
(org.jpos.gl.Account, actually org.jpos.gl.FinalAccount). 2

Figure 3.1. Card / CardHolder / Account Relatioship

CheckCard locates the Card from the card table, but there’s a caveat: the Primary Account
Number (PAN) available in the Context (placed by the CheckFields participant) can’t be used
to find the card in the table because, due to PCI compliance, cards are encrypted.

In addition, the encryption scheme we use (DUKPT 3 can not be used either, because the same
card encrypted two different times will create two different cryptograms. So jCard uses a hash
(hash column in the card table).

CheckCard then picks the PAN off the Context, computes its hash, and searches using that
hash in the Card database. Once found, a live reference to the org.jpos.ee.Card entity is
placed in the Context under the name CARD.

Once we have the Card reference in memory, we can pull the CardHolder using the
card.getCardHolder() method. CheckCard verifies that we have a valid and active
cardholder (its active property has to be true). It also performs some verifications and sanity
checks on the card (it must be active, not suspended/stolen/lost and its start and end dates are
within operational range).

CheckCard can raise some exceptions that would, in turn, abort the transaction, raising errors
such as:

• CARD_NOT_ACTIVE
• CARD_SUSPENDED
• CARD_STOLEN
• CARD_LOST
• CARD_NOT_CONFIGURED, if the card is not associated with a CardProduct entity.
• CARD_EXPIRED
• CARD_SUSPICIOUS, if the received expiration date doesn’t match our records.
2
The classes in the org.jpos.gl package are part of jPOS-EE’s miniGL [https://github.com/jpos/jPOS-EE/tree/master/modules/
minigl/src] module
3
Derived Unique Key Per Transaction

18
jCard Transaction
Manager Participants
• CARDHOLDER_NOT_CONFIGURED
• CARDHOLDER_NOT_ACTIVE
• CARDHOLDER_EXPIRED

CheckCard places the following new entries in the Context:

• CARD
• CARDHOLDER, pulled off the Card using card.getCardHolder()
• ISSUER, taken from the CardProduct associated with this Card
(card.getCardProduct().getIssuer())

3.4.4. CheckTerminal participant


Sample configuration
<participant class="org.jpos.jcard.CheckTerminal"
logger="Q2" realm="checkterminal" />

CheckTerminal instantiates an org.jpos.ee.TerminalManager and uses the MID and TID


context variables placed by the previous CheckFields participant (taken from fields 42 and 41
respectively) to locate a Terminal object from the database.

Figure 3.2. Terminal / Merchant related relationships

CheckTerminal reads a configuration property called force-check and decides if the terminal
and merchant has to be actually validated as the jCard system can be installed in situations
where the terminals and merchants are handled by the acquirer and are provided just as general
purpose information.

If check is required (force-check is true), the system validates that the Terminal exists and is
active, and that belongs to a Merchant that also exists and is active.

19
jCard Transaction
Manager Participants
There’s another optional flag, lock-terminal that can be used to lock the terminal, so that
transactions performed from a single terminal are serialized.

CheckTerminal can raise some exceptions that would in turn abort the transaction, raising
errors such as:

• INVALID_TERMINAL
• INVALID_MERCHANT
• INACTIVE_TERMINAL
• INACTIVE_MERCHANT
• ACQUIRER_MISMATCH

CheckTerminal places the following new entries in the Context:

• TERMINAL
• MERCHANT pulled off the Card using card.getCardHolder()

3.4.5. CheckAcquirer participant


Sample configuration
<participant class="org.jpos.jcard.CheckAcquirer"
logger="Q2" realm="checkacquirer" />

The Card, located by the previous CheckCard participant is associated with a CardProduct,
which in turn belongs to an Issuer, which is placed in the context (courtesy of CheckCard).

Issuer has a one-to-many relationship with Acquirer's. This participant is a placeholder


that would allow to easily configure restrictions for different card products/issuer/acquirer(s)
restrictions.

The current code will just pick the first active acquirer and place it in the Context.

In a multi-acquirer scenerio, this participant can be modified to validate that the


received acquirer ID from the original request (field 32) matches the selected
acquirer associated with this CardProduct/Issuer.

CheckAcquirer can raise the following exceptions:

• SYSCONFIG_ERROR : Acquirer not found.

and places the following new entry in the Context:

• ACQUIRER

3.4.6. SelectAccount participant


Sample configuration
<participant class="org.jpos.jcard.SelectAccount"
logger="Q2" realm="select-account" />

20
jCard Transaction
Manager Participants
Figure 3.3. Card / CardHolder / Account Relatioship

A Card belongs to a CardHolder which has many Account's.

As told in Section 3.4.3, “CheckCard participant”, org.jpos.gl.Account's are


general ledger accounts represented by miniGL's org.jpos.gl.FinalAccount
entities. miniGL is part of jPOS-EE, and you can read more about its concepts here:
http://jpos.org/private/miniGL.pdf

This participant uses the CardHolder reference provided by the CheckCard participant, and
the PCODE_ACCOUNT_TYPE and CURRENCY information provided by the CheckFields participant
in order to locate a cardholder’s account suitable for this account type (i.e. checking/savings/
credit/prepaid, etc.) and currency combination.

Once located, it places in the Context a reference to the FinalAccount object using the name
ACCOUNT.

If the transaction type (PCODE_TXN_TYPE) equals "40" (a transfer transaction according to jPOS
CMF), SelectAccount uses the destination account type (last two digits of field 3, stored in
PCODE_ACCOUNT2_TYPE) and currency to select the destination account, which is placed in the
context as ACCOUNT2.

SelectAccount can raise the following exceptions:

• ACCOUNT_NOT_FOUND

and places the following new entry or entries in the Context:

• ACCOUNT
• ACCOUNT2 (on transfer transactions)

In addition to setting variables in the Context, SelectAccount takes the opportunity to pick
the TranLog object created by the CreateTranLog participant from the Context (it’s stored
under the name TRANLOG) and populates the account and optionally account2 properties.

3.4.7. ComputeBalances participant


Sample configuration
<participant class="org.jpos.jcard.ComputeBalances"
logger="Q2" realm="compute-balances">
<property name="checkpoint" value="compute-balances" />
</participant>

ComputeBalances creates a miniGL session and picks the ACCOUNT subject to this balance
calculation from the Context. It uses the ISSUER in order to locate the miniGL Journal used
by this issuer (a Journal is the accounting book where all transactions specific to this issuer
get recorded), as well as the current TIMESTAMP provided by the PrepareContext participant.

21
jCard Transaction
Manager Participants
jCard uses miniGL' multi-layer feature to store its transactions. Its layer plan involves using
the href="http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html[ISO-4217
currency code] as the accounting layer (confirmed transactions that impacts the accounting
balance), and specific offset numbers for pending (unconfirmed authorizations that affect
the available balance but don’t touch the accounting balance) as well as credit overdraft
transactions.

The layer plan looks like this:

Currency Code Accounting Layer Pending Layer Credit Layer


US Dollars 840 1840 2840
Euros 978 1978 2978
Argentine Peso 032 1032 2032
Nigerian Naira 566 1566 2566

Relying on miniGL’s multi-layer support, it is easy to compute different kind of balances


at differents point in time. ComputeBalances uses the transaction’s currency code in order
to select the appropriate accounting layer, and then adds PENDING_OFFSET to know the layer
number used to record pending transactions (i.e. authorizations that are are not confirmed by
an advice transaction yet).

For an US dollar transaction (currency code 840), ComputeBalances would calculate:

• Accounting balance: taken from layer 840.


• Available balance: taken by combining transactions in layer 840 and layer 1840

This participant is used in the balance inquiry transaction, but also on other
transactions that have financial impact, such as POS purchases and ATM
withdrawals, and still return a balance (usually printed on receipts). For credit
transactions (account type equals 30), the accounting balance field returns the credit
allowance, in this case, taken from layer 2840.

ComputeBalances can raise the following exceptions:

• SYSERR_DB if the Issuer doesn’t have a Journal.

and places the following new entries in the Context:

• LEDGER_BALANCE
• AVAILABLE_BALANCE

In addition to setting variables in the Context, SelectAccount takes the opportunity to


pick the TranLog object, created by the CreateTranLog partitcipant, from the Context (it’s
stored under the name TRANLOG) and populates TranLog's account, and optionally account2,
properties.

22

You might also like