jcard internals[1]

28
jCard Internals

Upload: buggy-buggys

Post on 31-Dec-2015

66 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: jCard Internals[1]

jCard™ Internals

Page 2: jCard Internals[1]
Page 3: jCard Internals[1]

Contents

Chapter 1: jCard..............................................................................................5jCard Server..............................................................................................................................................6

jPOS CMF Server.........................................................................................................................6

jPOS XML Server........................................................................................................................7

jCard Request Dispatcher.............................................................................................................7

Incoming Handlers.......................................................................................................................8

jCard's Transaction Manager....................................................................................................................9

Transaction Manager Participants..........................................................................................................12

PrepareContext...........................................................................................................................12

Open...........................................................................................................................................14

Switch.........................................................................................................................................14

Balance Inquiry Group...............................................................................................................17

jPOS | TOC | 3

Page 4: jCard Internals[1]

4 | jPOS | TOC

Page 5: jCard Internals[1]

Chapter

1jCard

This chapter provides information about how the pieces fit together in the jCardsystem

Topics:

• jCard Server• jCard's Transaction Manager• Transaction Manager Participants

Page 6: jCard Internals[1]

jCard ServerThe 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• 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 canrun at external JVMs or even external systems and in turn connect to a native jCard server after the conversion to andfrom jPOS CMF took place.

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

jPOS CMF Server

The jPOS CMF server (ISO-8583 v2003) is defined in the file modules/jcard/deploy/50_server.xml andits 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)

Tip: 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 defaultjCard configuration, the property iso2003_server_port is defined in devel.properties with a valueof 8001.

The server uses the jPOS CSChannel and GenericPackager configured for ISO-8583 v2003. It uses a 5 minutestimeout (300000ms) and defines a request listener org.jpos.jcard.Dispatcher and passes some configurationparameters 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 andforwards the transaction to the appropriate class, i.e:

• Incoming_100

• Incoming_200

6 | jPOS | jCard

Page 7: jCard Internals[1]

• Incoming_220

• ...

• ...

jPOS XML Server

The jPOS CMF users ISO-8583 v2003, but for testing/debugging purposes, jCard also uses an ISO-8583 v2003 basedXML server configured in the file modules/jcard/deploy/50_xml_server.xml. The configuration lookslike 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)

Tip: See 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).

jCard Request Dispatcher

The jCard Request Dispatcher is an ISORequestListener that receives all traffic coming on the jCard main servers (bothISO-8583 v2003 and XML ones) and forwards them to the appropriate handler for the given MTI.

The code is located in modules/jcard/src/org/jpos/jcard/Dispatcher.java and its process methodlooks 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());

jPOS | jCard | 7

Page 8: jCard Internals[1]

} catch (InstantiationException e) { warn (e); } catch (IllegalAccessException e) { warn (e); } catch (ISOException e) { warn (e); } return false; }

Tip: Please note that we append the MTI to the configured prefix (org.jpos.jcard.Incoming_ in orderto locate the appropriate handler class. The MTI in jPOS includes the ISO-8583 version number (in this case thenumber '2' representing ISO-8583 version 2003), so we use the code mti.substring(1) to pick just thethree-letter MTI.

Incoming Handlers

Once a message reaches one of the jCard's ISOServers, it gets forwarded to the request-dispatcher, which in turn wouldinstantiate 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 isimplemented 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 complext and handled by the TransactionManager. The implementation classes inherit from IncomingSupport and are implemented like this:

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);

8 | jPOS | jCard

Page 9: jCard Internals[1]

if (m.hasField(3)) { 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:

• Create a TransactionManager Context• Create a transaction name variable (TXNNAME) based on the MTI, first two digits of processing code (data element

3), and optionally the content of data element 24 (function code), data element 25 (reason code). In situations wheredata element 24 is present, an optional data element 101 (file name) may be appeneded to the transaction name.

• Put a reference to the ISOSource provided by the process method of the ISORequestListener in the context underthe constant name 'SOURCE'.

• Place the Context in a space under the queue defined in the XML configuration for the server. This 'queue' has to bethe 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 would be lost. Aninteresting enough, due to the way the ISO-8583 operates, this is a good thing. If for some reason a transaction doesn'treach the TransactionManager in a reasonable short period of time, it would indicate that the system is experiencingproblems (such as a database down, extremely high looad, network issue, etc.). The best thing is to ignore the agingtransactions so that the system recovers faster when the situation gets resolved. The remote endpoint will retry thetransactions and the system will be back up and running faster than if we try to process transactions that wouldn't reachthe remote endpoint anyway, because they have been timed out already.

jCard's Transaction Manager

jCard uses the jPOS TransactionManager 1 to implement its business logic using reusable TransactionParticipants.

The TransactionManager implements a two-phase commit protocol where participants get called usually twice, the firsttime at prepare time, and then -- if all participants agree to proceed with the transaction -- at commit time. If for somereason one of the participants aborts the transaction, then those participants that were previously called (using theirprepare callback method) will get a call to their abort method. There are special type of participants, theAbortParticipants that get called even if the transaction is going to abort, and the GroupSelectors that can providesome handy grouping of related participants.

1 Documented in the jPOS Programmer's Guide on chapter 10

jPOS | jCard | 9

Page 10: jCard Internals[1]

Figure 1:Transaction Manager

The transaction manager configuration is located in modules/jcard/deploy/10_txnmgr.xml.

jCard splits the business logic implementation into small little reusable chunks that we call participants. A typicaltransaction 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 beging 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 so on 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:

10 | jPOS | jCard

Page 11: jCard Internals[1]

Figure 2:Transaction Participants

The transaction manager configuration is located in modules/jcard/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" /> ... ...

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

• queue: This is the name of the Space queue used to send transactions to the TransactionManager. We use the arbitraryname JCARD.TXN but it could have been any other name, as long as the name matches the queue name defined inthe request listeners (see deploy/50_*_server.xml

• sessions: The TransactionManager can process multiple simultaneous sessions. We use a low default value (2) inour 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 informationabout transaction and the participants involved, with their timing and results. Here is a sample debug ticket:

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

jPOS | jCard | 11

Page 12: jCard Internals[1]

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>

Note: We sometimes call this debug tickets

Transaction Manager Participants

Once the transaction reaches the top of the Transaction Manager's queue, it gets processed by the participants definedin the file deploy/10_txnmgr.xml.

PrepareContext

The PrepareContext participant is the very first participant in the execution chain. It is configured indeploy/10_txnmgr.xml like this:

... ... <participant class="org.jpos.jcard.PrepareContext" logger="Q2" realm="PrepareContext" />

12 | jPOS | jCard

Page 13: jCard Internals[1]

... ...

PrepareContext (available at modules/jcard/src/org/jpos/jcard/PrepareContext.java) preparethe Context (actually an org.jpos.transaction.Context) with helpful objects required by other participantsdown the execution chain, such as:

• TIMESTAMP: It is desirable that all participants in a given transaction use exactly the same timestamp, in orderto avoid edge conditions where a transaction starts at a given date (i.e. 23:59:59.99) and finish the next day (i.e.: at00:00:00.00). These conditions not only happen at day boundary, they could happen at

• TXNMGR: In situations where a transaction is forwarded from one transaction manager to another one (using theForward 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) { }}

The code is straight forward, but it deserves a few comments and clarifications:

• The Constants TIMESTAMP and TXNMGR are collected by an ant subtask defined in the eecore3min modulein modules/eecore3min/build.xml out of files with the extension *.k. In this particular case, these constantsare defined in the file modules/jcard/src/org/jpos/ee/Constants.k. These files are collected andplaced together in the org.jpos.ee.Constants interface.

The file is created in build/src/org/jpos/ee/Constants.java, but we also create a 'courtesy copy' backinto modules/src/jcard/src/org/jpos/ee/Constants.java so that the file can be easily recognizedby IDEs.

Note: Please note these files are auto-generated on every build.

• The method void setTransactionManager (TransactionManager txnmgr) is not part of theTransactionParticipant interface, but if available, it gets called by the TransactionManager -- providing a referenceto itself -- at initialization time. PrepareContext uses this2 technique in order to grab a reference to the transactionmanager in order to properly set the TXNMGR context variable.

2 Duck typing

jPOS | jCard | 13

Page 14: jCard Internals[1]

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 Constants.k). In addition, itbegins an 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 in order to have realtime fine grained informationabout the system 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 expressedin tenth of a second (in this case, 30.0 seconds).

org.jpos.transaction.Open is located in the eetxn module and its implementation uses the support classorg.jpos.transaction.TxnSupport.

Tip: TxnSupport provides a standard implementation of the prepare method which in turn calls a protecteddoPrepare method. TxnSupport's prepare method creates a safety net around the doPrepare method takingcare of catching and logging possible exceptions.

Switch

Once the Context is prepared, and an Hibernate/JDBC session has been opened, we are ready to analize the transactionand decide how to route it, using a TransactionManager's GroupSelector.

The participant org.jpos.jcard.Switch implements said GroupSelector. The implementation is quite straightforward:

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; }}

14 | jPOS | jCard

Page 15: jCard Internals[1]

Switch extends TxnSupport just to enjoy a couple of helper methods, such as the fact that it already implementsorg.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 ofgroups are going to process this transaction. It keys off then TXNNAME using configuration properties provided in thetransaction 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>

The configuration is self-explanatory, a balance inquiry transaction (MTI=100, processing code starts with 30) wouldrun the following groups:

• balanceinquiry: gets the balance for a given card/cardholder/account type• prepareresponse: prepare a response• logit: log the transaction to the database• close: commit the JDBC transaction so we can be sure the transaction is logged to persistent storage• sendresponse: send 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 thesystem reuses most of the transaction participant implementations, and even the groups of participants placed togetherunder a given name (i.e.: logit, or sendresponse, etc.).

jCard currently supports the following transactions:

Table 1: jCard supported transactions

DescriptionNameITC

Computes the balance available and ledger balance for a given accountidentified by the processing code's account type (third and forth digits ofdata element 003)

Balance Inquiry100.30

Authorization transaction, targets the cardholder's account associated withthe account type specified in the processing code.

Authorization100.00

Voids a previously authorized transactionAuthorization void100.02

Initiates a refund transactionRefund100.20

Voids a previously authorized refund transactionRefund void100.22

Similar to 100.00 (Authorization), operates on the accounting layer.POS Purchase200.00

jPOS | jCard | 15

Page 16: jCard Internals[1]

DescriptionNameITC

Business logic is similar to POS Purchase, but withdrawals get a specialITC (internal transaction code) for reporting and risk management purposes.

Cash Withdrawal200.01

Voids a POS Purchase or Cash WithdrawalVoid200.02

dittoFinancial refund200.20

Payment/Deposit to accountDeposit200.21

Tip: Returns and deposits use a special account which is notimmediately accessible to cardholders, until an EOD process movesit to an appropriate and usable account.

Voids a previouslyprocessedrefund/deposit

200.22

Used to transfer funds from different accounts of the same cardholder (i.e.:checking to savings)

Account transfer200.40

Purchase advice. Apreviously

220.00.0000

authorizedtransaction(pending layer)gets confirmed bya purchase advice.

Same for refundsRefund advice220.20.0000

Records a refund that was not previously authorized by the system. Thevalue '1000' here represents: "Stand-In processing at the card issuer'soption".

Force post220.00.1000

Tip: See jPOS-CMF document, Appendix D, Reason Codes.

RepresentmentForce post220.00.2000

Refund/Returnforce post

220.20.1000

Chargebacknotification

220.20.4500

Purchase/Authorizationreversal

420.00.0000

Cash withdrawalreversal

420.01.0000

Void reversal420.02.0000

Refund reversal420.20.0000

Deposit reversal420.21.0000

Transfer reversal420.40.0000

Adds a new customerFile update304.301.CUSTOMER

Adds a new merchantFile update304.301.MERCHANT

16 | jPOS | jCard

Page 17: jCard Internals[1]

Tip: For a complete list of Message Type Indicators and Processing Codes, refer to the jPOS-CMF document.

Balance Inquiry Group

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

• balanceinquiry• prepareresponse• logit• close• sendresponse

and then continue to the participants ProtectDebugInfo a nd Debug defined after the main Switch. This sectiondescribes the participants used by the balanceinquiry group.

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 optionalfields 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 whenfound, are then placed in the Context for the benefit of the following participants.

Table 2: CheckFields special constant names

DescriptionConstant Name

Extracts the PAN from the original message, either from data element 35 on a swipedtransaction, or from data elements 2 and 14. Places the entries PAN and EXP

PAN

(expiration) in the Context. Throws an INVALID_CARD business logic exception(BLException) if a primary account number could not be found in the request.

Puts four variables in the context:PCODE

• 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.

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

• 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

jPOS | jCard | 17

Page 18: jCard Internals[1]

DescriptionConstant Name

Picks the transaction amount off field 4 and places the following variables in thecontext:

AMOUNT

• AMOUNT: a BigDecimal containing the transaction amount. Decimals areadjusted according to the currency in use

• CURRENCY: ISO-4217 currency code.

Throws INVALID_AMOUNT BLException on errors.

Parses the capture date and places it in the Context as a java.util.Date Objectunder the name NETWORK_CAPTURE_DATE. Throws INVALID_REQUESTon errors.

NETWORK_CAPTURE_DATE

Picks additional amount off field 54.ADDITIONAL_AMOUNT

If Field 7 (transmission date) is present in the list of mandatory or optional fields, aTRANSMISSION_TIMESTAMP Date object is placed in the Context.

Field 7

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 12

If field 41 (Terminal ID) is present in the list of mandatory or optional fields, its stringrepresentation gets placed in the Context under the name TID.

Field 41

If field 42 (Merchant ID) is present in the list of mandatory or optional fields, itsstring representation gets placed in the Context under the name MID.

Field 42

Sample transaction

The Debug participant dumps the context after the transaction has been processed. A typical Context would look likethis:

<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>

18 | jPOS | jCard

Page 19: jCard Internals[1]

</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] 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=000000000144, originalItc=100.00, acquirer=000001, mid=001001,

jPOS | jCard | 19

Page 20: jCard Internals[1]

card=org.jpos.ee.Card@67360e7[id=4,pan=000000...0001], tid=29110001 ]) </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>

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.

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>

20 | jPOS | jCard

Page 21: jCard Internals[1]

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

The TranLog record is defined in the org.jpos.ee.TranLog entity (seemodules/jcard/src/org/jpos/ee/TranLog.java and itsmodules/jcard/src/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 thedeploy/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.

• checkpoint: This property is actually managed by CreateTranLog's super class TxnSupport which calls checkpointon 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 participant3.7ms. The second figure is the running total (in this case, 3.7ms+0.5ms=4.3ms).

Tip: Participants that extend TxnSupport can be configured to create a checkpoint in the profiler. This is veryuseful during application tunning.

CreateTranLog creates a TranLog record in the database, and populate a set of initial fields:

• Date: it uses the TIMESTAMP Date object available in the Context, courtesy of the PrepareContext participant.• LocalTransactionDate: LOCAL_TRANSACTION_TIMESTAMP taken by CheckFields off fields 12 and 13 when

available.• TransmissionDate: TRANSMISSION_TIMESTAMP taken by CheckFields off 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 take 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.

jPOS | jCard | 21

Page 22: jCard Internals[1]

• 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/JDBCsession (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

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, actuallyorg.jpos.gl.FinalAccount).

Figure 3: Card / CardHolder / Account Relatioship

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

In addition, the encryption scheme we use (DUKPT 3 can not be used either, because the same card encrypted twodifferent 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 search 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, we can pull the CardHolder using the card.getCardHolder() method. CheckCard verifiesthat we have a valid and active cardholder (its 'active' property has to be true). It also performs some verificationsand sanity checks on the card (is active, not suspended/stolen/lost and its start and end dates are within operationalrange).

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

3 Derived Unique Key Per Transaction

22 | jPOS | jCard

Page 23: jCard Internals[1]

• 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.• 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())

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 variablesplaced by the previous CheckFields participant (taken from fields 42 and 41 respectively) to locate a Terminal objectfrom the database.

Figure 4:Terminal / Merchant related relationships

CheckTerminal reads a configuration property called 'force-check' and decides if the terminal and merchant has to beactually validated as the jCard system can be installed in situations where the terminals and merchants are handled bythe 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 it's active, and that belongsto a Merchant that also exists and it's active.

There's another optional flag, lock-terminal that can be used to lock the terminal so that transactions performedfrom a single terminal are serialized.

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

jPOS | jCard | 23

Page 24: jCard Internals[1]

• 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()

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 anIssuer, which is placed in the context (courtesy of CheckCard).

Issuer have a one-to-many relationship with Acquirers. This participant is a place holder that would allow to easilyconfigure restrictions for different card products/issuer/acquirer(s) restrictions.

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

Note: In a multi-acquirer scenerio, this participant can be modified to validate that the received acquirer ID fromthe 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

SelectAccount participant

Sample configuration

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

Figure 5: Card / CardHolder / Account Relatioship

A Card belongs to a CardHolder which has many Accounts (actually general ledger accounts represented by miniGL'sorg.jpos.gl.FinalAccount entities).

24 | jPOS | jCard

Page 25: jCard Internals[1]

This participant uses the CardHolder reference provided by the CheckCard participant, and the PCODE_ACCOUNT_TYPEand CURRENCY information provided by the CheckFields participant in order to locate a cardholder's accountsuitable 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), SelectAccountuses the destination account type (last two digits of field 3, stored in PCODE_ACCOUNT2_TYPE) and currency to selectthe 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 createdby the CreateTranLog participant from the context (it's stored under the name TRANLOG) and populates the accountand optionally account2 properties.

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' whereall transactions specific to this issuer get recorded) as well as the current TIMESTAMP provided by the PrepareContextparticipant.

jCard uses miniGL' multi-layer feature to store its transactions. Its layer plan involves using the ISO-4217 currencycode as the accounting layer (confirmed transactions that impacts the accounting balance) and a specific offset numbersfor pending (unconfirmed authorizations that affect the available balance but doesn't touch the accounting balance) aswell as credit overdraft transactions.

The layer plan looks like this:

Credit LayerPending LayerAccounting LayerCurrency Code

28401840840US Dollars

29781978978Euros

20321032032Argentine Peso

25661566566Nigerian Naira

Relyaing in 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 addsPENDING_OFFSET to know the layer number used record pending transactions (i.e. authorizations that are are notconfirmed by an advice transaction yet).

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

jPOS | jCard | 25

Page 26: jCard Internals[1]

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

Note: This participant is used in the balance inquiry transaction, but also on other transactions that have financialimpact such as POS purchases and ATM withdrawals and still return a balance (usually printed on receipts). Forcredit 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's doesn't have a Journal.

and places the following new entriesin the Context:

• LEDGER_BALANCE• AVAILABLE_BALANCE

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

26 | jPOS | jCard

Page 27: jCard Internals[1]

Index

B

Balance Inquiry 17

C

CheckAcquirer 24CheckCard 22CheckFields 17CheckTerminal 23CMF Server 6, 7ComputeBalances 25CreateTranLog 20

D

Dispatcher 7

G

Group 17

H

Handlers 8

I

ISO-8583 v2003 6ISORequestListener 7, 8

J

jCard 5

M

MTI 7

O

Open 14

P

Participant 17, 20, 22, 23, 24, 25Participants 9, 12, 14PrepareContext 12

S

SelectAccount 24Server 6, 7Switch 14

T

TransactionManager 17Transaction Manager 9, 12

X

XML Server 7

jPOS | Index | 27

Page 28: jCard Internals[1]

28 | jPOS | Index