<?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-8752593855083431018</id><updated>2011-07-08T11:21:53.680+10:00</updated><category term='images'/><category term='Spring Web Flow'/><category term='DTD'/><category term='XML Entities'/><category term='JPA'/><category term='obfuscation'/><category term='SEAM'/><category term='JSP'/><category term='Lucene'/><category term='Entity Manager'/><category term='SGML'/><category term='comedy'/><category term='Dependency Injection'/><category term='Martin Fowler'/><category term='Hibernate'/><category term='Jenkov'/><category term='magic number'/><category term='Inversion of Control'/><category term='SWF'/><category term='Compass'/><category term='Open Source'/><category term='Release Strategy'/><category term='fop'/><category term='Data Access'/><category term='AONS'/><category term='OpenJPA'/><category term='ruby on rails'/><category term='integration'/><category term='configuration'/><category term='DocBook'/><category term='code comment'/><category term='domain specific language'/><category term='Toplink'/><category term='Eclipse'/><category term='dsl'/><category term='file command'/><category term='file identification'/><category term='middleware'/><category term='SourceForge'/><category term='SegmentReader'/><category term='Documentation'/><category term='Spring'/><category term='XML Schema'/><category term='Ant'/><category term='Tree Tag'/><category term='DAO'/><title type='text'>AONS 2 Development</title><subtitle type='html'>This blog is a grouping of issues relevant to the development of the AONS 2 application. For more information see &lt;a href="http://pilot.apsr.edu.au/wiki/index.php/AONS_II"&gt;AONS 2 Wiki&lt;/a&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-3023438742363293471</id><published>2007-10-02T13:26:00.000+10:00</published><updated>2007-10-03T11:14:04.924+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ant'/><category scheme='http://www.blogger.com/atom/ns#' term='fop'/><category scheme='http://www.blogger.com/atom/ns#' term='images'/><category scheme='http://www.blogger.com/atom/ns#' term='obfuscation'/><category scheme='http://www.blogger.com/atom/ns#' term='DocBook'/><title type='text'>DocBook + Images != Fun</title><content type='html'>I've been using DocBook for a little while now, and I have to say, I wish there was a better alternative (something which provides a nice base format for the creation of multiple formats). My latest niggle is working with images. Like most things with DocBook, the solution starts off only a little difficult, then gets a fair bit more complicated.&lt;br /&gt;&lt;br /&gt;Before I go on, I realise a big part of my complaint is to do with XSLT: at the end of the day, XSLT really is just about transforming the XML, and not about building finished documents. Any yet I can't help but feel that whatever solution a person uses for document creation should encompass the whole shebang, from the core documents to the images they contain.&lt;br /&gt;&lt;br /&gt;Back to the topic of conversation, DocBook and Images. Getting the initial block of XML needed for images isn't that hard, and here it is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;mediaobject id="Registry Types"&amp;gt;&lt;br /&gt;        &amp;lt;imageobject role="fo"&amp;gt;&lt;br /&gt;            &amp;lt;imagedata format="SVG" fileref="RegistryTypes.svg"&amp;gt;&lt;br /&gt;        &amp;lt;/imagedata&amp;gt;&lt;br /&gt;        &amp;lt;imageobject role="html"&amp;gt;&lt;br /&gt;            &amp;lt;imagedata format="PNG" fileref="RegistryTypes.png"&amp;gt;&lt;br /&gt;        &amp;lt;/imagedata&amp;gt;&lt;br /&gt;    &amp;lt;/imageobject&amp;gt;&lt;br /&gt;&amp;lt;/imageobject&amp;gt;&amp;lt;/mediaobject&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You'll notice that I've specified two formats, one for the PDF generation and one for the HTML generation. This represents the fact that scalable vector graphic support is still not as widely accepted as we'd like. So, now we've got to create multiple images to support two formats. I could have just used a raster image for the PDF, but due to the need for higher print quality (and also the fact that Magic Draw doesn't provide configurable dpi on it's rasters) I chose to do both formats.&lt;br /&gt;&lt;br /&gt;Now comes the trick: the 'fileref' is not relevant to either the HTML XSLT transformation or the FO XSLT transformation, it's only relevant to either the final destination of the HTML or as I would deem incorrectly, the base directory of the fop Ant task.&lt;br /&gt;&lt;br /&gt;For the HTML, what this means is that you have to define appropriate tasks to copy the images to a directory accessible to the final production. Not too difficult but worth remembering.&lt;br /&gt;&lt;br /&gt;For the PDF generation, you need to ensure that the images are relative to the base path where the Ant script is run... so the above declaration should probably be changed to something like "images/RegistryTypes.svg" so the "fop" task can access the required images.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-3023438742363293471?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/3023438742363293471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=3023438742363293471' title='33 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/3023438742363293471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/3023438742363293471'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/10/docbook-images-fun.html' title='DocBook + Images != Fun'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>33</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-2954538941414319764</id><published>2007-08-16T17:37:00.001+10:00</published><updated>2007-08-28T09:02:04.614+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='integration'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Martin Fowler'/><category scheme='http://www.blogger.com/atom/ns#' term='domain specific language'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='SEAM'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>AONS, Rails and Other Integration Frameworks</title><content type='html'>I think I'm one of the last people to try out &lt;a href="http://www.rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;. Well, I will be last if I ever do.&lt;br /&gt;&lt;br /&gt;Rather then state my opinions on RoR (how quickly one picks up another acronym) and risk the ire of the agile community, I think I'll just examine the technology stack within the context of creating &lt;a href="http://pilot.apsr.edu.au/wiki/index.php/AONS"&gt;AONS&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;First off, I don't know Ruby on Rails very well. I think I understand the principal though:&lt;br /&gt;- Add &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt;, a development language which is geared towards rapid development&lt;br /&gt;- Integrate (or create) any Ruby middleware technologies in a best of breed approach, essentially abstracting the developer away from this choice (saves time on tasks like integrating with one of many persistence implementations and learning it's quirks)&lt;br /&gt;- Create good facades for any commonly used subsystems (authentication, notification?)&lt;br /&gt;&lt;br /&gt;In principal, I admire RoR for integrating all those technologies because integrating technologies on a per/project basis is a pain (and as Martin Fowler says, it's a great domain specific application for writing web applications). As an example on AONS, it took about four weeks integrating and de-quirking &lt;a href="http://www.hibernate.org/397.html"&gt;Hibernate JPA&lt;/a&gt; (and finding a nice flavour), &lt;a href="http://www.opensymphony.com/compass/"&gt;Compass&lt;/a&gt;/&lt;a href="http://lucene.apache.org/java/docs/"&gt;Lucene&lt;/a&gt;, &lt;a href="http://www.springframework.org/"&gt;Spring&lt;/a&gt;, &lt;a href="http://www.jfree.org/jfreechart/"&gt;JFreeChart&lt;/a&gt;, &lt;a href="http://www.opensymphony.com/quartz/"&gt;Quartz&lt;/a&gt;, &lt;a href="http://www.castor.org/"&gt;Castor&lt;/a&gt;, &lt;a href="https://rome.dev.java.net/"&gt;ROME&lt;/a&gt;, a REST exposure methodology and Spring Web Flow (mainly in choosing one of many, many view technologies). Most of this was spent familiarizing myself with JPA and trying a few different implementations so realistically it could be cut down to one or two weeks if I had to repeat. But the point here is that if it is a common task, why do this at all? So, on this point, I do admire Ruby on Rails.&lt;br /&gt;&lt;br /&gt;Where I disagree with Ruby on Rails in the long term is that &lt;span style="font-style: italic;"&gt;learning and integrating with new technologies is an ability&lt;/span&gt;. Whilst it is nice not to have to constantly waste effort doing these kinds of tasks, &lt;span style="font-style: italic;"&gt;learning various approaches to wire in different technology stacks is a must have skill for all but the most trivial projects&lt;/span&gt;. So, I think the bonus Ruby gives should only be that it removes most of the integration tasks from a project - but at the end of the day a good developer should always be willing and able to integrate should existing technologies not prove sufficient. I believe part of the attraction to Ruby on Rails is that at the end of the day, we're lazy creatures. That's not necessarily a bad thing: having 80% of the integration job done means you'll get quicker return on investment getting that last part of integration done. But the ability to integrate is something which needs to be constantly honed otherwise it atrophies. I also believe Ruby on Rails offered a nice foot in the door to a lot of developers with minimal integration experience. Suddenly they could compete with the Java gurus who wore their hard won knowledge of integration like a badge. But here's where I believe the crux is: nothing can make up from the experience of learning to wire in some misbegotten technology. Every successful developer will have to do it, and time will be a good measure to show whether those who took up RoR learned how to take steps beyond the initial RoR framework... Did they keep  learn the "art" of integration or are they left waiting for the next RoR (SEAM?).&lt;br /&gt;&lt;br /&gt;So, integrating the technologies is an all go - now creating subsystems. I think I do agree that for a given domain specific language, you need a set of domain specific subsystems. I think RoR's success is a testament to the lack of commonly used functionality within the J2EE/EJB core (again back to the idea Martin Fowler talks about with Java being a domain independent language). Yes, in terms of "enterprisey" features they (J2EE/EJB) are fantastic, but up until recently, most of those features were hard to implement/understand. People need facades for the domain their working in... the job should be easy if you're doing a task in a common way. It may be necessary to slip past the facade should a job be more complicated, but that option should be there to do something simply. The main success of projects like SEAM/RoR is to go, "Hey, Java developers, use us and accelerate your development". And again, I'm forced to tip my hat in their direction.&lt;br /&gt;&lt;br /&gt;Just one point before I finish. The work I did for AONS could quick easily be stripped into an agile integration core offering similar features to something like SEAM or Ruby on Rails. Where it would fall down (without proper resourcing) would be the many, many hours it takes to write good examples and documentation so that using the framework became easy and intuitive.&lt;br /&gt;&lt;br /&gt;So, that's my thinking on Ruby on Rails (and a touch on SEAM). I'm not sure how helpful this will be to anyone... if nothing else maybe it will just resonate with thoughts going through other developers minds about the current successes in the small to medium application development world.&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;Dave&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-2954538941414319764?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/2954538941414319764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=2954538941414319764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2954538941414319764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2954538941414319764'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/08/ruby-on-rails.html' title='AONS, Rails and Other Integration Frameworks'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-169216667979103723</id><published>2007-08-07T14:36:00.000+10:00</published><updated>2007-08-07T14:48:45.216+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SourceForge'/><category scheme='http://www.blogger.com/atom/ns#' term='AONS'/><category scheme='http://www.blogger.com/atom/ns#' term='Release Strategy'/><category scheme='http://www.blogger.com/atom/ns#' term='Open Source'/><category scheme='http://www.blogger.com/atom/ns#' term='DocBook'/><title type='text'>Got 2 phase deployment done</title><content type='html'>I've now successfully added a two phase option to the AONS build. This is a handy mechanism to get the build completed up to the point where it would require client specific information (database connection info) and then stop the build there. What this means is that someone downloading a "release" sees a much more lightweight project structure then someone working with the full development structure. Another benefit is that we don't need to ask the deployer to compile the code against any required server libraries which can't be included in the release (due to more restrictive licensing).&lt;br /&gt;&lt;br /&gt;    This release also contains the compiled DocBook documentation (PDF, HTML single and HTML split) generated from the source DocBook XML which is included in the main project. So far I've got a basic Install Guide written and am working on the As Build Specification.&lt;br /&gt;&lt;br /&gt;    I know there's a lot of room for improvement, but between writing new features, bug fixing and finishing off existing documentation it's still a bit overwhelming. If anyone is reading this and downloads the release build from the &lt;a href="http://sourceforge.net"&gt;SourceForge&lt;/a&gt;, please let me know any issue encoutered or any "usability" ickiness which needs improvement. Any tweaking with included file structures is actually pretty easy to do, it's really just needs a bit of perspective from someone who hasn't had their face right against the coal face for the past few months.&lt;br /&gt;&lt;br /&gt;Well, for what it's worth, the build release is over &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=201332&amp;package_id=239335&amp;amp;release_id=530402"&gt;here&lt;/a&gt;. Remember, we're still in Beta so this build should be taken with a hefty grain of salt.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-169216667979103723?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/169216667979103723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=169216667979103723' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/169216667979103723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/169216667979103723'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/08/got-2-phase-deployment-done.html' title='Got 2 phase deployment done'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-4650495281336590700</id><published>2007-08-01T17:46:00.001+10:00</published><updated>2007-08-01T18:34:36.783+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DTD'/><category scheme='http://www.blogger.com/atom/ns#' term='Ant'/><category scheme='http://www.blogger.com/atom/ns#' term='XML Schema'/><category scheme='http://www.blogger.com/atom/ns#' term='Dependency Injection'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='SGML'/><category scheme='http://www.blogger.com/atom/ns#' term='DocBook'/><category scheme='http://www.blogger.com/atom/ns#' term='Documentation'/><category scheme='http://www.blogger.com/atom/ns#' term='XML Entities'/><title type='text'>hit with the documentation stick</title><content type='html'>Getting towards the end of this iteration of &lt;a href="http://pilot.apsr.edu.au/wiki/index.php/AONS"&gt;AONS&lt;/a&gt;, I'm starting to shift gear and work more on documentation. In an ideal world, I'd get the following done:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;As Built Specification (design/implementation focused document)&lt;br /&gt;&lt;/li&gt;&lt;ol&gt;&lt;li&gt;How AONS works (methodologies, design patterns etc)&lt;/li&gt;&lt;li&gt;Developing AONS (code conventions, source control etc)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Building AONS (development build and two phase distribution build)&lt;/li&gt;&lt;li&gt;Installation Guide (may also be an independent document)&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;User/Admin Guide&lt;/li&gt;&lt;li&gt;REST Interface Guide&lt;/li&gt;&lt;li&gt;Service Usage Model (SUM)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Future Extension Guide (anything we'd really like to have implemented in AONS, which there's a lot, but just plain ran out of time)&lt;/li&gt;&lt;li&gt;Fix up any not completed Javadoc&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;As always, time is heavily against us... and documenting this stuff with the effort it deserves is a little daunting. Ah well, if I just spend a few hours every day until the end of the project, I should be able to knock over most of it.&lt;br /&gt;&lt;br /&gt;From a technical perspective, one facet of this activity I am enjoying is that I'm using &lt;a href="http://www.blogger.com/www.docbook.org"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/www.docbook.org"&gt;DocBook&lt;/a&gt; as the source format for my documentation. This required a little learning to get started, but the idea of modular documents really suits my way of thinking. There's nothing worse then having to repeat sections within documentation and knowing that they'll get out of synch with the first update.&lt;br /&gt;&lt;br /&gt;One (minor) criticism with DocBook is the WSYIWYG tools are a little clunky. Not that I'm really using them much now that I've got my nice handful of tags under my belt. DocBook seems to be one of those things which you will just keep being surprised by it's breadth of features, but most tasks only require a very small subset.&lt;br /&gt;&lt;br /&gt;Another (minor) concern with DocBook is the usage of the &lt;a href="http://www.blogger.com/en.wikipedia.org/wiki/Document_Type_Definition"&gt;DTD&lt;/a&gt;. I was (and am) a little confused as to whether there is an &lt;a href="http://www.blogger.com/en.wikipedia.org/wiki/XML_Schema"&gt;XML Schema&lt;/a&gt; available for DocBook. The main reason I'd personally much prefer it is that the &lt;a href="http://www.blogger.com/www.eclipse.org"&gt;Eclipse&lt;/a&gt; content assist XML editor seems to only handle XML Schema, not DTD. I guess it comes down to DocBook being closer to &lt;a href="http://www.blogger.com/en.wikipedia.org/wiki/SGML"&gt;SGML&lt;/a&gt; then XML so maybe they can't use it... but it's kind of bucking the trend with most tools preferring XML Schema. Ah well, if it aint broke...&lt;br /&gt;&lt;br /&gt;Okay, seriously, last concern with DocBook. &lt;a href="http://www.irt.org/articles/js212/index.htm"&gt;Xml Entity&lt;/a&gt; objects. They really are outdated and there are many better ways to reference other objects. It kind of feels like a poor mans &lt;a href="http://www.blogger.com/www.martinfowler.com/articles/injection.html"&gt;Dependency Injection&lt;/a&gt;. Ant used to use them, but there were all sorts of issues... there must be a better way to reference other documents. My preference would be to leave the actual dependencies as undefined within the file which requests them (if they are resolved locally) and wait until all documents are composed together with a top level import document.&lt;br /&gt;&lt;br /&gt;[Update: Okay, just found the documentation for DocBook with XIncludes... looks like XML Entities were thrown out.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-4650495281336590700?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/4650495281336590700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=4650495281336590700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/4650495281336590700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/4650495281336590700'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/08/hit-with-documentation-stick.html' title='hit with the documentation stick'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-2078788234306598534</id><published>2007-07-11T11:11:00.000+10:00</published><updated>2007-07-11T11:24:43.865+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='code comment'/><category scheme='http://www.blogger.com/atom/ns#' term='file identification'/><category scheme='http://www.blogger.com/atom/ns#' term='comedy'/><category scheme='http://www.blogger.com/atom/ns#' term='file command'/><category scheme='http://www.blogger.com/atom/ns#' term='magic number'/><title type='text'>file identification funny</title><content type='html'>Occasionally one stumbles upon a code comment which both accurately states what the program is doing and also brings a smile to the face of the reader. Whilst reading through the source code for the "&lt;a href="http://www.tsfr.org/%7Eorc/Code/magicfilter/magicfilter-2.3.a/file/process.c"&gt;file&lt;/a&gt;" utility in it's attempts to identify a file, I came across this one which I thought was quite good:&lt;br /&gt;&lt;br /&gt;&lt;table style="border: 1px solid black; background-color: rgb(220, 210, 192);"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;blockquote&gt;&lt;pre&gt;/*&lt;br /&gt;* Try compression stuff&lt;br /&gt;*/&lt;br /&gt; if (!zflag || __lf_zmagic(buf, nb) != 1)&lt;br /&gt;  /*&lt;br /&gt;   * &lt;span style="color:blue;"&gt;try tests in /etc/magic (or surrogate magic file)&lt;/span&gt;&lt;br /&gt;   */&lt;br /&gt;  if (__lf_softmagic(buf, nb) != 1)&lt;br /&gt;   /*&lt;br /&gt;    * &lt;span style="color:blue;"&gt;try known keywords, check for ascii-ness too.&lt;/span&gt;&lt;br /&gt;    */&lt;br /&gt;   if (__lf_ascmagic(buf, nb) != 1)&lt;br /&gt;       /*&lt;br /&gt;        * &lt;span style="color:blue;"&gt;abandon hope, all ye who remain here&lt;/span&gt;&lt;br /&gt;        */&lt;br /&gt;       __lf_form("data");&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-2078788234306598534?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/2078788234306598534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=2078788234306598534' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2078788234306598534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2078788234306598534'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/07/file-identification-funny.html' title='file identification funny'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-8112706376389564544</id><published>2007-07-05T17:49:00.000+10:00</published><updated>2007-07-05T18:12:50.551+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='configuration'/><category scheme='http://www.blogger.com/atom/ns#' term='middleware'/><category scheme='http://www.blogger.com/atom/ns#' term='Martin Fowler'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>People Forget</title><content type='html'>After reading &lt;a href="http://gorif.wordpress.com/2007/07/01/5-reasons-why-i-think-i-will-not-use-spring/"&gt;this&lt;/a&gt; about &lt;a href="http://www.springframework.org/"&gt;Spring&lt;/a&gt; I kind of got a little bit annoyed. The number of people who forget or don't even know how bad a job configuration management used to be before Spring gave it one hell of a kick in the pants is staggering. Also to be thanked are &lt;a href="http://www.martinfowler.com/"&gt;Martin Fowler&lt;/a&gt; and the other IoC containers for starting the push.&lt;br /&gt;&lt;br /&gt;Just yesterday &lt;a href="http://aons2dev.blogspot.com/2007/07/lucene-issue.html"&gt;I found a lovely refresher on 'ye old days of bizarre configuration' &lt;/a&gt;in Lucene's SegmentReader via a global property which is still valid in it's current release. But nasty things like that don't happen much anymore do they? Now that the bar has been raised, isn't everyone quick to bemoan nasty things like well structured XML configuration.&lt;br /&gt;&lt;br /&gt;Oh geez, and the major complaint that "how would we live without Spring?". Continuing on from that, why would you? I'd be willing to bet that if you're using Spring in a deployable Application and not a piece of middleware, you're going to need a lot more then a Spring jar to run your application, and guess what, it's going to be a small to large job to change any of them. That's the world we live in as integrators first and developers second. If a developer doesn't like it, don't use any middleware and see how long it takes.&lt;br /&gt;&lt;br /&gt;Next, complaining about the start up time: again... is this really relevant? Not many people have weekly 'Friday server startup races'. Also, an empty Spring container will take a little while to start up, but once done, those load operations were concentrated in one tiny bit of the applications life: &lt;span style="font-style: italic;"&gt;meaning that you don't keep doing them for every operation, saving time&lt;/span&gt;. See that last part there, that was &lt;span style="font-style: italic;"&gt;key&lt;/span&gt;: do things which have to get done &lt;span style="font-style: italic;"&gt;once&lt;/span&gt;, then they don't have to be done every time you want to do the action. That logic will work as long as you don't do any unnecessary load operations in the Spring load... but then I guess you can also use Lazy loading if you want. See, options... it's all about options.&lt;br /&gt;&lt;br /&gt;And the Spring people are nice too... &lt;a href="http://www.adrenalini.com/"&gt;Yatzaa&lt;/a&gt;!!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.adrenalini.com/ADRENALINI_WPP800_0005.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px;" src="http://www.adrenalini.com/ADRENALINI_WPP800_0005.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-8112706376389564544?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/8112706376389564544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=8112706376389564544' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8112706376389564544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8112706376389564544'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/07/people-forget.html' title='People Forget'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-7501959456094560406</id><published>2007-07-04T13:01:00.000+10:00</published><updated>2007-07-04T13:35:14.779+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dependency Injection'/><category scheme='http://www.blogger.com/atom/ns#' term='Inversion of Control'/><category scheme='http://www.blogger.com/atom/ns#' term='Compass'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucene'/><category scheme='http://www.blogger.com/atom/ns#' term='SegmentReader'/><title type='text'>lucene issue</title><content type='html'>I feel sorry for Shay: he's written a beautiful object indexing layer, &lt;a href="http://www.opensymphony.com/compass/"&gt;Compass&lt;/a&gt;, on top of &lt;a href="http://lucene.apache.org/java/docs/"&gt;Lucene&lt;/a&gt; (the equivalent of writing the first good Object Relational mapping tool but for searching), yet is let down by the underlying interface to Lucene. Don't get me wrong, Lucene is great, but it does have some quirks.&lt;br /&gt;&lt;br /&gt;Take this one for example, setting a custom SegmentReader. Compass uses a custom SegmentReader (unsurprisingly called CompassSegmentReader), which in an of itself isn't a huge modification of Lucene. The quirk comes into play when we deploy multiple applications into the same Servlet container. It gets back to the method of setting the custom SegmentReader in Lucene; not changing a property on a factory or another configuration parameter... no, Lucene needs to set a system wide property. Yuck. This means that when Compass set's it's custom SegmentReader, it sets it for everything in that JVM. So App1 using Compass is okay, but App2 using pure Lucene then falls over unless the Compass jar file is included. Here's a &lt;a href="http://forums.opensymphony.com/thread.jspa?messageID=91812%F0%96%9A%A4"&gt;thread&lt;/a&gt; on the topic over at the Compass forums.&lt;br /&gt;&lt;br /&gt;In my case I've found this out when deploying &lt;a href="http://www.dspace.org/"&gt;DSpace&lt;/a&gt; on the same application server as AONS. I'm not sure how I'll get around it: I can probably ask the DSpace developers to include Compass in their distribution, or I'll probably just put in a README note about it. Either solution is less then ideal but probably the least path of resistance by far. Maybe the Lucene developers would be willing to change this... but the original post about this problem in the Compass forums was in 2005 so I have my doubts.&lt;br /&gt;&lt;br /&gt;Well, &lt;a href="http://www.cenqua.com/clover/20/samples/lucene/org/apache/lucene/index/SegmentReader.html#90"&gt;here's the offending code from org.apache.lucene.index.SegmentReader&lt;/a&gt; (valid as of Lucene 2.2.0):&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p class="MsoNormal"&gt;static {...&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;try {&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;      &lt;p class="MsoNormal"&gt;String name = System.getProperty("org.apache.lucene.SegmentReader.class", SegmentReader.class.getName());&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;IMPL = Class.forName(name);&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;} catch (ClassNotFoundException e) {&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;throw new RuntimeException("cannot load SegmentReader class: " + e, e);&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;} catch (SecurityException se) {&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;try {&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;IMPL = Class.forName(SegmentReader.class.getName());&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;} catch (ClassNotFoundException e) {&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;throw new RuntimeException("cannot load default SegmentReader class: " + e, e);&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;}&lt;/p&gt;  &lt;p class="MsoNormal"&gt;}&lt;/p&gt;&lt;/blockquote&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;}&lt;/p&gt;  This kind of code is exactly why &lt;a href="http://www.martinfowler.com/articles/injection.html"&gt;Inversion of Control&lt;/a&gt; (aka Dependency Injection) was so good when it came along: it got rid of static calls and global system properties like this and made property injection obvious and intuitive. I'm sure when this segment of code was first written, it was completely acceptable to do things like this... but nowadays configuration and anticipated customisation should be a little bit more elegant.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-7501959456094560406?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/7501959456094560406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=7501959456094560406' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7501959456094560406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7501959456094560406'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/07/lucene-issue.html' title='lucene issue'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-1717396057905819861</id><published>2007-06-14T17:01:00.000+10:00</published><updated>2007-06-14T17:31:40.979+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='Entity Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Access'/><category scheme='http://www.blogger.com/atom/ns#' term='Toplink'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring Web Flow'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>And now ... Hibernate's JPA</title><content type='html'>So, with a bit of a &lt;a href="http://aons2dev.blogspot.com/2007/06/tried-using-openjpa.html"&gt;hit and miss experience&lt;/a&gt; with &lt;a href="http://openjpa.apache.org/"&gt;OpenJPA&lt;/a&gt; after &lt;a href="http://www.oracle.com/technology/jpa"&gt;Toplink JPA&lt;/a&gt;, I decided to give &lt;a href="http://www.hibernate.org/397.html"&gt;Hibernate JPA&lt;/a&gt; (Hibernate Entity Manager) a go before going back to Toplink JPA with my tail between my legs. My initial reservation for trying out Hibernate's JPA implementation was mainly due to the rift between the Spring/Interface 21 people and the Hibernate/JBoss people. Whilst Hibernate and Spring have been and remain a fantastic combination, the bitter blood between the too camps can be a little intimidating. But... with another glowing article on using &lt;a href="http://icoloma.blogspot.com/2006/11/jpa-and-spring-fucking-cooltm_26.html"&gt;Spring and Hibernate JPA in combination&lt;/a&gt;, I set about my task.&lt;br /&gt;&lt;br /&gt;    Well, only and hour and a half later, and I can say that my faith in JPA has been restored, along with a nice bonus that I can remove any reference to a javaagent: Hibernate's implementation needs no sort of special run time weaver, which makes me wonder why the others do.&lt;br /&gt;&lt;br /&gt;    Looking back at my experiences with OpenJPA and Toplink, I'm willing to bet most of the pain I endured was due to the special weavers needed to run them on servlet containers like Tomcat. The special weavers bring out some very confusing bugs with IllegalAccessErrors, often quite deep in the Java reflection stack. So, depending on where you're going to be deploying to, I'd offer the following advice (with the proviso that this advice is only based on &lt;span style="font-style: italic;"&gt;observations&lt;/span&gt; and not hard fact):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;lightweight servlet container like tomcat: maybe avoid OpenJPA and Toplink until the javaagent weavers are no longer necessary, try Hibernate (or Kodo if it's a commercial application)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;EJB 3 container: The weaver concerns do not apply, OpenJPA and Toplink should be fine in these environments&lt;/li&gt;&lt;/ul&gt;[Note: I haven't actually had any experience on a full blown EJB 3 server as of yet with OpenJPA or Toplink, so feel free to let me know if your own experiences differ and they don't work as expected.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-1717396057905819861?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/1717396057905819861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=1717396057905819861' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/1717396057905819861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/1717396057905819861'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/06/and-now-hibernates-jpa.html' title='And now ... Hibernate&apos;s JPA'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-338737383515987208</id><published>2007-06-14T14:36:00.000+10:00</published><updated>2007-06-14T14:58:38.822+10:00</updated><title type='text'>Tried using OpenJPA</title><content type='html'>&lt;a href="http://www.oracle.com/technology/jpa"&gt;Toplink&lt;/a&gt; gave me yet another strange bug... which I wasn't even game to try and figure out (the object graph parsing and object and somehow updating it's ID invalidly... on a find operation).&lt;br /&gt;&lt;br /&gt;    I used to be a developer who'd happily hunt bugs whilst time slipped away. Since then I've realised that unless the bug is relatively easy to find/fix, the time taken away from a project is important and not really worth it. So, I through my hands up in disgust and decided to try test out &lt;a href="http://java.sun.com/developer/technicalArticles/J2EE/jpa/"&gt;JPA's&lt;/a&gt; benefits of being able to easily swap in/out a different implementation.&lt;br /&gt;&lt;br /&gt;    Oh how naive I was. I tried &lt;a href="http://openjpa.apache.org/"&gt;OpenJPA&lt;/a&gt;. Now, don't get me wrong, I think it's good that there will be another implementation of JPA out there - I just didn't feel OpenJPA was ready for prime time. Yes, they have "graduated" from their incubator status, but I could not get it working. Maybe Toplink let me do some naughty annotation things which OpenJPA didn't... that would have been fine if true.  What seemed to be my major issues with it were:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Weaving&lt;/li&gt;&lt;li&gt;Working with Compass&lt;/li&gt;&lt;li&gt;Weaving (again)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Weaving (yes, again)&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;    Now, I had a few heartaches getting compass to work with Toplink, but I found this doubly so with OpenJPA. I also found the documentation on utilising the javaagent to be sparse and outdated. When I tried OpenJPA's weaver/enhancer I could not get past the myriad of NoClassDefFound errors - in my mind, adding a javaagent jar file is okay for a temporary hack, but having to add another six libraries to the classpath is just those few steps too far towards making an almost impossible deploy job for a War file.&lt;br /&gt;&lt;br /&gt;Lastly, and this will probably be the reason I abandon OpenJPA: I could not get past the IllegalAccessException's with the "unsafe method invocation" and "GeneratedConstructor${index} could not access superclass".&lt;br /&gt;&lt;br /&gt;I don't completely understand the IllegalAccessException error: it appeared to be coming from the Java annotation/reflection stack. So maybe it was Spring's weaver, maybe it was compass, maybe it was OpenJPA... I really don't know. More importantly, I don't care. The level of complexity totally removed all the benefits of using JPA. So I'm going back to Toplink, with my tail between my legs - and will put up with one serious workaround in comparison to the alternative of using OpenJPA.&lt;br /&gt;&lt;br /&gt;I'd like to see OpenJPA become more usable for those using Tomcat - but it definitely isn't there yet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-338737383515987208?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/338737383515987208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=338737383515987208' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/338737383515987208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/338737383515987208'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/06/tried-using-openjpa.html' title='Tried using OpenJPA'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-7821119310434773995</id><published>2007-06-05T16:14:00.001+10:00</published><updated>2007-06-12T12:40:13.097+10:00</updated><title type='text'>Eclipse 3.3rc1 and imports</title><content type='html'>I'm using Eclipse 3.3 rc 1 and the automatic insertion of imports at the top of Java files isn't always working properly. I just had to hand craft my first import in what must be years. So I'll just take this opportunity to say thank you to Eclipse and all those other lovely IDE's out there which have made my daily development life so much easier - and even if it isn't working now, I'm sure it'll be working for the final.&lt;br /&gt;&lt;br /&gt;    I'm not going to bother creating a formal bug for this though - I'd have to first log on to the Eclipse site, which would mean username and password retrieval as well as first searching if the bug is even there already then lodging it if not. I &lt;span style="font-style: italic;"&gt;should&lt;/span&gt; lodge a bug report, but this time I'm not. I'm like a rebel without a cause;P&lt;br /&gt;&lt;br /&gt;    Okay I caved... the bug report is over &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=190962"&gt;here&lt;/a&gt;. So much for being a rebel;P&lt;br /&gt;&lt;br /&gt;[Note: This bug was pretty quickly closed as "works for me" since I didn't have a solid set of steps to reproduce the bug. Whilst I'll agree with this kind of thing in the most case, if it is stated that the bug is happening intermittently there is a good chance that there will never be a set of steps to reproduce this bug. Well, a bug that is happening only 1% of the time on a feature that is used 1000 times a day by a developer will very quickly come back to haunt when the latest version of Eclipse goes out for official 3.3 release. Intermittent bugs should only ever be ignored if they occur on a function which is used rarely.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-7821119310434773995?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/7821119310434773995/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=7821119310434773995' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7821119310434773995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7821119310434773995'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/06/eclipse-33rc1-and-imports.html' title='Eclipse 3.3rc1 and imports'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-2264593523148378431</id><published>2007-06-05T10:59:00.000+10:00</published><updated>2007-06-15T09:46:15.192+10:00</updated><title type='text'>Compass, Cascade and Cyclic References (oh my)</title><content type='html'>As identified &lt;a href="http://forums.opensymphony.com/thread.jspa?threadID=88029&amp;tstart=0"&gt;here&lt;/a&gt;, I'm having another issue with &lt;a href="http://www.opensymphony.com/compass/"&gt;Compass&lt;/a&gt;. Nothing major, just cyclic references between objects and cascades are a little wacky.&lt;br /&gt;&lt;br /&gt;   I use cyclic references between formats to link one format to another via a previous/next relationship. I am hoping to utilise Compass to do indirect matching on objects, but may have to hold off for a while the above mentioned issue gets resolved. It's only been a day though so plenty of time for a response from Shay or another talented compass developer.&lt;br /&gt;&lt;br /&gt;   If I can't get resolution on this issue, I could match indirect matches via a post-search process which just retrieves formats found in either a previous/next relationship. The problem I have with that is then my search mechanisms aren't as general purpose in the application... I'd need to somehow wire in post processors which would depend on the type of CompassHit found. I &lt;span style="font-style: italic;"&gt;could&lt;/span&gt; do it, but it would be pretty ugly and may be easier to just wait for the outcome of my forum post.&lt;br /&gt;&lt;br /&gt;   Sometimes it's hard to walk away from a feature which is "almost there", but I think in this case it's better that I leave a footnote here and look back at this in a month or so.&lt;br /&gt;&lt;br /&gt;[Update: it appears &lt;a href="http://forums.opensymphony.com/thread.jspa?messageID=158415&amp;#158415"&gt;my original idea about Compass' usage of SearchableReferences&lt;/a&gt; was a little off the mark. I figured that SearchableReferences were like pseudo properties; they would allow an object to match search criteria even though they didn't have the search match directly on them. This isn't the case... they're more a convenient way of storing object graphs.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-2264593523148378431?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/2264593523148378431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=2264593523148378431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2264593523148378431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2264593523148378431'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/06/compass-cascade-and-cyclic-references.html' title='Compass, Cascade and Cyclic References (oh my)'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-8579911295223427012</id><published>2007-05-29T10:37:00.000+10:00</published><updated>2007-05-29T10:55:07.562+10:00</updated><title type='text'>Using Eclipse's "go into" and Perspectives</title><content type='html'>I've finally started using &lt;a href="http://www.eclipse.org"&gt;Eclipse's&lt;/a&gt; "go into" functionality. Working with AONS 2, though not a giant project, was starting to get a little confusing; I was finding I was often moving between Java files, Spring configurations and various War resources (mainly JSP's). When you combine the weak checking going on between JSP's, SWF configurations and Java code, my short term memory proves to be quite inadequate. There is nothing worse then doing a build and realizing that I haven't changed a variable name in a SWF configuration file...&lt;br /&gt;&lt;br /&gt;    So, now working with my own deficiency taken into account, I have a perspective for:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Java&lt;/li&gt;&lt;li&gt;Run/Debug&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Spring configurations&lt;br /&gt;&lt;/li&gt;&lt;li&gt;WAR resources&lt;/li&gt;&lt;/ul&gt;    Using multiple screens to allow me to map (and check) between the various different screens is proving to be a much better option then trying to remember the latest iteration of variable name. It did take a little getting used to: previously I would only switch perspective when  absolutely necessary, like when running/debugging. I've got two monitors too so I've configured Eclipse to open each perspective in a new application frame so I can drag them around. I've also made sure to name my task allocated perspectives (WAR Resource, Spring Resource etc).&lt;br /&gt;&lt;br /&gt;    All this will hopefully be unnecessary one day when all the different parts of a project are tied together with sensible logic checks; regular Spring configurations have been infinitely more usable with &lt;a href="http://springide.org/"&gt;Spring IDE&lt;/a&gt;, and hopefully this continues with other Eclipse plugins.&lt;br /&gt;&lt;br /&gt;    As another option, maybe I should try training up my short term and long term memory... I hear &lt;a href="http://en.wikipedia.org/wiki/Mnemonic"&gt;memory mnemonics&lt;/a&gt; is good for that. One technique they say is to create a mental visualization of a place you've been, but every time I try visualise a mental "place" to put information I come up a little short. Maybe I should spend a little of my lunch time at the national library walking the floors to have a better mental picture....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-8579911295223427012?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/8579911295223427012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=8579911295223427012' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8579911295223427012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8579911295223427012'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/using-eclipses-go-into-and-perspectives.html' title='Using Eclipse&apos;s &quot;go into&quot; and Perspectives'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-6779347081991948530</id><published>2007-05-28T15:50:00.000+10:00</published><updated>2007-05-28T17:29:20.298+10:00</updated><title type='text'>JSR refactoring</title><content type='html'>Maybe I've focused far too much on immediate problems as I've gone down my path as a Java developer and just trusted that out there, somewhere, someone was making good decisions for the Java community, leading us forward - tally ho and all that...&lt;br /&gt;&lt;br /&gt;... and yet, looking towards the &lt;a href="http://jcp.org/en/home/index"&gt;JCP&lt;/a&gt; for information on interface polymorphism support in JPA (&lt;a href="http://jcp.org/en/jsr/detail?id=220"&gt;JSR 220&lt;/a&gt;), I've come up a little sparse. The best thread I've found on the topic was offsite on the Hibernate forums (over &lt;a href="http://opensource.atlassian.com/projects/hibernate/browse/ANN-9"&gt;here&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;As the thread suggested, I emailed my "favourite" expert member of the JSR 220 to suggest support for interface polymorphism - and on the random wheel of potential support, I choose Linda DeMichiel (Michael Keith was a close second, but can't seem to find his email in my rolodex).&lt;br /&gt;&lt;br /&gt;Something about this process seems a little light weight when compared with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;how much it affects a developer's daily life&lt;/li&gt;&lt;li&gt;just how many Java developers there are out there working with JPA in one form or another&lt;/li&gt;&lt;/ul&gt;So now truly seeing the JCP JSR process for the first time I can understand a bit more why &lt;a href="http://jcp.org/en/jsr/detail?id=306"&gt;JSR 306&lt;/a&gt; is so important: we need to change this process in order to save it (or at least make it meaningful for developers). Transparency is key in most good development environments and the JCP JSR process has been left alone for too long. And yet, despite the momentum this JSR initially had, it appears it is falling behind schedule (snipped from &lt;a href="http://www.infoq.com/news/jsr-306"&gt;here&lt;/a&gt;):&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;SR 306 passed JSR approval balloting unanimously.  The current schedule indicates an early draft in December 2006 followed by a public draft in February 2007 . Final approval balloting is slated for May of 2007. InfoQ sat down with Heather VanCura, Manager of the JCP Program Office, and Onno Kluyt, Director of the JCP Program at Sun, and Chair of the JCP to discuss this new JSR and the changes it will be attempting to bring the JCP process.&lt;/blockquote&gt;So a public draft was due in February.... well it's almost June and still nothing. As the solution to &lt;a href="http://today.java.net/pub/pq/123"&gt;many developers&lt;/a&gt; ills, it's running a little late.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-6779347081991948530?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/6779347081991948530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=6779347081991948530' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/6779347081991948530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/6779347081991948530'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/jsr-refactoring.html' title='JSR refactoring'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-1271737980189265436</id><published>2007-05-25T13:27:00.000+10:00</published><updated>2007-05-25T14:25:20.782+10:00</updated><title type='text'>JPA list ordering quirk</title><content type='html'>Seems JPA has one of those quirks which just doesn't make Java sense. It seems that in the &lt;a href="http://jcp.org/aboutJava/communityprocess/final/jsr220/index.html"&gt;JPA specification&lt;/a&gt;, there is no preservation of list ordering, except on attributes based on the target object. The order of a list should &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; be tied to attributes on that list. Though it makes database sense, a lists state is independent of the contained objects in the Java world and thus it should be true also when using lists in JPA... I'm sure there were reasons for doing it this way, but it's kinda dumb.&lt;br /&gt;&lt;br /&gt;   JPA implementations usually create a many to many table for the join here anyway, so all it would have needed is an extra attribute identifying the order of the list.&lt;br /&gt;&lt;br /&gt;   Maybe I'm asking a lot, but I would have thought this would be taken as a given. As a side note, I am glad to find the &lt;a href="http://www.apress.com/book/bookDisplay.html?bID=10093"&gt;Pro EJB 3: JPA&lt;/a&gt; book by Mike Keith and Merrick Schincariol covered this topic very well when I looked it up. Somehow &lt;a href="http://en.wikipedia.org/wiki/Google_%28verb%29"&gt;Googling&lt;/a&gt; for "JPA list order" just didn't come up with anything very clear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-1271737980189265436?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/1271737980189265436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=1271737980189265436' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/1271737980189265436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/1271737980189265436'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/jpa-list-ordering-quirk.html' title='JPA list ordering quirk'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-3245194119791901397</id><published>2007-05-16T08:44:00.000+10:00</published><updated>2007-06-13T09:23:53.783+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DAO'/><category scheme='http://www.blogger.com/atom/ns#' term='JSP'/><category scheme='http://www.blogger.com/atom/ns#' term='SWF'/><category scheme='http://www.blogger.com/atom/ns#' term='Jenkov'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring Web Flow'/><category scheme='http://www.blogger.com/atom/ns#' term='Tree Tag'/><title type='text'>Jenkov Tree Tag and Spring Webflow</title><content type='html'>I made a post over &lt;a href="http://forum.springframework.org/showthread.php?t=38673"&gt;here&lt;/a&gt; about using trees in &lt;a href="http://www.springframework.org/webflow"&gt;Spring Webflow&lt;/a&gt; (SWF); bascially I was asking if it was possible to do, and if so, what would be some good ways to go ahead. Since then I've implemented tree functionality within the AONS application to browse repository crawls. In order not to have to do everything myself, I integrated the &lt;a href="http://www.jenkov.dk/prizetags/treetag/dynamic_trees_using_tree_daos.tmpl"&gt;Jenkov Tree Tag&lt;/a&gt; with SWF actions. The end result is quite workable and I'm rather happy with myself (don't worry, my ego usually deflates within 24 hours).&lt;br /&gt;&lt;br /&gt;But, now at the end of the process, I can't help but offer some advice to those who'd also use the Jenkov Tree Tag (or the entire library).&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Documentation, though quite large, is often incorrect&lt;/li&gt;&lt;li&gt;The tag library itself has some newbie errors (like for example giving every ".tld" file the same URI).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The approach of injecting a Tree Node &lt;a href="http://en.wikipedia.org/wiki/Data_Access_Object"&gt;Data Access Object&lt;/a&gt; (DAO) object into the tree is flawed; the Tree and DAO object must be serializable, so if it depends on other long lived beans the plan won't work. Instead, make the TreeNodeDAO a long lived bean, and whenever a SWF action is called upon the Tree, just replicate the functionality internal to the Tree in the action.&lt;/li&gt;&lt;li&gt;The documentation on the TreeUpdater() is just plain confusing.&lt;/li&gt;&lt;li&gt;The amount of hand crafting to create a good JSP tree structure can take quite a long time. You'll get there in the end, but it is a lot of trial and error - playing with tables, CSS, icons etc.&lt;/li&gt;&lt;/ol&gt;Still, kudos goes to the people over at Jenkov for putting this out there; Open Source libraries aren't always going to be fantastic and it takes a lot of guts and sweat to put a nice package together for usage - and any documentation is better then none.&lt;br /&gt;&lt;br /&gt;Here's a picture of the tree utilised in the format summary page:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-RlQipI2_s8/Rko-OgWYJpI/AAAAAAAAAAM/EaguAtntel0/s1600-h/AONS+Screenshot+Snipped.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_-RlQipI2_s8/Rko-OgWYJpI/AAAAAAAAAAM/EaguAtntel0/s320/AONS+Screenshot+Snipped.JPG" alt="" id="BLOGGER_PHOTO_ID_5064929149854426770" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Some Java developers among you will notice the quite familiar icons from &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt;: in theory Eclipse is open source so we can use them, but I'd hate to ruin any good feeling about AONS from the Open Source community so will take them out if asked (yet I'm almost equally loathe to work with 16x16 bitmaps in MS paint...).&lt;br /&gt;&lt;br /&gt;[Update: After a little prodding, I've put up how I implemented the tree functionality over on the &lt;a href="http://forum.springframework.org/showthread.php?t=38673"&gt;Spring Web Flow forum&lt;/a&gt;. I think my reluctance to detail how I did it was partly due to how big the explanation became (I had to turn it into three separate forum posts). The solution isn't perfect, in fact alternative solutions are welcome, but I  do hope that it helps people out...feel free to post any questions (either here or on the blog)]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-3245194119791901397?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/3245194119791901397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=3245194119791901397' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/3245194119791901397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/3245194119791901397'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/jenkov-tree-tag-and-spring-webflow.html' title='Jenkov Tree Tag and Spring Webflow'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_-RlQipI2_s8/Rko-OgWYJpI/AAAAAAAAAAM/EaguAtntel0/s72-c/AONS+Screenshot+Snipped.JPG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-2869712038988678947</id><published>2007-05-12T10:42:00.000+10:00</published><updated>2007-05-12T11:15:44.913+10:00</updated><title type='text'>scheduling &amp; transaction proxy wrappers</title><content type='html'>Probably one of the most confusing parts of the last two applications I have written goes in the Scheduling area. I think I could be doing something better, but I'm just not sure how...&lt;br /&gt;&lt;br /&gt;The area of complexity comes into play when Scheduling is mixed with transactions - not so much in that it's hard to enter a transaction, more in that it's confusing to update a "status" flag on a domain object in a new discrete transaction to indicate that the object is running. I've toyed with the idea that I could just have the status a memory based object, but that seems to smell even worse.&lt;br /&gt;&lt;br /&gt;I guess further complexity is added by some databases locking for the duration of, what can be quite a long running, scheduled batch job. Most databases are okay with their database locks, but some are quite heavy handed in this, even when transactions are only read only. Luckily I'm  currently testing against PostgreSQL and Oracle  which, from past experience have shown to be quite smart in their locking processes so I probably won't have to cater for the unsaid bad database - whatever solution I talk about here, when the locking problem comes in too, things just get plain horrible.&lt;br /&gt;&lt;br /&gt;So what's my ideal process for the transaction algorithm?&lt;br /&gt;1.) Scheduled Job Starts, calls performSchedule on intended business manager&lt;br /&gt;2.) Manager called, creating a new transaction&lt;br /&gt;2.) New "tiny" transaction which commits quickly to indicate the domain object is running; there should also be a test in this small transaction to check that this domain object isn't already running.&lt;br /&gt;3.) The batch main body of work goes on&lt;br /&gt;4.) The batch main body of work is committed, we also indicate that the domain object is not running&lt;br /&gt;&lt;br /&gt;Should a runtime exception be thrown, we should abort the main block of code, but in a catch block, we should also create another "tiny" transaction to indicate that the job is also no longer running and possibly do any logging/notification regarding the failed job.&lt;br /&gt;&lt;br /&gt;Where this gets a little interesting is when transaction proxy wrapping mechanisms are thrown into the mix. Whilst not the worst code in the world by any means, we have to now employ a special mechanism to perform the two "tiny" transactions. There are a few ways to do this, some talked about &lt;a href="http://blog.exis.com/colin/archives/2005/07/18/spring-12s-java-5-based-transaction-annotations/"&gt;here&lt;/a&gt;, but even those solutions do not handle &lt;span style="font-style: italic;"&gt;changing&lt;/span&gt; the existing transaction demarcation around the proxy object. Since what we need to do is call a retrieve and and update which are normally PROPAGATION_REQUIRED in a very small transaction.&lt;br /&gt;&lt;br /&gt;Say we are using business managers in our application as the target for the transaction proxies. Assuming that the business manager for the domain object is also running the scheduling (and here could be my problem), the we need to make the manager call another manager which is wrapped by a transaction proxy to make the normally PROPAGATION_REQUIRED retrieve and update methods wrapped inside a new transaction.&lt;br /&gt;&lt;br /&gt;Trying to do this with Spring (at least with TransactionProxyFactoryBean methods), we get circular references which cause the context load to fail. Maybe this isn't the case anymore, but with Spring 2.0.2, this was still happening.&lt;br /&gt;&lt;br /&gt;Another option here is to us something similar to the DAO template method where we use transaction callbacks to do a segment of work inside a transaction of our choosing. Hang on I hear you say, shouldn't the code be unaware of transactions since that was the whole point of transaction demarcation? Well yes, you're correct, but this isn't exactly a very normal situation - and in this case the situation requires a different approach since the code algorithm is implicitly aware of the transaction boundaries.&lt;br /&gt;&lt;br /&gt;So in this solution, we create a transaction callback object, which would be a really basic interface with something like "TransactionCallback#execute()". This callback would then be passed to a TransactionManager... which would be wrapped by a transaction proxy. The TransactionManager would just have available methods like "executePropagationNew" and so forth.&lt;br /&gt;&lt;br /&gt;This is by no means a perfect solution, but should be one of the best available considering.&lt;br /&gt;&lt;br /&gt;Another possible solution would be to "break out" the scheduled methods from the relevant manager to a new manager. Still, even using this approach, the new manager would require the same implicit awareness of transaction boundaries and the resulting algorithm would be largely the same.&lt;br /&gt;&lt;br /&gt;I hope that all made some sense - if I've confused you horribly and something isn't clear, feel free to ask questions and I'll try fix this up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-2869712038988678947?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/2869712038988678947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=2869712038988678947' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2869712038988678947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2869712038988678947'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/scheduling-transaction-proxy-wrappers.html' title='scheduling &amp; transaction proxy wrappers'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-6649691178137027231</id><published>2007-05-10T16:27:00.000+10:00</published><updated>2007-05-10T16:40:13.357+10:00</updated><title type='text'>Serializable fumbling</title><content type='html'>Just a small post today; whilst working with &lt;a href="http://www.springframework.org/webflow"&gt;Spring Web Flow&lt;/a&gt; and &lt;a href="http://www.springframework.org"&gt;Spring's&lt;/a&gt; JSP &lt;a href="http://www.springframework.org/docs/api/org/springframework/web/servlet/tags/form/InputTag.html"&gt;form:input tag&lt;/a&gt;, I was noticing one of my fields going blank. Convinced my code was somehow not mapping correctly, I looked everywhere about, trying to work out why it wasn't being kept.&lt;br /&gt;&lt;br /&gt;I really should have noticed the significance sooner of the object reference changing between calls, even though in theory the object was instantiated only once. I think somewhere back in my mind I remembered a bit of a serializable issue once before, but unfortunately it didn't come up until after an hour of trying work out what was going wrong.&lt;br /&gt;&lt;br /&gt;And in the end, the problem turned out to be that I hadn't defined my parent class (which held the disappearing variable) to be serializable, but had just done it on my child class. In essence, I'd missed a step in a valid serializable path.&lt;br /&gt;&lt;br /&gt;Now, maybe I'm a bit cynical, but if a child class is defined serializable, isn't the parent implicitly serializable too? Obviously not, and thinking about it, I can sort of see why not since then someone could subclass something which was not designed to be serializable and whack on "implements serializable". I guess what I would have preferred happen is for the JVM to warn me about the potential issue here - maybe the Eclipse IDE should have too.&lt;br /&gt;&lt;br /&gt;It's nice to find an area of knowledge which I didn't even realise I was weak in and correct that, but the road to understanding isn't always as fun as I'd like... whoa, very zen;P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-6649691178137027231?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/6649691178137027231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=6649691178137027231' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/6649691178137027231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/6649691178137027231'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/serializable-fumbling.html' title='Serializable fumbling'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-4428878283747969311</id><published>2007-05-04T15:22:00.000+10:00</published><updated>2007-05-04T16:03:05.565+10:00</updated><title type='text'>format identification</title><content type='html'>AONS version 2, like the first version will be utilising &lt;a href="http://droid.sourceforge.net/"&gt;Droid&lt;/a&gt; and &lt;a href="http://hul.harvard.edu/jhove/"&gt;JHove&lt;/a&gt; for format identification. There is a bit of a catch 22 with regard to format identification tools and obsolescence/risk:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;People have, as far as I am aware, mainly written identifiers for well used formats&lt;/li&gt;&lt;li&gt;Formats which are most "at risk" will be lesser used and probably won't have identifiers&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;So, there is a large chance that neither Droid or JHove will be able to identify important, yet lesser used, formats. If there is a large chance that important yet obscure files in a repository cannot be identified, we probably should ensure that the result of a repository scan includes the location, number and all known signifiers (maybe extensions?) of these unidentified files. A very useful application (maybe AONS 2.X or maybe AONS 3.X) would also allow a user to view singular unidentified files.&lt;br /&gt;&lt;br /&gt;Now knowing that our repository crawl will give a metric for unidentified files, we should ensure that this metric is included when assessing the risk of obsolete documents within a repository - a repository with a high number of unidentified files should factor that in when viewing the obsolescence information.&lt;br /&gt;&lt;br /&gt;Also - I'm a little worried about JHove/Droid's reliability in file format identification - looking at &lt;a href="http://wiki.dspace.org/index.php/JhoveIntegration"&gt;this post&lt;/a&gt; on the DSpace wiki makes me wonder whether extension based identification would be imperfect yet doable solution.&lt;br /&gt;&lt;br /&gt;I think what I'll do is a bit of a combination approach:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Crawler gets a format resource as well as basic metadata about it (like location, full name, extension, mime type etc)&lt;/li&gt;&lt;li&gt;We have a list of format identifiers which will, for each, attempt to further identify the file (maybe determine version?) by using both the previous metadata and the actual file itself&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Once all "identifiers" have run against the file, the final metadata should be at least as good as it was when we began the identification&lt;/li&gt;&lt;li&gt;With this potentially improved metadata in hand, we'll try and look for internal formats (those in the deployed AONS system) which match&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Should a match be found between a repository format resource and an internal AONS format, we'll be able to link in the obsolescence information we have for that format. In the case where a link is not made, we will give the unidentified object, and any which have the same metadata the highest risk assessment possible.&lt;br /&gt;&lt;br /&gt;I'm also going to try put in place relatively easy methods for repository owners to create basic mappings between extensions and mime types so that niche formats are easily identified.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-4428878283747969311?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/4428878283747969311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=4428878283747969311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/4428878283747969311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/4428878283747969311'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/format-identification.html' title='format identification'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-8505518127261809373</id><published>2007-05-01T12:39:00.000+10:00</published><updated>2007-05-01T12:53:07.130+10:00</updated><title type='text'>Annotations - love to hate em</title><content type='html'>When annotations work, they really do feel nice. But when they don't, oh boy, the hurt they inflict can be quite horrible.&lt;br /&gt;&lt;br /&gt;I've been working with Compass and JPA annotations. I'm starting to get a bit better with Compass and was starting to do a bit more fine grained control over some of the fields which get stored but not indexed (via &lt;span style="font-family: courier new;"&gt;@Searchable(index=Index.NO)&lt;/span&gt;). Suddenly on a build I get the following error:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'registryDao' defined in ServletContext resource [/WEB-INF/spring/persistence-context.xml]: Cannot resolve reference to bean 'entityManagerFactory' while setting bean property 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/spring/persistence-context.xml]: Invocation of init method failed; nested exception is java.lang.IllegalAccessError: class sun.reflect.GeneratedConstructorAccessor11 cannot access its superclass sun.reflect.ConstructorAccessorImpl&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/spring/persistence-context.xml]: Invocation of init method failed; nested exception is java.lang.IllegalAccessError: class sun.reflect.GeneratedConstructorAccessor11 cannot access its superclass sun.reflect.ConstructorAccessorImpl&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Caused by: java.lang.IllegalAccessError: class sun.reflect.GeneratedConstructorAccessor11 cannot access its superclass sun.reflect.ConstructorAccessorImpl&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.misc.Unsafe.defineClass(Native Method)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:45)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:381)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at java.security.AccessController.doPrivileged(Native Method)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:377)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.MethodAccessorGenerator.generateConstructor(MethodAccessorGenerator.java:76)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:30)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at java.lang.reflect.Constructor.newInstance(Constructor.java:494)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:588)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.annotation.AnnotationParser.annotationForMap(AnnotationParser.java:239)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:229)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:69)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:52)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at java.lang.reflect.Field.declaredAnnotations(Field.java:1002)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at java.lang.reflect.Field.getAnnotation(Field.java:989)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at java.lang.reflect.AccessibleObject.isAnnotationPresent(AccessibleObject.java:175)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataHelper.isAnnotationPresent(MetadataHelper.java:653)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataHelper.isAnnotationPresent(MetadataHelper.java:668)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.MetadataAccessor.isAnnotationPresent(MetadataAccessor.java:377)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.ClassAccessor.isTransient(ClassAccessor.java:385)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.ClassAccessor.isValidPersistenceElement(ClassAccessor.java:408)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.ClassAccessor.isValidPersistenceField(ClassAccessor.java:417)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.ClassAccessor.processAccessorFields(ClassAccessor.java:525)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.ClassAccessor.processAccessors(ClassAccessor.java:552)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.ClassAccessor.process(ClassAccessor.java:483)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataProcessor.processAnnotations(MetadataProcessor.java:225)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:354)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:584)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createContainerEntityManagerFactory(EntityManagerFactoryProvider.java:178)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:204)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:242)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1118)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1085)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:429)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:250)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:141)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:247)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:161)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:245)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:124)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1019)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:809)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:425)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:250)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:141)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:247)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:161)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:273)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:346)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicationContext.java:156)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:246)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:184)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:49)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3763)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4211)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:759)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:739)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:524)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:809)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:698)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:472)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1122)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:310)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1021)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.StandardHost.start(StandardHost.java:718)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1013)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:442)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.StandardService.start(StandardService.java:450)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.core.StandardServer.start(StandardServer.java:709)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.Catalina.start(Catalina.java:551)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at java.lang.reflect.Method.invoke(Method.java:585)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:294)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:432)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;You'd think that some kind of sense would be made of that by a Java developer. But it's actually quite hard to begin digging for what was really going wrong:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;What was the class which caused the error?&lt;/li&gt;&lt;li&gt;What was the annotation being processed?&lt;/li&gt;&lt;/ul&gt;Trying to look into or step through the java.reflect package yields a "source not found". Finally, where to we look for answers - I was able to guess that this error was in one of my annotations for Compass which was a bit of a stab in the dark but worked, but this error could as likely be related to Compass, JPA/Toplink or Spring.&lt;br /&gt;&lt;br /&gt;So now having found the error - for some reason whenever I put on a "@SearchableProperty" on a member variable on one of my classes (it's just a plain old String variable...) I get this error. I've been able to workaround this error, but I can't see a way forward to identify which part of my technology stack is actually causing it - which makes the entire Java community all the poorer for it. If this is a common scenario in the community, are we headed for more fragile and confusing builds where debugging goes back to the opaque world it used to be.&lt;br /&gt;&lt;br /&gt;In case anyone thinks of it, I'm already using the InstrumentationLoadTimeWeaver instead of a RelfectiveLoadTimeWeaver due to previous JPA/Toplink + Tomcat errors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-8505518127261809373?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/8505518127261809373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=8505518127261809373' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8505518127261809373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8505518127261809373'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/05/annotations-love-to-hate-em.html' title='Annotations - love to hate em'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-7957375354090082079</id><published>2007-04-30T11:53:00.000+10:00</published><updated>2007-04-30T11:59:26.505+10:00</updated><title type='text'>JPA collections of basic objects</title><content type='html'>One small annoyance with &lt;a href="http://en.wikipedia.org/wiki/Java_Persistence_API"&gt;JPA&lt;/a&gt; is that when using collections with generics of basic objects (String, Long etc) we have to explicitly create a wrapper entity to contain them. On the one hand, this approach is a more pure DBA conceptualisation since we have to explicitly think about our domain objects and can't just assume it's a Java list - and I'm sure this will make things simpler in JPA queries - yet it's a bit of a nuisance for every list in the domain model to be extruded into a separate entity.&lt;br /&gt;&lt;br /&gt;It's a small annoyance, and if it makes the JPA queries easier to use then it's one we're probably going to have to live with;P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-7957375354090082079?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/7957375354090082079/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=7957375354090082079' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7957375354090082079'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7957375354090082079'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/04/jpa-collections-of-basic-objects.html' title='JPA collections of basic objects'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-8027772442633705163</id><published>2007-04-30T09:42:00.000+10:00</published><updated>2007-04-30T10:34:35.160+10:00</updated><title type='text'>Compass in hindsight</title><content type='html'>Okay, so now being a &lt;a href="http://jira.compassframework.org/browse/CMP-203"&gt;Compass&lt;/a&gt; veteran of at least a few days (har har, yeah okay, I'm still fumbling around in the dark), I think it's worth noting a few niggles I've found in it's usage:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Filtering results by class type is not easy within the index - I haven't yet tried it, but the issue is not covered in any of the supporting documents and this perspective is also reflected by this &lt;a href="http://jira.compassframework.org/browse/CMP-203"&gt;issue&lt;/a&gt; in Compass' JIRA installation. I'm pretty certain this is a common requirement. A workaround for this will be to maintain an index of all objects as a general search and also maintain indexes for each application domain object. Cumbersome, but should work (there are probably other methods of doing this by adding to the search string which I think I'll try out too).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Configuration error messages can be obtuse. Setting up the annotations necessary to get SearchableComponents will not be a simple job at first, and I found the error messages confusing. For one issue, which turned out to probably be a bug, I had to step through the code to see that setting root=false for a SearchableComponent was causing an error about mappings not being found.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Needs more examples on Collections - they do work, but the documentation does not give an actual example. Whenever I tried to get a SearchableComponent working which was a list and the component had no root, the list would fail - saying I should use generics when generics were in place (see the error message niggle).&lt;/li&gt;&lt;/ul&gt;Come to think of it, I think the (root=false) argument for a Searchable object probably just needs some rework in the Compass application. So, if you're going to use Compass as it stands at the moment, I'd avoid the (root=false) thingo altogether.&lt;br /&gt;&lt;br /&gt;Oh yeah, one more thing which I'm not 100% understanding is the position that Compass takes to try and "rehydrate" the object from the index. My preferred option will be to use my existing DAO to retrieve the object based on the ID of the object found... My gut feeling is that this is the main use case for this piece of middleware, yet the documentation and examples don't really discuss this.&lt;br /&gt;&lt;br /&gt;Hmmm, last thing, seriously. The GPS stuff in Compass is a little confusing - I'm using &lt;a href="http://www.springframework.org"&gt;Spring&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Java_Persistence_API"&gt;JPA&lt;/a&gt;; the Compass documentation is telling me I should be using the JPA GPS device, but I'm not exactly sure why - and if I do use this, how it changes any/all of the previous work I've done to integrate Compass. Moving on from the why, I'm not exactly sure how - though the written documentation is good, there is no example on integrating the JPA GPS device into a Spring application, just a few notes that it will not want a wrapped EntityManager.&lt;br /&gt;&lt;br /&gt;So I'm still groping around in the dark a bit with Compass - but it is better then dealing with Lucene by itself... well at least that's what I'm still pretty certain of... hmmm&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-8027772442633705163?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/8027772442633705163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=8027772442633705163' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8027772442633705163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8027772442633705163'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/04/compass-in-hindsight.html' title='Compass in hindsight'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-2475160499592061680</id><published>2007-04-26T09:24:00.000+10:00</published><updated>2007-04-26T09:49:44.500+10:00</updated><title type='text'>Compass for searching</title><content type='html'>It seems that every time an application is created we always get to that point where we have to implement a nice search box to, well, find stuff. Many questions come up here:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;how wide/specific should this search be (all domain objects or just one)&lt;/li&gt;&lt;li&gt;what kind of searching algorithm to use (literal matching or a relevance search algorithm similar to &lt;a href="http://www.rankforsales.com/search-engine-algorithms/google-hilltop-algorithm.html"&gt;Google's Hilltop Algorithm&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;Further, with REST as an exposed API into my application, how I'll translate a search on a REST CRUD object to an internal search will also be important.&lt;br /&gt;&lt;br /&gt;I'm about to implement searching of external registry formats - the formats which a deployed instance of the application has downloaded from an external source. I think this is an area where I can definitely over think the problem to something which is too complicated for practical usage... so I'm going to try keep the solution relatively lean.&lt;br /&gt;&lt;br /&gt;My goals here are to:&lt;br /&gt;1.) Make cross field searching the default&lt;br /&gt;2.) Keep the workload low&lt;br /&gt;3.) Ensure the solution can be integrated well with &lt;a href="http://www.springframework.org/"&gt;Spring&lt;/a&gt; and my existing transaction borders&lt;br /&gt;&lt;br /&gt;One nice little project which has come on my radar is &lt;a href="http://www.opensymphony.com/compass/"&gt;Compass&lt;/a&gt;; it seems to do all of the above and more, plus has a really good set of user documentation.&lt;br /&gt;&lt;br /&gt;So with Compass in hand, I'll see how I go.&lt;br /&gt;&lt;br /&gt;One area which I'm a little confused as to how I'll move forward is in relation to, well, relations. I'd personally like to use the relations between objects to raise profiles/relevancy, but I haven't seen if this is possible with Compass.&lt;br /&gt;&lt;br /&gt;Another area which I am unclear on is  working  the more traditional  manager find methods with something like Compass. Assuming that under the hood my application uses Compass for indexing and searching, does each manager make calls into compass for searches (to something like a CompassManager) and then we also need to expose a global search function for all domain objects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-2475160499592061680?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/2475160499592061680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=2475160499592061680' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2475160499592061680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/2475160499592061680'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/04/compass-for-searching.html' title='Compass for searching'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-8058066163805644187</id><published>2007-04-20T08:53:00.000+10:00</published><updated>2007-04-20T09:11:33.107+10:00</updated><title type='text'>JPA Experience</title><content type='html'>I've been using Toplink's JPA offering with HSQLDB as the databse platform. I'm really quite impressed with the offering as a whole:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Schema creation is a breeze&lt;/li&gt;&lt;li&gt;Annotations are pretty easy to use... I'm quickly getting hooked&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Really feels like I'm able to quickly develop my domain model as I grow the backend&lt;/li&gt;&lt;/ul&gt;I did have a few niggles getting the application working in deployment though. Actually you could say there were a few very frustrating problems but were luckily picked up on the Spring forums - I'm glad it wasn't me to first find some of the issues with Tomcat and Toplink classloading. And I've got mixed impressions on the Weavers offered in Spring for getting the annotations working - they seem to work... but could use a bit of improvement.&lt;br /&gt;&lt;br /&gt;The one big issue which I dislike is that I'm currently suckered with the InstrumentationLoadTimeWeaver which requires a -javaagent flag on my Tomcat startup. It's not the worst thing in the world, but I was hoping to get ReflectiveLoadTimeWeaver working but for some reason it wasn't picking up my annotations when combined with Tomcat/Toplink.&lt;br /&gt;&lt;br /&gt;I've put &lt;a href="http://forum.springframework.org/showthread.php?t=37563"&gt;the issue&lt;/a&gt; in the Spring forums, but so far no one has chimed in to either confirm they've had the issue or give me a pointer where I might be going wrong. I'm not crying sour grapes - help on the forum is only there if someone actually has the time to help and also the knowledge (and the issue is well written... maybe that's where I've gone wrong). Still, it feels horrible to still be suckered with that dang InstrumentationLoadTimeWeaver;)&lt;br /&gt;&lt;br /&gt;Maybe I should try that Spring 2.0.4... I'm still on Spring 2.0.2&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-8058066163805644187?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/8058066163805644187/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=8058066163805644187' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8058066163805644187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/8058066163805644187'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/04/jpa-experience.html' title='JPA Experience'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-6418539567113261811</id><published>2007-04-16T09:00:00.000+10:00</published><updated>2007-04-16T13:40:06.858+10:00</updated><title type='text'>Manually Exposing Business Methods with REST</title><content type='html'>&lt;p&gt;After disqualifying the existing Java libraries to expose my business methods via REST in &lt;a href="http://aons2dev.blogspot.com/2007/04/where-are-java-restful-libraries.html"&gt;this blog&lt;/a&gt;, I started on my path of exposing my business methods via REST with my own design. So how hard was it to create a RESTful endpoint to my application? Well not that difficult really. In fact I'm quite amazed I got through it so quickly (Maybe I'm too cynical but nothing like this is usually problem free). I'll try and go through how my controller works in a logical order of operation. Feel free to borrow or take wholesale any of this for your own REST solution... in theory my project is open source so it should be fine (I'll put up details of the license when we've got it finalised, but code snippets should be okay for now). Also, there was some refactoring from a pure "inhouse Servlet" solution to a "Spring Model 2 Controller/View solution", but I'll leave that out as a private "lessons learned".&lt;/p&gt;&lt;h2&gt;Tasks&lt;br /&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www2.blogger.com/post-edit.g?blogID=8752593855083431018&amp;postID=4896742608431675198#identifyTargetDomainObjectType"&gt;Identify the target RESTful domain object type&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www2.blogger.com/post-edit.g?blogID=8752593855083431018&amp;amp;postID=4896742608431675198#identifyTargetMethod"&gt;Identify the target method and override mechanism (for testing)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www2.blogger.com/post-edit.g?blogID=8752593855083431018&amp;postID=4896742608431675198#createMappingInterface"&gt;Create the mapping interface for a RESTful object to business managers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www2.blogger.com/pluralListsVirtualDomainObjectTypes"&gt;Plural ("lists") as virtual domain object types&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www2.blogger.com/post-edit.g?blogID=8752593855083431018&amp;amp;postID=4896742608431675198#bindingIncomingParameters"&gt;Binding incoming parameters&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www2.blogger.com/post-edit.g?blogID=8752593855083431018&amp;postID=4896742608431675198#errorHandling"&gt;Error handling&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id="identifyTargetDomainObjectType"&gt;Identify the target RESTful domain object type&lt;/h2&gt;The requirement here is that the portion of the URL after that identifying the target Servlet within the web archive should identify the domain object. So if we have a URL "http://localhost:8080/aons/rest/Registry" with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;http://localhost:8080&lt;/em&gt; identifying the server IP address and TCP port&lt;/li&gt;&lt;li&gt;&lt;em&gt;/aons&lt;/em&gt; identifying the web application&lt;/li&gt;&lt;li&gt;&lt;em&gt;/rest&lt;/em&gt; identifying the servlet&lt;/li&gt;&lt;li&gt;&lt;em&gt;/Registry&lt;/em&gt; identifying the target domain object&lt;/li&gt;&lt;/ul&gt;After refreshing my knowledge on all the little goodies in HttpServletRequest, I found the needed call in HttpServletRequest#getPathInfo(). We do have to remove the prefix forward slash, but apart from that, we've got a nice solid way of retrieving a target domain object type.&lt;br /&gt;&lt;br /&gt;So the code becomes:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;String pathInfo = request.getPathInfo&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;()&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;pathInfo == &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;  throw new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;RuntimeException&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"Servlet path information is null so we are unable to determine the domain object type."&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;domainObjectType = pathInfo.replaceFirst&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"/"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;""&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;logger.info&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"Domain object name is: " &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ domainObjectType&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;/blockquote&gt;Easy as pie (not to be confused with PI.. ba-doom-tish, chortle chortle):)&lt;br /&gt;&lt;p&gt;Okay, no more (bad) puns, I promise&lt;/p&gt;&lt;h2 id="identifyTargetMethod"&gt;Identify the target method and override mechanism (for testing)&lt;/h2&gt;Identifying the target method in a RESTful application is quite important - soo many applications don't place much thought or checking in what methods they accept, and usually that's fine. Not here - now we're making the method type dictate what kind of operation we're performing on the given REST domain object. So, getting the request type parameter - again, easy as pie thanks to HttpServletRequest#getMethod(). The only real item for consideration here is that we probably want to override the method type so developers can hand craft URLs to invoke RESTful methods. We do this below:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;            String methodType = request.getMethod&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;()&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request.getParameter&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"methodType"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;) &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;!= &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;String overridingMethodType = request.getParameter&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"methodType"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;logger.info&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"Overriding default method [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ methodType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"] with [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ overridingMethodType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"]"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                   &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;methodType = overridingMethodType;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Should the parameter methodType be included, we'll choose a different option then that included with from the HttpServletRequest#getMethod() call. I'm pretty certain there are security and caching considerations if this style of overriding was used in production so it's probably worthwhile putting in place a testing flag to disable this mechanism. Still, it is probably worthwhile a discussion  regarding the method override mechanism for doing more then the four CRUD options allow.&lt;br /&gt;&lt;h2 id="#createMappingInterface"&gt;Create the mapping interface for a RESTful object to business managers&lt;/h2&gt;This task is probably where most of the variation in different REST solutions exists. For my solution, I wanted to favour simplicity over extensibility: My interface basically just gives the domain object type it maps, and the four crud methods to invoke depending on the &lt;span class="code"&gt;methodType&lt;/span&gt;. So the initial interface is:&lt;br /&gt;&lt;blockquote class="code"&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Transformation class which maps a REST method for a&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* domain object to an underlying business object&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@author &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;DLEVY&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public interface &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;DomainHandler &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Retrieve the domain object type which this interface maps to&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@return &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;the domain object name handled&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;String retrieveDomainObjectName&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;()&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Handle client calls for a HTTP GET request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@param &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;request servlet request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@return &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;object requested of this domain type&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Object handleGet&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(63, 95, 191);"&gt; /**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Handle client calls for a HTTP PUT &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@param &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;request servlet request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@return &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;the identifier for the new object&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Long handlePut&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Handle client calls for a HTTP POST call which is typically updating&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@param &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;request servlet request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;void &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;handlePost&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Handle domain calls for HTTP DELETE call&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@param &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;request servlet request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;void &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;handleDelete&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;span style="color: rgb(255, 255, 255);"&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;At this point it's probably worthwhile mentioning some of the other options available to me in a solution. I could have used a mechanism which utilised reflection and annototations to seek REST methods on business objects. Whilst the benefits of annotations are definitely real, I figured that for my situation it was probably overkill since the above solution works pretty easily, is simple and nice and easy to understand. I could have also used a generic handler call for all method types like &lt;span class="code"&gt;handleCall(HttpServletRequest request, String methodType)&lt;/span&gt;. That would have left a specific handler to interpret the call and decide whether the operation could be performed. Again, it didn't really seem to make that much sense to do this - whilst it would have added another layer of abstraction the benefits would have been minimal. So in the end I went with this, and it's been going pretty well so far.&lt;br /&gt;In order to retrieve the handler in the &lt;span class="code"&gt;AonsRestController&lt;/span&gt;, we use a map abstraction mechanism:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Retrieve the intended domain object type&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Use the domain object type as a key in a map to the DomainHandler&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This code which retrieves the appropriate DomainHandler in AonsRestController can be seen below:&lt;br /&gt;&lt;/p&gt;&lt;blockquote class="code"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;singleDomainHandlerMap.containsKey&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;domainObjectType&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;DomainHandler handler = singleDomainHandlerMap.get&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;domainObjectType&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;String message = createAvailableDomainTypeString&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;domainObjectType&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;throw new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;RuntimeException&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;message&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;                &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;            &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;/blockquote&gt;An example of an implementation GET method for the Registry handler in AONS is like so:&lt;br /&gt;&lt;blockquote class="code"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Object handleGet&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;              &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Long registryId = handlerUtil.retrieveParameterAsLong&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request, &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"id"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;              &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;return &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;registryManager.retrieveRegistry&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;registryId&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;/blockquote&gt;&lt;p&gt;On the &lt;span class="code"&gt;DomainHandler&lt;/span&gt; we also put a method identifying which of the REST CRUD methods we implement, since not all domain objects will support the full stack:&lt;/p&gt;&lt;blockquote class="code"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Retrieve a list of methods we handle.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* The possible values returned here are:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* - GET&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* - PUT&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* - POST&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* - DELETE&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@return &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;list of possible values&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;List&lt;string&gt; retrieveHandledMethods&lt;/string&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;()&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;/blockquote&gt;To call this class, we have the following logic in our controller. It's very "if/else", but since we're only dealing with four operations, it was something where the cost of putting in an abstraction layer out weighed the benefit of doing so:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;!handler.retrieveHandledMethods&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;()&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.contains&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;methodType&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;throw new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;InvalidMethodTypeException&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"Can not perform method [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ methodType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"] on [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ domainObjectType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"], available methods " &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ handler.retrieveHandledMethods&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;())&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;                    &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(63, 127, 95);"&gt;// Okay, I could have used fancy reflection here&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(63, 127, 95);"&gt;// but at the end of the day, the if else block&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(63, 127, 95);"&gt;// really isn't too bad... and it's quite simple.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;methodType.equals&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;RestMethodTypes.DELETE&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;logger.info&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"We are performing a singular " &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ methodType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;" operation on [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+   domainObjectType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"]"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;handler.handleDelete&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;mv = &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;ModelAndView&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"NoReturnSuccessView"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, model&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;} &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;else if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;methodType.equals&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;RestMethodTypes.POST&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;logger.info&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"We are performing a singular " &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ methodType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;" operation on [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+   domainObjectType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"]"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;handler.handlePost&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;mv = &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;ModelAndView&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"NoReturnSuccessView"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, model&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;} &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;else if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;methodType.equals&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;RestMethodTypes.PUT&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;logger.info&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"We are performing a singular " &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ methodType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;" operation on [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ domainObjectType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"]"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;handler.handlePut&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;mv = &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;ModelAndView&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"NoReturnSuccessView"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, model&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;} &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;else if &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;methodType.equals&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;RestMethodTypes.GET&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;logger.info&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"We are performing a singular " &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ methodType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;" operation on [" &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;+ domainObjectType + &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"]"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Object object = handler.handleGet&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;model.put&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"object"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, object&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                      &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;mv = &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;ModelAndView&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"SingularGetSuccessView"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, model&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;                &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;/blockquote&gt;&lt;h2 id="pluralListsVirtualDomainObjectTypes"&gt;Plural ("lists") as virtual domain object types&lt;/h2&gt;&lt;p&gt;One "nice to have" identified was the ability to perform searching on domain objects. Since searching doesn't really fit into the four CRUD operations easily, I decided that I needed another mechanism to do this. I decided that when a person wants to do this in a RESTful world, they are really doing work on a virtual domain object. So for my code which concentrates on a Registry domain object, the plural Registries is the virtual domain object used for searching. The plural domain object only supports the GET call: no writes can be done at this level so PUT, POST and DELETE are all ignored. For convenience, I added the plural methods to the &lt;span class="code"&gt;DomainHandler&lt;/span&gt; interface rather then requiring creation of actual &lt;span class="code"&gt;DomainHandler&lt;/span&gt; implementations for these plural objects.&lt;/p&gt;&lt;p&gt;Below are the additional methods on &lt;span class="code"&gt;DomainHandler:&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;blockquote class="code"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Retrieve the plural version of this domain object for performing&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* GET lists of this object. If there is no plural version of this&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* domain object we just return null.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@return &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;plural object domain type for this handler&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;String retrievePluralDomainObjectName&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;()&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* Handle client calls for a GET plural request which is typically a search&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@param &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;request servlet request&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;* &lt;/span&gt;&lt;span style="color: rgb(127, 159, 191);"&gt;@return &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;list of desired objects which may be empty&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(63, 95, 191);"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;List handleGetPlural&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;The actual &lt;span class="code"&gt;AonsRestController&lt;/span&gt; uses this by having two key map objects, one for singular domain object types and one for the plurals. This was probably the more confusing part of the controller and I'll be looking to simplify it in future... but seems to work for now. The confusion is in working out in the controller if the domain object referenced is a singular or plural and then creating a pseudo CRUD method type GET_PLURAL. This pseudo CRUD method is internal only - the client still only passes a GET method with the plural domain object name.&lt;h2 id="bindingIncomingParameters"&gt;Binding incoming parameters&lt;/h2&gt;This was one of those things which could have been rather difficult, but since I was able to tap into &lt;a href="http://www.springframework.org/webflow"&gt;Spring Webflow's&lt;/a&gt; &lt;span class="code"&gt;WebDataBinder&lt;/span&gt;, the job was simplified significantly. The nice thing is that even nested properties aren't that difficult to get working - though I did find it annoying that it doesn't automatically create nested objects with a default constructor or allow for one to register a factory to perform this operation. In my scenario I found this out when trying to submit a new Registry object with a nested Schedule object inside it. I found I had to create the Schedule object &lt;em&gt;before&lt;/em&gt; performing the binding. For simpler structures, this isn't a big deal, but should input get relatively complex and be unknown at compile time it may pose an issues.&lt;br /&gt;&lt;br /&gt;Here's an example usage of the &lt;span class="code"&gt;WebDataBinder&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;void &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;handlePost&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;        &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Long registryId = handlerUtil.retrieveParameterAsLong&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request, &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"id"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;, &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;        &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Registry registry = registryManager.retrieveRegistry&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;registryId&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;        &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;WebDataBinder binder = &lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;WebDataBinder&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;registry, &lt;/span&gt;&lt;span style="color: rgb(42, 0, 255);"&gt;"registry"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;binder.bind&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;MutablePropertyValues&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;request.getParameterMap&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;()))&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;registryManager.updateRegistry&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;registry&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;/blockquote&gt;There was one issue with Spring's Webflow WebDataBinder: it would not automatically instantiate nested beans. So my Registry object has a Schedule object; this would have to be created by me before invoking the bind operation. Though I found a nice way to do this by checking for "schedule.*" parameters in the HttpServletRequest, it is something which should have been handled by the WebDataBinder. My attempts to fix/change the functionality in BeanWrapperImpl met with little success: The code changes really started to go &lt;a href="http://forum.springframework.org/showthread.php?t=37368"&gt;beyond a nice simple refactor&lt;/a&gt; with all the private, protected methods I would have needed to change. So, in the end, my final code block looks like this:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;public &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;void &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;handlePost&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;HttpServletRequest request&lt;/span&gt;&lt;span style="color:#000000;"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;Long registryId = handlerUtil.retrieveParameterAsLong&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;request, &lt;/span&gt;&lt;span style="color:#2a00ff;"&gt;"id"&lt;/span&gt;&lt;span style="color:#000000;"&gt;, &lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;Registry registry = registryManager.retrieveRegistry&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;registryId&lt;/span&gt;&lt;span style="color:#000000;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;createScheduleAsRequired&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;request, registry&lt;/span&gt;&lt;span style="color:#000000;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;WebDataBinder binder = &lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;WebDataBinder&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;registry, &lt;/span&gt;&lt;span style="color:#2a00ff;"&gt;"registry"&lt;/span&gt;&lt;span style="color:#000000;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;binder.bind&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;MutablePropertyValues&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;request.getParameterMap&lt;/span&gt;&lt;span style="color:#000000;"&gt;()))&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;registryManager.updateRegistry&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;registry&lt;/span&gt;&lt;span style="color:#000000;"&gt;)&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="color:#000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;private &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;void &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;createScheduleAsRequired&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;HttpServletRequest request, Registry registry&lt;/span&gt;&lt;span style="color:#000000;"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;Enumeration parameterNames = request.getParameterNames&lt;/span&gt;&lt;span style="color:#000000;"&gt;()&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;while &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;parameterNames.hasMoreElements&lt;/span&gt;&lt;span style="color:#000000;"&gt;()) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="color:#000000;"&gt;String parameterName = &lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;String&lt;/span&gt;&lt;span style="color:#000000;"&gt;) &lt;/span&gt;&lt;span style="color:#000000;"&gt;parameterNames.nextElement&lt;/span&gt;&lt;span style="color:#000000;"&gt;()&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;if &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#000000;"&gt;parameterName.startsWith&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#2a00ff;"&gt;"schedule"&lt;/span&gt;&lt;span style="color:#000000;"&gt;)) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="color:#000000;"&gt;registry.setSchedule&lt;/span&gt;&lt;span style="color:#000000;"&gt;(&lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;new &lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;Schedule&lt;/span&gt;&lt;span style="color:#000000;"&gt;())&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="color:#7f0055;"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="color:#000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#000000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="color:#000000;"&gt;}&lt;/span&gt;&lt;/blockquote&gt;&lt;p&gt;The solution isn't 100% perfect, but should do the job nicely for all I need&lt;/p&gt;&lt;h2 id="errorHandling"&gt;Error Handling&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;This wasn't actually as hard as it could have been, but was well worth doing. For error handling I want to ensure that any exceptions in the controller are caught and put inside a &lt;span class="code"&gt;ModelAndView&lt;/span&gt; object. This is then returned normally. The view which renders this then checks if it has a renderer for that exception or any of the superclasses of the exception. If it doesn't it rethrows the exception and lets the Servlet container render it. If we do have a renderer for that type of exception or it's superclass, then we render it as meaningfully as possible. It's a relatively simple and powerful mechanism and should mean we always give something back to a REST client which can be parsed. At the moment I've configured the application with a general exception handler for all top level exceptions and a few specific sub classes of &lt;span class="code"&gt;RuntimeException&lt;/span&gt; which should be handled (missing parameters and the like).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The only downside I can think of with doing this kind of thing is that by the time the View object has chosen to try render the exception, the contentType for the HttpServletResponse has been chosen. If we can't render the exception and rethrow it, then it's necessary for the contentType to be set again by the container. I'm not 100% certain if it is possible to change this more then once, but if the error is rethrown again and this has already been set, I'm not certain if the servlet can change this.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-6418539567113261811?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/6418539567113261811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=6418539567113261811' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/6418539567113261811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/6418539567113261811'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/04/manually-exposing-business-methods-with.html' title='Manually Exposing Business Methods with REST'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-4896742608431675198</id><published>2007-04-11T16:00:00.000+10:00</published><updated>2007-04-16T09:04:32.399+10:00</updated><title type='text'>Where are the Java RESTful libraries?</title><content type='html'>Where are the good Java RESTful libraries to help out with a typical application which already has business managers/facades and wants to expose them with REST? I came across these ones listed below but had to disqualify them:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://xfire.codehaus.org/"&gt;XFire&lt;/a&gt; - Only talk of REST in their issue manager, but don't have it listed as an implemented feature. I would have liked to use XFire since I've enjoyed their library for SOAP endpoints - though documentation is as usual the projects weakness.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.restlet.org/"&gt;Restlet&lt;/a&gt; - Strongly pushing the idea that everything from the business tier to the DAO is uneeded. Doesn't have anything which enables me to easily expose a relatively standard business interface with mappings to the CRUD operations.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://gomba.sourceforge.net/"&gt;Gomba&lt;/a&gt; - Ack, run away, run away, for the beast has been unleashed. The mission statement for that project is that modifying library code past APIs is good so why not do it from the beginning. Whilst there may be some virtue in that approach for prototypes which have &lt;em&gt;no&lt;/em&gt; possibility of life beyond a short project, it will pretty much ensure that any relativley standard library upgrades are painful. Reading this kind of project statement, I again wonder why a library designed to expose my application intends to give me any advice on how to structure my internals or my coding methodologies.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://incubator.apache.org/cxf/"&gt;Apache CXF&lt;/a&gt; - I wasn't really sure what to make of this project - it looks to be akin to &lt;a href="http://www.jboss.com/products/seam"&gt;JBoss' SEAM&lt;/a&gt; in that it will help you build applications from the ground up. It might be great, but I'm not going to bother learning an entire new integration framework for only one piece of the pie.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;So where does that leave me... well not in a very happy place. I'm quite loathe to have to do any &lt;em&gt;creation&lt;/em&gt; since this task should be answered by a solution in the industry/community - if RESTful methodologies really are popular there should be a pre-existing solution (maybe when JSR311 matures). Then I started chewing around a few ideas on how this kind of thing might work, and the more I thought about it, the easier it got. So as you'll see in the next section, I didn't end up using an existing library, but baked my own which has proved to be about a day and a half worth of work and covers the essential areas in a REST service:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;URL conventions and persistence&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Easy hand testing vi URL crafting&lt;/li&gt;&lt;br /&gt;&lt;li&gt;CRUD operations&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Plural "list" operations, for searching&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Exception wrapping&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Incoming parameter binding (thanks to reuse of WebDataBinder from the &lt;a href="http://www.springframework.org/webflow"&gt;Spring Webflow&lt;/a&gt; project)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-4896742608431675198?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/4896742608431675198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=4896742608431675198' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/4896742608431675198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/4896742608431675198'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/04/where-are-java-restful-libraries.html' title='Where are the Java RESTful libraries?'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-5759851688782294776</id><published>2007-03-21T13:57:00.000+11:00</published><updated>2007-03-21T14:00:51.327+11:00</updated><title type='text'>Creating Formats</title><content type='html'>Just a quick post to work through some potential methods for creating formats in our system:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;user driven&lt;/li&gt;&lt;li&gt;crawl driven&lt;/li&gt;&lt;/ol&gt;The more obvious case is user driven; as in the user creates a new format manually. The not so obvious answer is crawl driven, where the system would create empty formats in the case where a repository crawl found new formats. We will have to cater for both cases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-5759851688782294776?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/5759851688782294776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=5759851688782294776' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/5759851688782294776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/5759851688782294776'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/03/creating-formats.html' title='Creating Formats'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-1386791503229342223</id><published>2007-03-21T12:42:00.000+11:00</published><updated>2007-03-21T14:04:02.971+11:00</updated><title type='text'>REST methods and contextual help</title><content type='html'>&lt;h1&gt;Introduction&lt;/h1&gt;Yesterday we were asked by APSR to implement methods on the REST interfaces which would allow the end user to receive contextual help based on which page they were viewing. This issue, though not technically impossible or even difficult, raises the philosophical debate over what the REST/service interfaces intention purpose is.&lt;br /&gt;&lt;h1&gt;Background Information&lt;/h1&gt;&lt;p&gt;The AONS 2 application is an APSR funded application which is intended to work within the prototype federated architecture which will connect public registries together. Since initial discussions, it has been marked that AONS 2 will work not only within the federated architecture, but also in environments which are more traditional and closed. It is intended that APSR will create a remote GUI frontend, COSI (Collections Services and Infrastructures) for AONS 2 and other modules. This GUI frontend will handle conversational and session scope. The backend modules which AONS 2 is among will respond to calls from the APSR COSI frontend via REST services. On the COSI interface, it is intended that we have contextual help, depending on where the user is in the application (for example, step 3 of creating a new format).&lt;/p&gt;See &lt;a href="http://pilot.apsr.edu.au/wiki/index.php/AONS_II"&gt;AONS 2 Wiki&lt;/a&gt; for more information.&lt;br /&gt;&lt;h1&gt;Possible Solutions&lt;/h1&gt;&lt;p&gt;We have a few possible solutions to this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Expose help via contextual "page keys"&lt;/li&gt; &lt;li&gt;Do not expose any help methods&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Solution 1 - Expose Help&lt;/h2&gt;&lt;p&gt;This solution is not technically hard to do, but will be met with limited success. AONS 2 will be created with both the remote APSR COSI interface and also a local monolithic interface. Assuming that the same workflows are represented in each, it would not be difficult to create help for both. The only negative here is if the APSR COSI interface has different workflows then the core AONS 2 application. In this case, it would be wrong for the AONS 2 application to hold information about for workflows which it has no knowledge about. The important point to remember with this solution is that each of the user interface "steps" may not have a one-to-one mapping to a REST method. Going from best practices on web services, they should be relatively coarse grained and stateless (only request scope, not session or coversational). Therefore, it would only be possible to tie help to steps taken from AONS 2 monolithic interface.&lt;/p&gt;&lt;h2&gt;Solution 2 - Do Not Expose Help&lt;/h2&gt;&lt;p&gt;This is not as dire as it sounds. This solution simply acknowledges the idea that coarse grained REST methods should not be tied to user interface workflows. According to best practices, this is the ideal solution. If we are also developing user interfaces in parallel to those being developed by APSR, we should be able to give them a dump of any help we have developed an allow them to link it in to their own pages.&lt;/p&gt;&lt;h1&gt;Conclusion&lt;/h1&gt;I would have to say that I prefer solution 2 since it keeps the REST interfaces responsibility only with performing business logic and keeps conversational scoped help in that tier. However, seeing as solution 1 would not be a large piece of work to implement if our screens are the same (AONS 2 monolithic UI and APSR COSI UI) then it should be seen as a viable solution - &lt;i&gt;as long are we create the same workflows&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-1386791503229342223?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/1386791503229342223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=1386791503229342223' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/1386791503229342223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/1386791503229342223'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/03/rest-methods-and-contextual-help.html' title='REST methods and contextual help'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-7869263526528679648</id><published>2007-03-21T10:35:00.000+11:00</published><updated>2007-03-21T16:44:05.780+11:00</updated><title type='text'>Upstream Inconsistencies</title><content type='html'>&lt;h1&gt;Introduction&lt;/h1&gt;&lt;p&gt;Part of the function of AONS 2 is to utilise external registries of information which enables repository owners to make decisions regarding the obsolescence of a format. One of the inhibitors towards doing this is an inconsistent structure between different registries and what they offer. Further, a lack of a 100% consistent public unique identifier (PUID) means that we'll face issues even recognising that formats from different registries are one and the same. This post will discuss these two issues:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;How we will handle linkages between external formats with no guaranteed unifying identifier&lt;/li&gt;&lt;li&gt;How we will handle merges between vastly different data structures&lt;/li&gt;&lt;/ol&gt;&lt;h1&gt;Background Information&lt;/h1&gt;&lt;p&gt;Part of our work is to reference external sources (registries) of information to aid us in our judgment of obsolescence. It is assumed that in order to do this, a repository owner will utilise two types of information:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;External information which is usually subjective in nature are requires human decision making to turn into a format suitable for obsolescence rules.&lt;/li&gt;&lt;li&gt;Internal information which is objective and based on external subjective information (above).&lt;/li&gt;&lt;/ol&gt;The first information is utilised as the source for the second type. When the first type changes, we will need to re-evaluate the second. This implies:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;A clearly expressed link between internal objective rules and external subjective rules&lt;/li&gt;&lt;li&gt;A notification process when external subjective information changes which was used as the basis of internal objective information&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Easy to use application "flows" which allow users to work with these changes and re-evaluate them in a logical manor&lt;/li&gt;&lt;/ol&gt;&lt;h1&gt;Mismatching Identifiers&lt;/h1&gt;&lt;p&gt;The first big step is to link internal information objects to external subjective information. We have a few options here in how we'll do this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Auto-magically: Take the user out of the equation and just automatically look for matches in external registries. This is a "weak link" approach, is quite simple, but may serve the needs of our users. The main issue here is that with the PUID's not being 100% consistent a link which should be present it missed. Also, some repositories may only give us a name or mime type as the initial basis to create a format. In this case, we will &lt;span style="font-style: italic;"&gt;have&lt;/span&gt; to "help" the system identify what it is and make the linkage.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Explicitly defined: Make these linkages explicitly and manually enforced. A repository owner, on creating a new object (like an internal objective format) will have responsibility to search for external objects and link to them.&lt;/li&gt;&lt;li&gt;Combination approach: This approach uses a bit of a mix between the two approaches; first we auto-magically link to external subjective formats on object creation, but we also allow the user to manually change/affect these linkages.&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Solution 1 - Auto-magical Linkage&lt;/h2&gt;&lt;p&gt;Auto-magically would work, but exactly how is a bit unclear. An example algorithm would be:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;User begins creation of new internal objective object (like a format)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;User enters known fields (Name and/or PUID)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Auto-magic linking happens&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This process would not be too difficult to implement and may be all we need initially.&lt;/p&gt;&lt;h2&gt;Solution 2 - Explicitly Defined Linkage&lt;/h2&gt;&lt;p&gt;Explicitly defined would also work, but would require a bit more oversight from the user:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;User begins creation of new internal objective object (like a format)&lt;/li&gt;&lt;li&gt;User searches for "basis" external subjective objects&lt;/li&gt;&lt;li&gt;User accepts linkages&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Solution 3 - Combined Linkage Approach&lt;/h2&gt;&lt;p&gt;The combined approach is similar to the both steps, but it auto-magically searches for the linkages.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;User begins creation of new internal objective object (like a format)&lt;/li&gt;&lt;li&gt;User presented with "potential" linkages&lt;/li&gt;&lt;li&gt;User accepts linkages&lt;/li&gt;&lt;li&gt;User free to look for further linkages&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I think out of all of them, I like the combined approach the best - it fills in the fields as much as is possible but still gives the end user control of the whole process.&lt;/p&gt;&lt;h1&gt;Merge Disparate Datasets&lt;/h1&gt;&lt;p&gt;I think with the differences in offerings between various external registries we must be careful how we proceed with our merge strategy. We have to balance usefulness versus exponential application complexity.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Possible Solutions&lt;/h2&gt;&lt;p&gt;We currently have the following solutions to this problem:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Attempt to auto-magically merge external subjective repositories into internal objective objects which can be used for obsolescence rules&lt;/li&gt;&lt;li&gt;Evaluate each registry on its merits and provide partial auto-magical merging into internal objective formats.&lt;/li&gt;&lt;li&gt;Do not attempt to turn external subjective information into internal objective information, but instead ensure that external information is close at hand when users are making internal objective decisions to aid decision making.&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Solution 1 - Auto-Magically Merge&lt;/h2&gt;&lt;p&gt;I have used this approach before where datasets were so large that it removed the possibility that a user would have time to manually review any fix performed. This solution is less then ideal since it almost never can capture the intelligence of an end user and exponentially increases the complexity of the application logic.&lt;/p&gt;&lt;h2&gt;Solution 2 - Partial Merge&lt;/h2&gt;&lt;p&gt;This approach could work quite well, adding characteristics of solution 1 only where it was easy to do. The only problem with this as a solution is that different registries may offer suggestions on different fields, resulting in an uneven result.&lt;/p&gt;&lt;h2&gt;Solution 3 - No Merge&lt;/h2&gt;&lt;p&gt;This solution is probably one of the best we can aim for; it is simple and embodies the qualities of our project in that we only want to attempt functionality with a good return on investment but also gives the user enough usefulness to perform intelligent obsolescence rules.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I think of all of them, I like solution 3 the best: it's achievable and workable.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-7869263526528679648?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/7869263526528679648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=7869263526528679648' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7869263526528679648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7869263526528679648'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/03/working-with-upstream-inconsistencies.html' title='Upstream Inconsistencies'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8752593855083431018.post-7716847255081718114</id><published>2007-03-21T10:32:00.000+11:00</published><updated>2007-03-21T10:34:54.655+11:00</updated><title type='text'>AONS 2 Development Blog Created</title><content type='html'>Okay, in order to help refine ideas and also as a place to put things of interest, I've decided to put up an AONS 2 Developer blog. I'll aim to put up issues and crossroads as we face them. People reading this blog should also have a look at the &lt;a href="http://pilot.apsr.edu.au/wiki/index.php/AONS_II"&gt;AONS 2 Wiki&lt;/a&gt; which details more about the project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8752593855083431018-7716847255081718114?l=aons2dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aons2dev.blogspot.com/feeds/7716847255081718114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8752593855083431018&amp;postID=7716847255081718114' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7716847255081718114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8752593855083431018/posts/default/7716847255081718114'/><link rel='alternate' type='text/html' href='http://aons2dev.blogspot.com/2007/03/aons-2-development-blog-created.html' title='AONS 2 Development Blog Created'/><author><name>David Levy</name><uri>http://www.blogger.com/profile/16641056332221476985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
