"; */ ?>


21
Oct 09

They say offshore QA team, I say AUTOMATE IT!

automate testing

Part I. Poor Trees

I really see no advantage of having all these test scripts that are made as excel spread sheets and then printed out in hundreds (don’t you hear trees begging: “save us”?) and given to QA team members to spend a couple months to follow and make sure every little condition/case is met.

Guess what happens when new requirements come in, or the old ones get changed… Spend a week or two going through all these excel files, manually refactoring every little condition/case effected. And then what? Regression testing ..ummm.. another two months?

Oh.. shoot requirements changed in the middle of testing, what should we do.. hmm.. print more paper. Poor trees…

Part II. Can I get some sleep please?

Let’s make all this process twice as effective, let’s offshore 50% of the QA (testing). Oh.. ok:

– Hello? Do you speak English?

– Yes, hi we are a great software company, and yes we do speak English.

– Great! Can I outsource 50% of my testing to you guys, so we have 24 hour coverage?

– Sure – we’ll be glad to do that for you.

– Awesome! I just sent you the package with everything that needs to be done.

2 a.m. “Hello. We are looking at requirements, and we did not find any definition for ‘A’..”

3 a.m. “Hello. We need to make an important decision, and we were wondering… ”

5 a.m. “Hello. Before we send you today’s status, we wanted to make sure..”

Part III. Open up a little

Of course we need people in charge of QA, and we need QA teams – the guys are great! They make us shine when we ship our high quality creation out the door. But can they be more effective, and do less work at the same time? Can they use technologies that are available, instead of using MS Office for things that it was really not made for? Can they ensure that whoever comes to test after them will not be lost, can pick up where they left off, and keep doing an awesome job? Yes, Yes, and Yes, and many more Yeses!

The hardest part is to let go the fear and the standards that were set 20, 15, 10 years ago for Software Testing. Yes, it made sense then ( maybe :) ), but now there are dozens of tools and practices that will increase productivity tenfold, you just need to open up a little. You can do it!

Part IV. Automate yourself!

Let’s look at the simple example of using some of these time saving tools. Here is how one of the test cases can be automated by using easyB and Selenium. The automated test itself will worth a thousand words, so here it is:

before "start selenium", {
 given "selenium is up and running", {
   // start selenium
 }
}
 
scenario "a valid person has been entered", {
 
 when "filling out the person form with a first and last name", {
   selenium.open("http://acme.racing.net/greport/personracereport.html")
   selenium.type("fname", "Britney")
   selenium.type("lname", "Smith")
 }
 
 and "the submit link has been clicked", {
   selenium.click("submit")
 }
 
 then "the report should have a list of races for that person", {
   selenium.waitForPageToLoad("5000")
   values = ["Mclean 1/2 Marathon", "Reston 5K", "Herndon 10K", "Leesburg 10K"]
   for( i in 0..< values.size() ){
      selenium.getText("//table//tr[${(i+3)}]/td").shouldBeEqualTovalues[i]
   }
 }
}
 
after "stop selenium", {
  then "selenium should be shutdown", {
    // stop selenium
  }
}

And, let’s say Groovy is not your first language, and maybe you’re not a programmer at all, but really, can you read, and understand, that:

 when 'filling out the person form with a first and last name'
 and   'the submit link has been clicked'
 then  'the report should have a list of races for that person'

Ok, granted, you may not know regular expressions, and “//table//tr[${(i+3)}]/td” may be just a little over your head, but guess what.. It was auto-generated (by selenium) for you the first time you drove through the screens. And you know what the beauty of it is? It can run on it’s own, and it can tell you whether your application satisfy “this” particular requirement. You can schedule it to run every day, if you’d like, or every time the code is modified, or every Labor Day, or… you get the point. :)

Part V. We still need people, but they can be more productive!

“So what?”, you say, “One little test case – we have hundreds, and it would take us a month to create all these “automated” cases and scripts.”, and I say – yes, it may take a month now, but it will save you a year later. Why? Because if you create these scripts carefully, reflecting all the business requirements, these scripts will turn into the fastest, most accurate and “easy to interact with” QA team on Earth for your company/project. And that I would say, worth a month of work!

easyB example was taken from an extremely good presentation Industrial Strength Groovy by Paul King. Thank you Paul!


30
Aug 09

Key Value Store List

B Tree

While playing with CouchDB, I decided to expand on the subject and research to see what else is out there. Apparently there are lots of cool implementations of Key Value Stores. And since to try them all will take a long time, I decided make some notes of what I found, to simplify my journey.

Here I created a simple reference list of different, non-commercial implementations of Key Value Stores. Let me know if there are more interesting projects that are not in this list, so we can keep this list updated.

Tokyo Cabinet

A C library that implements a very fast and space efficient key-value store:

The database is a simple data file containing records, each is a pair of a key and a value. Every key and value is serial bytes with variable length. Both binary data and character string can be used as a key and a value. There is neither concept of data tables nor data types. Records are organized in hash table, B+ tree, or fixed-length array.

Besides bindings for Ruby, there are also APIs for Perl, Java, and Lua available.

To share Tokyo Cabinet across machines, Tokyo Tyrant provides a server for concurrent and remote connections.

Speed and efficiency are two consistent themes for Tokyo Cabinet. Benchmarks show that it only takes 0.7 seconds to store 1 million records in the regular hash table and 1.6 seconds for the B-Tree engine. To achieve this, the overhead per record is kept at as low as possible, ranging between 5 and 20 bytes: 5 bytes for B-Tree, 16-20 bytes for the Hash-table engine. And if small overhead is not enough, Tokyo Cabinet also has native support for Lempel-Ziv or BWT compression algorithms, which can reduce your database to ~25% of it’s size (typical text compression rate). Oh, and did I mention that it is thread safe (uses pthreads) and offers row-level locking?

good intro: Tokyo Cabinet Beyond Key Value Store

Project Voldemort

Voldemort is a very cool project that comes out of LinkedIn. They seem to even be providing a full time guy doing development and support via a mailing list. Kudos to them, because Voldemort, as far as I can tell, is great. Best of all, it scales. You can add servers to the cluster, you don’t do any client side hashing, throughput is increased as the size of the cluster increases. As far as I can tell, you can handle any increase in requests by adding servers as well as those servers being fault tolerant, so a dead server doesn’t bring down the cluster.

Voldemort does have a downside for me, because I primarily use ruby and the provided client is written in java, so you either have to use JRuby (which is awesome but not always realistic) or Facebook Thrift to interact with Voldemort. This means thrift has to be compiled on all of your machines, and since Thrift uses Boost C++ library, and Boost C++ library is both slow and painful to compile, deployment of Voldemort apps is increased significantly.

Voldemort is also intersting because it has pluggable data storage backend and the bulk of it is mostly for the sharding and fault tolerance and less about data storage. Voldemort might actually be a good layer on top of Redis or Tokyo Cabinet some day.

Voldemort, it should be noted, is also only going to be worth using if you actually need to spread your data out over a cluster of servers. If your data fits on a single server in Tokyo Tyrant, you are not going to gain anything by using Voldemort. Voldemort however, might be seen as a good migration path from Tokyo * when you do hit that wall were performance isn’t enough.(from: NoSQL If Only It Was That Easy)

CouchDB

Apache CouchDB is a document-oriented database that can be queried and indexed in a MapReduce fashion using JavaScript. CouchDB also offers incremental replication with bi-directional conflict detection and resolution.

CouchDB provides a RESTful JSON API than can be accessed from any environment that allows HTTP requests. There are myriad third-party client libraries that make this even easier from your programming language of choice. CouchDB’s built in Web administration console speaks directly to the database using HTTP requests issued from your browser.

It’s a “distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API”. Data is stored in ‘documents’, which are essentially key-value maps themselves, using the data types you see in JSON. CouchDB can do full text indexing of your documents, and lets you express views over your data in Javascript. I could imagine using CouchDB to store lots of data on users: name, age, sex, address, IM name and lots of other fields, many of which could be null, and each site update adds or changes the available fields. In situations like that it quickly gets unwieldy adding and changing columns in a database, and updating versions of your application code to match. (from: Anti RDBMS a List of Distributed Key Value Stores)

good intro: InfoQ: CouchDB From 10K Feet

MongoDB

MongoDB is not a key/value store, it’s quite a bit more. It’s definitely not a RDBMS either. I haven’t used MongoDB in production, but I have used it a little building a test app and it is a very cool piece of kit. It seems to be very performant and either has, or will have soon, fault tolerance and auto-sharding (aka it will scale). I think Mongo might be the closest thing to a RDBMS replacement that I’ve seen so far. It won’t work for all data sets and access patterns, but it’s built for your typical CRUD stuff. Storing what is essentially a huge hash, and being able to select on any of those keys, is what most people use a relational database for. If your DB is 3NF and you don’t do any joins (you’re just selecting a bunch of tables and putting all the objects together, AKA what most people do in a web app), MongoDB would probably kick ass for you.

Oh, and did I mention that, of all the NoSQL options out there, MongoDB is the one of the only ones being developed as a business with commercial support available? If you’re dealing with lots of other people’s data, and have a business built on the data in your DB, this isn’t trivial.

On a side note, if you use Ruby, check out MongoMapper for very easy and nice to use ruby access.(from: NoSQL If Only It Was That Easy)

MongoDB: Dwight Merriman, 10gen (slides, video)

Cassandra

Cassandra is a highly scalable, eventually consistent, distributed, structured key-value store. Cassandra brings together the distributed systems technologies from Dynamo and the data model from Google’s BigTable. Like Dynamo, Cassandra is eventually consistent. Like BigTable, Cassandra provides a ColumnFamily-based data model richer than typical key/value systems.

Cassandra was open sourced by Facebook in 2008, where it was designed by one of the authors of Amazon’s Dynamo. In a lot of ways you can think of Cassandra as Dynamo 2.0. Cassandra is in production use at Facebook but is still under heavy development.

Sounded very promising when the source was released by Facebook last year. They use it for inbox search. It’s Bigtable-esque, but uses a DHT so doesn’t need a central server (one of the Cassandra developers previously worked at Amazon on Dynamo). Unfortunately it’s languished in relative obscurity since release, because Facebook never really seemed interested in it as an open-source project. From what I can tell there isn’t much in the way of documentation or a community around the project at present. (from: Anti RDBMS a List of Distributed Key Value Stores)

good intro: Up and Running With Cassandra

MySQL Cluster / NDB

Although it is not your native Key Value Store, I found it interesting to put on the list. While it is commonly used through an SQL interface, the architecture and performance is exactly what you want: Cloud-like sharding, very good performance on key-value lookups, etc… And if you don’t want the SQL, you can use the NDB API directly, or REST through mod_ndb Apache module (http://code.google.com/p/mod-ndb/).

This would score high on your list if you evaluated it:

– Transparent sharding: Data is distributed through an md5sum hash on your primary key (or user defined key), yet you connect to whichever MySQL server you want, the partitions/shards are transparent behind that.

– Transparent re-sharding: In version 7.0, you can add more data nodes in an online manner, and re-partition tables without blocking traffic.

– Replication: Yes. (MySQL replication).

– Durable: Yes, ACID. (When using a redundant setup, which you always will.)

– Commit’s to disk: Not on commit, but with a 200ms-2000ms delay. Durability comes from committing to more than 1 node, *on commit*.

– Less than 10ms response times: You bet! 1-2 ms for quite complex queries even.

Other KVS I have in my backlog to expand on here later:

LightCloud

Lux IO

Flare

Tx

Oracle Berkeley DB

Ringo

Redis

Scalaris

Kai

HBase

Hypertable

Dynomite

MemcacheDB

ThruDB

And as a bonus – there is another quite interesting initiative started by Yehuda Katz:

Moneta

Moneta: A unified interface for key/value stores
================================================
 
Moneta provides a standard interface for interacting with various kinds of key/value stores.
 
Out of the box, it supports:
 
* File store for xattr
* Basic File Store
* Memcache store
* In-memory store
* The xattrs in a file system
* DataMapper
* S3
* Berkeley DB
* Redis
* SDBM
* Tokyo
* CouchDB
 
All stores support key expiration, but only memcache supports it natively. All other stores
emulate expiration.
 
The Moneta API is purposely extremely similar to the Hash API. In order so support an
identical API across stores, it does not support iteration or partial matches, but that
might come in a future release.

Any additional info / projects are welcome!


19
Aug 09

Erlang ! { me, Hello }.

send hello message to Erlang

Erlang has been around since I was 7, so by this point I had 23 years to say hello to Erlang, but just did not get to it until today.. At 10 I was busy with chess, at 15 with girls, at 20 girlfriends, at 25 I don’t remember (that was a quite frequent condition at that age), and only now at 3 o’clock in the beautiful Wednesday morning, here in one of many Chicago hotels, I can really say it outloud: “Erlang ! { me, Hello }.”, or as we all use to saying it “System.out.println( “Hello to Erlang from me” );”, or using the language of our grandparents: “Me: Hello Erlang!”

I already spent about 30 minutes playing with it – 5 minutes with erl interpreter, 5 minutes coding, and 20 minutes figuring out how the heck I can execute it from command line with passing parameters to functions. So here it goes 30 minute summary in “count yourself” number of sentences…

From “Erlang – Quick Start“, I stole a factorial (fac) function:

-module(test).
-export([fac/1]).
 
fac(0) -> 1;
fac(N) -> N * fac(N-1).

“Compile the program by typing c(test) then run it” said Erlang site, so I did:

3> c(test).
{ok,test}
4> test:fac(20).
2432902008176640000
5> test:fac(40).
815915283247897734345611269596115894272000000000
6>

What I wanted to do now is to have a more useful factorial that can actually take a number parameter and run from a command line. See, Erlang is cool with numbers, because it uses arbitrary-sized integers when it does integer arithmetic, and I wanted to see that 10000.. digit number on my screen, but I wanted to do it from command line…

Hence, reading further the Erlang’s documentation, in Erlang How To FAQ I found “How to run an Erlang program directly from the unix shell:”

        matthias >erl -compile hello
        matthias >erl -noshell -s hello hello_world -s init stop
        hello, world

Great, I thought, let’s run my factorial function then:

$ erl -noshell -s test fac 4 -s init stop
{"init terminating in do_boot",{undef,[{test,'test:fac',[['4']]},{init,start_it,1},{init,start_em,1}]}}
 
Crash dump was written to: erl_crash.dump
init terminating in do_boot ()

I tried many different combinations, prefixes, suffixes, but nothing seemed to work. Google (at this time) did not really help, and I spend another 5-10 minutes by going to actually study the language from multiple online resources I could find. After aggregating the knowledge, here goes a solution:

-module( matematika ).		% module name = file name
-export( [factorial/1] ).		% exporting a factorial function, that takes exactly 1 argument
 
% public, since exported above
factorial( [CommandLineParameter] ) ->
 
	% converting the input parameter to an integer, so we can use it in (private) fac below
	Number = list_to_integer( atom_to_list( CommandLineParameter ) ),
	FactorialResult = fac( Number ),
 
	io:format( "~w! = ~w~n" ,[Number, FactorialResult] ),			% pretty much like printf in C
	init:stop().											% need to explicitly stop it
 
% private, since not exported
fac( 0 ) -> 1;					% if 0, then return 1
fac( N ) -> N * fac( N - 1 ).			% else return fac of N minus 1

(I put %comments above for myself, so I can make sense of it tomorrow)

Let’s run it now:

$ erl -noshell -s matematika factorial 10

10! = 3628800

Awesome! My first stolen and adapted Erlang creation! Let’s see that factorial of .. let’s say 2500 :)

$ erl -noshell -s matematika factorial 2500


2500!=162888842416926354689668105747439663365399942834366593333
761170598517395953006666015681181171091114301822189949967063775
407379642957266480360849144773982699565766503949953039081536069
313589385624248687168633365117877728319632346514905978458047074
520807127737619451831790023662437656379915366899692425817099473
955735537991551620610205879561628364536090561091825520933523438
440298824173752468219542814600203368965255916069562338913433294
969546310263930229454748650689662592679638050717072642347493989
468072742236518740460239946352245451040613097756653973305720645
026457997934905356924399618617581860376174835804874205168542257
467008667252720784248969925977883224857503131037675382806351903
130554386521130700598953600694590165036980214021274304347037205
774546036842214862077129715702791830982471445806697511922924126
875707763824427831458131252725129871400134654305773736954160374
386043307314954277237484986013167770729137200202006247592856875
946971039429028314584331171481048021391502558449541563727025722
429319793486407721042419353225446943557177410280427218310573933
839468119502298621190184926686015339505156759957938618691111894
105137524428488796590017749394464101657140531047449031317150211
285312051145217906000448322292856476064080179041772517805638616
704522178956984018390162683438304694297727727823412207694734265
878202872900194730775246958252155279043555763913056000888393253
937210136778443737969895720575345197710315491879632577212080296
732791524306529332768002582234532193839787438122696823349137174
760687670811121707247122877205618078452290605963728534389393406
703483582596248272104119965697657195713053485619074455216492879
719763758474871783557654928157780691218383646855409834599921063
373144702996594627688077741944550267192758309026313016206320680
530057452746436412708183108931890404685083431502083760663324657
349706015263327982666486689576849283883469142513936741022368381
903094157650249629927012864342540407330646247523995884057015184
717062826800920338962166558742062917836339935141477580556616102
759761599188076139416375666490347795870693771994555537476372358
925544445791134700553339780029989334462364486499563386435498770
970697902521176942715439141796399164240719914064566047833333979
658667979051009689054775584486605430424545544714920455985028492
775158386405002083658607397637102066859718496781089357617987825
390662781413816362946370821897681257991937027979675382384665624
733872791767882787048074812304136442761397202291044563080832580
377638267813956876382413025080202917826793584257121650412123520
8825054296165661030756208371742686402825404804558501327839670
731298809850930719924452525141301863810787127140637580161952796
470931012669932742565234239616031337114081022694921413641260386
424388652301371711255153268827616495293442715781089495795404683
744579676459521729702016200147034375778237008585095355232063710
088291957991216310837002831440396924100323429063456827045895594
917126433490705797776990807538192111396635158758664846773837413
564155213989495350785689041240261464178518418465026963508203252
038246166655605208324074965984192733197462771017672726300923288
607540014472757890113403434211921496288437000162551272645252320
615215716654175248938850328046313070690361405371373329623736166
731299101093298365654056037733083226277004269609573104069448790
684864546219098996171110998911324197479806896470305987119560932
856582719643423019817880041224237194274668604715496198407207355
809431389490372488422206677783166941973289816036063374723748298
696836902300888969044824525828910570687623075008425420179724412
174632013134752558921448609478176626573353890791801685222886849
990731518133839408072332112603244018982882369997032825586118714
392208201914776888366261219130250913546151105147763080829651928
290074106631605007724254431488105804572887069328232683043301900
466160052172383665181738152989844063638391709547589900409420631
7468376377314153856018840069377218558903334939371343395777264
426365318130887683599836088345497158322556553595094840894654614
406383376396868199531042942079405403474627428650274595771829568
255995466465003325664472293654101201924430539079190443194487046
380416281749159026300696294947812447714612418298771332692848211
154125929312681287195951419960699391722211424311898584816200565
373258799897110855302098610980845978364362685231061369005215230
788471798866541648729889538439509890111560301062943923923769988
997147648363950708508382034563798637202146673551309938897540440
786998003118907883241416258343188784000679367284896011745823289
734561911522255979545433492376668285434347783001266108600121473
498779217963921384546755156766188951735866744108093964636023471
349527019498920540070752394649104708510770999131507315610483632
330982876174119389012968417760250231722884408641474340374893362
833795392300949100935853949419952854923937872507275773843355108
735204114864752466565493366395162830913421138498633186453324268
762572668445390770903011717202242312950408723851830364004678106
656009078222984968635868416766693788940980240045058068275614302
839043567118028698385054274108921811298084233976240006277809181
325997330000786683674194376654268377368369949823431206244095885
960702059149846318232687179678572748082487793549844548187548311
400556064744050666472476457947299489568330636742840865513804654
776149494225932236964194164784786218640251626514525549920894810
545056499250214652147224638246034892251401029945773476251196919
612592752826016419187902895630887737745713281219681141023586882
321633118519558748181198803719862314967759867112077291645583600
510531017148754676649505951293767894337326791942862414631993126
449392270145239108425380056269282654566300820253116701666036949
374826952156733286262700190206665725355635411559887439781283350
874285109852181238143636938256407098028863909426094536431398247
852543854757537942646791855344906017659039384905122375234004320
416026882823286655632286053156546748028668750196973803337027786
891236116711910780819707846081218679760982625290715984522150204
916425232591826590887410401320568045430558979943145617193692059
705465421939829497586908594951642657711985208269462425640322372
314303330475772671495014049400654155619566942191085558759378416
790160458835621823599743742665152596726797511419955382867531134
959437002011587472231152746047820309830039699792147174883667855
760287780241438038062954704157981072533480950728570115662921849
376586317866043009133972729549191452640224225320222817060812601
144385749818368781373067888827129923654130858902252804622762751
192618314790547633755929057344102888830740499275949997990026813
425216747458578654838647236496508876074530642629714199563056483
975900965902520059913821418901761372054615449749487163282905699
188377895083782877246773269374715942460000414707728522199826307
191493572953655749106244370767768017669677808468909623091993519
298870943235516530358122980923396832082235382703392292864000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000

Now, THAT is cool!


26
Jul 09

Apache Chain with Spring

“A popular technique for organizing the execution of complex processing flows is the “Chain of Responsibility” pattern, as described (among many other places) in the classic “Gang of Four” design patterns book. Although the fundamental API contracts required to implement this design patten are extremely simple, it is useful to have a base API that facilitates using the pattern, and (more importantly) encouraging composition of command implementations from multiple diverse sources.”

That is what Apache has to say as an intro to its Commons Chain API

It is no brainer, really, but Apache APIs do make it simpler to configure, implement and execute multiple Chains of Responsibilities. One thing, however, that feels “off”, when (if) implementing “Commons Chain” side by side with Spring, is there is no flexible, consistent (with Spring) way to setup Command objects: inject Command properties / refer to a single Command class as a bean, instead of duplicating the class name in Apache Chains, and Spring configuration, if Command object needs to be reused, etc…

Here is a simple way to utilize all the power that Apache offers + make it Spring friendly. Five components will be used in this example – 1 core class, 2 command classes, 1 test (driver) and Spring configuration file. Let’s see if you can figure out which is which :):

apache commons chain on spring: components

As you can see we are going to play an ultra short session of table tennis, or how it is sometimes called “Ping Pong”. It is going to be quite short, because we have two command objects: Ping and Pong, which are going to be chained, and run (by ChainRunner) once each: “Ping -> Pong”.

First, instead of relying on Apache way to configure chains, to make it consistent with all other application beans (classes) we’ll keep chain(s) configuration in Spring:

chain-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
 
	<bean name="pingPongChain" class="org.apache.commons.chain.impl.ChainBase">
		<constructor-arg>
			<util:list>
				<ref bean="pingCommand" />
				<ref bean="pongCommand" />
			</util:list>
		</constructor-arg>
	</bean>
 
	<bean name="pingCommand" class="org.dotkam.samples.chain.command.PingCommand">
		<constructor-arg value="ping"/>
	</bean>
 
	<bean name="pongCommand" class="org.dotkam.samples.chain.command.PongCommand">
		<constructor-arg value="pong"/>
	</bean>
 
	<bean id="chainRunner" class="org.dotkam.samples.chain.ChainRunner"/>
 
</beans>

A “pingPongChain” is configured as “org.apache.commons.chain.impl.ChainBase”, and have two Commad classes, that implement “org.apache.commons.chain.Command” interface, wired in.

NOTE: The best practice is to keep Commands either stateless, or, if they have to have a state – immutable. If this practice is followed, these Commands can be safely reused throughout many chains (or even as stand alone utilities). That is the reason, in configuration above, parameters are injected at Command’s creation time via constructor injection.

In this example Commands are ultra simple for clarity:

PingCommand.java:

package org.dotkam.samples.chain.command;
 
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
 
public class PingCommand implements Command {
 
	private String message;
 
	public PingCommand( String message ) {
		this.message = message;
	}
 
	public boolean execute( Context context ) throws Exception {
 
		System.err.println( message );
		return false;
	}
}

and PongCommand.java:

package org.dotkam.samples.chain.command;
 
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
 
public class PongCommand implements Command {
 
	private String message;
 
	public PongCommand( String message ) {
		this.message = message;
	}
 
	public boolean execute( Context context ) throws Exception {
 
		System.err.println( message );
		return false;
	}
}

Now let’s look at the heart of the “Spring Chainer” – the “ChainRunner.java”:

package org.dotkam.samples.chain;
 
import org.apache.commons.chain.impl.ChainBase;
import org.apache.commons.chain.impl.ContextBase;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
 
public class ChainRunner implements BeanFactoryAware {
 
	private BeanFactory beanFactory;
 
	public void runChain( String chainName ) {
		try {
			createChain ( chainName ).execute( new ContextBase() );
		}
		catch ( Exception exc ) {
			throw new RuntimeException(
					"Chain \"" + chainName + "\": Execution failed.", exc );
		}
	}
 
	public void setBeanFactory( BeanFactory beanFactory ) throws BeansException {
		this.beanFactory = beanFactory;
	}
 
	protected ChainBase createChain( String chainName ) {
		return ( ChainBase ) this.beanFactory.getBean( chainName );
	}
}

It only does a couple of things, really.

By implementing Spring’s “BeanFactoryAware” interface, at runtime ChainRunner will have a reference to a “beanFactory” which it is going to use to obtain a reference to the requested chain via “createChain” method.

“ChainRunner” has an entry point which is a “runChain” method, that executes a chain by chain name (bean name in configuration file). For example, in the configuration shown above “pingPongChain” name can be provided.

It would ideally need to use a couple of custom runtime exceptions: e.g. ChainNotFoundException, IsNotChainException and ChainExecutionException, but we’ll keep it short here for clarity.

Alternatively, to strong type chains a bit, “ChainRunner” could take a Map of chains with keys as chain names, and corresponding “ChainBase” chain objects as values.

“ChainRunner” is pretty much everything that is needed in order to configure an Apache chain in Spring. We can run it by creating a JUnit (not really a test, just a driver):

ChainTest.java:

package org.dotkam.samples.chain;
 
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration( locations={ "/conf/chain-config.xml"} )
public class ChainTest {
 
	@Resource
	ChainRunner chainRunner;
 
	@Test
	public void driveTheChain() {
		System.out.println("Starting up...      [Ok]");
		chainRunner.runChain( "pingPongChain" );
		System.out.println("Finised...          [Ok]");
	}
}

And here is the test/driver result:

apache commons chain on spring: results

Good start! Now it is time to sign up and see your name at the top of The International Table Tennis Federation (ITTF) World Ranking. Good Luck! :)


20
Jul 09

Blue Grails and not so Bluehost

Groovy on GrailsSomething pretty funny happened to me today. I went to the Bluehost website, just because I have one of my Rails applications deployed there, and without doing much of a research (did not spend 4 seconds googling), using their online chat, I decided to ask Bluehost support team about their Java support.

Our dialogue was quite short, and very amusing (“first time sales” is me):

Blue Host Support:                           Welcome to our real-time sales chat. How can I help you today?
 
FIRST TIME SALES QUESTION:        hello
Blue Host Support:                           how can I help you today?
FIRST TIME SALES QUESTION:        hi Bluehost
                                                         can you guys host a Grails app?
 
Blue Host Support:                           what requirements does it have?
FIRST TIME SALES QUESTION:        what do you mean?
                                                         we have a couple of Grails apps and looking for hosting
 
Blue Host Support:                            what is grails?
                                                         a programming language I assume
                                                         what is it based on?
 
FIRST TIME SALES QUESTION:        http://www.grails.org/
                                                         Groovy
 
Blue Host Support:                            looks like it is used with Java
                                                         we don't run Java
                                                         that isn't possible on our servers

It is hard to hold your smile when one of the biggest hosting companies comes up with phrases like “What is Grails?” and “Java? That isn’t possible on our servers“. Still smiling…