Skip to main content

· 2 min read
Alejandro Revilla

/by @apr thinking out loud/

We moved jPOS to the AGPL license about six years ago, in hindsight I'd like to share my thoughts about the move.

  • The AGPL is a good license, perfect for our project, if people were to read it.
  • It is based on the honor system, but nobody cares about honor these days unless honor is enforced someway or another.
  • My perception is that for a large number of developers, OpenSource is the same as Free Software, Apache license is the same as GPL, LGPL, AGPL, MPL, Potatoes, Potatos, same thing.

We used to sell commercial licenses under the jPOS PEP which is a combination of license+coaching/hand-holding. Participants get it for the hand-holding part, they rarely care to get a signed agreement, we need to push to get them signed. [UPDATE: we are not accepting new PEP members as of August/2010] We have some true license purchases, those come either from large companies with large legal teams reviewing every license or from companies being purchased/merged doing due-diligence procedures

The downside of a license like this is IMHO:

  • People not willing to release their code under a compatible license (that's probably 100% of our users) and not willing to purchase a commercial license (that's about 99.96% according to our guestimates) feel guilty and go dark, never participate, never contribute code, and limit themselves to ask questions under public e-mail addresses with lots of numbers in it. They know they are free riders and nobody is proud of that, so they hide.
  • Some open source power users and projects know the license is somehow restrictive, so if they can, they avoid it.

So my belief now is that the AGPL just slows down a project like ours. It's probably perfect for a larger organization with the ability to go to the street and enforce it, but this is not our case, we don't have the resources nor the willing to do so. That said, it's still the best fit for us, so we'll stick to it for the time being.

· 3 min read
Alejandro Revilla

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.

· One min read
Alejandro Revilla

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

· One min read
Alejandro Revilla

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.

· One min read
Alejandro Revilla

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.

· 3 min read
Alejandro Revilla

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

· One min read
Alejandro Revilla

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