Feeds:
Posts
Comments

Axiom has been mostly inactive for over 12 months now. I had hoped to revisit the framework sooner than this, but a pending move abroad has scuppered that and I suspect other projects will take precedence for at least another 6 months.

On a somewhat more positive note, I suspect that this new employment will offer ample opportunities to apply myself to complex integration testing scenarios, which will hopefully push me back into developing axiom again!

Watch this space.

The previous examples of http proxying only work for static (hard coded) urls. If you want the request path to be properly forwarded to the recipient, you’ll need to use the “bridgeEnpoint=true” option on the http receiver url in your route scripts, and this is only available in camel 2.1. Which doesn’t appear to be in any ‘well known’ maven repositories (isn’t on the apache ones for example) and doesn’t build from source (isn’t tagged and trunk has failing tests).

There is a workaround in camel 1.6 – 2.0 that involves some jiggery pokery with custom exchange headers, but I’ve not gotten it working yet. Hopefully 2.1 will go into a proper release soon so I can push axiom forward as a useful tool again.

I spent my lunch with a colleague today, trying to get axiom set up on a VM and demonstrating the basic http routing example I blogged about a few days ago. Sadly the release on sourceforge appears to be broken with respect to the packaged jars in the lib directory (duplicate versions of axiom-core). We got things worked out by pulling the current HEAD from github and running the maven package task before installing from the generated distro.

As I don’t plan to release to sourceforge again until 0.5.x, I would recommend this as the best approach if you’re planning to look at axiom. The version in revision control is usually quite stable as I do most experimental changes in branches anyway. Running the local maven build and installing from the generated distribution is quite simple:

 $ maven clean package assembly:assembly
 $ cd target 
 $ unzip axiom-complete.zip
 $ ./install.sh --help

links as promised

As promised, here are links to the source code on github and to the sourceforge project pages. I will create a project home page and some documentation as and when time allows.

One of the early use cases for axiom was to validate messaging based systems integration over http. The basic premise was that system-a talks to system-b over http (and vice versa) and that some basic tracing would be helpful, along with validation of xsd on the wire. There was also a desire to do the same thing with various other protocols and transports later on.

This is exactly the kind of thing that camel routes are good for, and was part of the inspiration for writing axiom. The long term goal I have is to be able to define this ‘scenario’ using a nice DSL:

# file http_a2b.scenario
scenario 'http://system-a.nat.mycorp.com/' => 'http://system-b.nat.mycorp.com/' do
  message_format = 'xml'
  message_schema = '/path/to/schema.xsd'

  assuming is_not(valid_schema?) { expect response(500) }

  assuming "/order[string-length(@uuid) <= 0]" do
    expect response(500)
  end

  assuming 'orderCorrelationId' => missingOrEmpty do
    expect response(401) { |resp| resp.body =~ /Order has not been created/ }
  end
end

I’d ideally like that code to sit in my project somewhere, and whenever somebody checks in, I’d like my build to run it for me. That’s the aspiration, and it includes generating random test data based on the supplied schema and producing build/test reports that will show up in my CI build status.

That’s the aspiration, but the reality is not nearly so complete. Testing a scenario with the current axiom release is a matter of setting up the route(s) yourself, then dealing with the outputs after the mediation layer has finished its work. Using the latest alpha release of axiom (0.4.5), I knocked up a quick example of how you might do this.

To start with, we’ll need to put the camel-jetty and camel-http jars into the endorsed/lib directory, along with any of their dependencies we don’t already have. After much messing around (a process called ‘discovery’), this led me to copy the following jars into the folder:


./endorsed/lib:
total 2600
drwxr-xr-x 12 pax staff 408 1 Apr 12:29 .
drwxr-xr-x 7 pax staff 238 31 Mar 17:37 ..
-rw-r--r-- 1 pax staff 33240 1 Apr 12:29 camel-http-1.5.0.jar
-rw-r--r-- 1 pax staff 21260 1 Apr 12:29 camel-jetty-1.5.0.jar
-rw-r--r-- 1 pax staff 30085 1 Apr 12:29 commons-codec-1.2.jar
-rw-r--r-- 1 pax staff 305001 1 Apr 12:29 commons-httpclient-3.1.jar
-rw-r--r-- 1 pax staff 66435 1 Apr 12:29 geronimo-servlet_2.4_spec-1.1.1.jar
-rw-r--r-- 1 pax staff 500206 1 Apr 12:29 jetty-6.1.11.jar
-rw-r--r-- 1 pax staff 34409 1 Apr 12:29 jetty-client-6.1.11.jar
-rw-r--r-- 1 pax staff 16900 1 Apr 12:29 jetty-sslengine-6.1.11.jar
-rw-r--r-- 1 pax staff 160524 1 Apr 12:29 jetty-util-6.1.11.jar
-rw-r--r-- 1 pax staff 132430 1 Apr 12:29 servlet-api-2.5-6.1.11.jar

The endorsed directory ($AXIOM_HOME/endorsed) is added to the class path, along with any jars present in the endorsed/lib directory, upon start-up. This makes it possible to use external jars and load scripts (and other resources) quite easily from your own scripts. Plans for dynamic reloading aren’t implemented yet.

After putting these in place, it is time to write up a camel route script to proxy between both http endpoints. The tracing part comes “out of the box” with camel and is just a matter of configuring your logging properties to put the trace output(s) into the correct destination. All we need in addition to this, is a record of any message bodies that didn’t conform to a given schema. Here’s an example file then:

require 'java'
require 'axiom'
require 'axiom/plugins'

route {
  xsd_file = "/tmp/http.request.xsd"
  logger.debug "reading schema from #{xsd_file}"

  intercept(is_not(valid_schema?(xsd_file))).
    to("file:///tmp/.badschemas")

  from("jetty:http://#{config >> 'http.test.inbound.uri'}").
    to("http://#{config >> 'http.test.outbound.uri'}")
}

You’ll need a properties file somewhere too, as the inbound and outbond uris are defined therein. When starting axiom up as a standalone application, you can pass the location of the additional properties file(s) using a system property, like so:

./axiom-server.sh start -Daxiom.configuration.externals=/path/to/file.properties:/more/files.properties

Running this example with the camel and/or axiom logging threshold set to debug will show that camel gets it’s knickers in a twist about the outbound http endpoint not being present. We can get around that with a little ruby script to listen and write all message bodies to standard out:

#!/usr/bin/env ruby

require 'uri'
require 'webrick'

uri = URI.parse('http://localhost:8080/test/outbound')
server = WEBrick::HTTPServer.new 'Port'.to_sym => uri.port
server.mount_proc uri.path do |request, response|
  STDOUT.puts request.body
  response.status = 200
end
server.start
puts 'done'

This is just a cobbled together example, so we don’t need to do much more to get ourselves ready. First we’ll kick off the ruby listener:

chmod +x listener.rb && ./listener.rb

Finally, once the listener is good to go, we can try testing the route out with curl:

curl http://localhost:8080/test/inbound -d "<request><data /></request>" -H "Content-Type: text/xml" -v

If the first message schema is valid, going to the directory (or file) in which you traced invalid schemas should be empty. Now you can try again with a broken document and (hopefully) see it picking up the messages and putting them in the invalid log file/directory.

Conclusion

What we’ve put together here, is a far cry from where I’d like to be. Using a DSL to describe your systems integration scenario in terms of expectations, and having your CI build execute this against a real test environment whilst generating test reports is my goal. Over the coming weeks however, I hope we’ll be able to see how these basic camel routes can be generated by the kind of DSL code we saw exemplified above, and how we can take the basic idea behind the stand-alone server and encode the same kind of behaviour into plugins for common build tools such as ant and maven.

You’d probably expect the first post in a blog about Axiom to explain what it actually is! Given my current user base of one person besides myself however, I suspect that word will have either gotten out some other way by the time others read this, or not at all. :P

Making use of java classes in your axiom test scripts is very simple. I use this technique internally to expose java classes without needing much ceremony. The mechanism is very simple, you just register the java class as a plugin in your route script (or your own plugin or helper script), supplying a name to reference the class in the DSL code. Here’s a simple example:

register_plugin :sample, org.axiom.SamplePlugin

Subsequently you can reference the ‘plugin’ using the supplied “method name” (i.e. the name you specified with the first argument to register_plugin) in your route scripts, custom plugins and helpers. This is only syntactic sugar for instantiating the specified object (in our case a new SamplePlugin instance would be returned for each call to the ‘sample’ method in your script). The value of it comes both from the “understand-ability” this adds to the camel DSL code that makes up your test scripts and routes. This registration mechanism also works across the whole execution context in which your code is run, meaning that a helper can register a class and it becomes transparently available to other code from then on. You can see this mechanism at work in the axiom-core modules, where the XML schema validation plugin is made globally available by simply registering a Java class for the task.

require 'axiom'
require 'axiom/plugins/builder'

import org.axiom.plugins.ValidXsdExpression
include Axiom::Plugins

register_plugin :valid_schema?, ValidXsdExpression

It really is that simple. There are several other ways to write and include custom plugins and I’ll explore some of these in my next post.

Yet another blog.

This one is focussed exclusively on axiom development work. Links to the sourceforge based web page and online documentation to follow.

Follow

Get every new post delivered to your Inbox.