<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1413304312041976659</id><updated>2012-02-09T23:17:18.691+11:00</updated><category term='maven release source deploy assembly plugin application'/><category term='Google Chrome Earth NPAPI OpenGL'/><category term='grails rails leaky abstraction GORM equals hashcode hibernate'/><category term='quartz composer opengl'/><category term='java eclipse performance maximum memory tabs slow'/><category term='JQL parameter list in instanceof'/><category term='macports port mac os x c c++ /opt package management'/><category term='cobertura'/><category term='polling provider consumer apache camel processor http cache time'/><category term='client server consumer publisher'/><category term='world global economic downturn software development'/><category term='jquery xml namespace javascript ajax date time utilities'/><category term='maven'/><category term='geography markup language gml journey tracking'/><category term='guice spring ioc inversion of control jsr 299'/><category term='Titan Class Web Store Share Google Earth jQuery Apache Camel'/><category term='iCal Outlook Java Javamail processing mime types email iCal4j'/><category term='Hibernate JPA annotations Java Persistance property field collection'/><category term='apache active mq camel maven mina tomcat cxf web services java spring anatomy service'/><category term='jax rs'/><category term='apache camel producer template pojo producertemplate dependency'/><category term='cxf rs'/><category term='code coverage'/><category term='spring'/><category term='property editor'/><category term='image compositor opengl mac os x quartz virtual memory mapped files mmap'/><category term='iPhone 4.0 multithreading multitasking threading'/><category term='POJO ORM Plain Old Java Object Dependent dependency'/><category term='WebOS PalmOS Palm Javascript iPhone Andriod'/><category term='ical4j camel java spring dao apache'/><category term='java swing javascript canvas html5'/><category term='json'/><category term='ioc'/><category term='jaas login modules mutual ssl authentication activemq ldap authorisation'/><title type='text'>Christopher Hunt on Software Development</title><subtitle type='html'>This is my blog where I like to focus on things of a software development nature.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>48</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-4696952438531694944</id><published>2011-09-08T07:40:00.001+10:00</published><updated>2011-09-08T14:06:45.660+10:00</updated><title type='text'>Application developers should not write frameworks and toolkits (much)</title><content type='html'>&lt;p&gt;On occasion I'm a little disappointed when I see developers create frameworks and toolkits. I understand that it is enjoyable to do so, but we, as application developers, should be majorly focused on the business needs of developing applications.&lt;/p&gt;&lt;p&gt;Quite often we think that xyz widget doesn't do exactly what is "required" and therefore pursue a path of days (weeks) writing frameworks and toolkits.&lt;/p&gt;&lt;p&gt;Let's not do this anymore.&lt;/p&gt;&lt;p&gt;Instead, every time you, as a developer, get the urge to write a framework or toolkit or even just a utility class, think about extending an existing open source project to meet your needs; or even starting a new open source project. For one thing, your requirements will most likely be challenged (which is a good thing). You will no doubt end up with something better than you could have created yourself (yes, that's hard to swallow, I know!). Importantly though, your organisation will benefit; the less "quirks" particular to an organisation the faster it is for them to ramp up resources and "Get Things Done".&lt;/p&gt;&lt;p&gt;Your organisation will also be able to share stuff between the silos. Imagine that.&lt;/p&gt;&lt;p&gt;I often hear, "but my organisation doesn't contribute to open source" (despite heavily using it). In this instance I always ask if the person in question has actually tried selling the business benefit (above) and attempted to make it happen. More often than not, the developer hasn't tried. Organisational behaviour is driven by the views of their employees and contractors. Organisations change and are changing.&lt;/p&gt;&lt;p&gt;I do believe that at the end of the day, it is better to suffer with an xyz widget that does most of what you need it to do than to re-invent the wheel. If you're an application developer then focus on the application, not frameworks and toolkits; unless you're contributing to open source projects.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-4696952438531694944?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/4696952438531694944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=4696952438531694944' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4696952438531694944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4696952438531694944'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/09/application-developers-should-not-write.html' title='Application developers should not write frameworks and toolkits (much)'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-2031053606963119847</id><published>2011-08-11T13:28:00.001+10:00</published><updated>2011-08-11T13:47:58.133+10:00</updated><title type='text'>Dependency Injection in Java - @Resource, @Inject or @Autowired?</title><content type='html'>&lt;p&gt;The &lt;a href="http://download.oracle.com/javaee/5/api/javax/annotation/Resource.html"&gt;@Resource documentation&lt;/a&gt; states that the "name" attribute refers to "The JNDI name of the resource". Spring has overloaded this to mean that you can refer to bean identifiers… but as far as the Java spec goes, there's no contractual obligation for a resource name to refer to a bean id. @Resource referring to Spring bean ids is therefore quite Spring-specific.&lt;/p&gt;&lt;p&gt;&lt;a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html"&gt;@Autowired&lt;/a&gt; is Spring specific.&lt;/p&gt;&lt;p&gt;&lt;a href="http://download.oracle.com/javaee/6/api/index.html?javax/inject/Inject.html"&gt;@Inject&lt;/a&gt; is not Spring specific and performs type-safe injection.&lt;/p&gt;&lt;p&gt;The other benefit you'll get from type-safe injection is the ability to safely re-factor within your favourite IDE, but I personally think that the contractual obligation mentioned above is more important.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-2031053606963119847?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/2031053606963119847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=2031053606963119847' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2031053606963119847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2031053606963119847'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/08/dependency-injection-in-java-resource.html' title='Dependency Injection in Java - @Resource, @Inject or @Autowired?'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-5154442098609946835</id><published>2011-08-10T12:45:00.001+10:00</published><updated>2011-08-10T13:52:27.133+10:00</updated><title type='text'>Versioning RESTful services</title><content type='html'>&lt;p&gt;I've seen some comment out there regarding how to version RESTful services and so thought it about time to add in my own position on this.&lt;/p&gt;&lt;p&gt;I don't subscribe to &lt;a href="http://blog.steveklabnik.com/2011/07/03/nobody-understands-rest-or-http.html"&gt;crafting your own MIME type&lt;/a&gt; as these should refer to well-known entities. I also don't subscribe to passing a version number as an Accept param. Despite there being client/server compatibilities in this regard (Ruby), the developer is not forced to specify the version. I think it is useful to specify the version of a service to use.&lt;/p&gt;&lt;p&gt;I'm an advocate of using a /v1 path in the url of a RESTful service, but it should be noted that great care should be taken in exactly what that version number refers to. I've long subscribed to the major.minor[.maintenance[-build]] approach as per Maven and reasonably discussed at &lt;a href="http://en.wikipedia.org/wiki/Version_number"&gt;Wikipedia&lt;/a&gt;. In the case of URL versioning, only the &lt;strong&gt;major&lt;/strong&gt; identification is used i.e. "1.0.2" becomes just "v1".&lt;/p&gt;&lt;p&gt;Major versions only change when there is an &lt;a href="http://en.wikipedia.org/wiki/Version_number#Degree_of_compatibility"&gt;API-breaking&lt;/a&gt; change that has been introduced. This should be &lt;strong&gt;very&lt;/strong&gt; rare. API-breaking generally means quite a big shift in the approach an API is taking which is why I found it interesting that Google declare their Google Maps API &lt;a href="http://code.google.com/apis/maps/documentation/javascript/basics.html#Versioning"&gt;will always be backwardly compatible&lt;/a&gt;. To me that's effectively what held Microsoft back with Windows until Vista came along and started to drop backwards compatibility (Windows 7 of course is the evolution of that good decision).&lt;/p&gt;&lt;p&gt;So I say use /v[major] as a convention, but be diligent in the definition of what is "major".&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-5154442098609946835?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/5154442098609946835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=5154442098609946835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5154442098609946835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5154442098609946835'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/08/versioning-restful-services.html' title='Versioning RESTful services'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-4097984094347078648</id><published>2011-07-22T22:36:00.001+10:00</published><updated>2011-07-22T22:36:22.978+10:00</updated><title type='text'>LMAX and the benefits of keeping things in memory</title><content type='html'>&lt;p&gt;I've now read Martin Fowler's review of the &lt;a href="http://martinfowler.com/articles/lmax.html"&gt;LMAX architecture &lt;/a&gt;and I feel good. This is very similar to what I've been doing for a long time with messaging (Spring Integration, Camel, AMQ, RMQ etc.).&lt;/p&gt;&lt;p&gt;LMAX is an event driven architecture. The Input Disruptor can be your favourite messaging broker. The Business Logic Processors are your message queue consumers. AMQP can certainly attain the goals described for the Output Disruptor (targeted consumers etc.).&lt;/p&gt;&lt;p&gt;The only thing "disruptive" about this article is that it introduces new terminology. I accept that there's probably a lot of optimisation going on, but from an architectural standpoint I don't see anything revolutionary.&lt;/p&gt;&lt;p&gt;Perhaps the most interesting points of the LMAX architecture are that everything is done in memory and that the processing of data is kept close to the data. These are things that we will all no doubt agree on being the main influence on performance.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-4097984094347078648?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/4097984094347078648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=4097984094347078648' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4097984094347078648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4097984094347078648'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/07/lmax-and-benefits-of-keeping-things-in.html' title='LMAX and the benefits of keeping things in memory'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-6864443189489384797</id><published>2011-06-26T17:31:00.001+10:00</published><updated>2011-06-26T17:39:10.723+10:00</updated><title type='text'>RESTful JSON fixtures for testing using CouchDB</title><content type='html'>&lt;p&gt; &lt;/p&gt;&lt;p&gt;I'm working in a distributed team at the moment where I don't have access to infrastructure available within the company's firewall. The application I'm working on has a nice &lt;a href="http://en.wikipedia.org/wiki/Restful"&gt;RESTful&lt;/a&gt; API with &lt;a href="http://www.json.org/"&gt;JSON&lt;/a&gt; payloads for its logic layer. As I'm mostly developing the presentation layer I needed a quick method of generating something that would simulate the logic layer.&lt;/p&gt;&lt;p&gt;One thing that I felt was important is that I shouldn't have to mutate any settings within my presentation application in order to work either against the simulated logic layer, or the real one. It is all too easy for such settings to creep into production and break things.&lt;/p&gt;&lt;p&gt;I had a few thoughts on how to achieve my objectives considering &lt;a href="http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html"&gt;Spring MVC,&lt;/a&gt;&lt;a href="http://en.wikipedia.org/wiki/Jax-rs"&gt;JAX-RS&lt;/a&gt; re-implementation using our existing interfaces (we're using JAX-RS in the real logic layer), writing a &lt;a href="http://jetty.codehaus.org/jetty/"&gt;Jetty&lt;/a&gt; based servlet handler and node.js. Then I remembered...&lt;/p&gt;&lt;p&gt;&lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; is a document oriented database that uses JSON as its Data Description Language (DDL). In addition CouchDB provides a RESTful JSON based API to access the database. This got me thinking that I could use sample responses from our real logic layer and enter them directly into the CouchDB database. It turns out you can using the &lt;a href="http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API"&gt;batch&lt;/a&gt; interface!&lt;/p&gt;&lt;p&gt;I then thought that I needed to create a CouchDB service that could understand the parameters of the web service request I needed to make. These parameters are properties of my JSON objects that are otherwise unavailable to the URL format that CouchDB provides for querying. The answer here is to provide a &lt;a href="http://wiki.apache.org/couchdb/HTTP_view_API"&gt;View&lt;/a&gt;. Here's my view:&lt;/p&gt;&lt;pre&gt;function(doc) { emit(doc.surname, doc) }&lt;/pre&gt;&lt;p&gt;The surname is a property of my JSON object that I'll want to query.&lt;/p&gt;&lt;p&gt;I call the view the same name as my logic layer service. In my case the view's name is "getCustomerBySurname". If I query my service using CouchDB's URL convention I would issue something like:&lt;/p&gt;&lt;pre&gt;http://localhost:5984/customerdb/_design&lt;br /&gt;/customerService-1.0/_view&lt;br /&gt;/getCustomerBySurname?key=%22Hunt%22&lt;/pre&gt;&lt;p&gt;This yields a result like:&lt;/p&gt;&lt;pre&gt;{"total_rows":1,"offset":0,"rows":[&lt;br /&gt;  {"id":"285b217949d54c29c4b27adf6d000da2","key":"Hunt","value":&lt;br /&gt;    {"id":1,"surname":"Hunt","firstname":"Christopher"...&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Note that I'm using a convention for versioning a resource so that I can evolve its API nicely in the future - this is quite important for RESTful requests as versioning isn't something supported by anything within HTTP&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I now have a web service that behaves the way the real service behaves. However, it doesn't look the same to the consumer for two reasons:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the result contains meta information about the query that the consumer does not expect ("total_rows" etc.); and&lt;/li&gt;&lt;li&gt;the URL we provide is not of the same form as the real logic layer service.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Transforming the JSON result&lt;/h2&gt;&lt;p&gt;To transform the payload returned by CouchDB into something our consumer expects we create a &lt;a href="http://guide.couchdb.org/draft/transforming.html"&gt;List&lt;/a&gt; in CouchDB-speak. My list function looks like this:&lt;/p&gt;&lt;pre&gt;function (head, req) {&lt;br /&gt;  provides('json', function() {&lt;br /&gt;    var results = [];&lt;br /&gt;    while (row = getRow()) { results.push(row.value); }&lt;br /&gt;    send(JSON.stringify(results));&lt;br /&gt;  });&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;I've declared my list by the name of "rows". The function is focused on pulling out just the row.value property of each row and returning that back to the consumer. To access the view that I created and have it render through the list you provide a URL like this:&lt;/p&gt;&lt;pre&gt;http://localhost:5984/customerDB/_design/&lt;br /&gt;customerService-1.0/_list/rows/&lt;br /&gt;getCustomerBySurname?key=%22Hunt%22&lt;/pre&gt;&lt;p&gt;This now yields something like:&lt;/p&gt;&lt;pre&gt;[{"id":1,"surname":"Hunt","firstname":"Christopher"...&lt;/pre&gt;&lt;p&gt;...which is what my consumer expects.&lt;/p&gt;&lt;h2&gt;Transforming the url&lt;/h2&gt;&lt;p&gt;The url is transformed via &lt;a href="http://httpd.apache.org/"&gt;Apache httpd&lt;/a&gt; using a &lt;a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html"&gt;RewriteRule&lt;/a&gt;. In order to avoid &lt;a href="http://en.wikipedia.org/wiki/Same_origin_policy"&gt;Same Origin Policy&lt;/a&gt; we've had to proxy requests for our presentation component and its web services anyhow. Here is the re-write rule I ended up with:&lt;/p&gt;&lt;pre&gt;RewriteEngine On&lt;br /&gt;RewriteOptions Inherit&lt;br /&gt;RewriteRule ^/CustomerDB/services-1.0/rest/Customers?surname=(.*) http://localhost:5984/customerdb/_design/customerService-1.0/_view/getCustomerBySurname?key="$1" [QSA,P]&lt;/pre&gt;&lt;p&gt;... and that's it. I now have a means of using CouchDB to provide fixtures for the purposes of development.&lt;/p&gt;&lt;h2&gt;One last important thought...&lt;/h2&gt;&lt;p&gt;The really interesting thing about using CouchDB for the use-case I set out to solve is that I'm really starting to wonder whether the real logic layer should be written using CouchDB... it is so simple and powerful!&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-6864443189489384797?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/6864443189489384797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=6864443189489384797' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6864443189489384797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6864443189489384797'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/06/restful-json-fixtures-for-testing-using.html' title='RESTful JSON fixtures for testing using CouchDB'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-6056981595194360785</id><published>2011-04-08T21:39:00.001+10:00</published><updated>2011-04-08T21:42:22.379+10:00</updated><title type='text'>DAO coding paradigms can require some skill</title><content type='html'>&lt;p&gt;"DAO coding paradigms can require some skill" is a sentence that presently &lt;a href="http://en.wikipedia.org/wiki/Data_access_object"&gt;appears at Wikipedia&lt;/a&gt; in the description of Data Access Objects. I find DAOs very useful and honing the skill is worth it. The article goes on to state a benefit being, "Improved efficiency and performance of the data layer since it is standard reusable software".&lt;/p&gt;&lt;p&gt;The majority of DAO implementations that I see tend to provide similar functionality to the &lt;a href="http://en.wikipedia.org/wiki/Active_record"&gt;Active Record pattern&lt;/a&gt; i.e. &lt;a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete"&gt;CRUD&lt;/a&gt;. Unfortunately these DAOs do not achieve the benefit of improved efficiency and performance. Let's say I have a customer, with orders that relate to products. My use-case is that I want the customers along with the orders and their products. With a straight CRUD approach I tend to get the customers (c) and then I get the orders (o) and then I get the products (p). That's potentially c * o * p or more requests on the database over the network.&lt;/p&gt;&lt;p&gt;The method signatures of my DAOs are shaped by the service layer that drives them. Here are a few methods of one of my real-world DAOs to serve as an example:&lt;/p&gt;&lt;pre&gt;public void createSMSSubscription(&lt;br /&gt;    String msn, String flightNo,&lt;br /&gt;    String actualText, String receivedParsedText, &lt;br /&gt;    Date scheduled, Date eventTime, &lt;br /&gt;    AbstractSMSEvent subscriptionEvent) {&lt;/pre&gt;&lt;pre&gt;&lt;div&gt;public Collection&amp;lt;Subscription&amp;gt; getActiveSubscriptions(&lt;br /&gt;    AbstractRenderedFlight renderedFlight) {&lt;/div&gt;&lt;/pre&gt;&lt;div&gt;&lt;pre&gt;public Collection&amp;lt;ReceivedSMSFlightSubscription&amp;gt;&lt;br /&gt;    getCurrentReceivedSubscriptions(&lt;br /&gt;        String msn, Date receivedTime) {&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may be that the service layer simply asks for a Customer to be created, but more often than not, the methods tend to be tailored to what the service layer wants to do e.g. "create an order for a customer that exists and only for products that exist", or "create an order for a customer that has not exceeded their credit limit" and so forth. I like to have my DAOs do as much as possible at the database with the objective of minimising the number of calls made to it. In short, my DAOs tend to comprise of fairly coarsely grained functions instead of finely grained CRUD style operations. I'll admit that it is a bit of an art in getting the granularity correct and that re-factoring commonly occurs, but the overriding goal is to reduce the IO between my logic layer and the data layer. Performance and efficiency then typically follow.&lt;/p&gt;&lt;p&gt;My DAOs are developed as the service layer evolves i.e. they are &lt;strong&gt;not&lt;/strong&gt; developed before the service layer. As stated above I let the service layer determine what functionality the DAO should provide. If I've developed a service with the DAO development alongside, and then develop another service that wants more out of the DAO then I tend to done one of two things:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;parameterise the existing methods of a DAO such that their behaviour can be varied; or&lt;/li&gt;&lt;li&gt;create new methods on the DAO.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;One more thing while I'm thinking about DAOs... they're a great place to encapsulate persistence functionality of course. It used to be that we may have wanted to hide away the differences of dealing with multiple types of relational database. However we now find ourselves thinking about providing non-relational stores (NoSQL) as well. DAOs give you the freedom to choose the best persistence implementation to suit your application's requirements.&lt;/p&gt;&lt;p&gt;Long live the DAO!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-6056981595194360785?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/6056981595194360785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=6056981595194360785' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6056981595194360785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6056981595194360785'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/04/dao-coding-paradigms-can-require-some.html' title='DAO coding paradigms can require some skill'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-3039020667606987368</id><published>2011-04-03T02:22:00.000+10:00</published><updated>2011-04-03T02:22:00.097+10:00</updated><title type='text'>Zoneinfo TZ v1.0.0 is now available!</title><content type='html'>&lt;p&gt;My &lt;a href="http://zoneinfo-tz.codehaus.org/"&gt;Zoneinfo TZ &lt;/a&gt;library is now available up at the &lt;a href="http://codehaus.org/"&gt;Codehaus&lt;/a&gt;. V1.0.0 should make it to the central Maven repo shortly. The project has mailing lists, continuous integration, issue tracking and all of those things you'd come to expect.&lt;/p&gt;&lt;p&gt;Interestingly, the &lt;a href="http://www.twinsun.com/tz/tz-link.htm"&gt;site&lt;/a&gt; that hosts the zoneinfo files themselves has disappeared tonight. Fingers crossed that it'll come back soon!&lt;/p&gt;&lt;p&gt;I hope that this project proves useful to someone other than me! Enjoy.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-3039020667606987368?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/3039020667606987368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=3039020667606987368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3039020667606987368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3039020667606987368'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/04/zoneinfo-tz-v100-is-now-available.html' title='Zoneinfo TZ v1.0.0 is now available!'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-1175745349978717387</id><published>2011-03-02T09:18:00.001+11:00</published><updated>2011-03-02T09:18:51.208+11:00</updated><title type='text'>GWT and GXT</title><content type='html'>&lt;p&gt;Recently I've been doing a lot of development in &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt;. I have to say that, despite being a big fan of pure JavaScript &lt;a href="http://en.wikipedia.org/wiki/Rich_Internet_application"&gt;RIA&lt;/a&gt;, I'm liking GWT a lot. It has been a couple of years since I touched GWT and it has come a long way. I particularly like the &lt;a href="http://code.google.com/webtoolkit/doc/trunk/DevGuideMvpActivitiesAndPlaces.html"&gt;Activities and Places&lt;/a&gt; API, although there's a bit of a learning curve there.&lt;/p&gt;&lt;p&gt;One thing I don't particularly like though is &lt;a href="http://www.sencha.com/products/extgwt/"&gt;Sencha's EXT-GWT&lt;/a&gt;, or GXT as it is known. For those that don't know, GXT provides an abundance of widgets including a fully featured Grid. This is of course highly enticing, but what I've found is that GXT appears to be an all-or-nothing proposition. GXT is more akin to a framework than a toolkit because it effects how you lay out your code. What isn't clear to me is why it has its own layout architecture and its own event architecture. That's just confusing!&lt;/p&gt;&lt;p&gt;I'm starting to think that GXT plugged a few gaps in GWT 1.x and is becoming increasing less relevant. GWT 2.x deprecates a lot of GXT; even GWT 1.6 introduced a new event model.&lt;/p&gt;&lt;p&gt;Don't even get me started on GXT's Grid separation of concerns; its one of those widgets that likes to influence how the data transfer objects look. Plain wrong. The whole loader concept is terribly confusing as well.&lt;/p&gt;&lt;p&gt;I feel that if GWT's TableCell was as fully featured as GXT's Grid then no one would probably use GXT.&lt;/p&gt;&lt;p&gt;Perhaps I'm being a little harsh though. GXT widgets present nicely. It is just that they don't just "slot in"; you've got to buy into all of GXT to use a little of it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-1175745349978717387?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/1175745349978717387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=1175745349978717387' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/1175745349978717387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/1175745349978717387'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/03/gwt-and-gxt.html' title='GWT and GXT'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-3175398598489342907</id><published>2011-01-13T10:13:00.001+11:00</published><updated>2011-01-13T10:13:50.755+11:00</updated><title type='text'>I have a new job</title><content type='html'>&lt;p&gt;&lt;img title="spring09_logo.png" src="http://lh5.ggpht.com/__zfCVFcU_Ac/TS41jBImGdI/AAAAAAAAADo/Yvxbi72zAXg/spring09_logo.png?imgmax=800" border="0" alt="spring09_logo.png" width="240" height="50" /&gt;&lt;/p&gt;&lt;p&gt;I now have a job with VMware starting January 24th and I'm excited! My role is as a &lt;a href="http://www.springsource.com/products/cloud-application-platform"&gt;vFabric&lt;/a&gt; consulting software engineer within the professional services division .&lt;/p&gt;&lt;p&gt;Over the past 12 years I've been an independent contracting developer/architecture/designer and launched quite a few of my own products. I suppose one of the initial drivers to go contracting for me back then was that it was lucrative to do so. I now feel that the gap in remuneration between going permanent and contracting has diminished.&lt;/p&gt;&lt;p&gt;Another incredibly important factor was my family. Contracting can be great but the cash flow can be stressful. With 4 kids I needed more stability.&lt;/p&gt;&lt;p&gt;Finally, I wanted to work with more like-minded people. During my contracting years I've met some truly inspirational people along the way; but I want to meet more! This can be difficult as a contractor as you tend not to stay around long enough to work on the strategic projects and with an organisation's best people.&lt;/p&gt;&lt;p&gt;So, back in May last year I decided to look around for some permanent work. I choose some companies with &lt;a href="http://en.wikipedia.org/wiki/SpringSource"&gt;SpringSource&lt;/a&gt; being one of them. I thought, if I go for a permanent job then who would I really want to work for? It is important to "tow the corporate line" of course and so I needed to ensure that this would be a no-brainer. I'm not very good at lying!&lt;/p&gt;&lt;p&gt;I've been using the Spring framework for quite some time and became very interested in the work of some of the SpringSource people; namely &lt;a href="http://www.springone2gx.com/conference/speaker/rod_johnson"&gt;Rod Johnson&lt;/a&gt; and &lt;a href="http://www.springone2gx.com/conference/speaker/ben_alex"&gt;Ben Alex&lt;/a&gt;. Towing the line for SpringSource would not be a difficult proposition... I contacted SpringSource and ended up meeting with &lt;a href="http://au.linkedin.com/pub/guy-baldwin/0/51a/764"&gt;Guy Baldwin&lt;/a&gt; and the ball then started to roll. I instantly liked Guy and his technical knowledge along with his amiable personality makes him a great face of VMware/SpringSource.&lt;/p&gt;&lt;p&gt;'better had just get one thing straight: VMware acquired SpringSource in 2009 and so SpringSource is now a division of VMware. I'll refer to SpringSource as VMware for the rest of this blog ('hope that is politically correct!).&lt;/p&gt;&lt;p&gt;vFabric is the name given to VMware's Cloud Application Platform, meaning the whole stack of technologies that enable applications to live in a cloud environment. Technically speaking the cloud may not be the actual cloud as in the internet, but live behind the corporate firewall; it doesn't really matter though. What the platform is really about is enabling applications to be scaled in order to meet unanticipated demand.&lt;/p&gt;&lt;p&gt;My specific role is a first here in Asia/Pac. VMware have a vFabric consulting presence in the US and I'm their first consultant for them here in our region. It is exciting.&lt;/p&gt;&lt;p&gt;I'll continue to post my own views on software development here but needless to say, they'll be my views and not necessarily VMware's!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-3175398598489342907?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/3175398598489342907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=3175398598489342907' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3175398598489342907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3175398598489342907'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/01/i-have-new-job.html' title='I have a new job'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/__zfCVFcU_Ac/TS41jBImGdI/AAAAAAAAADo/Yvxbi72zAXg/s72-c/spring09_logo.png?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-3372860914350874822</id><published>2011-01-03T21:19:00.001+11:00</published><updated>2011-01-03T21:19:08.513+11:00</updated><title type='text'>The Low Cloud</title><content type='html'>&lt;p&gt;I was chatting with a CIO mate today about the future of cloud computing and how his company are looking to build their own &lt;a href="http://natishalom.typepad.com/nati_shaloms_blog/"&gt;Cloud Enabled Application Platform (CEAP)&lt;/a&gt;. I feel that many companies are sensitive to putting their data in the cloud itself and my friend definitely echoed that sentiment. There are some things his enterprise could put in to the cloud for economic reasons, but most things will reside behind their firewall.&lt;/p&gt;&lt;p&gt;Interestingly my friend's main driver for a CEAP was to achieve horizontal scalability. He has some performance issues that lend themselves well to being addressed in a highly parallel manner.&lt;/p&gt;&lt;p&gt;During this conversation I used the term "low cloud" to describe CEAP hosted behind the enterprise firewall. So, you heard the term, "low cloud" here first. :-)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-3372860914350874822?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/3372860914350874822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=3372860914350874822' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3372860914350874822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3372860914350874822'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2011/01/low-cloud.html' title='The Low Cloud'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-4938820861230666903</id><published>2010-12-29T22:13:00.001+11:00</published><updated>2010-12-29T22:15:54.839+11:00</updated><title type='text'>Timezones, timezones and a new time zone library</title><content type='html'>&lt;p&gt;I've had a bit of a thing about time zones and daylights savings rules for quite some time i.e. they interest me. This was first apparent in an application I wrote for the Palm OS originally named Time Traveler (which became &lt;a href="http://www.classactionpl.com/index2.htm"&gt;Titan Class&lt;/a&gt;). Its time zone database was inspired by &lt;a href="http://en.wikipedia.org/wiki/Tz_database"&gt;zoneinfo&lt;/a&gt;, but was no where near as sophisticated. The Palm OS was without time zone support in its first few incarnations. Eventually time zone support was incorporated but IMHO it was weak. I digress a little... the point is I've really liked the zoneinfo database that underpins most Unix based platforms for quite some time.&lt;/p&gt;&lt;p&gt;Java supports zoneinfo in its implementation by use of the &lt;a href="http://site.icu-project.org/"&gt;ICU&lt;/a&gt; library. There is also a &lt;a href="http://jcp.org/en/jsr/detail?id=310"&gt;JSR&lt;/a&gt; that's about 3 years old which aims to provide greater support for zoneinfo.&lt;/p&gt;&lt;p&gt;I recently had a need to ensure that my application had the latest time zone rules available. From a Java perspective, Sun or Apple (or whoever) provide a patch when time zone rules change. You then typically restart your application. I didn't want that. My goals were:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;to have the latest rules on a monthly basis; and&lt;/li&gt;&lt;li&gt;to be able to dynamically update the time zones without having to restart my application.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;JSR-310 could probably help me out here but I had another nagging concern; in fact a couple:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the JSR is 3 years old and doesn't appear to have progressed; and&lt;/li&gt;&lt;li&gt;I like the zoneinfo structure and wanted to use something that honoured its structure closely.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I might be a little unfair toward JSR-310 and if it becomes approved then it'll be difficult to avoid. I'm also strongly aware of the "Not Invented Here" syndrome... not my style though. Then, there's the &lt;a href="http://www.jimjag.com/imo/index.php?/archives/242-The-JCP-Is-Dead.html"&gt;JCP-is-dead&lt;/a&gt; thingy...&lt;/p&gt;&lt;p&gt;So, what I've done is created a new Java time zone library that takes zoneinfo files and produces a JDK compatible facade. The library uses &lt;a href="http://www.antlr.org/"&gt;ANTLR&lt;/a&gt; to parse the zoneinfo files thus actually providing a parser that can be used for many languages. I'll shortly be open-sourcing this library and probably at &lt;a href="http://codehaus.org/"&gt;The Codehaus&lt;/a&gt; depending on how well it is received there. Meanwhile here is an overview of its structure:&lt;/p&gt;&lt;p style="font-size: 11px;"&gt;&lt;img title="Zoneinfo TZ.png" src="http://lh6.ggpht.com/__zfCVFcU_Ac/TRsYZwf_sDI/AAAAAAAAADg/PF1mt9GeRGk/Zoneinfo%20TZ.png?imgmax=800" border="0" alt="Zoneinfo TZ.png" width="350" height="258" /&gt;&lt;/p&gt;&lt;p&gt;The library is effectively done and has reasonable test coverage. I hope that you'll join me and help improve it. Meanwhile any thoughts and ideas are most welcome.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-4938820861230666903?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/4938820861230666903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=4938820861230666903' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4938820861230666903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4938820861230666903'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/12/timezones-timezones-and-new-time-zone.html' title='Timezones, timezones and a new time zone library'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/__zfCVFcU_Ac/TRsYZwf_sDI/AAAAAAAAADg/PF1mt9GeRGk/s72-c/Zoneinfo%20TZ.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-5881898596260482406</id><published>2010-12-07T21:52:00.001+11:00</published><updated>2010-12-07T21:52:07.476+11:00</updated><title type='text'>Memory grids</title><content type='html'>&lt;p&gt;There's a &lt;a href="http://www.se-radio.net/2010/11/episode-169-memory-grid-architecture-with-nati-shalom/"&gt;great podcast on Software Engineering Radio&lt;/a&gt; with &lt;a href="http://natishalom.typepad.com/nati_shaloms_blog/"&gt;Nati Shalom.&lt;/a&gt; The podcast discusses memory grids and I certainly found it insightful. In essence memory grids are being looked upon as the next disk.&lt;/p&gt;&lt;p&gt;The clincher for me was the revelation that the durability of data is not related to it being persisted to disk; it is related to the number of geographically disbursed copies of that data at any one time. Taken to the extreme this could mean that you don't need disk at all, but practically the data gets persisted to disk in an asynchronous manner. This is called "write behind" and can be performed at n nodes, if not all of them.&lt;/p&gt;&lt;p&gt;I think memory grids are very interesting. My prediction is that &lt;a href="http://www.terracotta.org/open-source/"&gt;memcached&lt;/a&gt;, a popular open source memory cache that can be distributed over many nodes, will become a memory grid offering write-behind persistence. Same goes for &lt;a href="http://www.terracotta.org/open-source/"&gt;Ehcache/Terracotta&lt;/a&gt; i.e. these memory caches will evolve beyond being just that. There are of course commercial memory caches out there including &lt;a href="http://www.google.com.au/aclk?sa=l&amp;amp;ai=CXWDIMQb-TKefL8m5cMTHia0LjsOg7gGG1OKuFs37pv8BCAAQASC5VCgCUMj7iLf7_____wFgpfiRgJABoAHSzeb-A8gBAaoEHE_Qpo7Fis1D7IoQZqRLiKcyYtc2iMdlDyY8-VSABZBO&amp;amp;sig=AGiWqtxU5EdXVeHOFZ1MP1wpq39oSMp3ZA&amp;amp;adurl=http://www.springsource.com/landing/next-generation-data-management-cloud-java-apps%3Fcid%3D70170000000XDkY%26_kk%3Dgemfire%26_kt%3D1b971ad3-e059-4997-b3ca-b2bfd82b4017"&gt;vmware's Gemfire&lt;/a&gt; and &lt;a href="http://www.oracle.com/technetwork/middleware/coherence/overview/index.html"&gt;Oracle's Coherence.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;One reason in my mind as to why memory grids are topical is commodity hardware being able to address one heck of a lot of memory resident data. Since the introduction of 64 bit computing for the masses, we now have a situation where a cheap processor can generally access about 256TB data - more than enough for most databases! Of course, with 32 bit processors about 4GB could be addressed which is less than many databases.&lt;/p&gt;&lt;p&gt;I think something that can be overlooked with memory grids is persistence. As mentioned, write-behind appears typical, but what isn't focused on is what performs the write-behind. There's no reason why that write-behind can't be done with a conventional RDBMS and I understand that many memory grids support such a thing. Thus with memory grids, it appears that you can have the best of both worlds.&lt;/p&gt;&lt;p&gt;Bring on the memory grid (preferably open sourced!).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-5881898596260482406?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/5881898596260482406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=5881898596260482406' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5881898596260482406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5881898596260482406'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/12/memory-grids.html' title='Memory grids'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-3783623027177571627</id><published>2010-11-06T21:09:00.001+11:00</published><updated>2010-11-06T21:10:44.061+11:00</updated><title type='text'>Mac OS X Virtualisation</title><content type='html'>&lt;p&gt;This evening I read that Apple are &lt;a href="http://images.apple.com/xserve/pdf/L422277A_Xserve_Guide.pdf"&gt;retiring the Xserve&lt;/a&gt;. I guess that's a shame as I always wanted to see more of OS X in the server space. I think that this will relegate OS X to the SOHO market; unless... Apple permit virtualised instances of OS X.&lt;/p&gt;&lt;p&gt;Permitting virtualisation would be a very smart move by Apple. Let's face it, unless you can run on OS as a virtualised instance then you're never going to be a player in the enterprise and in the elastic cloud.&lt;/p&gt;&lt;p&gt;Time will tell if Apple see the merits of virtualisation.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-3783623027177571627?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/3783623027177571627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=3783623027177571627' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3783623027177571627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3783623027177571627'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/11/mac-os-x-virtualisation.html' title='Mac OS X Virtualisation'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-7745701452270847489</id><published>2010-11-04T12:20:00.001+11:00</published><updated>2010-11-04T13:00:49.121+11:00</updated><title type='text'>JavaScript Dependency Management and JSLint Tools</title><content type='html'>&lt;p&gt;I've been focusing on JavaScript Rich Internet Application development for some time now and have felt that while JavaScript is a capable language, it has sorely lacked tooling. This situation is changing of course and we're seeing more JavaScript tools come from the likes of Mozilla, Apple and Google quite frequently.&lt;/p&gt;&lt;p&gt;I feel that the lack of dependency management with good version control in any language is painful and JavaScript was no exception. I recently spent a good part of my day sorting out dependencies in a .NET environment; I sorely missed Apache Maven there. Given my JavaScript development activities I decided to provide the dependency management functionality of Maven to JavaScript via a Maven Plugin.&lt;/p&gt;&lt;p&gt;Imagine writing just the following in your JavaScript code when you want to ensure that jQuery or Prototype.js is present at runtime:&lt;/p&gt;&lt;pre&gt;var $;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Alternatively when there are no global variables declared by a JavaScript dependency you can import it without being concerned about its file location and version:&lt;/p&gt;&lt;pre&gt;/**&lt;br /&gt; * @import com.jqueryui:jquery-ui&lt;br /&gt; */&lt;/pre&gt;&lt;p&gt;The com.jqueryui:jquery-ui artifact along with its version is declared in Maven's POM file.&lt;/p&gt;&lt;p&gt;This frictionless approach to declaring JavaScript dependency requirements is the motivation for the Maven JavaScript Import Plugin.&lt;/p&gt;&lt;p&gt;I'm pleased to announce the availability of my &lt;a href="http://mojo.codehaus.org/js-import-plugin/"&gt;JavaScript Import Plugin at Codehaus&lt;/a&gt; where I have now also become a committer (a great honour!).&lt;/p&gt;&lt;p&gt;Along the way  I decided to create a plugin that provided efficient &lt;a href="http://www.jslint.com/"&gt;JSLint&lt;/a&gt; invocation during JavaScript development. This plug is also released at the Codehaus and is named the &lt;a href="http://mojo.codehaus.org/jslint-plugin/"&gt;JSLint Plugin&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;﻿Please help the professional JavaScript developer community by downloading and building the projects from source and try out some development using the plugins.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-7745701452270847489?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/7745701452270847489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=7745701452270847489' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7745701452270847489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7745701452270847489'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/11/maven-based-javascript-tools-at.html' title='JavaScript Dependency Management and JSLint Tools'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-5528718223139935144</id><published>2010-11-04T11:18:00.001+11:00</published><updated>2010-11-04T11:20:41.537+11:00</updated><title type='text'>Maven crashing with a bus error/invalid memory access given Java 10.6 update 3</title><content type='html'>&lt;p&gt;I had this very annoying scenario where all of a sudden the following happened:&lt;/p&gt;&lt;pre&gt;﻿mvn&lt;/pre&gt;&lt;pre&gt;Invalid memory access of location 0x133cd800a rip=0x100504444&lt;/pre&gt;&lt;pre&gt;Bus error&lt;/pre&gt;&lt;p&gt;This seemed to happen as a result of updating to Java 10.6 update 3 on Mac OS X Snow Leopard; but not straight away!&lt;/p&gt;&lt;p&gt;After a while I started to wonder if the update was installed correctly. So, I manually downloaded the update from here:&lt;/p&gt;&lt;p&gt;&lt;a href="http://support.apple.com/kb/dl972"&gt;﻿http://support.apple.com/kb/dl972&lt;/a&gt;&lt;/p&gt;&lt;p&gt;...and presto, things appear to be ok again... let's see how long that lasts!&lt;/p&gt;&lt;p&gt;I understand that as of this update, Apple are handing over control to Oracle in terms of managing the distribution of Java on Mac OS X. I think that this is generally good given that Apple has always been a little behind in terms of the latest Java release. Let's hope that the quality of the distro on Mac OS X does not go south though!&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-5528718223139935144?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/5528718223139935144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=5528718223139935144' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5528718223139935144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5528718223139935144'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/11/maven-crashing-with-bus-errorinvalid.html' title='Maven crashing with a bus error/invalid memory access given Java 10.6 update 3'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-7634751506007323823</id><published>2010-10-06T10:39:00.001+11:00</published><updated>2010-10-06T10:39:43.657+11:00</updated><title type='text'>When is a unit test not a unit test?</title><content type='html'>&lt;p&gt;There's a great deal written on this topic already, but obviously not enough. I had a very interesting chat with a colleague the other day about what constitutes a unit test vs integration, system etc.&lt;/p&gt;&lt;p&gt;I think the boundaries are mirky, but for me at least, a unit test is something that can be constructed with little friction and it can execute fast. I don't really care much about whether I'm testing things that are technically outside of the "unit" I'm working on e.g. if there's an in-memory database available and I can easily construct a test of my code, I don't think I'm crossing the boundary into integration testing. In fact what I've found is that it is sometimes easier to set up an  in memory database for the purposes of testing rather than mocking it.&lt;/p&gt;&lt;p&gt;Now of course when you start crossing process boundaries you are moving into the world of integration tests. This falls into the category of "being slow to run" though.&lt;/p&gt;&lt;p&gt;At the end of the day I'm not too worried about whether my test is a unit test so long as its easy to write and quick to execute. If it isn't then I'm happy to have it fall into another category of testing.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-7634751506007323823?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/7634751506007323823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=7634751506007323823' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7634751506007323823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7634751506007323823'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/10/when-is-unit-test-not-unit-test.html' title='When is a unit test not a unit test?'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-210604541000699067</id><published>2010-08-07T17:24:00.001+10:00</published><updated>2010-08-07T17:26:35.397+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cxf rs'/><category scheme='http://www.blogger.com/atom/ns#' term='jax rs'/><title type='text'>A MessageBodyWriter isWriteable method for a collection example</title><content type='html'>&lt;p&gt;I can’t believe how much time I’ve spent today on providing an isWritable method for my JAX-RS &lt;a href="http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/ext/MessageBodyWriter.html"&gt;MessageBodyWriter&lt;/a&gt; class. I just couldn't find a good example out there that did what I wanted to do. Maybe Google search wasn't behaving today!&lt;/p&gt;&lt;p&gt;My goal was to have a provider that translates a List&amp;lt;GPSTrackerCollection&amp;gt; object into an application/xml output stream. GPSTrackerCollection is my own class.&lt;/p&gt;&lt;p&gt;The tricky thing was learning how to test for the presence of a List of GPSTrackerCollection objects within my provider.&lt;/p&gt;&lt;p&gt;First things first, I needed to wrap my collection in a &lt;a href="http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/GenericEntity.html"&gt;GenericEntity&lt;/a&gt; object in order to preserve information on the parameterised type; the runtime strips this information of course (this is known as &lt;a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ005"&gt;erasure&lt;/a&gt;). Here's an example service implementation from my code base:&lt;/p&gt;&lt;pre&gt;@GET&lt;br /&gt;@Path("/history")&lt;br /&gt;public Response getHistory() {&lt;br /&gt;  List&amp;lt;GPSTrackerCollection&amp;gt; list = new ArrayList&amp;lt;GPSTrackerCollection&amp;gt;();&lt;br /&gt;  GenericEntity&amp;lt;List&amp;lt;GPSTrackerCollection&amp;gt;&amp;gt; entity =&lt;br /&gt;    new GenericEntity&amp;lt;List&amp;lt;GPSTrackerCollection&amp;gt;&amp;gt;(list) {};&lt;br /&gt;  return Response.ok(entity).build();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;My MessageBodyWriter ends up looking something like the following:&lt;/p&gt;&lt;pre&gt;@Produces("application/xml")&lt;br /&gt;@Provider&lt;br /&gt;public class GPSTrackerCollectionProvider implements&lt;br /&gt;    MessageBodyWriter&amp;lt;List&amp;lt;GPSTrackerCollection&amp;gt;&amp;gt; {&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public long getSize(List&amp;lt;GPSTrackerCollection&amp;gt; arg0, Class&amp;lt;?&amp;gt; arg1,&lt;br /&gt;      Type arg2, Annotation[] arg3, MediaType arg4) {&lt;br /&gt;    return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public boolean isWriteable(Class&amp;lt;?&amp;gt; type, Type genericType,&lt;br /&gt;      Annotation[] arg2, MediaType arg3) {&lt;br /&gt;&lt;br /&gt;    // Ensure that we're handling only List&amp;lt;GPSTrackerCollection&amp;gt; objects.&lt;br /&gt;    boolean isWritable;&lt;br /&gt;    if (List.class.isAssignableFrom(type)&lt;br /&gt;        &amp;amp;&amp;amp; genericType instanceof ParameterizedType) {&lt;br /&gt;      ParameterizedType parameterizedType = (ParameterizedType) genericType;&lt;br /&gt;      Type[] actualTypeArgs = (parameterizedType.getActualTypeArguments());&lt;br /&gt;      isWritable = (actualTypeArgs.length == 1 &amp;amp;&amp;amp; actualTypeArgs[0]&lt;br /&gt;          .equals(GPSTrackerCollection.class));&lt;br /&gt;    } else {&lt;br /&gt;      isWritable = false;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return isWritable;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public void writeTo(List&amp;lt;GPSTrackerCollection&amp;gt; gpsTrackerCollections,&lt;br /&gt;      Class&amp;lt;?&amp;gt; arg1, Type arg2, Annotation[] arg3, MediaType arg4,&lt;br /&gt;      MultivaluedMap&amp;lt;String, Object&amp;gt; arg5, OutputStream os)&lt;br /&gt;      throws IOException {&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The key thing here is that we check the parameterised type argument for equality against the class of GPSTrackerCollection. My intuition was that I could do an instanceof operation here, but this is not permitted. Check out &lt;a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ102"&gt;this FAQ&lt;/a&gt; as to why.&lt;/p&gt;&lt;p&gt;Enjoy.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-210604541000699067?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/210604541000699067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=210604541000699067' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/210604541000699067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/210604541000699067'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/08/messagebodywriter-iswriteable-method.html' title='A MessageBodyWriter isWriteable method for a collection example'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-6732846517788622923</id><published>2010-07-31T12:45:00.001+10:00</published><updated>2010-07-31T16:51:10.887+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='ioc'/><category scheme='http://www.blogger.com/atom/ns#' term='json'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Application development feelings 2010</title><content type='html'>&lt;p&gt;Every now and again I review my practice of developing web based software. Here is a summary of how I write my applications in the context of a &lt;a href="http://en.wikipedia.org/wiki/Multitier_architecture"&gt;multi-tier architecture&lt;/a&gt;.&lt;/p&gt;&lt;h1&gt;The presentation layer&lt;/h1&gt;&lt;p&gt;In essence I'm a big fan of &lt;a href="http://en.wikipedia.org/wiki/Rich_Internet_application"&gt;RIA&lt;/a&gt; (Rich Internet Application) for situations where I'm interested in developing a web based application as distinct from a web site full of HTML pages. I feel that this is a distinction lost on many people and I also think that those same people struggle with combining HTML/CSS/JS to make a web application.&lt;/p&gt;&lt;p&gt;I'm quite keen on developing something with &lt;a href="http://www.sproutcore.com/"&gt;Sproutcore&lt;/a&gt; as in a way, it blows away HTML and CSS and gives you the widgets to build a fully fledged MVC style app that works within the browser; its very similar to developing a native desktop application. The same can be said for &lt;a href="http://code.google.com/webtoolkit/"&gt;Google Web Toolkit&lt;/a&gt; (GWT) however I slightly favour Sproutcore as it embraces JavaScript (JS) as a language whereas GWT embraces Java that produces JS i.e. Sproutcore "feels" lighter. Perhaps I should get over that... what Google have developed in the form of Google Wave is impressive.&lt;/p&gt;&lt;p&gt;There are other JS MVC frameworks out there (&lt;a href="http://javascriptmvc.com/"&gt;JavascriptMVC&lt;/a&gt; and &lt;a href="http://puremvc.org/"&gt;PureMVC&lt;/a&gt; for starters), but I'm not sure that they drop HTML/CSS as a dependency for the developer to consider. I suppose what I'm feeling is that HTML and CSS do not belong in a web based application. Given HTML's start in life as a mark up language for documents I'm comfortable in acknowledging that it does not have a place in my web application.&lt;/p&gt;&lt;p&gt;The biggest thing for me right now with regards to JS RIA is the lack of development tooling. I've been using the Jetbrains &lt;a href="http://www.jetbrains.com/webstorm/"&gt;WebStorm&lt;/a&gt; IDE for a couple months and while I'm impressed on its Window's implementation, it doesn't feel like a native Mac OS X application. Given that Mac OS X is where I like to spend a lot of my time this unfortunately creates a problem for me.&lt;/p&gt;&lt;p&gt;In my ideal world I'd be using &lt;a href="http://maven.apache.org/"&gt;Apache Maven&lt;/a&gt; for building and deploying my JS RIA's. I've really come to appreciate Maven in the Java space and it is just waiting for someone (may be even me!) to extend it for JS development (I'm familiar with &lt;a href="http://mojo.codehaus.org/javascript-maven-tools/"&gt;JS Maven Tools&lt;/a&gt; but I understand that this project hasn't had activity for a long time). The pressures of family life and my daily job curtails the development of developer tools.&lt;/p&gt;&lt;p&gt;I shall pursue the use of SproutCore for my next RIA. So far I've just used HTML/CSS/JS and jQuery having implemented MVC in the raw. However when it comes to developing a website with perhaps a few dynamic requirements, may be I'll stay with trusty old JSP/&lt;a href="http://struts.apache.org/2.x/index.html"&gt;Struts&lt;/a&gt; that communicates with my logic layer. When it comes to mobile and desktop, I will continue to do as the Romans do and develop native applications that communicate with my logic layer.&lt;/p&gt;&lt;h1&gt;The logic layer&lt;/h1&gt;&lt;p&gt;I've used &lt;a href="http://camel.apache.org/"&gt;Apache Camel&lt;/a&gt; on several projects now and just love it. What I end up with is a Java based application that can be managed as a service typically deployed to some brand of Unix. I've been using VMware's &lt;a href="http://www.hyperic.com/"&gt;Hyperic&lt;/a&gt; to monitor the applications and given JMX I get some very deep monitoring capabilities.&lt;/p&gt;&lt;p&gt;I just love the &lt;a href="http://www.springsource.org/"&gt;Spring&lt;/a&gt; IoC framework and associated toolkits; particularly Spring JPA DAOs and Spring Test.&lt;/p&gt;&lt;p&gt;My applications tend to consist to lots of components that can exist independently of each other, and each with minimal dependencies on other frameworks and toolkits. For example, my application services containing the important business logic tend to be written as Java beans and have no or very little dependence on external libraries.&lt;/p&gt;&lt;p&gt;I lean towards creating RESTful services and look to leverage &lt;a href="http://cxf.apache.org/"&gt;Apache CXF&lt;/a&gt; in this regard. I'm not yet using a toolkit to scaffold some of my RESTful DAO functionality but will at some point. I'm also a big fan of JSON as a payload format but XML's schema definitions have an important place in my heart. &lt;a href="http://json-schema.org/"&gt;JSON with schemas&lt;/a&gt; would be a killer and I've just got to get into this.&lt;/p&gt;&lt;p&gt;Messaging is key and &lt;a href="http://json-schema.org/"&gt;Active/MQ&lt;/a&gt; has been a great performer. I'm really looking forward to v.5.4 and its support of HTML 5 web sockets. This will allow messaging to be utilised by the JS RIA and I find that prospect quite exciting.&lt;/p&gt;&lt;p&gt;&lt;a href="http://maven.apache.org/"&gt;Apache Maven&lt;/a&gt; plays a huge role in developing and deploying my logic layer applications.&lt;/p&gt;&lt;h1&gt;The data layer&lt;/h1&gt;&lt;p&gt;I've been very happy with &lt;a href="http://www.postgresql.org/"&gt;Postgres&lt;/a&gt; as a database and look forward to its forthcoming redundancy features. I'm also curious about &lt;a href="http://en.wikipedia.org/wiki/BigTable"&gt;Big table&lt;/a&gt; style approaches and &lt;a href="http://en.wikipedia.org/wiki/Document-oriented_database"&gt;Document Oriented Databases&lt;/a&gt;. I'm not quite sure why SQL should continue to play an application development standpoint (reporting, data mining etc. yes, but perhaps not within the application itself). &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORMs&lt;/a&gt; have pushed me to the "&lt;a href="http://en.wikipedia.org/wiki/NoSQL"&gt;NoSQL&lt;/a&gt;" conclusion and I like not having to deal with queries as much.&lt;/p&gt;&lt;h1&gt;Summary&lt;/h1&gt;&lt;p&gt;Multi-tier works for me. RIA appears to be the way of the future for web applications as distinct from web documents/pages. If you've not seen Apache Camel check it out. Postgres is great but I'm curious about Document Oriented Databases.&lt;/p&gt;&lt;p&gt;Please share your thoughts.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-6732846517788622923?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/6732846517788622923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=6732846517788622923' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6732846517788622923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6732846517788622923'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/07/application-development-feelings-2010.html' title='Application development feelings 2010'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-2589661237635500760</id><published>2010-07-30T08:10:00.001+10:00</published><updated>2010-07-30T08:12:43.738+10:00</updated><title type='text'>Development using Salesforce</title><content type='html'>&lt;p&gt;I'm presently on a short contract developing using the Salesforce platform.&lt;/p&gt;&lt;p&gt;I've been using Salesforce for over 2 months now and I'm afraid to conclude that it doesn't make it as a viable platform for cloud application deployment. The reason for this is quite simple: it forces you to develop in the cloud as distinct from deploying to the cloud.&lt;/p&gt;&lt;p&gt;Salesforce thought that it would be great to re-invent the wheel, introduce a new language (Apex) and introduce the associated tooling. From a developer perspective this means that all of your regular tooling such as version control, continuos integration, deployment management, dependency management... I could go on... simply isn't there. Let me re-state a bit of that: no version control!&lt;/p&gt;&lt;p&gt;Developing on the Salesforce platform also means that you're dealing with 300ms (ish) round trips for every resource in their web development screens. This is because the platform is hosted in the US and the speed of light being what it is. A developer can quite commonly be waiting for several seconds while the development web app is doing its thing; reminds of my COBOL days 25 years ago when we had to submit stuff to a shared compiler resource and wait.&lt;/p&gt;&lt;p&gt;I'm quite turned on by the idea of deploying to the cloud and I think that VMforce and Google App Engine have chosen the right approach; they of course allow you to develop locally and then deploy to the cloud. Full scale application development in the cloud though is another thing and frankly Salesforce have got it wrong.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-2589661237635500760?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/2589661237635500760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=2589661237635500760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2589661237635500760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2589661237635500760'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/07/development-using-salesforce.html' title='Development using Salesforce'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-2118223748485368475</id><published>2010-06-04T09:31:00.001+10:00</published><updated>2010-06-04T09:32:12.506+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cobertura'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><category scheme='http://www.blogger.com/atom/ns#' term='code coverage'/><title type='text'>Invoking Maven and having it ignore your local settings</title><content type='html'>&lt;p&gt;I recently found myself working remotely from my network and needed to perform a build using Maven. My ~/.m2/settings.xml file is configured with information about my network's Nexus repository and a few other things. I therefore needed to find a way to tell Maven to ignore my regular settings; preferably without mutating my settings.xml file. In particular I just wanted to have Maven pull out a plugin from the Central repo.&lt;/p&gt;&lt;p&gt;The documentation on the Maven command doesn't mention how it can be invoked to ignore your settings.xml. However if you type the following then it will ignore it (in my case I wanted to download the wonderful &lt;a href="http://cobertura.sourceforge.net/"&gt;Cobertura&lt;/a&gt; plugin and produce a code coverage report) :&lt;/p&gt;&lt;pre&gt;mvn -s/dev/null cobertura:cobertura﻿&lt;/pre&gt;&lt;p&gt;All good.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-2118223748485368475?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/2118223748485368475/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=2118223748485368475' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2118223748485368475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2118223748485368475'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/06/invoking-maven-and-having-it-ignore.html' title='Invoking Maven and having it ignore your local settings'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-7983618067992370091</id><published>2010-05-12T11:35:00.001+10:00</published><updated>2010-05-12T11:35:25.774+10:00</updated><title type='text'>Flash on the iPhone</title><content type='html'>&lt;p&gt;Given Steve Job's most recent letter concerning &lt;a href="http://www.apple.com/hotnews/thoughts-on-flash/"&gt;Flash on the iPhone&lt;/a&gt;, I'd like to broaden the debate to native plugins on the iPhone. Mr. Jobs provides a host of reasons why Flash is not permitted and it reminds me largely of his previous argument around needing native applications on the iPhone (remember that they encouraged us to create nice web apps instead at first; then there was the whole multi-tasking debate..).&lt;/p&gt;&lt;p&gt;There reaches a point with web applications where HTML, Javascript and CSS just can't do what you need them to do. These technologies have come an awful long way and HTML5 in particular is great. I spend a lot of time with these technologies and they are top of mind when considering new applications.&lt;/p&gt;&lt;p&gt;Let's take a concrete example of when you do require a plugin: Google Earth. Google Earth exists as a web plugin as well as a standalone executable. There are times when you'd like to embed Google Earth in a web page given its 3D capabilities; that's why the plugin exists of course!&lt;/p&gt;&lt;p&gt;Another example is with our own web plugin; it is something similar to Google Earth and has advanced capabilities with regards to map projections. We rely on third party C++ libraries and we utilise OpenGL.&lt;/p&gt;&lt;p&gt;Actually I think when it comes to 3D and the use of, say, OpenGL, web technologies fall short. There is a &lt;a href="http://www.khronos.org/webgl/"&gt;Mozilla proposal to expose OpenGL ES to Javascript&lt;/a&gt;, and that's great, but ES doesn't provide full OpenGL capability. Believe me, there are times when you need full OpenGL capability.&lt;/p&gt;&lt;p&gt;If I thought about it I'm sure there are other applications with dependencies such that you need to go native with a web plugin; not often perhaps, but we need to leave the native plugin door open for these situations.&lt;/p&gt;&lt;p&gt;I think Mr. Jobs has his reasons for not supporting Flash, but that's a separate consideration to supporting native web plugins.&lt;/p&gt;&lt;p&gt;In the end, I think that Adobe and Apple will come to an agreement and Adobe will release a well written and performant Flash plugin. The rest of us will then be able to install and write plugins for the iPhone when they are required.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-7983618067992370091?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/7983618067992370091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=7983618067992370091' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7983618067992370091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7983618067992370091'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/05/flash-on-iphone.html' title='Flash on the iPhone'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-3410880568268194525</id><published>2010-04-16T12:43:00.002+10:00</published><updated>2010-06-04T09:32:59.311+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='property editor'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='ioc'/><category scheme='http://www.blogger.com/atom/ns#' term='json'/><title type='text'>Spring PropertyEditor for JSON map and array properties</title><content type='html'>&lt;p&gt;I'm a big fan of Spring but found that it does not support map and list expressions in a property file to be substituted when using a PropertyPlaceholder. So I rolled my own PropertyEditor and can now express a map using JSON in my properties file e.g.:&lt;/p&gt;&lt;pre&gt;myMapProperty ={"en-AU": "SKY", "ms": "SKY"}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here's the property editor (depends on json-lib):&lt;/p&gt;&lt;pre&gt;package &amp;lt;packagename&amp;gt;;&lt;p&gt;import java.beans.PropertyEditorSupport; &lt;/p&gt;&lt;p&gt;import net.sf.json.JSON;&lt;br /&gt;import net.sf.json.JSONSerializer;&lt;/p&gt;&lt;p&gt;/**&lt;br /&gt; * Converts JSON expressions to Java arrays or maps and vice versa.&lt;br /&gt; *&lt;br /&gt; * @author huntc&lt;br /&gt; *&lt;br /&gt; */&lt;br /&gt;public class JSONPropertyEditor extends PropertyEditorSupport {&lt;/p&gt;&lt;p&gt;@Override&lt;br /&gt;  public String getAsText() {&lt;br /&gt;    Object object = getValue();&lt;br /&gt;    JSON jsonObject = JSONSerializer.toJSON(object);&lt;br /&gt;    return jsonObject.toString();&lt;br /&gt;  }&lt;/p&gt;&lt;p&gt;@Override&lt;br /&gt;  public void setAsText(String text) {&lt;br /&gt;    JSON json = JSONSerializer.toJSON(text);&lt;br /&gt;    setValue(json);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;and here's what you must declare in your spring configuration xml:&lt;/p&gt;&lt;pre&gt;&amp;lt;bean id="customEditorConfigurer"&lt;br /&gt;  class="org.springframework.beans.factory.config.CustomEditorConfigurer"&amp;gt;&lt;br /&gt;  &amp;lt;property name="customEditors"&amp;gt;&lt;br /&gt;    &amp;lt;map&amp;gt;&lt;br /&gt;      &amp;lt;entry key="java.util.Map"&amp;gt;&lt;br /&gt;        &amp;lt;bean class="&amp;lt;packagename&amp;gt;.JSONPropertyEditor" /&amp;gt;&lt;br /&gt;      &amp;lt;/entry&amp;gt;&lt;br /&gt;    &amp;lt;/map&amp;gt;&lt;br /&gt;  &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The above indicates that for any required substitution of a map, use my property editor e.g.:&lt;/p&gt;&lt;pre&gt;&amp;lt;bean id="someBeanWithAMapProperty"&lt;br /&gt;  class="someClass"&amp;gt;&lt;br /&gt;  &amp;lt;property name="someMapProperty"&lt;br /&gt;    value="${myMapProperty}" /&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-3410880568268194525?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/3410880568268194525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=3410880568268194525' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3410880568268194525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3410880568268194525'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/04/spring-propertyeditor-for-json-map-and.html' title='Spring PropertyEditor for JSON map and array properties'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-4746086857487763028</id><published>2010-04-13T11:40:00.003+10:00</published><updated>2010-04-13T11:52:16.928+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone 4.0 multithreading multitasking threading'/><title type='text'>iPhone and multitasking</title><content type='html'>So here we are. Apple appears to be finally opening up the threading APIs to developers on the iPhone.&lt;br /&gt;&lt;br /&gt;I've had numerous conversations with colleagues since the iPhone came out and they've been all sorts of reactions as to why there's no multithreading. Actually, now that I've just typed multithreading let's get this straight. Multitasking relates to the human experience of doing multiple things at the same time; it is a use-case; it is something that I've been told (by my wife) that men can't do and women can (!).&lt;br /&gt;&lt;br /&gt;Multithreading is the ability for an OS to cooperatively or pre-emptively (generally the latter) slice processor time between different paths of execution within and outside of a number of processes (generally applications).&lt;br /&gt;&lt;br /&gt;The iPhone has supported multitasking and multithreading forever. The difference now is that Apple appears to have opened up the multithreading API to non-Apple developers. I've not seen the details on this, perhaps they've constrained the thread APIs in some interesting way with the goal of limiting battery usage, but it is a very good (and necessary) thing that there will now be multithreading.&lt;br /&gt;&lt;br /&gt;One application that I'm really looking forward to using is Skype. Finally, we'll be able to receive Skype calls with the same experience of receiving regular mobile calls; so long as you're on a WiFi network of course. I think that this will be amazing as I'm never near my computer when someone wants to contact me via Skype. However, I always have my iPhone at hand of course. &lt;br /&gt;&lt;br /&gt;I can't wait for SIP supporting applications to come along for the iPhone either. The prospect of receiving my home phone calls when away from home via VOIP is fantastic.&lt;br /&gt;&lt;br /&gt;Oh and one thing I'd like to joyfully throw back at the multithreading doubters: get over it. Yes, multithreaded programming is harder but its just the way the world is. Multiple things happen at the same time. Embrace it.&lt;br /&gt;&lt;br /&gt;Well done Apple. I look forward to iPhone 4.0.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-4746086857487763028?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/4746086857487763028/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=4746086857487763028' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4746086857487763028'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4746086857487763028'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/04/iphone-and-multitasking.html' title='iPhone and multitasking'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-8643736937661606401</id><published>2010-04-12T14:31:00.007+10:00</published><updated>2010-07-11T14:17:34.879+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JQL parameter list in instanceof'/><title type='text'>The pitfall of setting a list of parameters on a JQL query</title><content type='html'>&lt;p&gt;I recently had a need to provide a collection as a parameter to a JQL IN expression. This is what I did:&lt;/p&gt;&lt;pre&gt;List results = getJpaTemplate()&lt;br /&gt;  .find(&lt;br /&gt;    "from AbstractEvent e "&lt;br /&gt;    + "where "&lt;br /&gt;    + "(e.subscription, e.eventTime) in "&lt;br /&gt;    + "(select e.subscription, max(e.eventTime) "&lt;br /&gt;    + "from e "&lt;br /&gt;    + "where "&lt;br /&gt;    + "e.class in "&lt;br /&gt;    + "(SentSMSFlightSubscribed,"&lt;br /&gt;    + " ReceivedSMSFlightUnsubscribe) and "&lt;br /&gt;    + "e.subscription.flightNo in (?) and "&lt;br /&gt;    + "e.subscription.scheduled = ? "&lt;br /&gt;    + "group by e.subscription)",&lt;br /&gt;    renderedFlight.getFlights(),&lt;br /&gt;    renderedFlight.getScheduled());&lt;/pre&gt;&lt;p&gt;The problem with the query is that you get a class cast exception when an attempting to substitute the collection (renderedFlight.getFlights) .&lt;/p&gt;&lt;p&gt;To fix this you simply need to be explicit about the parameters:&lt;/p&gt;&lt;pre&gt;    + "e.subscription.flightNo in (?1) and "&lt;br /&gt;    + "e.subscription.scheduled = ?2 "&lt;/pre&gt;&lt;p&gt;Problem solved.&lt;/p&gt;&lt;p&gt;Updated: Sunday 11 July 2010: Even using position parameters doesn't always work. While it works in the above example it didn't work for me when using a parameter of a non-primitive type; at least I think that was the issue. So in a nutshell, if the above doesn't work for you then just use findByNamedParams instead.&lt;/p&gt;&lt;p&gt;You may also note this beauty of a line:&lt;/p&gt;&lt;pre&gt;e.class in (&lt;br /&gt; SentSMSFlightSubscribed,&lt;br /&gt; ReceivedSMSFlightUnsubscribe)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;That is how you perform an "instanceof" style of operation in JQL. Nice.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-8643736937661606401?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/8643736937661606401/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=8643736937661606401' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8643736937661606401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8643736937661606401'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/04/pitfall-of-setting-list-of-parameters.html' title='The pitfall of setting a list of parameters on a JQL query'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-7893175771450148987</id><published>2010-02-28T00:51:00.004+11:00</published><updated>2010-02-28T00:59:17.944+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java swing javascript canvas html5'/><title type='text'>Java's Swing framework for Javascript and Canvas</title><content type='html'>It is 0051 on Sunday morning and I just had a wild thought...&lt;br /&gt;&lt;br /&gt;I've been developing applications in Javascript using jQuery and taking an interest in Sproutcore. I love jQuery but most definitely subscribe to Sproutcore's architecture where it makes a very strong statement about web applications being distinct from web documents (there is a place for both).&lt;br /&gt;&lt;br /&gt;...and then it occurred to me... why not try and implement Java's Swing framework in Javascript and use the Canvas element almost exclusively for web applications? Do away as much as possible with CSS and HTML - I don't think they're great for web applications anyhow...&lt;br /&gt;&lt;br /&gt;I don't doubt that it'd be a lot of work implementing Swing in Javascript, but there's an awful lot of design to be leveraged there.&lt;br /&gt;&lt;br /&gt;I think I'll sleep on it...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-7893175771450148987?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/7893175771450148987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=7893175771450148987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7893175771450148987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7893175771450148987'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/02/javas-swing-framework-for-javascript.html' title='Java&apos;s Swing framework for Javascript and Canvas'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-3882606552224896793</id><published>2010-02-17T21:08:00.005+11:00</published><updated>2010-02-17T21:43:04.364+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails rails leaky abstraction GORM equals hashcode hibernate'/><title type='text'>Does Grails lower the barriers of entry to programming?</title><content type='html'>&lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt; is the &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; equivalent of &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails &lt;/a&gt;and I've been working with Grails for the past couple of months.&lt;br /&gt;&lt;br /&gt;I'm a big fan of programming by convention and adopted &lt;a href="http://maven.apache.org/"&gt;Apache Maven&lt;/a&gt; many moons ago for just this reason. Grails also promotes programming by convention and by and large its quite reasonable for building server hosted web applications.&lt;br /&gt;&lt;br /&gt;However one thing in particular has been bothering me. It seems that there is a view that Grails saves you the trouble of worrying about what goes on underneath it. This attitude is similar to one where using ORMs such as Hibernate save you the need to understand databases. &lt;br /&gt;&lt;br /&gt;These attitudes are fraught with dangers as has been beautifully pointed out by Joel Spolsky in his &lt;a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html"&gt;Leaky Abstractions&lt;/a&gt; article.&lt;br /&gt;&lt;br /&gt;I would agree that Grails can assist in increasing productivity but not at the expense of knowing what goes on under the hood. As Joel puts it, "... the abstractions save us time working, but they don't save us time learning".&lt;br /&gt;&lt;br /&gt;Today I came across a Grails situation where I compared a newly instantiated domain object with one obtained through GORM. From my perspective both objects were equivalent as they had the same identifiers. I had wrongly assumed though that GORM had adopted the Hibernate convention of providing hashCode() and equals() on a natural key. Because Grails does all this magic for me, I had just assumed that this would be done. Well, it doesn't; and that's fair enough; how would GORM know what the natural key is? (declaring the natural key could be a nice feature for GORM). The point is that I could quickly find the problem because I'm familiar with Java/JPA/Hibernate and know that hashCode() and equals() should be provided for natural keys.&lt;br /&gt;&lt;br /&gt;My advice is to stay curious. Don't be content with copy and pasting a bit of code you found using Google, seeing it work but not understanding it. This situation will bite you on the bum when your product goes live and you get a problem that you can't diagnose because you don't really understand what the code is doing.&lt;br /&gt;&lt;br /&gt;Programming computers is a complex business and that's a fact that should not be avoided. Embrace the complexity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-3882606552224896793?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/3882606552224896793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=3882606552224896793' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3882606552224896793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3882606552224896793'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/02/does-grails-lower-barriers-of-entry-to.html' title='Does Grails lower the barriers of entry to programming?'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-8634316834204322678</id><published>2010-02-13T22:18:00.004+11:00</published><updated>2010-02-13T22:42:20.784+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iCal Outlook Java Javamail processing mime types email iCal4j'/><title type='text'>Processing Javamail emails for specific mime types</title><content type='html'>I recently had to write some software that received an email and processed it for iCal events. I wanted my program to be tolerant of receiving the iCal events within the body or as a attachment. Furthermore if the attachment was a mail message then I wanted to look inside that email for the event and so on...&lt;br /&gt;&lt;br /&gt;When I thought about the problem initially I thought that processing just the attachments of an email would be sufficient. That's not the case given Microsoft Outlook though. I quickly learnt that Outlook sends its iCal events within the body of an email and not as an attachment.&lt;br /&gt;&lt;br /&gt;I ended up with the following bit of Javamail/iCal4j/Java code that should generally be useful for processing mail messages. In my case I'm looking for a text/calendar object but it could be anything of course. The addCalendarDataToCalendars function can be called recursively and adds any calendar objects it finds to the collection passed in. Enjoy.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Process a data handler's content looking for a &lt;br /&gt;   * calendar object.&lt;br /&gt;   * &lt;br /&gt;   * @param calendars&lt;br /&gt;   *            the collection of calendars that we &lt;br /&gt;   *            must add any found calendar to.&lt;br /&gt;   * @param dataHandler&lt;br /&gt;   *            the data handler to use.&lt;br /&gt;   */&lt;br /&gt;  private void addCalendarDataToCalendars(&lt;br /&gt;      Collection&lt;Calendar&gt; calendars,&lt;br /&gt;      DataHandler dataHandler) {&lt;br /&gt;    MimeType mimeType;&lt;br /&gt;    try {&lt;br /&gt;      mimeType = &lt;br /&gt;        new MimeType(dataHandler.getContentType());&lt;br /&gt;&lt;br /&gt;      if (mimeType.getBaseType()&lt;br /&gt;            .equals("text/calendar")) {&lt;br /&gt;        // Calendar data is what we're ultimately &lt;br /&gt;        // searching for.&lt;br /&gt;        CalendarBuilder builder = &lt;br /&gt;          new CalendarBuilder();&lt;br /&gt;        Calendar calendar = builder.build(&lt;br /&gt;          dataHandler.getInputStream());&lt;br /&gt;        calendars.add(calendar);&lt;br /&gt;&lt;br /&gt;      } else if (mimeType.getBaseType()&lt;br /&gt;                   .equals("message/rfc822")) {&lt;br /&gt;        // Found an object representing an email &lt;br /&gt;        // address in its entirety.&lt;br /&gt;        Message mailMessage = (Message) dataHandler&lt;br /&gt;            .getContent();&lt;br /&gt;        addCalendarDataToCalendars(calendars, &lt;br /&gt;          mailMessage.getDataHandler());&lt;br /&gt;&lt;br /&gt;      } else if (mimeType.getBaseType()&lt;br /&gt;                   .startsWith("multipart/")) {&lt;br /&gt;        // Found a bunch of attachments so &lt;br /&gt;        // process them each.&lt;br /&gt;        Multipart multipart = &lt;br /&gt;          (Multipart) dataHandler.getContent();&lt;br /&gt;        for (int i = 0, n = multipart.getCount(); &lt;br /&gt;             i &lt; n; ++i) {&lt;br /&gt;          Part part = multipart.getBodyPart(i);&lt;br /&gt;&lt;br /&gt;          String disposition = &lt;br /&gt;            part.getDisposition();&lt;br /&gt;&lt;br /&gt;          if ((disposition != null)&lt;br /&gt;             &amp;&amp; ((disposition.equals(Part.ATTACHMENT) &lt;br /&gt;             || (disposition.equals(Part.INLINE))))) {&lt;br /&gt;            addCalendarDataToCalendars(calendars, &lt;br /&gt;              part.getDataHandler());&lt;br /&gt;&lt;br /&gt;          } else if (disposition == null) {&lt;br /&gt;            MimeBodyPart mimeBodyPart = &lt;br /&gt;              (MimeBodyPart) part;&lt;br /&gt;            addCalendarDataToCalendars(calendars, &lt;br /&gt;              mimeBodyPart.getDataHandler());&lt;br /&gt;&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;    } catch (MimeTypeParseException e) {&lt;br /&gt;      logger&lt;br /&gt;          .warn("Ignoring attachment - could not " +&lt;br /&gt;                "parse the mime type of: "&lt;br /&gt;              + dataHandler.getContentType()&lt;br /&gt;              + " - " + e);&lt;br /&gt;    } catch (IOException e) {&lt;br /&gt;      logger.error(e);&lt;br /&gt;    } catch (ParserException e) {&lt;br /&gt;      logger&lt;br /&gt;          .warn("Ignoring attachment - could not " +&lt;br /&gt;                "interpret the calendar object: "&lt;br /&gt;              + dataHandler.getName() + " - " + e);&lt;br /&gt;    } catch (MessagingException e) {&lt;br /&gt;      logger&lt;br /&gt;          .warn("Ignoring attachment - could not " +&lt;br /&gt;              "decode the calendar object: "&lt;br /&gt;              + MimeUtility.getEncoding(dataHandler) &lt;br /&gt;              + " - " + e);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-8634316834204322678?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/8634316834204322678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=8634316834204322678' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8634316834204322678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8634316834204322678'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2010/02/processing-javamail-emails-for-specific.html' title='Processing Javamail emails for specific mime types'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-5879350653195586966</id><published>2009-12-28T12:37:00.003+11:00</published><updated>2009-12-28T12:41:05.693+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java eclipse performance maximum memory tabs slow'/><title type='text'>Eclipse and friends are memory hungry</title><content type='html'>I've been using Eclipse Galileo for some time now and have quite a few favourite (and necessary!) plugins installed. These included m2eclipse, subeclipse, findbugs, checkstyle and many more.&lt;br /&gt;&lt;br /&gt;I had noticed though that things started to slow down. Even clicking between tabs was slow (started out ok after launching and then got worse over time).&lt;br /&gt;&lt;br /&gt;This smelled like a memory performance issue so I re-configured Eclipse to have a maximum memory size of 2GB and all now appears well. 2GB may have been an over-reaction - your mileage might vary, but for me it seems to have done the trick.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-5879350653195586966?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/5879350653195586966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=5879350653195586966' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5879350653195586966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5879350653195586966'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/12/eclipse-and-friends-are-memory-hungry.html' title='Eclipse and friends are memory hungry'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-8770696056222839844</id><published>2009-12-10T11:01:00.008+11:00</published><updated>2009-12-10T11:40:47.158+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Google Chrome Earth NPAPI OpenGL'/><title type='text'>Chrome on Mac - No Google Earth plugin though</title><content type='html'>I've just installed the &lt;a href="http://www.google.com/chrome/"&gt;Chrome beta &lt;/a&gt;on my Mac. Looks good overall.&lt;br /&gt;&lt;br /&gt;However the first thing I did ('cause its close to what I'm involved in) was try out the &lt;a href="http://code.google.com/apis/earth/"&gt;Google Earth Plugin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;No dice:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__zfCVFcU_Ac/SyA8OyMKRmI/AAAAAAAAACY/6v7H3dNooTk/s1600-h/Screen+shot+2009-12-10+at+11.00.12+AM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 342px;" src="http://4.bp.blogspot.com/__zfCVFcU_Ac/SyA8OyMKRmI/AAAAAAAAACY/6v7H3dNooTk/s400/Screen+shot+2009-12-10+at+11.00.12+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5413392976787949154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So perhaps the same constraints holding back the plugin under Safari 4 are holding up it working under Chrome also; perhaps it is the out of process plugin architecture, and/or the new requirement to use Core Animation to render OpenGL...&lt;br /&gt;&lt;br /&gt;Actually I've noticed that Chrome doesn't presently support the Core Animation for OpenGL NPAPI plugins (my CA NPAPI plugin isn't able to instantiate - most likely due to the browser stating that CA/Cocoa is unsupported due to the graceful failure).&lt;br /&gt;&lt;br /&gt;In searching for some technical insight I noticed that Google provide &lt;a href="http://www.google.com/googlebooks/chrome"&gt;a great article&lt;/a&gt; on the motivation behind Chrome.&lt;br /&gt;&lt;br /&gt;First impressions then are that Chrome looks interesting but it isn't quite there for me yet given my specialised NPAPI requirements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-8770696056222839844?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/8770696056222839844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=8770696056222839844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8770696056222839844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8770696056222839844'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/12/chrome-on-mac-no-google-earth-plugin.html' title='Chrome on Mac - No Google Earth plugin though'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__zfCVFcU_Ac/SyA8OyMKRmI/AAAAAAAAACY/6v7H3dNooTk/s72-c/Screen+shot+2009-12-10+at+11.00.12+AM.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-6692631994426812667</id><published>2009-12-04T16:11:00.005+11:00</published><updated>2009-12-04T16:24:54.966+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='macports port mac os x c c++ /opt package management'/><title type='text'>MacPorts - my new best friend</title><content type='html'>Perhaps it is just that I'm getting older, but I've resisted using package managers on Linux and Mac OS X for some time. I dunno, I guess I preferred to download the source and build it myself. What a sucker I am for punishment!&lt;br /&gt;&lt;br /&gt;I think that I had a similar resistance to Apache Maven originally - I just didn't want the learning curve of a new tool.&lt;br /&gt;&lt;br /&gt;I'd got to the point with a C++ project that I was fed up managing, building and sorting out the dependencies of various C/C++ based libraries. The catalyst for me was when I started using &lt;a href="http://www.cairographics.org/"&gt;Cairo&lt;/a&gt;, a 2D vector and imaging library (which is great!). Cairo had many dependencies and the project recommended a number of package managers for my OS X build environment.&lt;br /&gt;&lt;br /&gt;I ended up with &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt; and haven't looked back. Managing those dependencies just got a whole lot easier. MacPorts was apparently started by a group of Apple engineers and it grew from there. At the time of writing there are now over 6,000 packages available through MacPorts.&lt;br /&gt;&lt;br /&gt;MacPorts likes to put everything in /opt by default. For some bizarre reason I was against using /opt as my root folder for all MacPorts derived packages - talk about resisting change for no good reason! However I got over that and must take a leaf out here and try to resist such time consuming temptations. Who really cares where MacPorts puts stuff so long as at the end of the day your dependencies are being managed and your applications build?&lt;br /&gt;&lt;br /&gt;The only thing I found myself changing with the default configuration was the /opt/local/etc/macports/variants.conf file. I wanted +universal as a default. My projects tend to build both 32 bit and 64 bit targets and so I needed MacPorts to do this by default (I kept forgetting to specify the variant on the command line).&lt;br /&gt;&lt;br /&gt;All good. MacPorts is great and is another tool that helps me focus on the problem at hand.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-6692631994426812667?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/6692631994426812667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=6692631994426812667' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6692631994426812667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6692631994426812667'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/12/macports-my-new-best-friend.html' title='MacPorts - my new best friend'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-5903461639819705871</id><published>2009-11-26T11:58:00.004+11:00</published><updated>2009-11-26T12:07:02.361+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ical4j camel java spring dao apache'/><title type='text'>Write less code</title><content type='html'>I think that old adage of "Sorry I wrote you such a long letter, if I had more time I'd write you a shorter one" certainly applies to software development as well. If you spend a great deal of time learning how to write less code by using more off-the-shelf toolkits and frameworks you will write less code in the end. Sounds obvious, but I still see developers re-inventing the wheel far too often.&lt;br /&gt;&lt;br /&gt;The following code requires a steep learning curve around Java, Apache projects, iCal4j (a great calendaring toolkit for iCalendar) Spring, Spring DAO and Maven; and probably many more things. Look how straightforward the expression is though:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from(calendarEventEmailInboundEndpoint).to(&lt;br /&gt;  "bean:calendarAttachmentTranslator").to(&lt;br /&gt;  "bean:calendarEventTranslator").to(&lt;br /&gt;  "bean:calendarEventDAO?method=save");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The above Java code shows a Camel route that reads emails from a pop3 or imap inbox (depending on how calendarEventEmailInboundEndpoint is configured), extracts iCalendar attachments from one or more emails, translates the iCal4j representation into a model form for persistence, and finally persists the calendar event(s) in a database.&lt;br /&gt;&lt;br /&gt;Pretty sophisticated stuff for 4 lines of code. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-5903461639819705871?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/5903461639819705871/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=5903461639819705871' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5903461639819705871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5903461639819705871'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/11/write-less-code.html' title='Write less code'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-345474777781426625</id><published>2009-10-18T20:16:00.008+11:00</published><updated>2009-10-18T21:05:26.918+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven release source deploy assembly plugin application'/><title type='text'>Maven Release Plugin - My new friend</title><content type='html'>One tool that slipped my radar until only this week was the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/"&gt;Maven Release Plugin.&lt;/a&gt; If you are a Maven user and you release what you produce with it (I would hope so!) then you should take a look at this plugin.&lt;br /&gt;&lt;p&gt;My applications tend to be containers for the many pre-fabricated components of other projects I have. For instance I have 19 projects in my Eclipse workspace where 3 of them are the containers - if you like, the applications themselves.&lt;br /&gt;&lt;p&gt;Having lots of projects means that it can be easy to miss updating the version numbers for them when it comes time to perform a release; particularly missing that a project is being depended on as a snapshot.&lt;br /&gt;&lt;p&gt;In summary two big reasons to use the Maven Release Plugin are:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;it ensures that there are no snapshot dependencies; and&lt;/li&gt;&lt;br /&gt;&lt;li&gt;it updates your pom's version number automatically.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;In order to use the plugin I found myself having to add an scm element, an element for the plugin itself and a distributionManagement element.&lt;br /&gt;&lt;p&gt;The scm element let's the plugin know where to tag a release. Each time you make a release the plugin will create a tag for it in your source code repository. I was doing this as a manual task prior to the plugin so this feature is great.&lt;br /&gt;&lt;p&gt;I configured the plugin to ignore deploying my source code and javadoc to the repository. I actually had a problem with the maven source plugin given spaces contained in my path. I also didn't need to deploy the source code as I have it within my scm repository and I don't intend releasing the source to other parties.&lt;br /&gt;&lt;p&gt;Lastly you need to let the deploy plugin know how to deploy your project's artifacts in a maven repository i.e. the jar files in my case. The release plugin will invoke the deploy goal by default (actually it does a deploy and then "site deploy"). My projects generally rely upon the default goal with exception to those "application" projects. The application projects simply invoke the assembly plugin as I'm interested in producing a tar.gz file of the entire application. I therefore don't need to specify repository deployment details in my pom for these application projects as there is none.&lt;br /&gt;&lt;p&gt;All in all the maven release plugin saves me time and improves my release build quality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-345474777781426625?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/345474777781426625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=345474777781426625' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/345474777781426625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/345474777781426625'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/10/maven-release-plugin-my-new-friend.html' title='Maven Release Plugin - My new friend'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-6234996893159927275</id><published>2009-09-17T21:06:00.010+10:00</published><updated>2009-09-17T21:38:56.767+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='client server consumer publisher'/><title type='text'>Client/server or consumer/provider</title><content type='html'>Wow, I can't believe that it is now September and I've not posted anything since July. In a nutshell I landed a new airport customer (Subang Skypark - the Kuala Lumpur domestic airport) and so life has been terribly busy. As a result there's a lot of software development to be discussed since my last post. However I'll start with this little one as a result of an interesting conversation today.&lt;br /&gt;&lt;br /&gt;I designed an interface today that describes a set of remote services. As the interface is a consumer of those services I came up with the name XXXConsumer (I didn't really use XXX though). A friend of mine asked why not call it XXXClient? I had to really think about that.&lt;br /&gt;&lt;br /&gt;Two seconds later I blurted out that client and server had become an overloaded term and that the hip terms are now consumer and provider respectively. In other words I didn't really know why I preferred to use the word consumer and provider and put it down to the time I've spent with &lt;a href="http://en.wikipedia.org/wiki/Java_Message_Service"&gt;JMS&lt;/a&gt; and &lt;a href="http://camel.apache.org/"&gt;Apache Camel&lt;/a&gt;. These technologies often use the terms consumer and provider.&lt;br /&gt;&lt;br /&gt;Wikipedia offer a &lt;a href="http://en.wikipedia.org/wiki/Client_server"&gt;nice definition of client and server&lt;/a&gt; that effectively implies that these names are used for fairly course-grained objects such as applications and systems. My assertion having thought about this a little more is that consumers and providers are used in a finer-grained context. By finer-grained I refer to the software components found within my application.&lt;br /&gt;&lt;br /&gt;In addition client and server are certainly overloaded terms and typically imply that an application or system has just this one role. By contrast I often see that components are both consumers and providers of services. Perhaps this is another difference.&lt;br /&gt;&lt;br /&gt;Thank you for allowing me to client^H^H^H^H^H&lt;span style="font-weight:bold;"&gt;consume&lt;/span&gt; your time!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-6234996893159927275?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/6234996893159927275/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=6234996893159927275' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6234996893159927275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/6234996893159927275'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/09/clientserver-or-consumerpublisher.html' title='Client/server or consumer/provider'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-500487972793354257</id><published>2009-07-17T15:00:00.005+10:00</published><updated>2009-07-17T15:25:26.601+10:00</updated><title type='text'>Replacing jsvc for Java daemons</title><content type='html'>For some time I have been using the &lt;a href="http://commons.apache.org/daemon/"&gt;Apache Commons Daemon&lt;/a&gt; project to run and maintain my Java based services. jsvc did/does a reasonable job but I start to worry when a project has not been touched for a while.&lt;br /&gt;&lt;br /&gt;In addition I am in the midst of deploying a Java based service on Mac OS X and so I am in the world of &lt;a href="http://en.wikipedia.org/wiki/Launchd"&gt;launchd&lt;/a&gt;. I wanted a better way of controlling Java based services; particularly one that did not fork multiple processes given &lt;a href="http://www.devworld.apple.com/technotes/tn2005/tn2083.html"&gt;launchd's garbage collection&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The principal issue with a Java service running in the background is that you need to have it respond asynchronously to various singals; particularly SIGTERM which of course is issued when the OS is being shutdown. My service needs to shut down gracefully.&lt;br /&gt;&lt;br /&gt;Enter in a feature of Java 1.4.2 that I did not realise existed: &lt;a href="http://java.sun.com/j2se/1.4.2/docs/guide/lang/hook-design.html"&gt;Shutdown Hooks&lt;/a&gt;. In essence Shutdown Hooks provides your Java application an opportunity to respond to the application quitting.&lt;br /&gt;&lt;br /&gt;Followers of this blog know that I am an &lt;a href="http://camel.apache.org/"&gt;Apache Camel&lt;/a&gt; addict. You will not therefore be surprised to find that what follows is an example of how to start up and shutdown a Camel context using Java's Shutdown Hooks.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class EntryPoint {&lt;br /&gt;  static Logger logger = &lt;br /&gt;    Logger.getLogger(EntryPoint.class.getName());&lt;br /&gt;&lt;br /&gt;  static EntryPoint entryPoint;&lt;br /&gt;&lt;br /&gt;  Main main;&lt;br /&gt;&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    entryPoint = new EntryPoint();&lt;br /&gt;&lt;br /&gt;    Runtime.getRuntime()&lt;br /&gt;     .addShutdownHook(new Thread() {&lt;br /&gt;      public void run() {&lt;br /&gt;        try {&lt;br /&gt;          entryPoint.stop();&lt;br /&gt;        } catch (Exception e) {&lt;br /&gt;          logger.fatal(e.toString());&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;    try {&lt;br /&gt;      entryPoint.start();&lt;br /&gt;    } catch (Exception e) {&lt;br /&gt;      logger.fatal(e.toString());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void start() throws Exception {&lt;br /&gt;    logger.info("Starting up");&lt;br /&gt;&lt;br /&gt;    // Start up the context&lt;br /&gt;    main = new Main();&lt;br /&gt;    main.start();&lt;br /&gt;&lt;br /&gt;    logger.info("Started");&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void stop() throws Exception {&lt;br /&gt;    logger.info("Stopping");&lt;br /&gt;&lt;br /&gt;    // Shutdown the context&lt;br /&gt;    main.stop();&lt;br /&gt;&lt;br /&gt;    logger.info("Stopped");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-500487972793354257?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/500487972793354257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=500487972793354257' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/500487972793354257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/500487972793354257'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/07/replacing-jsvc-for-java-daemons.html' title='Replacing jsvc for Java daemons'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-9048282625869264394</id><published>2009-07-10T17:19:00.008+10:00</published><updated>2009-07-10T17:38:29.625+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='polling provider consumer apache camel processor http cache time'/><title type='text'>A Camel based XML Payload HTTP polling provider</title><content type='html'>Wow, what a mouthful of a title that is.&lt;br /&gt;&lt;br /&gt;The EAI &lt;a href="http://www.eaipatterns.com/PollingConsumer.html"&gt;Polling Consumer pattern&lt;/a&gt; is well documented. Polling consumers are particularly useful for HTTP clients such as AJAX applications. Their presence provides a means of implementing publish and subscribe.&lt;br /&gt;&lt;br /&gt;What I needed was some code to service my AJAX consumer; a Polling Provider so to speak.&lt;br /&gt;&lt;br /&gt;Given my immersion in &lt;a href="http://camel.apache.org/"&gt;Apache Camel&lt;/a&gt; I came up with a Polling Provider for XML objects provided by &lt;a href="http://xmlbeans.apache.org/"&gt;XMLBeans&lt;/a&gt;. The provider assumes that an HTTP endpoint is to be interacted with and thus sets the HTTP time headers appropriately.&lt;br /&gt;&lt;br /&gt;The Polling Provider holds the notion that the xml object is updated by one thread and then consumed by another. Furthermore the time the xml object was last updated is retained. This allows HTTP consumers to specify the HTTP ifModifiedSince header and block if the condition is not met.&lt;br /&gt;&lt;br /&gt;To update the provider (&lt;span style="font-style:italic;"&gt;fidsDocumentPollingProvider&lt;/span&gt; is an instance of it and &lt;span style="font-style:italic;"&gt;newFidsDocument&lt;/span&gt; is an XML document object):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;fidsDocumentPollingProvider.update(&lt;br /&gt;  newFidsDocument, new Date());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To retrieve the resource in a RESTful manner:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// Provide a RESTful service to retrieve FIDS data&lt;br /&gt;from("jetty:http://0.0.0.0:9000/FIDSService/FIDS")&lt;br /&gt;  .inOut("direct:getFIDS");&lt;br /&gt;&lt;br /&gt;// Provide a component to process FIDS requests&lt;br /&gt;from("direct:getFIDS")&lt;br /&gt;  .process(fidsDocumentPollingProvider);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is the code I came up with for the provider. I would be very interested to hear of better ways to do this given Apache Camel.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package com.classactionpl.camel.xmlbeans;&lt;br /&gt;&lt;br /&gt;import java.text.ParseException;&lt;br /&gt;import java.text.SimpleDateFormat;&lt;br /&gt;import java.util.Date;&lt;br /&gt;import java.util.Locale;&lt;br /&gt;import java.util.TimeZone;&lt;br /&gt;import java.util.concurrent.TimeUnit;&lt;br /&gt;import java.util.concurrent.locks.Condition;&lt;br /&gt;import java.util.concurrent.locks.Lock;&lt;br /&gt;import java.util.concurrent.locks.ReentrantLock;&lt;br /&gt;&lt;br /&gt;import org.apache.camel.Exchange;&lt;br /&gt;import org.apache.camel.Processor;&lt;br /&gt;import org.apache.camel.component.http.HttpProducer;&lt;br /&gt;import org.apache.xmlbeans.XmlObject;&lt;br /&gt;&lt;br /&gt;public class XMLHttpPayloadPollingProvider implements Processor {&lt;br /&gt;  XmlObject xmlObject;&lt;br /&gt;  Date lastModified;&lt;br /&gt;  Lock lock = new ReentrantLock();&lt;br /&gt;  Condition update = lock.newCondition();&lt;br /&gt;&lt;br /&gt;  public void update(XmlObject xmlObject, Date lastModified) {&lt;br /&gt;    lock.lock();&lt;br /&gt;    try {&lt;br /&gt;      this.xmlObject = xmlObject;&lt;br /&gt;      // We don't need the milliseconds and they can upset&lt;br /&gt;      // our comparisons given that they are not passed from the&lt;br /&gt;      // outside world.&lt;br /&gt;      this.lastModified = new Date((lastModified.getTime() / 1000) * 1000);&lt;br /&gt;      update.signal();&lt;br /&gt;    } finally {&lt;br /&gt;      lock.unlock();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void process(Exchange exchange) throws Exception {&lt;br /&gt;    lock.lock();&lt;br /&gt;    try {&lt;br /&gt;      boolean waitForUpdate = true;&lt;br /&gt;      Date ifModifiedSince = null;&lt;br /&gt;      if (lastModified != null) {&lt;br /&gt;        String ifModifiedSinceStr = exchange.getIn().getHeader(&lt;br /&gt;            "If-Modified-Since", String.class);&lt;br /&gt;        if (ifModifiedSinceStr != null) {&lt;br /&gt;          try {&lt;br /&gt;            SimpleDateFormat rfc822DateFormat = new SimpleDateFormat(&lt;br /&gt;                "EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z",&lt;br /&gt;                Locale.US);&lt;br /&gt;            ifModifiedSince = rfc822DateFormat&lt;br /&gt;                .parse(ifModifiedSinceStr);&lt;br /&gt;            waitForUpdate = (lastModified&lt;br /&gt;                .compareTo(ifModifiedSince) &lt;= 0);&lt;br /&gt;          } catch (ParseException e) {&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      boolean provideDateHeader;&lt;br /&gt;&lt;br /&gt;      if (waitForUpdate) {&lt;br /&gt;        update.await(90, TimeUnit.SECONDS);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (xmlObject != null) {&lt;br /&gt;        if (ifModifiedSince == null) {&lt;br /&gt;          ifModifiedSince = lastModified;&lt;br /&gt;        }&lt;br /&gt;        if (lastModified.compareTo(ifModifiedSince) &gt; 0) {&lt;br /&gt;          exchange.getOut().setBody(xmlObject.newInputStream());&lt;br /&gt;          exchange.getOut().setHeader("Content-Type", "text/xml");&lt;br /&gt;          provideDateHeader = true;&lt;br /&gt;        } else {&lt;br /&gt;          exchange.getOut().setHeader(&lt;br /&gt;              HttpProducer.HTTP_RESPONSE_CODE, 304);&lt;br /&gt;          provideDateHeader = true;&lt;br /&gt;        }&lt;br /&gt;      } else {&lt;br /&gt;        exchange.getOut().setHeader(HttpProducer.HTTP_RESPONSE_CODE,&lt;br /&gt;            404);&lt;br /&gt;        provideDateHeader = false;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (provideDateHeader &amp;&amp; lastModified != null) {&lt;br /&gt;        SimpleDateFormat rfc822DateFormat = new SimpleDateFormat(&lt;br /&gt;            "EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' GMT'", Locale.US);&lt;br /&gt;        rfc822DateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));&lt;br /&gt;        exchange.getOut().setHeader("Last-Modified",&lt;br /&gt;            rfc822DateFormat.format(lastModified));&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;    } finally {&lt;br /&gt;      lock.unlock();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-9048282625869264394?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/9048282625869264394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=9048282625869264394' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/9048282625869264394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/9048282625869264394'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/07/camel-based-xml-payload-http-polling.html' title='A Camel based XML Payload HTTP polling provider'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-8239063504889313596</id><published>2009-05-14T20:06:00.004+10:00</published><updated>2009-05-14T20:37:59.448+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Titan Class Web Store Share Google Earth jQuery Apache Camel'/><title type='text'>Titan Class goes into production</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__zfCVFcU_Ac/SgvuS3_gZ0I/AAAAAAAAACQ/hNM0VGUrOnk/s1600-h/tcv.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 271px;" src="http://1.bp.blogspot.com/__zfCVFcU_Ac/SgvuS3_gZ0I/AAAAAAAAACQ/hNM0VGUrOnk/s400/tcv.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5335620191585855298" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;She's finished, well as finished as they always are - which of course means that they are never finished.&lt;br /&gt;&lt;br /&gt;I am referring to my work over the past few months which is really just a concerted effort building on years of work. I'm now in a position to track vehicles, containers, you name it.&lt;br /&gt;&lt;br /&gt;From a software development perspective there are many things that I'm happy about. I've previously discussed jQuery which really has eased the AJAX programming. From a backend perspective I am using the amazingly functional, scalable and distributable Apache Camel (also discussed in other posts).&lt;br /&gt;&lt;br /&gt;One thing with the client-side that has really impressed me is the Google Earth plugin. I hope that you agree that it works very, very well (a link to the site is provided at the end of this post). Some of our potential customers will require their own maps along with their own projections and Google Earth will not handle that (Antarctica for example). However for many scenarios, Google Earth will be great.&lt;br /&gt;&lt;br /&gt;Incidentally where we will be required to use specialised maps with funky projections, I have written a Java applet using JavaFX. The applet supports many types of map projections and is based on the work of &lt;a href="http://trac.osgeo.org/proj/"&gt;Proj.4&lt;/a&gt; and friends.&lt;br /&gt;&lt;br /&gt;Here is a quick list of the OSS projects I utilised (and even contributed back to in some cases!):&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Apache ActiveMQ,&lt;br /&gt;Apache Camel&lt;br /&gt;Apache Directory Server&lt;br /&gt;Apache MINA&lt;br /&gt;Apache Tomcat&lt;br /&gt;Apache Web Server&lt;br /&gt;GEOS&lt;br /&gt;Eclipse&lt;br /&gt;Hibernate&lt;br /&gt;Hibernate Spatial&lt;br /&gt;jQuery&lt;br /&gt;JSON&lt;br /&gt;JTS&lt;br /&gt;JUnit&lt;br /&gt;Linux&lt;br /&gt;Log4J&lt;br /&gt;Maven&lt;br /&gt;PostgresQL&lt;br /&gt;PostGIS&lt;br /&gt;Proj.4&lt;br /&gt;Spring&lt;br /&gt;Subversion&lt;br /&gt;xmlbeans&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Go OSS!&lt;br /&gt;&lt;br /&gt;Feel free to &lt;a href="http://titanclass.blueglue.com.au/Google Ocellus Reference"&gt;visit the tracking site&lt;/a&gt; and play around with the demo data.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-8239063504889313596?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/8239063504889313596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=8239063504889313596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8239063504889313596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/8239063504889313596'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/05/titan-class-goes-into-production.html' title='Titan Class goes into production'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__zfCVFcU_Ac/SgvuS3_gZ0I/AAAAAAAAACQ/hNM0VGUrOnk/s72-c/tcv.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-1518775855147032645</id><published>2009-05-11T09:45:00.004+10:00</published><updated>2009-05-11T09:56:25.112+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guice spring ioc inversion of control jsr 299'/><title type='text'>Guice</title><content type='html'>I found &lt;a href="http://crazybob.org/2007/06/introduction-to-guice-video-redux.html"&gt;this video introduction on Guice &lt;/a&gt;very good. Guice is another &lt;a href="http://en.wikipedia.org/wiki/Inversion_of_Control"&gt;Inversion of Control&lt;/a&gt; (IoC) container, much like &lt;a href="http://static.springframework.org/spring/docs/2.0.x/reference/beans.html"&gt;Spring IoC&lt;/a&gt;, but with the advantage of coming later. What's particularly interesting about Guice is that it largely forms the basis of &lt;a href="http://jcp.org/en/jsr/detail?id=299"&gt;JSR-299&lt;/a&gt;'s IoC.&lt;br /&gt;&lt;br /&gt;I'm a big user of Spring IoC and frankly don't have a problem with it. However I can see that Guice could save me some wiring code and, therefore, potentially bugs (not that there are bugs in my code!). I might well consider using Guice for future projects. The outcome of JSR-299 will weigh in heavily on this decision though as I like my code to be as standards-compliant as possible.&lt;br /&gt;&lt;br /&gt;One thing that I am comfortable about with Spring though (vs Guice) is that my beans have no knowledge of being injectable; they simply are by being bean conforming. With Guice you must declare what is potentially injectable. I do like the loose coupling between my bean code and the IoC that Spring provides, yet I can see that Guice, by declaring what is injectable, can save some of the wiring code.&lt;br /&gt;&lt;br /&gt;I'll guess I'll just have to give Guice a whirl to find out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-1518775855147032645?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/1518775855147032645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=1518775855147032645' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/1518775855147032645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/1518775855147032645'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/05/guice.html' title='Guice'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-119517181535290952</id><published>2009-05-06T11:18:00.012+10:00</published><updated>2009-05-06T12:22:49.365+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery xml namespace javascript ajax date time utilities'/><title type='text'>jQuery</title><content type='html'>&lt;div&gt;I have just completed an &lt;a href="http://en.wikipedia.org/wiki/Ajax_(programming)"&gt;Ajax&lt;/a&gt; application that uses the &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; framework. jQuery's promise is to "write less, do more", which I suppose is the objective of most frameworks. Does jQuery deliver though? In a nutshell, yes.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Writing an Ajax application is hard; not because of network paradigms or Javascript, but because each browser brings with it some quirk. Catering for all of these browsers is simply time consuming so, by hard, I really mean time consuming. It is therefore hard to knock out an Ajax application quickly given the shear amount of cross-browser testing that has to be performed.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;jQuery does not eliminate cross-browser issues but it certainly minimises them. With my application, the only real short-fall I found with jQuery was its lack of support for dealing with XML documents (not XHTML). This was primarily due to the lack of XML namespace support and I think that this is an area that jQuery should focus on. However it is important to note that the real culprit for the lack of namespace support is Internet Explorer. In essence there is no support for namespaces with IE. I find this extremely difficult to understand... ok, IE 6 with no namespaces is understandable to a degree, but version 7, and worse even version 8 do not support XML namespaces. Microsoft virtually invented SOAP given their backing of it, yet their browsers can't parse SOAP documents accurately (you can ignore the namespaces, but then you ignore the value of namespaces of course).&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Here are some other things I found myself having to cater for explicitely...&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;big&gt;iframe shims&lt;/big&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://www.oratransplant.nl/2007/10/26/using-iframe-shim-to-partly-cover-a-java-applet/"&gt;iframes shims&lt;/a&gt; are provided by a jQuery plugin named &lt;a href="http://plugins.jquery.com/project/bgiframe"&gt;bgiframe&lt;/a&gt; and you can set up jQuery's dialog so that it uses an iframe. Unfortunately IE6 is not the only browser that requires iframes for the purposes of overlaying html objects on OS rendered content (buttons, applets, objects etc.). I therefore found myself having to roll my own. Here's a snippet of what needs to be done in the case of displaying a login dialog when some label is clicked:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var loginDialog = $("#loginDialog").dialog({&lt;br /&gt;autoOpen: false,&lt;br /&gt;close: function() {&lt;br /&gt;loginDialogIframeShim.css("visibility", "hidden");&lt;br /&gt;},&lt;br /&gt;...&lt;br /&gt;});&lt;br /&gt;var loginDialogIframeShim = $(document.createElement("iframe"));&lt;br /&gt;loginDialogIframeShim.attr("frameborder", "0");&lt;br /&gt;loginDialogIframeShim.attr("scrolling", "no");&lt;br /&gt;loginDialogIframeShim.attr("allowtransparency", "false");&lt;br /&gt;loginDialogIframeShim.css("position", "absolute");&lt;br /&gt;loginDialogIframeShim.css("visibility", "hidden");&lt;br /&gt;$("body").append(loginDialogIframeShim);&lt;br /&gt;&lt;br /&gt;var login = $("#login").click(function() {&lt;br /&gt;loginDialog.dialog('open');&lt;br /&gt;var loginDialogParent = loginDialog.parent();&lt;br /&gt;var offset = loginDialogParent.offset();&lt;br /&gt;loginDialogIframeShim.css("left", offset.left + "px");&lt;br /&gt;loginDialogIframeShim.css("top", offset.top + "px");&lt;br /&gt;loginDialogIframeShim.css("width", loginDialogParent.outerWidth() + "px");&lt;br /&gt;loginDialogIframeShim.css("height", loginDialogParent.outerHeight() + "px");&lt;br /&gt;loginDialogIframeShim.css("visibility", "visible");&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;The above works well for Windows FF and IE 7 and Mac OS FF and Safari. I haven't tested other browsers.&lt;br /&gt;&lt;br /&gt;&lt;big&gt;Datepicker ranges&lt;/big&gt;&lt;br /&gt;&lt;div&gt;It would be great to see the Datepicker (which is really great as is) enhanced to support a date range selection.&lt;/div&gt;&lt;br /&gt;&lt;big&gt;XmlHttpRequest&lt;/big&gt;&lt;br /&gt;&lt;div&gt;While jQuery does a lot to abstract away the peculiarities of browsers with XmlHttpRequest, I did find myself having to encode credentials for Safari. This is because Safari likes to send credentials as part of the URL initially (if that fails then it tries the conventional way using an authorisation header - I do not understand why).&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if($.browser.safari) {&lt;br /&gt; requestUsername = encodeURIComponent(requestUsername);&lt;br /&gt; requestPassword = encodeURIComponent(requestPassword);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;$.ajax({&lt;br /&gt; url: "...",&lt;br /&gt; dataType: "xml",&lt;br /&gt; username: requestUsername,&lt;br /&gt; password: requestPassword,&lt;br /&gt;   ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;big&gt;Date/time utilities&lt;/big&gt;&lt;br /&gt;&lt;div&gt;In general terms I found these lacking. Quite often with XML one has to convert from ISO8601 to a Javascript date and back. I needed to provide these functions:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function formatISO8601Time(time) {&lt;br /&gt;  var timeStr;&lt;br /&gt;  &lt;br /&gt;  var year = time.getUTCFullYear();&lt;br /&gt;  timeStr = "" + year;&lt;br /&gt;  timeStr += "-";&lt;br /&gt;  &lt;br /&gt;  var month = time.getUTCMonth() + 1;&lt;br /&gt;  if (month &lt; 10) {&lt;br /&gt;    month = "0" + month;&lt;br /&gt;  } else {&lt;br /&gt;    month = "" + month;&lt;br /&gt;  }&lt;br /&gt;  timeStr += month;&lt;br /&gt;  timeStr += "-";&lt;br /&gt;  &lt;br /&gt;  var day = time.getUTCDate();&lt;br /&gt;  if (day &lt; 10) {&lt;br /&gt;    day = "0" + day;&lt;br /&gt;  } else {&lt;br /&gt;    day = "" + day;&lt;br /&gt;  }&lt;br /&gt;  timeStr += day;&lt;br /&gt;  timeStr += "T";&lt;br /&gt;  &lt;br /&gt;  var hour = time.getUTCHours();&lt;br /&gt;  if (hour &lt; 10) {&lt;br /&gt;    hour = "0" + hour;&lt;br /&gt;  } else {&lt;br /&gt;    hour = "" + hour;&lt;br /&gt;  }&lt;br /&gt;  timeStr += hour;&lt;br /&gt;  timeStr += ":";&lt;br /&gt;  &lt;br /&gt;  var minute = time.getUTCMinutes();&lt;br /&gt;  if (minute &lt; 10) {&lt;br /&gt;    minute = "0" + minute;&lt;br /&gt;  } else {&lt;br /&gt;    minute = "" + minute;&lt;br /&gt;  }&lt;br /&gt;  timeStr += minute;&lt;br /&gt;  timeStr += ":";&lt;br /&gt;  &lt;br /&gt;  var second = time.getUTCSeconds();&lt;br /&gt;  if (second &lt; 10) {&lt;br /&gt;    second = "0" + second;&lt;br /&gt;  } else {&lt;br /&gt;    second = "" + second;&lt;br /&gt;  }&lt;br /&gt;  timeStr += second;&lt;br /&gt;  timeStr += "Z";&lt;br /&gt;  &lt;br /&gt;  return timeStr;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function parseISO8601Time(time) {&lt;br /&gt;  var date = new Date();&lt;br /&gt;  &lt;br /&gt;  var year = time.substr(0, 4);&lt;br /&gt;  var month = time.substr(5, 2);&lt;br /&gt;  var day = time.substr(8, 2);&lt;br /&gt;  var hour = time.substr(11, 2);&lt;br /&gt;  var minute = time.substr(14, 2);&lt;br /&gt;  var second = time.substr(17, 2);&lt;br /&gt;  &lt;br /&gt;  date.setUTCFullYear(year);&lt;br /&gt;  date.setUTCMonth(month - 1);&lt;br /&gt;  date.setUTCDate(day);&lt;br /&gt;  date.setUTCHours(hour);&lt;br /&gt;  date.setUTCMinutes(minute);&lt;br /&gt;  date.setUTCSeconds(second);&lt;br /&gt;  date.setUTCMilliseconds(999);&lt;br /&gt;  &lt;br /&gt;  return date;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function formatLocalHoursAndMinutes(time) {&lt;br /&gt;  var timeStr;&lt;br /&gt;  &lt;br /&gt;  var hour = time.getHours();&lt;br /&gt;  if (hour &lt; 10) {&lt;br /&gt;    hour = "0" + hour;&lt;br /&gt;  } else {&lt;br /&gt;    hour = "" + hour;&lt;br /&gt;  }&lt;br /&gt;  timeStr = hour;&lt;br /&gt;  &lt;br /&gt;  var minute = time.getMinutes();&lt;br /&gt;  if (minute &lt; 10) {&lt;br /&gt;    minute = "0" + minute;&lt;br /&gt;  } else {&lt;br /&gt;    minute = "" + minute;&lt;br /&gt;  }&lt;br /&gt;  timeStr += minute;&lt;br /&gt;  &lt;br /&gt;  timeStr += "h";&lt;br /&gt;&lt;br /&gt;  return timeStr;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;big&gt;XML Namespace utilities&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;As mentioned before there is very little support namespaces so here's what I had to roll:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function getElementsByTagNameNS(node, namespaceURI, localName) {&lt;br /&gt;    var nodeList;&lt;br /&gt;    &lt;br /&gt;    if (node.getElementsByTagNameNS != null) {&lt;br /&gt;      nodeList = node.getElementsByTagNameNS(namespaceURI, localName);&lt;br /&gt;    } else {&lt;br /&gt;        nodeList = node.getElementsByTagName(resolveNS(namespaceURI) + localName);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return nodeList;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function getAttributeNS(node, namespaceURI, localName) {&lt;br /&gt;    var attrVal;&lt;br /&gt;    &lt;br /&gt;    if (node.getAttributeNS != null) {&lt;br /&gt;      attrVal = node.getAttributeNS(namespaceURI, localName);&lt;br /&gt;    } else {&lt;br /&gt;        attrVal = node.getAttribute(resolveNS(namespaceURI) + localName);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return attrVal;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function isNode(node, namespaceURI, localName) {&lt;br /&gt;  var nodeMatched;&lt;br /&gt;  if (node.localName != null) {&lt;br /&gt;    nodeMatched = (node.namespaceURI == namespaceURI &amp;&amp; node.localName == localName);&lt;br /&gt;  } else {&lt;br /&gt;    nodeMatched = (node.nodeName == (resolveNS(namespaceURI) + localName));&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  return nodeMatched;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function resolveNS(namespaceURI) {&lt;br /&gt;  var namespacePrefix;&lt;br /&gt;  if (namespaceURI == "http://www.yoururigoeshere") {&lt;br /&gt;    namespacePrefix = "ns1:";&lt;br /&gt;  } else if (namespaceURI == "you are getting the idea now hopefully") {&lt;br /&gt;    namespacePrefix = "ns:";&lt;br /&gt;  }&lt;br /&gt;  return namespacePrefix;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;big&gt;Summary&lt;/big&gt;&lt;br /&gt;All in all though jQuery saved me a lot of code, particularly around manipulating and traversing my XHTML DOM. The long short of this was that my XHTML page is semantically correct containing absolutely no erroneous divs, style or class declarations i.e. no presentation considerations.&lt;br /&gt;&lt;br /&gt;My last Ajax application was a couple of years ago and I must say that using a framework like jQuery has certainly improved programming here. I think we are now seeing some maturity in the browsers and the Javascript framework.&lt;br /&gt;&lt;br /&gt;I look forward to continued use of jQuery.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-119517181535290952?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/119517181535290952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=119517181535290952' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/119517181535290952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/119517181535290952'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/05/jquery.html' title='jQuery'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-263740513905694751</id><published>2009-03-30T16:58:00.003+11:00</published><updated>2009-03-30T17:14:37.490+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate JPA annotations Java Persistance property field collection'/><title type='text'>Java Persistance with Hibernate - what I had to re-visit after reading the book</title><content type='html'>&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;I recently had a JPA related issue and decided that it was high time to purchase a good book on the subject; particularly as JPA/Hibernate tend to play a very important role of course.&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;I ended up discovering "Java Persistance with Hibernate" (Bauer, King). This book is a revision of "Hibernate in Action" and it certainly reads as a complete reference to all things ORM. What attracted me to this book in particular was its coverage of JPA. I prefer to use JPA over Hibernate interfaces so that my ORM implementation choice is left open as much as possible. Having said that Hibernate gives me no reason to move to another ORM.&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;I must have been using Hibernate/JPA for the past 18 months. When I started I recall wanting to skim over the ORM subject as much possible in order to get things done i.e. I did not think deeply about the implications of some of my decisions; or rather I misinterpreted the way things worked e.g. the 2nd level cache. To this end here is a list of things that I found myself re-visiting:&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;* property annotations instead of field annotations;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;* using the Collection interface instead of the Set interface;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;* cache annotations;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;* bi-directional one-to-many relationships;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;* immutable entities&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;Using property access can boost performance when performing operations on a collection (also as opposed to a set). For example if you want to add to the collection Hibernate does not have to load the existing collection from the database. If you use a Set then it does in order to guarantee Set semantics.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;Understanding the second level cache is very important and if you don't have time to learn it then disable it. It is also a good idea to understand whether you have immutable entities so that you can use the Hibernate @Entity(mutable=false) annotation and flag to the cache that the object is read only. This permits Hibernate a few optimisations including a minimisation on the number of update statements that require preparing at startup.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;I always wondered why my bi-directional relationships were generating a join table. It finally sunk in that the mappedBy attribute on an association describes the foreign key. No more join tables for bi-directional relationships.&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;There's no excuse; just buy the book if you're doing any ORM. Having said that even before I made these changes Hibernate was performing exceptionally well!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-263740513905694751?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/263740513905694751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=263740513905694751' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/263740513905694751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/263740513905694751'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/03/i-recently-had-jpa-related-issue-and.html' title='Java Persistance with Hibernate - what I had to re-visit after reading the book'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-2435442527048844873</id><published>2009-03-17T22:01:00.011+11:00</published><updated>2009-03-17T23:43:46.422+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jaas login modules mutual ssl authentication activemq ldap authorisation'/><title type='text'>Mutual SSL authentication and LDAP authorisation for ActiveMQ</title><content type='html'>I now have quite a lot of software infrastructure supporting the business of tracking things that move; particularly aircraft flights. The back-bone of all of this is ActiveMQ. ActiveMQ is an incredible messaging work-horse and easily handles 300 messages per second being received from a number of radar sensors.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have also re-developed my Titan Class Vision client application using &lt;a href="http://javafx.com/"&gt;JavaFX&lt;/a&gt; (the subject of another blog entry). The goal of this re-write was to be able to deploy Vision on a wider variety of platforms than I could do so previously. Before the JavaFX version Vision was a turn-key hardware/software combination written in Objective-C/C++ and ran on Mac OS X only.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With the advent of the new version I am able to deploy Vision across the internet. Given this there are suddenly many more potential candidates in terms of users and I had a security question to consider: how can I demonstrate to whoever is concerned that I have made every effort to ensure that this sensitive real-time flight data is not being mis-used by anyone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:180%;"&gt;Authentication&lt;/span&gt;&lt;/div&gt;&lt;div&gt;My requirement therefore became one centered around SSL. ActiveMQ permits connections to be established using SSL. Server only authentication is fairly straightforward and &lt;a href="http://activemq.apache.org/how-do-i-use-ssl.html"&gt;covered here&lt;/a&gt;. What I was after though was client certificate verification; otherwise known as &lt;a href="http://en.wikipedia.org/wiki/Mutual_authentication"&gt;mutual SSL authentication&lt;/a&gt;. In a nutshell, the server verifies the client's certificate as one it trusts, and the client verifies the server's certificate as one it trusts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When it comes to the client application, in my case the JavaFX application, you need to make sure that the client's keystore is accessible. Don't do as I did and try using the JRE's default keystore for this purpose. I just couldn't get that to work. Instead do as the &lt;a href="http://activemq.apache.org/how-do-i-use-ssl.html"&gt;ActiveMQ SSL page&lt;/a&gt; suggests and provide the client with its own keystore.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another tip for the client, is to set the &lt;i&gt;javax.net.ssl.*&lt;/i&gt; properties within the application itself; before you try establishing the JMS connection of course. I express the location of the client's keystore in relation to the &lt;i&gt;user.home &lt;/i&gt;system property.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;From a broker (server) perspective, one has to use a &lt;a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASLMDevGuide.html"&gt;JAAS LoginModule&lt;/a&gt; that permits certificate based authentication. Fortunately I found an ActiveMQ-JAAS class named &lt;a href="http://activemq.apache.org/maven/5.2.0/activemq-jaas/apidocs/org/apache/activemq/jaas/CertificateLoginModule.html"&gt;CertificateLoginModule&lt;/a&gt; (of all things). &lt;b&gt;One very subtle thing to note&lt;/b&gt;: when specifying the use of this login module in activemq.xml you must use the jaasCertificateAuthenticationPlugin element instead of the jaasAuthenticationElement. I think that this is because the certificate login module requires a different login callback to obtain the client's certificate.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;CertificateLoginModule is only half the picture in the same way that authentication is only half the picture. Authorisation is required and the CertificateLoginModule has to be extended to support this; the login module does not know how to authorise a certificate. I can help there as I have provided this code. More on that later though (I insist on you reading the rest of this entry!).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally on authentication, you need to tell ActiveMQ that you want to perform client certificate authentication; it will not do it unless told to do so. You do this by specifying "needClientAuth=true" parameter on the ssl transport in activemq.xml.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;transportconnector name="ssl" uri="ssl://localhost:61617?needClientAuth=true"&gt;&lt;/transportconnector&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;transportconnector name="ssl" uri="ssl://localhost:61617?needClientAuth=true"&gt;&lt;/transportconnector&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You might want to disable the other connectors and open up your firewall just for 61617 SSL connectivity. I think that once you make authentication a priority with the broker then you need to give up the non-secure connectors.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:180%;"&gt;&lt;span class="Apple-style-span"&gt;Authorisation&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;With authentication done (I know who you are, you know who I am), I needed to deal with authorisation (now I know who you are, what am I going to allow you to do). For this I wanted to centralise my user and group/role information. ActiveMQ allows you to specify user/group associations in its configuration file, but I wanted to do what all grown-ups do: specify my users and groups in a centralised LDAP directory.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The CertificateLoginModule requires extension to specify how authorisation is done. I have created a &lt;a href="http://jaasloginmodules.googlecode.com/svn/javadoc/1.0/com/classactionpl/jaas/activemq/CertificateLoginDirectoryRolesModule.html"&gt;CertificateLoginDirectoryRolesModule&lt;/a&gt; that will take the subject DN from each client certificate presented (there can be many but typically just one), and then call upon my LDAP store to determine which groups the DN is a member of.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p   style="margin: 0px; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;font-family:Helvetica;font-size:12px;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p   style="margin: 0px; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;font-family:Helvetica;font-size:12px;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p   style="margin: 0px; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;font-family:Helvetica;font-size:12px;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  &lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;div&gt;I have set up my LDAP server (&lt;a href="http://directory.apache.org/"&gt;ApacheDS&lt;/a&gt; - fabulous) to allow anonymous access but also enabled access controls. This means that, by default, the LDAP server permits very little authorisation with just admin access. I then created a group named "activemq" off the "groups" node and used an ACI to allow anonymous searching of that group. I ended up with a group hierarchy as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ou=system&lt;br /&gt;  ou=groups&lt;br /&gt;    ou=activemq (anonymous users can see this and below)&lt;br /&gt;      cn=jms-services&lt;br /&gt;      cn=activemq-users&lt;br /&gt;      cn=com.classactionpl.javaFlightTopic.Subscribers&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Correspondingly here is my authorisation mapping within activemq.xml:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;authorizationPlugin&amp;gt;&lt;br /&gt;  &amp;lt;map&amp;gt;&lt;br /&gt;    &amp;lt;authorizationMap&amp;gt;&lt;br /&gt;      &amp;lt;authorizationEntries&amp;gt;&lt;br /&gt;        &amp;lt;authorizationEntry queue="&amp;gt;"&lt;br /&gt;          read="jms-services"&lt;br /&gt;          write="jms-services"&lt;br /&gt;          admin="jms-services" /&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;authorizationEntry topic="&amp;gt;"&lt;br /&gt;          read="jms-services"&lt;br /&gt;          write="jms-services"&lt;br /&gt;          admin="jms-services" /&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;authorizationEntry topic="com.classactionpl.javaFlightTopic"&lt;br /&gt;          read="com.classactionpl.javaFlightTopic.Subscribers" /&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;authorizationEntry topic="ActiveMQ.Advisory.&amp;gt;"&lt;br /&gt;          read="activemq-users"&lt;br /&gt;          write="activemq-users"&lt;br /&gt;          admin="activemq-users" /&amp;gt;&lt;br /&gt;      &amp;lt;/authorizationEntries&amp;gt;&lt;br /&gt;    &amp;lt;/authorizationMap&amp;gt;&lt;br /&gt;  &amp;lt;/map&amp;gt;&lt;br /&gt;&amp;lt;/authorizationPlugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What the above states is that jms service providers, such as my Camel based applications, can effectively publish and subscribe to anything. However my client belongs to the javaFlightTopic.Subscribers group and the activemq-users group and so can only consume from a specific topic and perform all required advisory services; the latter being an ActiveMQ requirement.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is possible to express the authorisation mappings in an LDAP store as well. We'll see if the need surfaces.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:180%;"&gt;Source Code&lt;/span&gt;&lt;/div&gt;&lt;div&gt;I have created an open-source project named &lt;a href="http://code.google.com/p/jaasloginmodules/"&gt;jaasloginmodules&lt;/a&gt; that hosts this JAAS login module and have tested and used the classes. The CertificateLoginDirectoryRolesModule is ready for &lt;a href="http://code.google.com/p/jaasloginmodules/downloads/list"&gt;download&lt;/a&gt; and use.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-2435442527048844873?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/2435442527048844873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=2435442527048844873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2435442527048844873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2435442527048844873'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/03/mutual-ssl-authentication-and-ldap.html' title='Mutual SSL authentication and LDAP authorisation for ActiveMQ'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-2401949910436244527</id><published>2009-03-03T22:35:00.004+11:00</published><updated>2009-03-03T22:51:46.256+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='POJO ORM Plain Old Java Object Dependent dependency'/><title type='text'>When is a POJO no longer a POJO</title><content type='html'>When is a &lt;a href="http://en.wikipedia.org/wiki/Plain_Old_Java_Object"&gt;Plain Old Java Object&lt;/a&gt; no longer a Plain Old Java Object?&lt;br /&gt;&lt;br /&gt;My take on POJOs is that they are no longer POJOs when there is an import statement for something not conforming to the expression "java*.*".&lt;br /&gt;&lt;br /&gt;I see quite a lot of frameworks and toolkits claiming benefits around POJO oriented development. However either through annotations, extension, implementation etc. they require dependencies on non JRE artifacts.&lt;br /&gt;&lt;br /&gt;This situation is quite OK of course; I just think that it is useful to distinguish a POJO from its dependent form. For example if you're looking for &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;Object Relational Mapping&lt;/a&gt; then you might want to consider the&lt;a href="http://en.wikipedia.org/wiki/Java_Persistence_API"&gt; Java Persistence API&lt;/a&gt; instead of being directly dependent on an implementation; such as &lt;a href="http://en.wikipedia.org/wiki/Hibernate_(Java)"&gt;Hibernate&lt;/a&gt;. Maintaining this distinction allows you to consider migration strategies to other implementations if required.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Sometimes you need to be dependent on a toolkit or framework and that is of course perfectly acceptable. Being aware is the significant point.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-2401949910436244527?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/2401949910436244527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=2401949910436244527' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2401949910436244527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/2401949910436244527'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/03/when-is-pojo-no-longer-pojo.html' title='When is a POJO no longer a POJO'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-5374423076531320342</id><published>2009-02-21T09:07:00.005+11:00</published><updated>2009-02-21T09:44:18.535+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WebOS PalmOS Palm Javascript iPhone Andriod'/><title type='text'>Who is Palm trying to attract for WebOS development?</title><content type='html'>I must say that my first impressions of what Palm is offering in terms of the WebOS leaves me curious.&lt;br /&gt;&lt;br /&gt;I wrote for the Palm OS over a long period of time. I started my Palm OS development when Palm were US Robotics and programmed the original PalmPilot. The PalmPilot was an amazing achievement for the time.&lt;br /&gt;&lt;br /&gt;There were a few things that attracted me to the original Palm OS platform, but a major one was that I could use my C++ skills to create robust and high-performance deliverables. The Metrowerks Codewarrior environment was a joy and I could use the same IDE for Mac OS (then Mac OS 8!) and Palm OS development.&lt;br /&gt;&lt;br /&gt;I think that it is reasonable to state that the original Palm OS attracted seasoned software developers; a lot of them were also Mac developers that understood things like usability. &lt;br /&gt;&lt;br /&gt;I am little surprised to learn that the WebOS is a Javascript world for the developer. To me Javascript is a language that evolved i.e. it does not appear to have been well thought out from the start. I am not attempting to criticise Javascript here - in fact I think that it is amazing what has been enabled via Javascript in the context of a web browser. I also understand why it has evolved the way it has. The thing is I am just surprised that Palm have chosen Javascript as their primary programming environment for WebOS. Who exactly is it that Palm are trying to attract to their platform?&lt;br /&gt;&lt;br /&gt;I suppose what I am saying here is that while Javascript can be written in a disciplined manner, I do not often see this to be the case. I am therefore curious about the quality of applications that will be delivered to the WebOS.&lt;br /&gt;&lt;br /&gt;I think that Apple have things almost right with the iPhone SDK and that Google have it completely right with Andriod. Where Apple need to improve is simply to provide a notification mechanism for an application. The notification handler should be able to operate in the background. The original Palm OS provided such a mechanism for handling alarm and other events. The benefit was that you could get an application to do things as a result of various device stimuli. This capability is very important and the iPhone falls short in this regard; so much so that I cannot consider porting my Palm OS based Titan Class Vision software.&lt;br /&gt;&lt;br /&gt;In the case of Google I think that the choice of Java is correct. Java is a great way to deliver robust software and rich in its tooling. However Google have to solve the battery life implications of their environment which presently make their phone unusable in many quarters.&lt;br /&gt;&lt;br /&gt;I digress slightly. The question remains though, who is Palm trying to attract for WebOS development?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-5374423076531320342?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/5374423076531320342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=5374423076531320342' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5374423076531320342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5374423076531320342'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/02/who-is-palm-trying-to-attract-for-webos.html' title='Who is Palm trying to attract for WebOS development?'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-3423840547741809134</id><published>2009-02-04T08:02:00.004+11:00</published><updated>2009-02-04T08:22:50.287+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='apache camel producer template pojo producertemplate dependency'/><title type='text'>Using Camel ProducerTemplate in a POJO</title><content type='html'>I am enjoying &lt;a href="http://camel.apache.org/"&gt;Apache Camel&lt;/a&gt; immensely. My productivity in terms of delivering enterprise grade services has increased dramatically. No doubt that the quality of my deliverables has also increased. All of this with no compromise to performance...&lt;br /&gt;&lt;br /&gt;In the case of having deployed about 3 Camel based applications (containers for services) and a couple of non-Camel ESB applications, I think that one of the major ESB benefits is the de-coupling the service implementation from the transport. This of course allows the service code to be written as a POJO and with dependency injection, DAOs and a few other patterns, the resulting service has a clean focus on the business logic.&lt;br /&gt;&lt;br /&gt;I recently had to implement a service that initialised a biometric device. Initialisation comprised of communicating several messages over a TCP connection to each biometric device. In the first instance I used Camel's &lt;a href="http://camel.apache.org/producertemplate.html"&gt;ProducerTemplate&lt;/a&gt; to send my messages. This all worked fine and of course meets that goal of separating out the transport delivery from the business logic. However I now had a Camel dependency in my otherwise pure POJO service. This did not satisfy my design goal of ensuring that the service remained a POJO so that I could be free with my ESB choice (not that I see myself moving from Camel for any reason!).&lt;br /&gt;&lt;br /&gt;To avoid this Camel dependency I created and used my own ProducerTemplate interface. This is merely a proxy to Camel's and only has the methods I need from my service. It looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface ProducerTemplate {&lt;br /&gt; Object sendBody(String endpoint, Object body);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I then pass a ProducerTemplate instance and its endpoint details to the invocation of my service along with any other parameters the service needs:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;void process(ProducerTemplate producerTemplate, String deviceEndpoint,&lt;br /&gt; Collection&lt;Fingerprint&gt; fingerprints)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that the ProducerTemplate is passed in on each invocation of the service. This is because the template can potentially change between service invocations.&lt;br /&gt;&lt;br /&gt;My Camel container project includes the project housing the above POJO. The container defines and instantiates its ProducerTemplate that forwards calls on to Camel's ProducerTemplate. The result is that I now have a POJO based service that interacts with other services in a non-Camel dependent manner.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-3423840547741809134?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/3423840547741809134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=3423840547741809134' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3423840547741809134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/3423840547741809134'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2009/02/using-camel-producertemplate-in-pojo.html' title='Using Camel ProducerTemplate in a POJO'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-4932127708370631772</id><published>2008-12-05T22:22:00.006+11:00</published><updated>2008-12-05T23:18:01.669+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='apache active mq camel maven mina tomcat cxf web services java spring anatomy service'/><title type='text'>Anatomy of a service/Apache anyone?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__zfCVFcU_Ac/STkPQX20x7I/AAAAAAAAAB4/lsEhw7jALjY/s1600-h/Anatomy+of+a+service.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 355px; height: 287px;" src="http://1.bp.blogspot.com/__zfCVFcU_Ac/STkPQX20x7I/AAAAAAAAAB4/lsEhw7jALjY/s400/Anatomy+of+a+service.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5276265212397537202" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is a pattern that I have implemented a few times now.&lt;br /&gt;&lt;br /&gt;I have had requirements to provide a web service, typically SOAP based, that persists something in a database (or whatever). Here's a general flow of events that I'm finding works particularly well:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1. Web browser to web service&lt;/span&gt;&lt;br /&gt;A web application (typically Javascript executing in a web browser) sends a SOAP request. Given that my web service is written using Apache CXF it can generate the required Javascript for the browser's invocation by appending a ?js parameter to the web service. Check out the CXF doco to see how. &lt;br /&gt;&lt;br /&gt;My CXF based web service is developed on a contract-first basis i.e. the SOAP interface is defined using Java. The reason I like that (as opposed to a WSDL-first approach), is because WSDL appears overly complex to me. It is much easier, in my most humble opinion, to create the Java interface and have CXF generate the WSDL. I reckon that CXF does a pretty good job of this too.&lt;br /&gt;&lt;br /&gt;My web service has the responsibility of marshaling the SOAP XML into a Java object that is representative of my information model. Here's a critical point: you must have an information model to work with aka domain model. If you don't have that nutted out very well then you tend to spin wheels. &lt;br /&gt;&lt;br /&gt;The classes of the information model are used as a normalised object for messaging and also for persistence. The web service marshals the XML into model objects, performs various integrity checks and then forwards the model objects on to a JMS queue.&lt;br /&gt;&lt;br /&gt;I'm using Spring's JMS template classes to forward on my JMS messages; when it comes to sending messages, lots of code is taken care of using these classes (I've also programmed JMS without them so I can make a direct comparison as to what Spring offers in this respect).&lt;br /&gt;&lt;br /&gt;In summary my web browser invokes a SOAP web service using some nice Javascript code that CXF can generate. My CXF based service has a relatively simple roll of marshaling the SOAP XML input into a domain object of my information model and sending it to a queue.&lt;br /&gt;&lt;br /&gt;Oh, by the way, I'm using Apache Tomcat to host my CXF based web application.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2. Sending to ActiveMQ&lt;/span&gt;&lt;br /&gt;I'm typically sending to queues dedicated to specific functions e.g. "queue to persist the biometric fingerprint of a person". These queues are persistent (a JMS default) so that messages are stored until they can be guaranteed delivery.&lt;br /&gt;&lt;br /&gt;I like ActiveMQ. Apart from the price tag being very attractive (free), the Apache products are built to a very high standard. ActiveMQ is fast and reliable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3. ActiveMQ replies&lt;/span&gt;&lt;br /&gt;Once ActiveMQ replies back to my web service guaranteeing delivery, my web service replies to my browser application.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4. Browser processes the reply &amp; Camel service consumes queue&lt;/span&gt;&lt;br /&gt;These are concurrent activities. Of course the browser delivered the SOAP request in (1) asynchronously and registered call backs for processing any errors and successful responses. This way the user's browser remains responsive.&lt;br /&gt;&lt;br /&gt;The design of my browser application is very much around the store-and-forward paradigm. Depending on how critical it is to feed back the results of an operation, it is generally adequate to inform the user that their requested has been posted. In the case where the request is involved in retrieving, say, customer details, receiving a response is important so I would use a request-reply enterprise integration pattern. However in many scenarios, store and forward is perfectly adequate and really suites a browser style application.&lt;br /&gt;&lt;br /&gt;Almost as soon as ActiveMQ makes a message available to the queue (2) my Apache Camel based service is able to consume it. &lt;br /&gt;&lt;br /&gt;I like Apache Camel. It really helps me assemble services very loosely given the strong promotion of enterprise integration patterns. You can build content based routers, aggregators, request-reply mechanisms and so forth - Camel provides the framework for you to build your services on. Camel almost forces you to think about the correct separation of concerns given its abstractions.&lt;br /&gt;&lt;br /&gt;I typically deploy my Camel based services using jsvc - Apache's daemon toolkit (part of the Apache Commons project). jsvc is a very simple wrapper so that you can make your application run as a service on Unix and Windows based platforms. From a programming perspective, you implement a lifecycle interface (init, destroy, start, stop) and that's about it. I want to move toward using OSGi, and I have played with it. However I have not found a OSGi based container that I'm totally happy with yet (they don't appear to have totally satisfied use-cases associated with administrators - just programmers at this point).&lt;br /&gt;&lt;br /&gt;I have many services do many things but a common task is persisting and retrieving data from a relational database. For that I program to JPA and use Hibernate as my JPA implementation. I prefer JPA over Hibernate directly so that I have the ultimate freedom of using other ORM implementations should I need to - I don't think I will be needing to at this point though as Hibernate is great.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Performance&lt;/span&gt;&lt;br /&gt;I get great performance. The slowest parts tend to be associated with persisting data in an RDBMS (nothing to do with Hibernate etc - normal RDBMS stuff) and network latency. CXF and Camel fly along - you're mostly counting small units of milliseconds with these technologies.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Scalability&lt;/span&gt;&lt;br /&gt;I've not had to do much in the way of scaling yet, but I know I have the correct separation of concerns to cope with most of what the world can throw at these services. In the performance testing that I have done I tend to exceed my customer's expectations. As stated above, it is network latency that appears to be the bottleneck given that the internet often sits between the browser and the web service.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Apache, Apache&lt;/span&gt;&lt;br /&gt;It may appear that I work for Apache or something, but I don't. I do value the Apache Projects though. In summary here's what I'm presently using:&lt;br /&gt;&lt;br /&gt;* Active/MQ&lt;br /&gt;* Camel&lt;br /&gt;* CXF&lt;br /&gt;* Maven&lt;br /&gt;* MINA&lt;br /&gt;* Tomcat&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-4932127708370631772?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/4932127708370631772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=4932127708370631772' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4932127708370631772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4932127708370631772'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2008/12/anatomy-of-serviceapache-anyone.html' title='Anatomy of a service/Apache anyone?'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__zfCVFcU_Ac/STkPQX20x7I/AAAAAAAAAB4/lsEhw7jALjY/s72-c/Anatomy+of+a+service.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-7790108397584948542</id><published>2008-11-29T12:39:00.008+11:00</published><updated>2008-11-29T14:38:43.429+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='world global economic downturn software development'/><title type='text'>Software Development and the Global Economic Downturn</title><content type='html'>There appears to be plenty of software development work around at the moment.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A manager at a large company that I have been doing some work for recently commented that when a business looks to contract, the demands on IT increase.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I agree.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The reason for this is automation; something that the business should always strive for of course. The point is that they don't. Large companies would rather throw multitudes of people at a problem than optimise operational tasks... until external pressures such as world economic downturns occur. I have friends that work for some other large companies that are typically regarded as being innovative. One of the common threads is how, from an operational perspective, they always automate the mundane tasks as much as possible.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So for me at least, as a small software developer, there appears to be plenty of work around and a great deal is focused on automation.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-7790108397584948542?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/7790108397584948542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=7790108397584948542' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7790108397584948542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7790108397584948542'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2008/11/long-live-recession.html' title='Software Development and the Global Economic Downturn'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-7691477514160530084</id><published>2007-10-19T14:13:00.001+10:00</published><updated>2008-11-30T19:59:50.651+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='image compositor opengl mac os x quartz virtual memory mapped files mmap'/><title type='text'>An Image Compositor Technique for a Planet</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__zfCVFcU_Ac/STC0WH20pHI/AAAAAAAAABo/FZNfokhJwEk/s1600-h/Untitled.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 316px; height: 159px;" src="http://3.bp.blogspot.com/__zfCVFcU_Ac/STC0WH20pHI/AAAAAAAAABo/FZNfokhJwEk/s400/Untitled.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5273913455809963122" /&gt;&lt;/a&gt;&lt;br /&gt;I had a need to develop a capability within &lt;a href="http://www.classactionpl.com/"&gt;Titan Class Vision&lt;/a&gt; to composite many images representing parts of our planet at different resolutions. In particular, these images could be quite large; perhaps 200MB each.&lt;br /&gt;&lt;br /&gt;I decided to give memory mapped files a go using the low-level paging mechanisms available to modern operating systems. In a nutshell we’re looking at the use of mmap and munmap. Memory mapping files is very fast and highly optimised - it is by far the fasted way of reading bytes in to memory from disk.&lt;br /&gt;&lt;br /&gt;My main image of the planet is about 200MB in size. What I do is have a Windows BMP file mapped saved in BGRAUnsignedInt8888Rev form (this is the optimal format for something to be textured on Mac OS X) and then use memory mapped file IO to page the BMP into memory. I then have an image compositor object that is able to composite many of these images e.g. I have a BMP for the entire planet, and one for just a given state of Australia (NSW). When it comes to client code making a request the compositor assembles a composited buffer of my layers as required and in the resolution required. This composited buffer is then sent to a texture using GL_STORAGE_SHARED_APPLE as an optimisation. I also keep some of these textures around for situations where I know in advance that I'm going to zoom in on something; it is then consequently very fast when it comes to rendering as no dynamic composition is required.&lt;br /&gt;&lt;br /&gt;Oh, and I'm using the &lt;a href="http://developer.apple.com/hardwaredrivers/ve/vector_libraries.html"&gt;Mac OS X Accelerate Framework&lt;/a&gt; for high quality and high performance scaling given that Titan Class Vision targets this platform.&lt;br /&gt;&lt;br /&gt;It all works pretty well and is fast, even on a tired old G4 Powerbook. Multiprocessors are utilised given the Accelerate Framework. One naturally has to be considerate of virtual memory usage with the compositor, but that is a resource management exercise.&lt;br /&gt;&lt;br /&gt;Here’s the class structure that I came up with; feel free to use it in your own work but please be kind and include a reference to this page and some credits.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;namespace WorldLayerCompositor {&lt;br /&gt;    typedef unsigned long BGRA;&lt;br /&gt;    &lt;br /&gt;    inline unsigned short SwapInt16LittleToHost(&lt;br /&gt;        unsigned short arg&lt;br /&gt;        ) throw();&lt;br /&gt;&lt;br /&gt;    inline unsigned long SwapInt32LittleToHost(&lt;br /&gt;        unsigned long arg&lt;br /&gt;        ) throw();&lt;br /&gt;&lt;br /&gt;class Layer {&lt;br /&gt;  public:&lt;br /&gt;virtual ~Layer();&lt;br /&gt;&lt;br /&gt;inline void GetCentreLatLong(&lt;br /&gt;            double&amp; outLat, double&amp; outLong&lt;br /&gt;            ) const throw();&lt;br /&gt;&lt;br /&gt;inline double GetResolution() const throw();&lt;br /&gt;&lt;br /&gt;inline void GetSizePx(&lt;br /&gt;            unsigned&amp; outWidthPx, &lt;br /&gt;            unsigned&amp; outHeightPx&lt;br /&gt;            ) const throw();&lt;br /&gt;&lt;br /&gt;virtual BGRA* GetBuffer() const throw() = 0;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class MemoryMappedBMPFileLayer : public Layer {&lt;br /&gt;  public:&lt;br /&gt;MemoryMappedBMPFileLayer(&lt;br /&gt;            const std::string&amp; inFile&lt;br /&gt;            ) throw();&lt;br /&gt;virtual ~MemoryMappedBMPFileLayer();&lt;br /&gt;&lt;br /&gt;virtual BGRA* GetBuffer() const throw();&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class LayerCompositor {&lt;br /&gt;  public:&lt;br /&gt;LayerCompositor() throw();&lt;br /&gt;&lt;br /&gt;typedef std::list&amp;lt;boost::shared_ptr&amp;lt;Layer&amp;gt; &amp;gt;&lt;br /&gt;            LayerList;&lt;br /&gt;&lt;br /&gt;LayerList::iterator AddLayer(&lt;br /&gt;            boost::shared_ptr&amp;lt;Layer&amp;gt; inLayerP&lt;br /&gt;            ) throw();&lt;br /&gt;&lt;br /&gt;void RemoveLayer(&lt;br /&gt;            const LayerList::iterator&amp; inLayerIter&lt;br /&gt;            ) throw();&lt;br /&gt;&lt;br /&gt;bool GetNextSubBuffer(&lt;br /&gt;            unsigned long** inBGRAUnsignedInt8888RevPP, &lt;br /&gt;            unsigned&amp; outSubXPx, &lt;br /&gt;            unsigned&amp; outSubXPy,&lt;br /&gt;            unsigned&amp; outSubWidthPx, &lt;br /&gt;            unsigned&amp; outSubHeightPx&lt;br /&gt;            ) const throw();&lt;br /&gt;&lt;br /&gt;void GetEffectiveSizePx(&lt;br /&gt;            unsigned&amp; outWidthPx, &lt;br /&gt;            unsigned&amp; outHeightPx&lt;br /&gt;            ) const throw();&lt;br /&gt;&lt;br /&gt;inline void SetSubRegion(&lt;br /&gt;            double inLat, double inLong,&lt;br /&gt;            double inResolution,&lt;br /&gt;            unsigned inWidthPx, unsigned inHeightPx&lt;br /&gt;            ) throw();&lt;br /&gt;};&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I intend to evolve this class much further and make it considerate of planet related things. For example if a request is presently made for a region that extends over the dateline then I move the region back either east or west. In the future I’ll be handling this so that the compositing considers the dateline.&lt;br /&gt;&lt;br /&gt;Another thought is to be able to add layers described in vector terms using SVG and GML... I think that there are some interesting possibilities.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-7691477514160530084?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/7691477514160530084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=7691477514160530084' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7691477514160530084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/7691477514160530084'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2007/10/image-compositor-technique-for-planet.html' title='An Image Compositor Technique for a Planet'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/__zfCVFcU_Ac/STC0WH20pHI/AAAAAAAAABo/FZNfokhJwEk/s72-c/Untitled.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-5562647515861725038</id><published>2007-07-16T13:56:00.001+10:00</published><updated>2008-11-30T19:58:50.349+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='geography markup language gml journey tracking'/><title type='text'>Using The GML’s Moving Object Status for presenting Flight Information</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__zfCVFcU_Ac/STCvrQ0JoGI/AAAAAAAAABg/QzVm4o7imMo/s1600-h/Journeys.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 336px;" src="http://1.bp.blogspot.com/__zfCVFcU_Ac/STCvrQ0JoGI/AAAAAAAAABg/QzVm4o7imMo/s400/Journeys.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5273908321433788514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is something that I’ve wanted to share for sometime now - how to use the Geography Mark-up Language (GML) for tracking things that move in the real world. GML can be a lot to get one’s head around so I hope that this real-world implementation will help you. We have been using GML for sometime now with our &lt;a href="http://www.classactionpl.com/"&gt;Titan Class Vision&lt;/a&gt; product.&lt;br /&gt;&lt;br /&gt;I want to show you how GML can be used to describe flight data; the sort of data you’ll see presented in the arrival and departure halls of airports. I have a hope that the world can share a view on how airport flight information should be provided to many kinds of application.&lt;br /&gt;&lt;br /&gt;GML provides a set of abstractions that are intended to be specialised by applications for their own purpose. Consequently we have defined a schema to describe journeys. This schema is represented by the class diagram above and is &lt;a href="http://www.classactionpl.com/gml/JourneyFeatures.xsd"&gt;available in XSD form&lt;/a&gt; from our website.&lt;br /&gt;&lt;br /&gt;Journeys describe a track between point A (departure port) and point B (arrival port). They have a scheduled departure and scheduled arrival time. A specific type of journey is a flight which has no other characteristic than its type for distinguishing itself.&lt;br /&gt;&lt;br /&gt;A Journey is a specialisation of a GML DynamicFeature. Dynamic features are things that have a relationship to geography (as per a regular Feature) but can also change over time and record when they do so. Consequently snapshots of a dynamic feature can be expressed given the availability of a validTime element. Additionally, and importantly, dynamic features can also have a “track” element. Tracks define a set of objects that describe a feature’s status over a period of time. These objects are known as GML’s MovingObjectStatus and minimally describe the time that the status applies to (validTime) and the location of the dynamic feature. A location can also be “null” i.e. unknown; this is pertinent to us and I’ll come back to it. The other elements are also very useful when tracking the position of a dynamic feature. For example, given acceleration, speed, bearing (horizontal and vertical), elevation etc. one can reasonably predict where the feature will be next. For most flight information displays in airports though, these elements are less important (Titan Class Vision at the airport is attempting to change this situation!).&lt;br /&gt;&lt;br /&gt;We have further specialised MovingObjectStatus as a JourneyStatus with the discriminating element being the Estimated Time of Arrival (ETA). Thus for a given validTime we can report what the ETA was.&lt;br /&gt;&lt;br /&gt;Enough words! Let’s have an example based on our journey schema:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;j:FeatureCollection ...&amp;gt;&lt;br /&gt;&amp;lt;name&amp;gt;Journeys&amp;lt;/name&amp;gt;&lt;br /&gt;&amp;lt;boundedBy&amp;gt;...&amp;lt;/boundedBy&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;featureMembers&amp;gt;&lt;br /&gt;&amp;lt;j:Flight&amp;gt;&lt;br /&gt;&amp;lt;name&amp;gt;QF32&amp;lt;/name&amp;gt;&lt;br /&gt;&amp;lt;validTime&amp;gt;&lt;br /&gt;&amp;lt;TimeInstant&amp;gt;&lt;br /&gt;    &amp;lt;timePosition&amp;gt;&lt;br /&gt;        2006-05-01T10:30:00Z&lt;br /&gt;    &amp;lt;/timePosition&amp;gt;&lt;br /&gt;&amp;lt;/TimeInstant&amp;gt;&lt;br /&gt;&amp;lt;/validTime&amp;gt;&lt;br /&gt;&amp;lt;track&amp;gt;&lt;br /&gt;&amp;lt;j:JourneyStatus&amp;gt;&lt;br /&gt;&amp;lt;validTime&amp;gt;&amp;lt;TimeInstant&amp;gt;&lt;br /&gt;        &amp;lt;timePosition&amp;gt;&lt;br /&gt;            2006-05-01T10:30:00Z&lt;br /&gt;        &amp;lt;/timePosition&amp;gt;&lt;br /&gt;&amp;lt;/TimeInstant&amp;gt;&amp;lt;/validTime&amp;gt;&lt;br /&gt;&amp;lt;location&amp;gt;&amp;lt;Null/&amp;gt;&amp;lt;/location&amp;gt;&lt;br /&gt;&amp;lt;j:ETA&amp;gt;&lt;br /&gt;    2006-05-02T00:05:00Z&lt;br /&gt;&amp;lt;/j:ETA&amp;gt;&lt;br /&gt;&amp;lt;/j:JourneyStatus&amp;gt;&lt;br /&gt;&amp;lt;/track&amp;gt;&lt;br /&gt;&amp;lt;j:departPort xlink:href="..."/&amp;gt;&lt;br /&gt;&amp;lt;j:departTime&amp;gt;&lt;br /&gt;   2006-05-01T11:15:00Z&lt;br /&gt;&amp;lt;/j:departTime&amp;gt;&lt;br /&gt;&amp;lt;j:arrivePort xlink:href="..."/&amp;gt;&lt;br /&gt;&amp;lt;j:arriveTime&amp;gt;&lt;br /&gt;    2006-05-02T00:00:00Z&lt;br /&gt;&amp;lt;/j:arriveTime&amp;gt;&lt;br /&gt;&amp;lt;/j:Flight&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/featureMembers&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;validTime&amp;gt;&amp;lt;TimeInstant&amp;gt;&amp;lt;timePosition&amp;gt;&lt;br /&gt;    2006-05-01T10:30:00Z&lt;br /&gt;&amp;lt;/timePosition&amp;gt;&amp;lt;/TimeInstant&amp;gt;&amp;lt;/validTime&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/j:FeatureCollection&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Please note that the above is not valid XML i.e. I’ve removed the namespace declarations and the xlink:href contents so that I could fit everything on the page and just present what is relevant to this discussion. A &lt;a href="http://www.classactionpl.com/gml/JourneyFeatures.xml"&gt;valid version&lt;/a&gt; of the above can be found on our website.&lt;br /&gt;&lt;br /&gt;The above document states, “here are the flights as at 1030 GMT. There is just one flight named QF32 which is scheduled to arrive at midnight GMT. However the current ETA is 0005 GMT.”. In the real world there would be a number of Flight elements for a given airport and a number of JourneyStatus elements if there have been a number of ETA revisions. The location is not important for most flight information displays at airports and hence we show that as having a null value.&lt;br /&gt;&lt;br /&gt;ETA could have been included as a element of Journey. I chose to have it as an element of JourneyStatus (aka MovingObjectStatus) so that I could have a number of ETAs reported for historical reasons. Additionally the reporting of an ETA could be further analysed by location. &lt;br /&gt;&lt;br /&gt;Plans are deemed other features (including other Journey features) that can further describe a given Journey feature. For example we have journeys that describe the frequently used flight paths between various destinations. These paths can include various way-points and record typical elevation and speed at those points.&lt;br /&gt;&lt;br /&gt;Our schema can also be used to describe a schedule such as a flight schedule. The validTime element of a Journey feature has the potential to be used to distinguish different schedules depending on the day of the week. For example a scheduled flight might only occur on Mondays and Fridays.&lt;br /&gt;&lt;br /&gt;I’m hoping that it is becoming apparent that more than just the ETA of a flight can be described. Firstly the structure of our schema permits the actual positions of flights at given time instances. We have embarked on consuming air radar data using our journey schema. This will enable us to render the real-time track of aircraft with our flight information display.&lt;br /&gt;&lt;br /&gt;Secondly anything that has a journey should be able to be described. This includes trains, ships, cars and trucks - even people swiping their security cards.&lt;br /&gt;&lt;br /&gt;In a future blog I shall describe various forms of accessing journey data using the &lt;a href="http://www.opengeospatial.org/standards/wfs"&gt;Web Feature Service (WFS)&lt;/a&gt; and also how this data can be published and subscribed using an enterprise messaging bus such as IBM’s &lt;a href="http://www-306.ibm.com/software/integration/wmq/"&gt;Websphere MQ&lt;/a&gt; and others that use the &lt;a href="http://en.wikipedia.org/wiki/Java_Message_Service"&gt;Java Messaging Service (JMS)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Meanwhile if you find that our journey schema is useful to you then please add a comment or do &lt;a href="http://www.classactionpl.com/contact.htm"&gt;get in touch&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-5562647515861725038?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/5562647515861725038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=5562647515861725038' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5562647515861725038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/5562647515861725038'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2007/07/using-gmls-moving-object-status-for.html' title='Using The GML’s Moving Object Status for presenting Flight Information'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__zfCVFcU_Ac/STCvrQ0JoGI/AAAAAAAAABg/QzVm4o7imMo/s72-c/Journeys.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1413304312041976659.post-4380093647919979080</id><published>2007-04-26T13:43:00.006+10:00</published><updated>2008-11-30T19:58:19.712+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quartz composer opengl'/><title type='text'>Titan Class Vision &amp; Quartz Composer</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__zfCVFcU_Ac/STC3duSgoXI/AAAAAAAAABw/iILH6RFO3F0/s1600-h/shapeimage_2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/__zfCVFcU_Ac/STC3duSgoXI/AAAAAAAAABw/iILH6RFO3F0/s400/shapeimage_2.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5273916884920607090" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I’ve just about finished integrating Quartz Composer with &lt;a href="http://www.classactionpl.com/"&gt;Titan Class Vision&lt;/a&gt;. For those of you that know nothing of Titan Class Vision, it provides a global flight information display that tracks aircraft in real-time. Our "Google Earth" type display presents new revenue generation opportunities for airports and also serves as a good airport-customer initiative. Titan Class Vision has been installed on two displays near the A/B exit of the Terminal 1 Arrivals Hall in Sydney International Airport (T1), Australia.&lt;br /&gt;&lt;br /&gt;Before I describe my initial requirements and how I’ve integrated Quartz Composer &lt;a href="http://www.classactionpl.com/SACL/Panasonic%20PDP%20Changes.mp4"&gt;here is a movie&lt;/a&gt; showing the animated integration.&lt;br /&gt;&lt;br /&gt;I needed to consider using Titan Class Vision with Plasma Display Panels and thus minimise burn-in issues. Titan Class Vision is already quite animated zooming between various resolutions. However more movement was required to remove static text and a header and footer margin.&lt;br /&gt;&lt;br /&gt;I could have programmed these animations into Titan Class Vision directly but I’ve always felt that something like Quartz Composer should be composing Vision’s image with other digital media and effects. By externalising most of the content (other than the planet and the 3d objects that get overlaid on to the planet e.g. the flight paths), I can now customise the display contents quite easily for individual customers - and with great effect!&lt;br /&gt;&lt;br /&gt;Before I continue thanks to everyone on the Quartz Composer forum that have helped me over the past few weeks. In particular thanks go to “tkoelling”, Alessandro Sabatelli and Pierre-Olivier Latour.&lt;br /&gt;&lt;br /&gt;The approach that I’ve taken is to render my 3D world into a Core Video (CV) buffer. The viewport is the size of the screen and is rendered once per frame. I then pass this CV buffer to Quartz Composer (QC). QC and CV share their OpenGL resources (context). Thus the image that I have rendered remains on the GPU side of the fence (I think that CV creates my image as a texture). QC receives the CV buffer as an image parameter and my scripts can do what they need to do. Pierre describes how to do QC/CV integration on the forum and I also posted &lt;a href="http://lists.apple.com/archives/quartzcomposer-dev/2007/Apr/msg00011.html"&gt;some code&lt;/a&gt; there.&lt;br /&gt;&lt;br /&gt;Titan Class Vision makes no assumption with regards to the name and location of the QC file. Instead I use AppleScript to pass in the path of the composition and this causes the instantiation of a new QCRenderer object (releasing any previously held one of course). At this time I also reset the timing for my composition if it is a different file to the last one. In summary I have some external program (which I actually call “Bootstrap”) that tells Titan Class Vision what to do - now including telling it where my composition file is. The Bootstrap is an Applescript Studio application that bundles the composition file as a resource.&lt;br /&gt;&lt;br /&gt;Bootstrap tells Titan Class Vision to zoom through different resolutions on a periodic basis - typically every 30 seconds. It now also sets up input parameters to the QCRenderer so that parts of my composition are enabled/disabled. I typically have one composition file per client’s implementation and enable sub-patches as necessary depending on what I want to show. This approach eradicates any performance impact of instantiating a new QCRenderer object (not that there appeared to be much of an impact though). Note that I do release/alloc a new QCRenderer if my context is re-shaped due to a bug with QC taking note of its viewport only on instantiation.&lt;br /&gt;&lt;br /&gt;For your interest, Bootstrap passes input parameters to my QCRenderer via Applescript as a URL encoded string parameter e.g.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;set composition parameters to "Fade_In=1&amp;amp;Fade_Out=0&amp;amp;World_Actual_Size=1&amp;amp;World_Zoomed=0"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That’s about it from a high level perspective other than to say that I can easily get 60fps on my relatively slow development machine (dual G4 1Ghz). I haven’t released my changes to my Quad Xeon yet but will do so in the next couple of months and all of this should fly (pun intended)!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Please note that when rendering to a CVOpenGLBuffer it must be treated as something that is immutable i.e. after you have written to it and passed it to the QCRenderer do not try writing to it again. This is in fact exactly what I was doing on Tiger and all was well. However with Leopard I had a problem given that the QC imaging pipeline had apparently changed.&lt;br /&gt;&lt;br /&gt;The resolution is to use a CVOpenGLBufferPool and then use CVOpenGLBufferPoolCreateOpenGLBuffer each time you want to render a new frame. After the frame has been passed to the QCRenderer you then release the CVOpenGLBuffer. Problem solved.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1413304312041976659-4380093647919979080?l=christopherhunt-software.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christopherhunt-software.blogspot.com/feeds/4380093647919979080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1413304312041976659&amp;postID=4380093647919979080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4380093647919979080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1413304312041976659/posts/default/4380093647919979080'/><link rel='alternate' type='text/html' href='http://christopherhunt-software.blogspot.com/2007/04/titan-class-vision-quartz-composer.html' title='Titan Class Vision &amp; Quartz Composer'/><author><name>Christopher</name><uri>http://www.blogger.com/profile/06860404627954267472</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/__zfCVFcU_Ac/STCihHBLfSI/AAAAAAAAAAg/YLf9TrAvc_A/S220/shapeimage_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__zfCVFcU_Ac/STC3duSgoXI/AAAAAAAAABw/iILH6RFO3F0/s72-c/shapeimage_2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
