-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
---------- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | ||
====== | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters