Está en la página 1de 28

jCard Internals

jPOS | TOC | 3

Contents
Chapter 1: jCard..............................................................................................5
jCard 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

4 | jPOS | TOC

Chapter

1
jCard
Topics: jCard Server jCard's Transaction Manager Transaction Manager Participants
This chapter provides information about how the pieces t together in the jCard system

6 | jPOS | jCard

jCard Server
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 Customer specic 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 specic servers (either running on the same JVM or on external JVMs) Source Stations.

jPOS CMF Server


The jPOS CMF server (ISO-8583 v2003) is dened in the le modules/jcard/deploy/50_server.xml and its conguration 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 conguration instantiates a standard jPOS ISOServer that listens on a port dened in the target le (i.e. devel.properties) Tip: The jPOS-EE build process uses Jakarta Ant's lters to preprocess properties dened in the build les (i.e. build.xml, build.properties, devel.properties) providing property expansion. In the default jCard conguration, the property iso2003_server_port is dened in devel.properties with a value of 8001. The server uses the jPOS CSChannel and GenericPackager congured for ISO-8583 v2003. It uses a 5 minutes timeout (300000ms) and denes a request listener org.jpos.jcard.Dispatcher and passes some conguration parameters to it, such as a space, a transaction manager queue (JCARD.TXN) and a class prex (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

jPOS | jCard | 7

Incoming_220 ... ...

jPOS XML Server


The jPOS CMF users ISO-8583 v2003, but for testing/debugging purposes, jCard also uses an ISO-8583 v2003 based XML server congured in the le modules/jcard/deploy/50_xml_server.xml. The conguration 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 conguration instantiates a standard jPOS ISOServer that listens on a port dened in the target le (i.e. devel.properties) Tip: See cmf-server for an explanation of how lters work as well as how the request listener is congured. 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 trafc coming on the jCard main servers (both ISO-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 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());

8 | jPOS | jCard

} 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 congured 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.

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 complext and handled by the Transaction Manager. 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);

jPOS | jCard | 9

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, rst 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 where data element 24 is present, an optional data element 101 (le 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 under the constant name 'SOURCE'. Place the Context in a space under the queue dened in the XML conguration 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 dene 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. An 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 down, extremely high looad, 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.

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

Documented in the jPOS Programmer's Guide on chapter 10

10 | jPOS | jCard

Figure 1: Transaction Manager The transaction manager conguration 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 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 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 simplied example of the aforementioned steps:

jPOS | jCard | 11

Figure 2: Transaction Participants The transaction manager conguration is located in modules/jcard/deploy/10_txnmgr.xml. The conguration 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 dene a name attribute, so the element name is used as the service name) and dene the following properties: queue: This is the name of the Space 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 dened in the request listeners (see 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 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

12 | jPOS | jCard

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 dened in the le deploy/10_txnmgr.xml.

PrepareContext
The PrepareContext participant is the very rst participant in the execution chain. It is congured in deploy/10_txnmgr.xml like this:

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

jPOS | jCard | 13

... ... PrepareContext (available at modules/jcard/src/org/jpos/jcard/PrepareContext.java) prepare 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 nish the next day (i.e.: at 00: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 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) { } } The code is straight forward, but it deserves a few comments and clarications: The Constants TIMESTAMP and TXNMGR are collected by an ant subtask dened in the eecore3min module in modules/eecore3min/build.xml out of les with the extension *.k. In this particular case, these constants are dened in the le modules/jcard/src/org/jpos/ee/Constants.k. These les are collected and placed together in the org.jpos.ee.Constants interface. The le is created in build/src/org/jpos/ee/Constants.java, but we also create a 'courtesy copy' back into modules/src/jcard/src/org/jpos/ee/Constants.java so that the le can be easily recognized by IDEs. Note: Please note these les are auto-generated on every build. The method void setTransactionManager (TransactionManager txnmgr) is not part of the TransactionParticipant interface, but if available, it gets called by the TransactionManager -- providing a reference to itself -- at initialization time. PrepareContext uses this2 technique in order to grab a reference to the transaction manager in order to properly set the TXNMGR context variable.

Duck typing

14 | jPOS | jCard

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 (dened in Constants.k). In addition, it begins an Hibernate/JDBC transaction, and stores it under the name TX. The conguration 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 conguration denes the following properties: checkpoint: This participant uses the general purpose jPOS Proler in order to have realtime ne grained information about 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 expressed in 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 class org.jpos.transaction.TxnSupport. Tip: 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 the doPrepare method taking care 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 transaction and decide how to route it, using a TransactionManager's GroupSelector. 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; } }

jPOS | jCard | 15

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

Then the select method uses the TXNNAME provided by the incoming handlers in order to gure out which set of groups are going to process this transaction. It keys off then TXNNAME using conguration properties provided in the transaction manager conguration le (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 conguration 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: 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 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 1: jCard supported transactions ITC 100.30 Name Balance Inquiry Description Computes the balance available and ledger balance for a given account identied by the processing code's account type (third and forth digits of data element 003) Authorization transaction, targets the cardholder's account associated with the account type specied in the processing code.

100.00 100.02 100.20 100.22 200.00

Authorization

Authorization void Voids a previously authorized transaction Refund Refund void POS Purchase Initiates a refund transaction Voids a previously authorized refund transaction Similar to 100.00 (Authorization), operates on the accounting layer.

16 | jPOS | jCard

ITC 200.01 200.02 200.20 200.21

Name Cash Withdrawal Void Financial refund Deposit

Description Business logic is similar to POS Purchase, but withdrawals get a special ITC (internal transaction code) for reporting and risk management purposes. Voids a POS Purchase or Cash Withdrawal ditto Payment/Deposit to account Tip: 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 Account transfer Purchase advice. A previously authorized transaction (pending layer) gets conrmed by a purchase advice. Refund advice Force post Same for refunds 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". Tip: See jPOS-CMF document, Appendix D, Reason Codes. Used to transfer funds from different accounts of the same cardholder (i.e.: checking to savings)

200.40 220.00.0000

220.20.0000 220.00.1000

220.00.2000 220.20.1000 220.20.4500 420.00.0000 420.01.0000 420.02.0000 420.20.0000 420.21.0000 420.40.0000

Force post Refund/Return force post Chargeback notication Purchase/Authorization reversal Cash withdrawal reversal Void reversal Refund reversal Deposit reversal Transfer reversal

Representment

304.301.CUSTOMER File update 304.301.MERCHANT File update

Adds a new customer Adds a new merchant

jPOS | jCard | 17

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 dened after the main Switch. This section describes 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 optional elds in the incoming message (available in the Context under the constant name REQUEST. In addition to checking eld presence by their eld number, CheckFields understands several special names that when found, are then placed in the Context for the benet of the following participants. Table 2: CheckFields special constant names Constant Name PAN Description 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. Puts four variables in the context: PCODE: full content of data element 3 (6 digits) PCODE_TXN_TYPE: transaction type (rst 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)

PCODE

Throws an INVALID_REQUEST BLException on errors. ORIGINAL_DATA_ELEMENTS Parses eld 56 and places the following variables in the Context: ORIGINAL_MTI: with the MTI of the original transaction ORIGINAL_STAN: with the STAN (eld 11) of the original transaction ORIGINAL_TIMESTAMP: Timestamp (eld 7) of the original transsaction

18 | jPOS | jCard

Constant Name AMOUNT

Description Picks the transaction amount off eld 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 Field 7 Field 12 Field 41 Field 42 Picks additional amount off eld 54. If Field 7 (transmission date) is present in the list of mandatory or optional elds, a TRANSMISSION_TIMESTAMP Date object is placed in the Context. If Field 12 (local transaction date) is present in the list of mandatory or optional elds, a LOCAL_TRANSACTION_TIMESTAMP Date object is placed in the Context. If eld 41 (Terminal ID) is present in the list of mandatory or optional elds, its string representation gets placed in the Context under the name TID. If eld 42 (Merchant ID) is present in the list of mandatory or optional elds, 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>

jPOS | jCard | 19

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

20 | jPOS | jCard

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>

jPOS | jCard | 21

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 dened in the org.jpos.ee.TranLog entity (see modules/jcard/src/org/jpos/ee/TranLog.java and its modules/jcard/src/org/jpos/ee/TranLog.hbm.xml mapping le). The CreateTranLog participant understands the following conguration parameters: capture-date: This is the name of the CaptureDate service (org.jpos.ee.CaptureDate) dened 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 congure 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 checkpoint on the proler available in the Context. When the Context gets dumped by the last participant (the Debug participant), the proler 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 gure is the running total (in this case, 3.7ms+0.5ms=4.3ms). Tip: Participants that extend TxnSupport can be congured to create a checkpoint in the proler. This is very useful during application tunning. CreateTranLog creates a TranLog record in the database, and populate a set of initial elds: Date: it uses the TIMESTAMP Date object available in the Context, courtesy of the PrepareContext participant. LocalTransactionDate: LOCAL_TRANSACTION_TIMESTAMP taken by CheckFields off elds 12 and 13 when available. TransmissionDate: TRANSMISSION_TIMESTAMP taken by CheckFields off eld 7, usually available. Node: this is the Node name taken from the participant's conguration 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 eld 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 eld 32, if present, otherwise, defaults to 000000. Mid: Merchant ID, taken directly from eld 42, if present. Tid: Terminal ID, taken directly from eld 41 (usually present). Stan: Serial Transaction Audit Number, taken directly from eld 11 (usually present). ApprovalNumber: taken from eld 38, if available.

22 | jPOS | jCard

ResponseCode: on force-post transactions, eld 39 (response code) may be present. Currency: The CURRENCY object optionally placed in the Context by CheckFields, taken from the composite amount eld 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 eld 24, if present. ReasonCode: Taken directly from eld 25, if present. FileName: on File Update transactions (MTI=304), taken from eld 101 (le name), if present.

After populating the TranLog object with the aforementioned elds, 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

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

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 in the Context (place by the CheckFields participant) can't be used to nd 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 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 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 veries that we have a valid and active cardholder (its 'active' property has to be true). It also performs some verications and sanity checks on the card (is 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
3

CARD_NOT_ACTIVE CARD_SUSPENDED CARD_STOLEN CARD_LOST

Derived Unique Key Per Transaction

jPOS | jCard | 23

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 variables placed by the previous CheckFields participant (taken from elds 42 and 41 respectively) to locate a Terminal object from the database.

Figure 4: Terminal / Merchant related relationships CheckTerminal reads a conguration 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 it's active, and that belongs to a Merchant that also exists and it's active. There's another optional ag, 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

24 | jPOS | jCard

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 an Issuer, 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 easily congure restrictions for different card products/issuer/acquirer(s) restrictions. The current code would just pick the rst active acquirer and place it in the Context. Note: In a multi-acquirer scenerio, this participant can be modied to validate that the received acquirer ID from the original request (eld 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's org.jpos.gl.FinalAccount entities).

jPOS | jCard | 25

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 eld 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. 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 specic to this issuer get recorded) as well as the current TIMESTAMP provided by the PrepareContext participant. jCard uses miniGL' multi-layer feature to store its transactions. Its layer plan involves using the ISO-4217 currency code as the accounting layer (conrmed transactions that impacts the accounting balance) and a specic offset numbers for pending (unconrmed authorizations that affect the available balance but doesn't touch the accounting balance) as well as credit overdraft transactions. The layer plan looks like this: Currency Code US Dollars Euros Argentine Peso Nigerian Naira Accounting Layer 840 978 032 566 Pending Layer 1840 1978 1032 1566 Credit Layer 2840 2978 2032 2566

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 adds PENDING_OFFSET to know the layer number used record pending transactions (i.e. authorizations that are are not conrmed by an advice transaction yet). For an US dollar transaction (currency code 840), ComputeBalances would calculate:

26 | jPOS | jCard

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 nancial 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 eld 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 created by the CreateTranLog participant from the context (it's stored under the name TRANLOG) and populates the account and optionally account2 properties.

jPOS | Index | 27

Index
B
Balance Inquiry 17

J
jCard 5

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

M
MTI 7

O
Open 14

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

D
Dispatcher 7

G
Group 17

S
SelectAccount 24 Server 6, 7 Switch 14

H
Handlers 8

T
TransactionManager 17 Transaction Manager 9, 12

I
ISO-8583 v2003 6 ISORequestListener 7, 8

X
XML Server 7

28 | jPOS | Index

También podría gustarte