Monday, May 31, 2010

Quartz Task Scheduling on JBOSS 4.2.2

I've been working on a J2EE app which needed to run a specific task at 8.00 AM every morning. I've used Quartz as a scheduler with Spring on Weblogic, but I'm not using Spring on my current project so I was probably going to have to use Quartz raw. That is, until I read that JBOSS has Quartz built in. This has been handled as a resource adapter. That's the quartz-ra.rar file.

How to use this goodness, is to create a Message driven bean (MDB). You can do this by creating a class that extends the org.quartz.Job interface. See an example here.

Notice that I have commented out the annotations just above the class definition as I believe those are deployment specific decisions hence would prefer to make those declarations in configuration files. If you're not as picky you could uncomment them. Note that the @ResourceAdapter annotation is JBOSS specific and would impact negatively on the portability of your code!

In your ejb-jar.xml you define the class as an EJB. See example here.

If you're following my advice and not using proprietary annotations, you'll need to create a jboss.xml file like this.

The jboss.xml file creates the link between the EJB and the resource adapter while the MDB definition in the ejb-jar.xml file. Be careful with the cronTrigger property as it does not behave in the exact same manner that cron does in UNIX (Cron on Wikipedia). There is an additional position on the left for seconds. Follow the Quartz Scheduler tutorial here. Deploy and enjoy!

Sunday, May 23, 2010

Creating On-Demand Demonstration Sites for Java Based Systems using EC2

If you have developed web-based Java systems and are a small time shop, you will have encountered the issue of how to showcase your work given the relatively higher costs of Java hosting compared to Ruby, PHP and Python (Google App Engine). Did I mention the inexperience of many shops that try to provide Java hosting outside of Virtual Private Servers? Ever counted how many times you need to restart Tomcat when debugging deployment? After recently attending an Amazon Web Services meetup (where I got 50$ in AWS credit), I decided to give it a go.

The Requirements
The application in question has the following specs:
  1. Runs on Java 1.5+, Apache Tomcat 5.5.x+
  2. MySql
In addition to these 'undemanding' technical requirements, I've decided the following for prospective users of my system:
  • Demos should only be created when a propsective client requests them. I only want to pay when a real opportunity is present.
  • Prospective clients are to have individual instances. No sharing of instances or data.
  • Prospective clients are to have unlimited time trials. Their test data should also be retained should they chose to go ahead with using the system.
  • Provisioning of new instances should be automated with no human actions required (except of course the prospective client request).
I've managed to get it working with the following architecture:



As can be seen from above, the user requests an instance from my website. A request is sent using a PHP library for EC2 to create an instance based on a prepared image stored in Amazon S3. The user can then access this instance [n] through its public dns once the instance is up and running. Sounds simple enough?

The details for getting all this up and running is very involving and writing a tutorial for all the steps would be quite consuming given the information for this already exists elsewhere. What I will outline here are links to the tutorials and web resources I used to get this going and point out some of the challenges I faced i.e. things not pointed out in the tutorials and generally problems I had with the implementation.

Creating an Amazon AWS Account
This is off course the easiest part of the setup. Here's a presentation by Simone Brunozzi (AWS Evangelist) on how to sign up. I suggest playing around with EC2 instances before carrying on and Elastic Fox is an excellent Firefox plugin which you can use to manage your instances. When I was working on this, ElasticFox did not come preconfigured with the APAC region. This is easily fixed. Other minor stumbles include changing the permissions for the .pem files (chmod 0600 ...) otherwise ssh won't use the key to connect to the instances (Another gripe I had was the fact that the wizard for launching an instance on ElasticFox is to big to display on my MacBook even at top resolution).

Preparing your AMI Image
Hopefully by now you are familiar with what an AMI image is. Here's an excellent tutorial(which links to an existing Fedora 8 image with almost everything required to run java) on how to prepare your image on EC2. I opted to have MySql storing the information on the instance instead of on a Elastic Block Storage device because it is expected that the instances will be running for the life of the user trial. This is a simplification I chose otherwise I would need to have an EBS for each instance which is an excessive complication. However, should the instance terminate unexpectedly, the user would lose their data.

The MySql database for my application is created using a script that is 120MB. It has a lot of sample data. I uploaded it using Cyberduck for MacOS using SFTP.

Creating an S3 Bucket
S3 is AWS simple storage service. You need to have a bucket created. You need to make a decision as to which availability zone you want to run your instance from because buckets are not shared between instances. The image referred to in the preparing your AMI image tutorial is available in the us regions whereas I wanted to have my instance running of the newly minted Singapore region. I used the S3 Fox Organizer plugin to create my bucket and its a nice plugin overall to manage your S3 storage.

Automating the Creation of Instances
Once you are happy with the Image, you need a way of remotely creating instances. My website is currently running on Joomla! so I needed a PHP way of doing this. There is a PHP client library as part of the sample code and it works like a charm as well as provides sample code. For my purposes I only needed to execute the "runInstances" command to create the instance and the "describeInstances" command to check the status of the machine and get the public dns of the site in order to create the url to show the user.

Create Instance

  1. include_once ('/<path-to-the-ec2-library>/Amazon/EC2/Samples/.config.inc.php');
  2. $service = new Amazon_EC2_Client(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
  3. try
  4. {
  5. $response = $service->runInstances(array('ImageId' => '<your-image-id>', 'MinCount' => '1', 'MaxCount' => '1'));
  6. if ($response->isSetRunInstancesResult()) {
  7. $runInstancesResult = $response->getRunInstancesResult();
  8. if ($runInstancesResult->isSetReservation()) {
  9. $reservation = $runInstancesResult->getReservation();
  10. $runningInstanceList = $reservation->getRunningInstance();
  11. $instance_id = 'NA';
  12. foreach ($runningInstanceList as $runningInstance) {
  13. if ($runningInstance->isSetInstanceId())
  14. {
  15. $instance_id = $runningInstance->getInstanceId();
  16. $state = 'pending';
  17. $response = $service->describeInstances(array('InstanceId' => $instance_id));
  18. if ($response->isSetDescribeInstancesResult()) {
  19. $describeInstancesResult = $response->getDescribeInstancesResult();
  20. $reservationList = $describeInstancesResult->getReservation();
  21. foreach ($reservationList as $reservation) {
  22. $runningInstanceList = $reservation->getRunningInstance();
  23. foreach ($runningInstanceList as $runningInstance) {
  24. if ($runningInstance->isSetInstanceState()) {
  25. $instanceState = $runningInstance->getInstanceState();
  26. $state = $instanceState->getName();
  27. if ($runningInstance->isSetPublicDnsName())
  28. {
  29. }
  30. }
  31. }
  32. }
  33. }
  34. }
  35. }
  36. }
  37. }
  38. }
  39. catch (Amazon_EC2_Exception $ex)
  40. {
  41. echo("Caught Exception: " . $ex->getMessage() . "
  42. ");
  43. echo("Response Status Code: " . $ex->getStatusCode() . "
  44. ");
  45. echo("Error Code: " . $ex->getErrorCode() . "
  46. ");
  47. echo("Error Type: " . $ex->getErrorType() . "
  48. ");
  49. echo("Request ID: " . $ex->getRequestId() . "
  50. ");
  51. echo("XML: " . $ex->getXML() . "
  52. ");
  53. exit();
  54. }
Line 8 is where the instance is created. Line 33 and 36 get the state of the created instance and the public dns name respectively. I've experienced wait periods of up to 5 minutes from creating the instance to when its fully up and running, therefore you need to find a way of either doing this check asynchronously. It was a touch of irony, when my first thought was to execute a "popen" call so that the process could run in the background, only to discover "popen" is disabled by my current hosting providers. How long till I move my website to run on its own EC2 instance where I can do whatever I want?

WareRU Online

Finally! After a weekend full of blood, sweat and tears, I now have an on-demand trial of the WareRU Inventory management system online backed up by the wonderful Amazon Web Services. It has been a real learning experience getting this going and it allows me to showcase a great piece of software that was not available to try due to the prohibitive costs of Java hosting.


Enough said! Give it a go at http://bit.ly/blJxMi

Saturday, May 22, 2010

Amazon Web Services Meetup - Melbourne

I recently attended a cloud computing meetup in Melbourne hosted by an Amazon Web Services evangelist. I'm usually quite sceptical of the content of such meetups - I've met my share of salesmen from big vendors in my career - but the community aspect of such a meeting was too tempting to ignore. There was about 35 developers in attendance, mostly rubyists and sys-admin types. In all it was a productive session which had me thinking, when will I put this to use?

It turns out, one of the systems I've previously built has been languishing in neglect because of expensive and unmanageable Java hosting. I used to host a Virtual Private Server (VPS) for about 90$ (AUD) a month. This hosted a Tomcat Server, MySql, mail server and my website (PHP). I found this to be quite an expense, given the demo was rarely accessed - as it is specialised software. Also I had the hassle of cleaning up the data so that prospective clients found a professional demo ready for their use. This also needed to allow for long term trials so cleaning up the database every hour wasn't feasible.

It is a tribute to the maturity of Amazon's Web Services that it has been able to meet my requirements. I am in the process of chronicling the challenges I faced in creating this on-demand demo service.

Saturday, May 15, 2010

NameError: uninitialized constant GData

I was trying out the GData gem from Google as part of my chex rewrite when I got struck with a bit of an idea how the Ruby console works. This has been one of the things I've loved about programming in Ruby as opposed to Java / NET or the other programming languages I program in. I installed the gem using: "sudo gem install gdata" which worked like a treat. Next thing I did was fire up the console to start playing around with gem - "ruby script/console", only to be greeted by this error.

  1. trevors-macbook-4:chexscheduler trevor$ ruby script/console
  2. Loading development environment (Rails 2.3.5)
  3. /Library/Ruby/Gems/1.8/gems/rails-2.3.5/lib/rails/gem_dependency.rb:119:Warning: Gem::Dependency#version_requirements is deprecated and will be removed on or after August 2010. Use #requirement
  4. >> client = GData::Client::Calendar.new
  5. NameError: uninitialized constant GData
  6. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:443:in `load_missing_constant'
  7. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:80:in `const_missing'
  8. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:92:in `const_missing'
  9. from (irb):1
  10. >> client = GData::Client::DocList.new
  11. NameError: uninitialized constant GData
  12. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:443:in `load_missing_constant'
  13. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:80:in `const_missing'
  14. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:92:in `const_missing'
  15. from (irb):2
  16. >> client = GData::Client::DocList.new
  17. NameError: uninitialized constant GData
  18. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:443:in `load_missing_constant'
  19. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:80:in `const_missing'
  20. from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:92:in `const_missing'
  21. from (irb):3
  22. >> ^Dtrevors-macbook-4:chexscheduler trevor$
  23. trevors-macbook-4:chexscheduler trevor$ clear
This is peculiar as the gem has already been installed globally. However, as it was not added to the environment.rb, it was not picked up during the launch of the console. Only when I added the line " config.gem 'gdata', :lib => 'gdata' " to environment.rb and relaunched the console did it work. Back to playing around with the gem.

Adjusting to the Agile way

As I mentioned in a previous post, I'm rewriting one of my previous applications written in Python in Ruby on Rails. I've decided to spend sometime thinking and journalling the process - not just the technical hurdles of reimplementing in Ruby, but also the changes in project management methodology. I've fully embraced a scrum methodology for this project and I'm writing user stories on a notebook when I'm on the go and inputing them into Ice Scrum for traceability.

One of the challenges I find when I'm developing a new product is to treat myself as a client. I get so many brain waves and at times I'm not always disciplined enough to write them down. I just assume that since I originated the idea, it'll always be there. Sometimes its not necessarily a technical solution, it could be something that inspires the general vybe of the application (To be fair this also applies to when I'm using other methodologies). Having to condense this into a user story is a challenge.

Also, as the sole developer, there is a laziness involved in spending time writing something which your never sure will be read by anyone else. I feel like jumping straight into the actual deliverable. Note to self: Need to find out whether apps like twitter / facebook were built by their original developers using a strict development methodology. Do these methodologies apply at the edge of such innovation? I'd love to write the user stories for Twitter. I'm sure they could fit in 140 characters. Someone should write a tool using twitter for user stories.

Monday, May 10, 2010

Rewriting Chex Scheduler on Ruby on Rails

I was recently taking some speculative phone interviews a few weeks ago and I came across an international consulting company with a strong focus on Ruby on Rails and Agile practices. I remember remarking that I was not 'over-enthusiastic' about RoR (big mistake!). Anyway, I justified my reasons. I recently thought over my reasons for my dislike and decided to do my next major project using RoR. This happened to be my rewrite of Chex Scheduler - an online scheduling application written in Python and ExtJS running on the Google App Engine.

I'm also fully embracing the Agile way - using scrum in this instance - and I'll be cataloguing my experience. I'm pleased to have some tool support for project management in scrum in the form of Ice Scrum. Its great! The application will be deployed to Heroku and I'm hence using the git, version control system. I'm still undecided on what to use for Javascript, perhaps JQuery-UI. I think ExtJS was a bit heavy handed for what I wanted to achieve. So far, those are the design decisions I've made. I'll be updating the blog on how I'm proceeding.

Sunday, May 9, 2010

My experience map

Now, for some shameless self-plugging...

I've been answering some deeply personal questions about my experiences across my employment history for a head-hunting website and below is my experience map. I'm not sure the information is very useful - more than the nice graphic - and it doesn't capture all the technologies that I've worked on. It's interesting though, and cute.

To see my full career page, click here
http://mycareer-headhunter.com.au/people/trevorkimenye