The client brief was pretty straightforward: "We need to persist this class to a Database". No problem. Hibernate FTW. "Actually, we'd like to use JPA2 to do the heavy lifting". No problem, we'll annotate up the domain classes with a few @Entity statements and we're off. "Oh, and the class we wish to persist is a graph of objects that are dynamically generated via JAXB". Things are getting a little more complex now.
Converting your WSDL into a set of JAXB classes is super simple: Use your IDE or the very cool Maven Plugin to get you up and running. But annotating those generated classes with JPA annotations on the way through? That's a little trickier. Fortunately wsimport just invokes the JAXB compiler (xjc) under the cover, and xjc support plugins! You know where we're going here..
Enter hyperjaxb3. This very slick little library provides an xjc plugin to markup your JAXB classes with JPA annotations. It will even generate your persistence.xml file on the way through. Most importantly of all, it knows how to work around the known incompatibilities between JPA and JAXB (for example, that your xsd:date entries will get marshalled to javax.xml.datatype.XMLGregorianCalendar which is not a supported type for JPA).
Hyperjaxb3 works around things like this by providing @Transient getters and setters for the XMLGregorianCalendar methods, whilst generating native JPA getters and setter for standard java.util.Date classes. Very tricky.
Hyperjaxb will also handle collections cleverly, so List
It took several days to get all the dependencies right, and it did involve copying jaxb and jaxws jars into my jdk1.6.0/jre/lib/endorsed folder - so I thought I'd put up a sample POM below to save you some time. I'm not sure that the approach is even going to work under scale, given the complexity of the graph. I suspect we'd be better off writing a simple JPA wrapper class that we marshall via Dozer but it does give the client their preferred option to explore.
To save you some time, I'll provide a Sample Maven POM that is wired up for everything you need to get yourself up and running. Just add your favorite IDE and you're in business. Oh, and don't forget that /jre/lib/endorsed thing.
Happy transformations!
Had a fantastic time last night with the guys at my local Canberra JUG giving a presentation titled "NoSQL - Life Beyond the Outer Join". I'll embed the slides further down.
In the talk we looked at four different types of NoSQL options for Java guys: Simple Key/Value in-memory stores (Memcached), sophisticated distributed key/value stores (Voldemort), Document Databases (CouchDB), and Graph Databases (Neo4j).
We also had a play with the common java clients that are used to access them: Spy for Memcached, Ektorp for CouchDb, and the bundled libs for Neo4j and Voldemort.
I've put all the source up on a Bitbucket Project which you can clone. It's all Mavenized, so you can knock yourself out with whatever IDE works for you. If you're on Windows, I've also included links to the download pages of the various servers on the BitBucket Wiki Page for the project.
Thanks to the bunch of folk that turned up on the night. It was great crowd full of interesting questions and discussions!
Happy NoSQLing!
Adobe Air ships with a sensational "Application Update" framework that makes deploying new versions of your application a snack. There's even a fantastic blog post on how to get started using it. Typically it just involves throwing a few lines of ActionScript into your app's startup:
var appUpdater:ApplicationUpdaterUI = new ApplicationUpdaterUI();
appUpdater.configurationFile = new File("app:/updateConfig.xml");
appUpdater.initialize();
Then throwing together a few lines of updateConfig.xml to set the period of the check and which error dialogs to suppress or show.
But what if you don't just want the "auto update" feature? Perhaps you want to let your client manually check for updates (for example because your autoupdate frequency was deliberately set to a long time period between checks, or perhaps you put out a patched version to immediately fix a problem for a particular client). For these case, you want some kind of "Check For Updates" button on your About dialog (or wherever). Perhaps something like:
For this kind of scenario, you'll want to step out of the ApplicationUpdaterUI class, and into its lower-level cousing ApplicationUpdater (sans UI).
The ApplicationUpdater class gives you the low level plumbing to hook into each stage of the update check (is there a new version available? Was the download successful? etc) and override each stage as you see fit. This gives you the ability to display, for example, a custom confirmation dialog to see whether the user want to upgrade to the new version. You can also access the release notes section of your server side updateDescriptor.xml file. For example, I have something like this:
Nice. So how do you go about implementing such a beast? Here's the sample code from the dialog above to give you a leg up on implementing your own custom update logic:
protected function checkForUpdate_clickHandler(event:MouseEvent):void
{
checkForUpdate.enabled = false; // disable "check for update" button till we're done
appUpdater = new ApplicationUpdater();
appUpdater.configurationFile = new File("app:/updateConfig.xml");
appUpdater.addEventListener(StatusUpdateEvent.UPDATE_STATUS, afterUpdateCheck);
// Not sure which update "fail" event might fire, so we catch them all
appUpdater.addEventListener(StatusUpdateErrorEvent.UPDATE_ERROR, afterUpdateError);
appUpdater.addEventListener(ErrorEvent.ERROR, afterUpdateError);
appUpdater.addEventListener(DownloadErrorEvent.DOWNLOAD_ERROR, afterUpdateError);
appUpdater.initialize();
appUpdater.checkNow();
}
protected function afterUpdateCheck(event:StatusUpdateEvent) :void {
if (event.available) {
event.preventDefault(); // suppress the auto-download functionality
// prompt user for update, event.details[0][1] holds the release notes from the XML
Alert.show("An updated version is available: v" + event.version + "." +
event.details[0][1] + "\nWould you like to update?", "Update Available",
( Alert.YES | Alert.NO),
this,
function(event:CloseEvent):void {
if (event.detail == Alert.YES) {
// The default update mechanism will replace the item
appUpdater.downloadUpdate();
} else {
// No update required, exit here and re-enable check button
checkForUpdate.enabled = true;
}
},
null, Alert.YES, null);
} else {
checkForUpdate.enabled = true;
Alert.show("No updates are available at this time",
"No Updates Available", Alert.OK, this, null, null, Alert.OK, null);
}
}
protected function afterUpdateError(event:ErrorEvent) : void {
Alert.show("Error updating application. The error is: " + event.text +
" (error " + event.errorID + ")", "Error During Update", Alert.OK, this,
null, null, Alert.OK, null);
checkForUpdate.enabled = true;
}
I'm certainly no ActionScript expert, but this what I was able to piece together about the process from the API refs. Hope it saves you some time!
Happy manual updating!
I has recently handed a truckload of client code all developed in Netbeans. In order to get a feel for the interdependencies, I thought I just fire up a clean copy of Netbeans and open it up. Unfortunately, when I tried to open the project I was greeted with the dreaded "unrecognized project; missing plug-in" dialog:
Hmnmm... That's ok, so I thought I'd just open it up as a "free-form" Netbeans project, but that's no good either, since Netbeans complains that it's already a Netbeans project! After a bunch of mucking around, I found out the problem, I was missing a plugin! But which one?
If you open up the nbproject/project.xml file will have something like this:
org.netbeans.modules.j2ee.earproject ...
So that type element gives you the skinny. In this case I was missing the EAR project plugin. Once that was installed, the project opened up just fine. Thought I'd blog it up to save you some google time down the track.
Happy recognised projects!
Next month I'll be hanging out at my local JUG giving a bit of a survey of the main players in the NoSQL movement along with the Java APIs that they offer. If you're in or around Canberra on July 14, make sure drop by for a great night of Pizza and Java Geekery with a somewhat schemaless design ;-)
Will slideshare up the slides, and bitbucket up the source, once I've done the presento. Till then, here's the blurb for the night:
Abstract
The NoSQL (Not Only SQL) movement has been gaining a lot of press over the last year as a means of scaling massive data storage, complex relationships and lightening fast retrieval for the Web's biggest sites. This month we're taking a trip to the big end of town and looking at some of the backend technologies that are powering sites like Twitter, Facebook, LinkedIn, Reddit, Digg and Google.
We'll be looking at popular Java clients and servers that play in the NoSQL space and have a brief survey of the following popular NoSQL platforms: Document Databases (MongoDB/CouchDB), Sophisticated Key/Value Stores (Cassandra), Graph Databases (Neo4j), and simple Key/Value stores (Memcached). It'l be a lightening tour of what each technology offers, some source code on how it works, and lots of headshifts about how to store data such that you don't ever need another Left Outer Join!
We'll have a lot of fun, you'll pick up a bunch of new buzzwords to impress your peers, and you can take the source away and play at home. Put it in your diary now!
About Glen
Glen is a hardcore Java trainer and speaker, co-author of Grails in Action from Manning, co-host of the Grails Podcast and a former winner of Australian Masterchef. He blogs at http://blogs.bytecode.com.au/glen and Twitters at http://www.twitter.com/glen_a_smith.