Skip to main content

148 posts tagged with "jpos"

View All Tags

TransactionManager's new property

· 3 min read
Alejandro Revilla
jPOS project founder

TransactionManager is one of the most important features of jPOS. It is used to implement transaction flows using TransactionParticipants. Usually the participants are organized in groups and GroupSelector interface is used to implement decision points in the transaction flow. TransactionManager calls each participant in the order they appear in the deployment configuration xml file. When it encounters a participant that implements GroupSelector interface, its select() method is called which should return the names of the groups to be called next. TransactionManager then recursively calls participants in selected group(s). This calling of participants is done twice. First, the prepare() method is called during the PREPARE phase. If all the participants are PREPARED, the commit() method of the participants is called in the COMMIT phase. A participant can abstain from being called during COMMIT by returning PREPARED | NO_JOIN from its prepare() method. For GroupSelectors, the prepare() method is called first and then the select() method is called. If any of the participant returns ABORTED from its prepare() method, the transaction flow changes. From this point onwards, the prepareForAbort() method is called for those remaining participants that implement the AbortParticipant interface. Interestingly, if the participant that first aborts or any further participants happen to implement GroupSelector then their select() method is called based on the new **call-selector-on-abort** boolean property of the TransactionManager. Before this property was introduced, the TransactionManager would always call the select() method of such GroupSelectors. Therefore the default value of call-selector-for-abort property is true to ensure backward compatibility. Lets see an example. Suppose we have a TransactionManager configuration like below:

<txnmgr class="org.jpos.transaction.TransactionManager" logger="Q2">
<property name="queue" value="myTxnQueue" />
<property name="sessions" value="2" />
<property name="max-active-sessions" value="15" />
<property name="debug" value="true" />
....
<participant class="com.my.company.Participant1" logger="Q2" />
<participant class="com.my.company.Participant2" logger="Q2" />

<participant class="com.my.company.Selector1" logger="Q2">
<property name="12" value="group1 group2"/>
<property name="34" value="group3 group4"/>
</participant>

<group name="group1">
<participant class="com.my.company.Participant11" logger="Q2" />
<participant class="com.my.company.Participant12" logger="Q2" />
<participant class="com.my.company.Selector2" logger="Q2">
<property name="ab" value="groupA"/>
<property name="cd" value="groupC groupD"/>
</participant>
</group>

<group name="groupA">
<participant class="com.my.company.Participant11A" logger="Q2" />
<participant class="com.my.company.Participant11B" logger="Q2" />
</group>

<participant class="com.my.company.Participant3" logger="Q2" />
....
</txnmgr>

Let us assume that:

  • Selector1 and Selector2 implement GroupSelector interface
  • Selector1 will return "12"
  • Selector2 will return "ab"
  • Participant12, Participant11A, Participant3 implement AbortParticipant interface
  • Participant1's prepare method returns PREPARED | NO_JOIN
  • Participant2's prepare method returns PREPARED
  • Selector1's prepare() method returns ABORTED

Now, since the call-selector-on-abort parameter is not defined, it defaults to true and the transaction will be processed by the TransactionManager as below:

        prepare: com.my.company.Participant1 NO_JOIN
prepare: com.my.company.Participant2
prepare: com.my.company.Selector1 ABORTED
selector: com.my.company.Selector1 group1 group2
prepareForAbort: com.my.company.Participant12
selector: com.my.company.Selector2 groupA groupB
prepareForAbort: com.my.company.Participant11A
prepareForAbort: com.my.company.Participant3
abort: com.my.company.Participant2
abort: com.my.company.Selector1
abort: com.my.company.Participant12
abort: com.my.company.Participant11A
abort: com.my.company.Participant3
....

Now if we set the call-selector-on-abort property to false...

<txnmgr class="org.jpos.transaction.TransactionManager" logger="Q2">
<property name="queue" value="myTxnQueue" />
<property name="sessions" value="2" />
<property name="max-active-sessions" value="15" />
<property name="debug" value="true" />
**<property name="call-selector-on-abort" value="false" />**
....

With that the TransactionManager would behave something like this:

        prepare: com.my.company.Participant1 NO_JOIN
prepare: com.my.company.Participant2
prepare: com.my.company.Selector1 ABORTED
prepareForAbort: com.my.company.Participant3
abort: com.my.company.Participant2
abort: com.my.company.Selector1
abort: com.my.company.Participant3
....

As one can see, call-selector-for-abort property significantly affects the transaction flow when the transaction aborts. If no participant aborts, this property does not come into picture at all.

Logger lifespan attribute

· One min read
Alejandro Revilla
jPOS project founder

A typical jPOS log output looks like this (lines wrapped for easy reading here):

... ... ...

Let's start with a simple comment, the '.544' here after the year are the milliseconds since second 30 (in this example). Now the subject of this post, the 'lifespan' attribute. jPOS' logger is not a line-logger, we use it to put together multiple information related to a given transaction. The 'lifespan' attribute shows us the time elapsed between the LogEvent creation and the time where we actually display it by calling Logger.log(evt). So depending on the code using the logger, the meaning of the 'lifespan' attribute vary. In the ChannelAdaptor for example, we create a LogEvent, and then call channel.receive(), so the 'lifespan' attribute basically shows us how much time the channel was idle and we were waiting for a message to come. In order to understand the lifespan attribute, you need to take a look at the code that generates it. Final notes:

  • if the lifespan is 0ms, we don't display it.
  • On Windows systems, clock accuracy is 15ms

jPOS 1.8.9 templates

· One min read
Alejandro Revilla
jPOS project founder

In jPOS 1.8.8 we had a nice Maven Archetype that got lost in our move to Gradle. As a replacement, in 1.8.9 we have a lightweight [https://github.com/jpos/jPOS-template](jPOS template) project that you can fork or download. Just rename with your own project name and you are ready to go. The following commands will create you a sample Eclipse project:

git clone git://github.com/jpos/jPOS-template.git mv jPOS-template myproject cd myproject ./gradlew eclipse

In order to run jPOS, you can:

./gradlew installApp cd build/install/myproject bin/q2

You can create your own source files in src/main/java and resources in src/main/resources. The directory structure is pretty much the standard Maven one.

./gradlew tasks

Is your friend. UPDATE: Changed installApp task to use standard build/install instead of runtime directory.

jPOS 1.8.8 has been released

· One min read
Alejandro Revilla
jPOS project founder

jPOS 1.8.8 has been released (download, ChangeLog). We are moving development to 1.8.9 where we'll switch the build system from Maven to Gradle. You will still be able to fetch jPOS using Maven as we'll produce compatible artifacts, so nothing changes for end users, unless you're building jPOS from sources.

The Peter Effect

· 3 min read
Alejandro Revilla
jPOS project founder

/by apr/ When I was a child I used to spend a lot of time with my grand parents.

A neighbor of them had a radio/tv repair shop, his name was Peter (obviously locally pronounced Peh-tehr), for me, he was a genius.

A family with probably twice the IQ of the rest of the neighborhood together (I remember Peter's father playing chess all the time, against himself using a large mirror), and Peter always repairing stuff, you entered the place and enjoyed that very special solder smell that I still like.

Peter was a man of very few words, he knew me since I was born, but he'd never talked to me like a child, he was very serious, yet had a sarcastic sense of humor, the kind of humor smart people have. Later, when I was probably 10 or 12, a couple very good friends and an awesome game introduced me to electronics.

After finishing several small projects on the wooden board, and burning several AF-116s and AC-126s transistors, I was ready for a larger project, a six-transistor AM radio receiver. I was very anxious, so I started soldering some components, but then I ran out of solder, probably over the weekend where I couldn't buy more. That wasn't going to stop me, so I continued mixing cables together without soldering, and using GLUE (yes, glue, I'm embarrased to say that, but I was a child, and an anxious one, I "needed" that radio receiver running!).

The moment came where I had to apply voltage and test, but of course, the thing wouldn't work. Several tests here and there, the whole thing was wrong, half baked, short circuits everywhere, transistors probably over-heated and melted by my inhability to properly use the soldering gun, everything was a mess. Then I had a brilliant idea: Peter! I waited until Monday, headed to my grand parent's and onto Peter's.

I handed him the project and said, very seriously: "Can you repair this? it suddenly stopped working". I still remember Peter's reaction, he laughed, yelled, laughed, then yelled again, THIS THING HAS NEVER WORKED!! (probably thinking what a little liar son of a b....!).

You may wonder why I'm telling you this story and here is the answer: In jPOS Consulting, we receive "for repair" things that never worked and customers claim they are broken.

We get blasted by walls of code that never ever worked, they are flawed by design, and customers ask us to fix them. It would be much much easier and cheaper to engage us earlier in the project definition and development than wasting their time creating code that's impossible to fix.

When we receive code like that, we call it The Peter Effect.

PS.- I wanted to write this post a long time ago, because this is a recurring problem we have here, and wanted to read it to my friend Peter. Unfortunately, I was busy to do it, and he recently passed away. I really miss him, we exchanged very few words because he didn't like to talk a lot, but I knew he appreciated my interest in electronics, and I've always respected him a lot. If you asked me what I wanted to be when I was a child, I didn't want to go to the moon or be a policeman or a fireman, I probably wanted to run a repair shop like Peter's.

jPOS-EE SysConfigConfigurationFactory

· One min read
Alejandro Revilla
jPOS project founder

jPOS-EE sysconfig module has a new SysConfigConfigurationFactory class that can be used to pull configuration properties from the sysconfig table instead of the XML configuration file (see jPOS-79). By adding the attribute configuration-factory="org.jpos.ee.SysConfigConfigurationFactory" to any QBean element, one can then set properties using the 'sysconfig:' prefix and the property's id in the database, i.e.:

Here is an example:

clientsimulator-send clientsimulator-receive 10000

TransactionManager Debug and Trace events

· 2 min read
Alejandro Revilla
jPOS project founder

While working on a project, from time to time, we might request the TransactionManager 'Debug' and 'Trace' events.

The Debug event is the one created by the org.jpos.transaction.Debug participant and looks like this:

    JCARD
100.55
org.jpos.iso.channel.CSChannel@71e13a2c
open \[0.6/0.6\]
prepare-response \[6.0/6.6\]
close \[1.0/7.6\]
end \[15.3/15.3\]
Sun Feb 12 22:47:39 UYST 2012
txnmgr
org.jpos.ee.DB@7a315068
100.55 (notsupported prepareresponse close sendresponse)
invalid.request
Unsupported transaction
...
...

It basically dumps the Context. On the other hand, the Trace event usually comes after the Debug (provided the TransactionManager's trace property is set to true) and looks like this:

 txnmgr-1:2
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
groupSelector: notsupported prepareresponse close sendresponse
prepare: org.jpos.jcard.NotSupported NO_JOIN
prepare: org.jpos.jcard.PrepareResponse 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=3, tail=3, outstanding=0, active-sessions=2/2, tps=0, peak=0, avg=0.00, elapsed=22ms
prepare: org.jpos.jcard.PrepareContext \[0.0/0.0\]
prepare: org.jpos.jcard.CheckVersion \[0.0/0.0\]
prepare: org.jpos.transaction.Open \[0.5/0.6\]
prepare: org.jpos.jcard.Switch \[0.0/0.6\]
prepare: org.jpos.jcard.NotSupported \[0.1/0.7\]
prepare: org.jpos.jcard.PrepareResponse \[5.8/6.6\]
prepare: org.jpos.transaction.Close \[0.0/6.6\]
prepare: org.jpos.jcard.SendResponse \[0.0/6.6\]
prepare: org.jpos.jcard.ProtectDebugInfo \[0.0/6.7\]
prepare: org.jpos.transaction.Debug \[0.0/6.7\]
commit: org.jpos.transaction.Close \[1.0/7.7\]
commit: org.jpos.jcard.SendResponse \[4.3/12.0\]
commit: org.jpos.jcard.ProtectDebugInfo \[0.2/12.3\]
commit: org.jpos.transaction.Debug \[9.3/21.7\]
end \[22.8/22.8\]

UPDATE - in recent versions of jPOS, the Debug and Trace events are placed together by the TransactionManager.