Skip to content

Commit

Permalink
Work on TM chapter
Browse files Browse the repository at this point in the history
  • Loading branch information
ar committed Oct 20, 2014
1 parent efb6e97 commit 995bd04
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 0 deletions.
118 changes: 118 additions & 0 deletions doc/src/asciidoc/ch09/assembly_line.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
== Assembly Line

Before delving into the TM details, we'd like to step back and describe it
using a metaphor, the *assembly line* metaphor.

Here is an example of a typical transaction (in this case taken from
the jCard system):

The TransactionManager encourages and allows developers to write reusable
and configurable components called _Participants_. Here is a short
description of a typical Balance Inquiry transaction, splitted into many
small (easy to develop, easy to reuse, easy to maintain) participants:


.AssemblyLine
[cols="2,8", options="header"]
|===============
|Name|Description
|PrepareContext
|We prepare the context with some handy objects, such
as a transaction +TIMESTAMP+, a +Profiler+ and optional
user specific data required by all participants down
the execution line.
|CheckVersion
|We usually receive messages using a specific version. In this case,
jCard uses the link:http://jpos.org/doc/jPOS-CMF.pdf[jPOS-CMF] which
has a specific field indicating the interchange version. This participant
just check that and early aborts the transaction if it doesn't match our
expectations
|Open
|If version is OK, we probably want to log the message in a database.
The +Open+ participant gets a JDBC connection and starts a JDBC Transaction.
|Switch
|We'll explain later the +GroupSelectors+ that allows us to put together
groups of partipants in the XML configuration. In this example, the
selector returns a String with the following content:
+"balanceinquiry prepareresponse logit close sendresponse"+
indicating that the TM needs to execute the participants defined
in those groups.
|CheckFields
|Different transactions require the presence of different ISO8583 fields
in the incoming message. Some are mandatory, some are optional, this
reusable participant takes care of that. For example, in the case of
a balance inquiry, we want to make sure that we have fields that allows
us to identify the card and probably its PIN.
|CreateTranLog
|If we readh this participant it means the incoming message is kinda OK,
it has the proper version, it has the required mandatory fields, so we
create a TranLog record. This is specific to jCard, but your implementation
is likely to require some kind of transaction log record.
|CheckCard
|In order to compute the balance of a given account, we first need to locate
the card. This involves getting the card by different means, could be track1
data, track2 data, ICC, etc. The +CheckCard+ participant takes care of that,
and will place a handy Card object in the Context using a well known constant
name (in the case of jCard, that constant is called +CARD+ and is defined in
the +org.jpos.ee.Constants+ interface, but you can define it in an +enum+).
|CheckTerminal
|We need to check that the client terminal is valid, active, and perhaps check
its capabilities in order to provide responses in different formats (i.e. for
printing purposes)
|CheckAcquirer
|We need to know the acquirer, perhaps to validate fees involved in this
transaction.
|SelectAccount
|We know the Card, so we know the CardHolder, depending on the transaction type
and processing code, we may choose a different account (i.e. checking versus
saving)
|ComputeBalances
|Now we know the account, so we compute its balances (available, accounting)
and place it in the Context
|PrepareResponse
|We have the balances in the Context in +BigDecimal+ objects under well
known contant keys (i.e. +AVAILABLE_BALANCE+, +ACCOUNTING_BALANCE+), but
we need to place those in the ISO8583 response, probably in field 54 (additional
amounts).
|LogIt
|Remember we've created a +TranLog+ record in the +CreateTranLog+ participant above,
now we need to pick some of the data we have been gathering in the Context and
place it there, so that it gets persisted in a database row.
|Close
|Before we send a response, we need to commit the JDBC transaction and return the
JDBC session to the pool.
|SendResponse
|Now we send the response back to the network
|ProtectDebugInfo
|The following participant (_Debug_) dumps the Context's content to the jPOS log,
something very useful for debugging purposes, but there's some sensitive data
in the Context, so this little participant take care of masking it.
|Debug
|Dumps the Context to the jPOS log.
|===============

----------
prepare: org.jpos.jcard.PrepareContext NO_JOIN
prepare: org.jpos.jcard.CheckVersion READONLY NO_JOIN
prepare: org.jpos.transaction.Open READONLY NO_JOIN
prepare: org.jpos.jcard.Switch READONLY NO_JOIN
selector: balanceinquiry prepareresponse logit close sendresponse
prepare: org.jpos.jcard.CheckFields NO_JOIN
prepare: org.jpos.jcard.CreateTranLog NO_JOIN
prepare: org.jpos.jcard.CheckCard NO_JOIN
prepare: org.jpos.jcard.CheckTerminal NO_JOIN
prepare: org.jpos.jcard.CheckAcquirer NO_JOIN
prepare: org.jpos.jcard.SelectAccount NO_JOIN
prepare: org.jpos.jcard.ComputeBalances 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
----------

58 changes: 58 additions & 0 deletions doc/src/asciidoc/ch09/intro.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
The TransactionManager (also called _TM_ in this document) is just another Q2
Service, but it is such an important component in a jPOS based application that
it stands out, deserving its own chapter.

jPOS is typically used to implement mission-critical applications that
have to carefully deal with error conditions.

When you access a web page and a transient network error occurs,
you just hit the *reload* button on your browser. By contrast, a complex
financial transaction involves a lot of activities such as contacting remote
hosts, perform PIN-based validations and pin-block translations, database logging,
etc.

So, if something goes wrong or your system just dies due to a power failure,
it's more complicated than simply hitting the *reload* button: you have to reverse
the impact of whatever actions had been committed until the failure point.

The +org.jpos.transaction+ package - along with the Q2-based *TransactionManager*
implementation - provides the necessary framework and components required to deal
with the previous scenario. This combination also fosters code reuse and
_componentization_.

The key class is the
link:http://jpos.org/doc/javadoc/org/jpos/transaction/TransactionParticipant.html[TransactionParticipant]
which exposes the following interface:

[source,java]
-------------
public interface TransactionParticipant extends TransactionConstants {
public int prepare (long id, Serializable context);
public void commit (long id, Serializable context);
public void abort (long id, Serializable context);
}
(for the records, TransactionConstants provides the following constants)
public interface TransactionConstants {
public static final int ABORTED = 0;
public static final int PREPARED = 1;
public static final int RETRY = 2;
public static final int PAUSE = 4;
public static final int NO_JOIN = 0x40;
public static final int READONLY = 0x80;
}
-------------

The TransactionManager implementation _drives_ the transaction by calling all of its
participants' +prepare+ method. If all of them return +PREPARED+ (indicating that
they are ready to proceed with the transaction), then the transaction moves
to the _COMMITTING_ phase, at which point the TransactionManager will call all of the
participants' +commit+ method.

If one of the participants' +prepare+ method returns +ABORTED+, then the transaction
moves into an _ABORTING_ phase, and all the participants' +abort+ methods would get called.

52 changes: 52 additions & 0 deletions doc/src/asciidoc/ch09/transaction_constants.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
== TransactionConstants

.TransactionConstants
[cols="2,1,6", options="header"]
|===============
|Name|Value|Description

|ABORTED|0|
The participant is not prepared. Transaction should be aborted.
|PREPARE|1|
The participant is prepared to commit the transaction, provided
all other participants down the list return PREPARED too.
|RETRY|2|
The transaction will be retried after a short period of time
defined by the +retry-timeout+ TransactionManager
property (which defaults to 5 seconds).
This can be used in situations where a transient error has been
detected (such as a link down situation).
|PAUSE|4
a|
The transaction will be paused and will be resumed
in the following situations:
* Some external thread calls +resume+ in the transaction's Context
(provided the Context implements the +Pausable+ interface)
* A timeout specified by the Context's Pausable interface occurs
* A default timeout specified by the TransactionManager's +pause-timeout+ property
(which defaults to five minutes)

|NO_JOIN|0x40|
This modifier is a hint to the TransactionManager to let it know
that it is not required to call this participant's
+commit+ or +abort+ methods once the committing or aborting
phase of the transaction is reached.
|READONLY|0x80|
This modifier is a hint to the TransactionManager to let it know
that this participant has not modified any persistent information
in the context, so saving a snapshot of the context is not required.
|===============

[NOTE]
======
Despite the fact that a partipant may indicate that it doesn't want to
JOIN a given transaction (by using the +NO_JOIN+ run-time modifier),
under certain recovery situations the TransactionManager
may still call its +commit+ or +abort+ method, so the participant developer
should be prepared to receive a +commit+ or +abort+ call for an
unknown transaction. The code should check the +long id+
and / or +Serializable context+ in order to figure out what to do. That
said, most participants returning +NO_JOIN+ actually have empty +commit()+
and +abort()+ callbacks.
======

44 changes: 44 additions & 0 deletions doc/src/asciidoc/ch09/transaction_context.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
== Transaction Context

The only constraint imposed on a Context implementation is that it has
to implement the +java.io.Serializable+ interface. That's
because the TransactionManager has to write +snapshots+
of it at different check points.

You can use any +Serializable+ object, either a
custom object such as an application-specific _Bean_,
or a general-purpose object such as a +java.util.Map+
implementation (e.g., a +Hashmap+).

But we found it very useful to use a general-purpose context holding
two maps, a regular (persistent) map and a transient one, so that
one can store serializable data that can be automatically persisted
by the TransactionManager (for recovery purposes) as well as 'live'
references (such as a TCP/IP socket or a JDBC connection).

So there's a general purpose
link:http://jpos.org/doc/javadoc/org/jpos/transaction/Context.html[Context]
reference implementation that in addition implements the
link:http://jpos.org/doc/javadoc/org/jpos/transaction/Pausable.html[Pausable]
interface, required if you plan to use transaction continuations (+PAUSE+
modifier).

This Context reference implementation has two kind of 'put' operations:

[source,java]
-------------
public void put (Object key, Object value)
-------------

and

[source,java]
-------------
public void put (Object key, Object value, boolean persist)
-------------

When using the latter, if +persist == true+, then the object can
get automatically persisted by the TransactionManager (if configured to
do so, using the +persistent-space+ property).


6 changes: 6 additions & 0 deletions doc/src/asciidoc/master.asc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ include::ch08/one_shot_channel_adaptor.asc[]
include::ch08/qmux.asc[]
include::ch08/qserver.asc[]

= TransactionManager
include::ch09/intro.asc[]
include::ch09/transaction_constants.asc[]
include::ch09/transaction_context.asc[]
include::ch09/assembly_line.asc[]

//include::ch02.asciidoc[]
//include::ch03.asciidoc[]
//include::ch04.asciidoc[]
Expand Down

0 comments on commit 995bd04

Please sign in to comment.