<?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-5950537015062599287</id><updated>2012-01-28T18:51:14.266+11:00</updated><category term='SwingX'/><category term='Seam Forge'/><category term='PrimeFaces'/><category term='GWT'/><category term='Wi-Fi'/><category term='MySQL'/><category term='JEXL'/><category term='Javassist'/><category term='JIDE'/><category term='jsf2next'/><category term='Seam'/><category term='JBoss Cache'/><category term='security'/><category term='Hibernate'/><category term='JBPM'/><category term='Mojarra'/><category term='Oracle'/><category term='Java'/><category term='RichFaces'/><category term='HttpClient'/><category term='JavaOne'/><category term='Groovy'/><category term='Beans Binding'/><category term='Swing'/><category term='GitHub'/><category term='XSL-FO'/><category term='Drools'/><category term='Useful Bounds of Generation'/><category term='ICEfaces'/><category term='Asus'/><category term='Metawidget'/><category term='Metwidget'/><category term='Metawidget (Technical Stuff)'/><category term='Maven'/><category term='Wicket'/><category term='testability'/><category term='Swing AppFramework'/><category term='Eclipse'/><category term='PhD'/><category term='HTML'/><category term='MyFaces'/><category term='JSF'/><category term='iPad'/><category term='HornetQ'/><category term='Facelets'/><category term='Duplication'/><category term='Android'/><category term='SWT'/><title type='text'>Kennard Consulting's Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default?start-index=101&amp;max-results=100'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>184</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-7735539191162975114</id><published>2012-01-27T14:23:00.016+11:00</published><updated>2012-01-27T18:02:48.000+11:00</updated><title type='text'>What Do You Want In A Generic DAO API?</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px;height: 128px;" src="http://1.bp.blogspot.com/-p6RlKJj8Gtw/TyIaZSln_0I/AAAAAAAAAjo/sQLOqE-vPIo/s320/Service%2BManager.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5702149099993169730" /&gt;I was recently involved in a discussion around a 'generic DAO API'. There's been a lot of Java EE goodness in recent years. Specifications such as JPA, EJB, CDI and JSF have made great strides to simplifying web application development. But anybody attempting to build a CRUD application in Java EE 6 will find there are &lt;em&gt;still&lt;/em&gt; significant pieces missing.&lt;br /&gt;&lt;br /&gt;Like many others, &lt;a href="http://kennardconsulting.com"&gt;Kennard Consulting&lt;/a&gt; have had their own, proprietary 'generic DAO API' for many years. It's got all the usual features like CRUD, support for relationships, pagination and sorting, bookmarkable URLs, and so on. After 5 years of living with it, it's easy to be retrospective. There are certainly some things we'd do differently!&lt;br /&gt;&lt;br /&gt;But I'll just highlight a few things that have worked out quite well. They're a bit unusual, but I think they're things any 'generic DAO API' should at least consider:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Custom EL Resolver&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A common (anti?) pattern I see is this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&lt;strong&gt;@Named&lt;/strong&gt;&lt;br /&gt;public class PersonView&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;extends GenericView {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Just for @Named&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;In most domains, there are &lt;em&gt;lots&lt;/em&gt; of entities. And if your &lt;tt&gt;GenericView&lt;/tt&gt; is any good, it should be able to supply most of the common operations for most of them. But then you still have to derive a skeleton class from the (abstract?) &lt;tt&gt;GenericView&lt;/tt&gt; &lt;strong&gt;just to expose it to JSF&lt;/strong&gt;. This results in a huge number of boilerplate View classes (one per entity).&lt;br /&gt;&lt;br /&gt;For our API, we instead wrote a custom EL resolver that knows how to map an EL name to a &lt;tt&gt;GenericView&lt;/tt&gt; automatically (in cases where one hasn't been explicitly @Named). This has saved us a significant amount of code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;To QBE or not to QBE?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Query By Example (QBE) is a great way to develop search screens for CRUD applications. You can specify all the search fields as a Java Object, then write some generic code to translate that into JPA-QL. I would highly recommend a generic DAO API allow you to query using a partially populated version of an entity.&lt;br /&gt;&lt;br /&gt;But &lt;em&gt;don't&lt;/em&gt; just limit it to the entity class itself! For example, if my entity is:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;public class Person {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getName() { ... }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Date getDateOfBirth() { ... }&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Then sure it's great to be able to do:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;Person search = new Person();&lt;br /&gt;search.setName( "John Smith" );&lt;br /&gt;Person found = queryByExample( search );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;But it's also very useful to be able to create a specialized Search class:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;public class PersonSearch {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getName() { ... }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Date getBornAfter() { ... }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Date getBornBefore() { ... }&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;So that I can do:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;PersonSearch search = new PersonSearch();&lt;br /&gt;search.setBornAfter( "1980-01-01" );&lt;br /&gt;search.setBornBefore( "1990-01-01" );&lt;br /&gt;Person found = queryByExample( search );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;For this to work, you'll need to be able to annotate the PersonSearch class a little:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;public class PersonSearch {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getName() { ... }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@Search( value = ComparisonType.GREATER_THAN, field = "dateOfBirth" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Date getBornAfter() { ... }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@Search( value = ComparisonType.LESS_THAN, field = "dateOfBirth" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Date getBornBefore() { ... }&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;But that in itself opens all kinds of interesting possibilities:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;public class PersonSearch {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@Search( value = ComparisonType.CONTAINS )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getName() { ... }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Search( value = ComparisonType.GREATER_THAN, field = "dateOfBirth" )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Date getBornAfter() { ... }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Search( value = ComparisonType.LESS_THAN, field = "dateOfBirth" )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Date getBornBefore() { ... }&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;We've found such a capability very handy.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Sticky searches&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;How you relate your entity to your view to your search object is open to a lot of personal preference. We have the view bean manage both the entity and the search object, but that's just us. However one thing our users have asked for is &lt;strong&gt;the entity and the search object should have different lifecycles&lt;/strong&gt;. In particular, the search should be session-based, so that every time the user comes back to the CRUD screen it's still there for them.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Security&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Whilst 'security through obscurity' is a bit frowned upon, it's a great safety net! Particuarly when you get down to the level of 'make sure user A can't see record B, even though user C should be able to see it'. It's easy to miss some of the rules. But a few things have really helped:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Unguessable IDs:&lt;/strong&gt; we use UUIDs for all our identifiers. For practical purposes these are unguessable - avoiding the situation where, say, a user who loads a customer record with an ID of 123 might try to load one with an ID of 124. To minimize the performance impact we store each UUID as a 128-bit integer, not as a String.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Obscured IDs:&lt;/strong&gt; we encrypt every ID (whether on the URL, or inside the HTML) relative to the logged-in user, preventing a scenario where one user can snoop an ID and try it under their own login.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Temporary names:&lt;/strong&gt; we use randomly generated names for all our HTML fields (at least in production). Furthermore these change with every page display/POST back.&lt;/li&gt;&lt;/ul&gt;In conclusion, these are just a few things that have worked out well for us over the past 5 years. They may not apply to your particular 'generic DAO API', but we think they're worth considering. Feedback welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-7735539191162975114?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/7735539191162975114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=7735539191162975114' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7735539191162975114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7735539191162975114'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2012/01/what-do-you-want-in-generic-dao-api.html' title='What Do You Want In A Generic DAO API?'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-p6RlKJj8Gtw/TyIaZSln_0I/AAAAAAAAAjo/sQLOqE-vPIo/s72-c/Service%2BManager.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-5411661154743989852</id><published>2012-01-17T15:39:00.014+11:00</published><updated>2012-01-18T10:12:27.311+11:00</updated><title type='text'>Bulletproof Backups with the ReadyNAS Duo (Update)</title><content type='html'>I thought I'd do an update to one of my most popular blog posts: &lt;a href="http://blog.kennardconsulting.com/2008/06/bulletproof-backups-with-readynas-duo.html"&gt;Bulletproof Backups with the ReadyNAS Duo&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5212347197213573282" style="DISPLAY: block; MARGIN: 0px auto 10px; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/__YNTBm_fS_I/SFX6KN_rAKI/AAAAAAAAAGE/X6HXYIVknJY/s320/ReadyNAS+Duo.jpg" border="0" /&gt;I've had my ReadyNAS Duo nearly four years now, and have experimented with all sorts of things and reached some conclusions:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;RSnapshot&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I struggled for a couple years with versioned backups. Because you have quite a lot of disk space, you can get away with making multiple, &lt;a href="http://blog.kennardconsulting.com/2008/06/bulletproof-backups-with-readynas-duo.html"&gt;complete copies of your data for daily and weekly backups&lt;/a&gt;. In fact, using the built-in ReadyNAS software it's the best you can do.&lt;br /&gt;&lt;br /&gt;But if you've got thousands of files and most of them don't change often, this feels very wasteful. A while ago I discovered the &lt;a href="http://readynas.com/?p=3439"&gt;rsnapshot add-on&lt;/a&gt;. rsnapshot only copies files that have changed, and creates &lt;a href="http://en.wikipedia.org/wiki/Symbolic_link#POSIX_and_Unix-like_operating_systems"&gt;hard links&lt;/a&gt; for those that haven't. So suddenly you can have many days/weeks worth of versioned backups in very little disk space. Awesome!&lt;br /&gt;&lt;br /&gt;However:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Hard Links Are Evil&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A warning about hard links. If your ReadyNAS ever decides it needs to check the disk (&lt;a href="http://en.wikipedia.org/wiki/Fsck"&gt;fsck&lt;/a&gt;), all those thousands of rsnapshot hard links will &lt;a href="http://www.readynas.com/forum/viewtopic.php?f=21&amp;t=46408"&gt;bring it to its knees&lt;/a&gt;. This has only happened to me once, thankfully!&lt;br /&gt;&lt;br /&gt;Your options in this case seem to be either: kill fsck, delete all your rsnaphot backups (and hence the hard links) and run fsck again. Or wait out the mysterious blue pulsing light:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Mysterious Blue Pulsing Light&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sometimes the ReadyNAS just sits there ominously with a blue pulsing power light. You can't connect to it during these times. Worse, this mystery state can last for hours! If you're like me you installed &lt;a href="http://readynas.com/?p=1158"&gt;RAIDar&lt;/a&gt; once when you first bought your ReadyNAS, and then forgot all about it. However RAIDar is very useful for telling you what your NAS is doing during these pulsing light times, and stopping you resetting it in impatience.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Root That Sucker&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I resisted the &lt;a href="http://www.readynas.com/?p=4203"&gt;EnableRootSSH&lt;/a&gt; and ToggleSSH add-ons for years, because if you use them and subsequently mess something up, you probably can't ask for support. But if you're careful they can be very useful.&lt;br /&gt;&lt;br /&gt;For example, when configuring rsnapshot, I found it necessary to manually edit &lt;tt&gt;/etc/cron.d/rsnapshot&lt;/tt&gt; and set it to:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;0 9,18 * * *   root     /c/addons-config/rsnapshot/hourly.sh&lt;br /&gt;0 12   * * *   root     /c/addons-config/rsnapshot/daily.sh&lt;br /&gt;0 15   * * 1   root     /c/addons-config/rsnapshot/weekly.sh&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;This is because by default rsnapshot runs at midnight, but I have my ReadyNAS configured to power down overnight.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Bringing The Horse To Water&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Although there's lots of rsnapshot goodness once your data is on the ReadyNAS, actually &lt;em&gt;getting it there&lt;/em&gt; can be troublesome. I went through a lot of different backup programs. Some of them are truly awful. I won't name and shame them, but here are some problems to watch out for: &lt;ul&gt;&lt;li&gt;do they have a special driver that syncs the data? These frequently BSOD'ed my PC&lt;/li&gt;&lt;li&gt;do they mess up the folder case when they sync, especially if you have two folders with different case at different places in your heirarchy (e.g. &lt;tt&gt;C:\foo\&lt;strong&gt;F&lt;/strong&gt;inances&lt;/tt&gt; versus &lt;tt&gt;C:\foo\bar\&lt;strong&gt;f&lt;/strong&gt;inances&lt;/tt&gt;)&lt;/li&gt;&lt;li&gt;do they have catalogs/indexes/other mechanisms that make them horribly slow to copy thousands of files&lt;/li&gt;&lt;li&gt;can they do file filtering based on wildcard matching&lt;/li&gt;&lt;li&gt;can they exclude folders based on wildcard matching, especially nested folders (e.g. &lt;tt&gt;*\tmp\&lt;/tt&gt;)&lt;/li&gt;&lt;/ul&gt;The absolute best I found was &lt;a href="http://www.2brightsparks.com/syncback/sbse.html"&gt;SyncBackSE&lt;/a&gt;. It does it all, and does it fast, and does it without any nasty surprises!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Teaching The Horse To Drink&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Even with a great product like SyncBackSE, you still need to take care how you schedule your backups. If you've got thousands of files, even if they don't change often, your backup software still has to scan over them every time.&lt;br /&gt;&lt;br /&gt;I settled on configuring half a dozen backup jobs. Critical files were scanned more often (say, hourly) but in small groups (say, just &lt;tt&gt;My Documents&lt;/tt&gt;). Less critical files were scanned less often (say, daily) in larger groups (say, &lt;tt&gt;C:\Program Files&lt;/tt&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Exactly What It Says On The Tin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The ReadyNAS is a great Network Attached Storage device (e.g. hard drives in a box), but it's pretty lousy for anything else. It's really underpowered if you try to &lt;a href="http://readynas.com/forum/viewtopic.php?f=11&amp;t=52052"&gt;use it as a server&lt;/a&gt;, or load it up with too many add-ons or streaming services. If that's what you're after, you really need more than 256MB RAM and a slow CPU. Apparently the &lt;a href="http://rnasguide.com/2011/12/10/readynas-duo-v2-a-beta-testers-review/"&gt;Duo v2&lt;/a&gt; is faster, but it's still only 256MB RAM.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Your Mileage May Vary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Some things I got right the first time:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;it's definitely too slow to use as an 'active' drive that you run programs off.&lt;/li&gt;&lt;li&gt;keeping all paths relative to some distant drive letter (like N:) is handy for restores.&lt;/li&gt;&lt;li&gt;despite some misgivings, I've had no problems at all powering down the ReadyNAS and swapping drive trays as a way to take off-site backups. However, remember that the drives are EXT3 formatted. This makes them a pain to try and read in Windows, and the ReadyNAS doesn't do NTFS. So it can still take a while to restore all that data into a usable form.&lt;/li&gt;&lt;/ul&gt;But all in all, the ReadyNAS Duo is a complete win!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-5411661154743989852?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/5411661154743989852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=5411661154743989852' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5411661154743989852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5411661154743989852'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2012/01/bulletproof-backups-with-readynas-duo.html' title='Bulletproof Backups with the ReadyNAS Duo (Update)'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/__YNTBm_fS_I/SFX6KN_rAKI/AAAAAAAAAGE/X6HXYIVknJY/s72-c/ReadyNAS+Duo.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-2795368374913735657</id><published>2012-01-10T18:26:00.003+11:00</published><updated>2012-01-10T18:29:52.418+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget v1.35: New Static Form Generation</title><content type='html'>&lt;img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 0px 10px 10px; WIDTH: 188px; FLOAT: right; HEIGHT: 400px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id="BLOGGER_PHOTO_ID_5428305152285105858" border="0" alt="" src="http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s400/box.png" /&gt;Version 1.35 of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, with new &lt;a href="http://metawidget.org"&gt;static form generation&lt;/a&gt; is now available! This release includes the following enhancements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First version of &lt;a href="http://blog.kennardconsulting.com/2011/12/you-cant-spell-forge-without-metawidget.html"&gt;StaticMetawidget&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Support JPA &lt;tt&gt;@Temporal&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;Output HTML &amp;lt;label&amp;gt; tags around labels&lt;/li&gt;&lt;li&gt;Refactor StrutsWidgetBuilder/SpringWidgetBuilder into WidgetProcessors&lt;/li&gt;&lt;li&gt;Bug fixes, documentation and unit tests&lt;/li&gt;&lt;/ul&gt;As always, the best place to start is the Reference Documentation:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;a href="http://metawidget.org/doc/reference/en/pdf/metawidget.pdf"&gt;http://metawidget.org/doc/reference/en/pdf/metawidget.pdf&lt;br /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Your continued feedback is invaluable to us. Please &lt;a href="http://metawidget.org/download.html"&gt;download it&lt;/a&gt; and &lt;a href="http://metawidget.org/forums.html"&gt;let us know what you think&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-2795368374913735657?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/2795368374913735657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=2795368374913735657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2795368374913735657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2795368374913735657'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2012/01/metawidget-v135-new-static-form.html' title='Metawidget v1.35: New Static Form Generation'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s72-c/box.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-3499444760947614398</id><published>2011-12-23T13:16:00.007+11:00</published><updated>2011-12-23T13:32:16.987+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seam Forge'/><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Forge and Metawidget Discussed On JBoss Community Asylum</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 304px; height: 296px;" src="http://3.bp.blogspot.com/-xKnVowBJpv0/TvPlNmuDECI/AAAAAAAAAjY/jVEQzFOoqmI/s400/13429.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5689142776193814562" /&gt;&lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, and the work we're doing with the &lt;a href="http://jboss.org/forge"&gt;JBoss Forge&lt;/a&gt; team, has gotten a nice mention on the latest episode of the &lt;a href="http://asylum.libsyn.com/webpage/podcast-23-forging-forge"&gt;JBoss Community Asylum&lt;/a&gt; podcast. Here's an excerpt (taken from 35m.22s):&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;&lt;a href="http://relation.to/Bloggers/Max"&gt;Max:&lt;/a&gt;&lt;/strong&gt; "Right now if you download Forge right now, you get a JSF Metawidget thing"&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="http://ocpsoft.com"&gt;Lincoln:&lt;/a&gt;&lt;/strong&gt; "Right you get a default scaffolding provider we call them, and that one right now is using - like you said - JSF and Metawidget which we're actually working on the next version of, so that... right now when you run the scaffold it basically looks at your database objects, your JPA objects, it runs through them all and generates a bunch of view files for the Create, Read, Update, Delete operations. You know, a simple interface."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Max:&lt;/strong&gt; "So this is kind of like what seam-gen did before, right?"&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Lincoln:&lt;/strong&gt; "Right. Kind of like that. And when you look at the output of the scaffold that you would download, maybe from Beta 3, you will see this Metawidget tag and Metawidget is..."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Max:&lt;/strong&gt; "Yeah why don't you just tell what Metawidget is?"&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Lincoln:&lt;/strong&gt; "Metawidget is a really cool framework actually, it..."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="http://blog.emmanuelbernard.com"&gt;Emmanuel:&lt;/a&gt;&lt;/strong&gt; "We should interview... er... forgot his name..."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Max:&lt;/strong&gt; "Richard? Richard something? Kennard"&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Lincoln:&lt;/strong&gt; "Richard Kennard"&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Max:&lt;/strong&gt; "Yeah Kennard"&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Lincoln:&lt;/strong&gt; "...it's a really cool framework for, basically you just point this tag at an Object or a bean and it runs through that bean and looks at all the properties and builds up an interface that shows up on the page."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Max:&lt;/strong&gt; "Yeah, and in your JSF you just have one [line] and say this is the bean I want to do and it builds the UI. And it does it for... er... Swing, and..."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Lincoln:&lt;/strong&gt; "You can do Swing, you can do GWT, you can do JavaFX I think. Lots of stuff."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Max:&lt;/strong&gt; "So actually it is pretty powerful, but it's not..."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Lincoln:&lt;/strong&gt; "The problem is then you've got this tag in there and it's... if you want to customize that then you're learning the Metawidget framework. And so what we are doing right now actually is we're customizing Metawidget so that, using the same inspection process that Metawidget provides, generate real code. Materializes it into real XML, real JSF pages. Then you can go in and modify those pages just like you would have done by yourself."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Listen to the &lt;a href="http://asylum.libsyn.com/webpage/podcast-23-forging-forge"&gt;full podcast&lt;/a&gt; here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-3499444760947614398?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/3499444760947614398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=3499444760947614398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3499444760947614398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3499444760947614398'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/12/forge-and-metawidget-discussed-on-jboss.html' title='Forge and Metawidget Discussed On JBoss Community Asylum'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-xKnVowBJpv0/TvPlNmuDECI/AAAAAAAAAjY/jVEQzFOoqmI/s72-c/13429.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-5468267606522235517</id><published>2011-12-19T09:30:00.014+11:00</published><updated>2011-12-25T09:47:52.205+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seam Forge'/><category scheme='http://www.blogger.com/atom/ns#' term='Metwidget'/><title type='text'>You Can't Spell Forge Without Metawidget</title><content type='html'>JBoss have just released &lt;a href="http://jboss.org/forge"&gt;Beta 4 of JBoss Forge&lt;/a&gt;. There are a host of &lt;a href="https://issues.jboss.org/secure/ReleaseNote.jspa?projectId=12311820&amp;version=12318358"&gt;new features in this release&lt;/a&gt;. Most exciting for me being the new UI scaffolding.&lt;br /&gt;&lt;br /&gt;Scaffolding has been significantly rewritten to use a new static &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;. This allows Forge to output pure JSF tags, with no runtime dependencies on any non-Java EE libraries. The UI includes creating, updating, deleting, pagination and searching. It also supports one-to-many, many-to-many, many-to-one and one-to-one relationships:&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://1.bp.blogspot.com/-nLXy1bl12OE/Tu5sJ0spX4I/AAAAAAAAAjM/HJJd8okglBs/s1600/forge2.png"&gt;&lt;img style="display:block; text-align:center;cursor:pointer; cursor:hand" src="http://1.bp.blogspot.com/-nLXy1bl12OE/Tu5sJ0spX4I/AAAAAAAAAjM/HJJd8okglBs/s320/forge2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5687602295436042114" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://1.bp.blogspot.com/-RuP6PfolKVI/Tu5p26yFOaI/AAAAAAAAAjA/imu0JwVwlQE/s1600/forge.png"&gt;&lt;img style="display:block; text-align:center;cursor:pointer; cursor:hand" src="http://1.bp.blogspot.com/-RuP6PfolKVI/Tu5p26yFOaI/AAAAAAAAAjA/imu0JwVwlQE/s320/forge.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5687599771628681634" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;The code it generates is very clean:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;h:panelGrid columnClasses="label,component,required" columns="3"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;h:outputLabel for="customerBeanCustomerFirstName" value="First Name:"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;h:panelGroup&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;h:inputText id="customerBeanCustomerFirstName" value="#{customerBean.customer.firstName}"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;h:message for="customerBeanCustomerFirstName" styleClass="error"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/h:panelGroup&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Behind the scenes, Forge is still using the same Metawidget pipeline as before - the same Inspectors, WidgetBuilders, WidgetProcesors and Layouts. This means the scaffolding is pluggable to adapt to your needs - including custom UI libraries, custom layouts, even custom langauges (&lt;a href="http://ceylon-lang.org"&gt;Ceylon&lt;/a&gt;, anyone?).&lt;br /&gt;&lt;br /&gt;The new static Metawidget is also used to generate Java code for the JSF backing beans. Again using WidgetBuilders and outputting very clean code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;String firstName = this.search.getFirstName();&lt;br /&gt;if (firstName != null &amp;&amp; !"".equals(firstName)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;predicatesList.add(builder.like(root.&amp;lt;String&amp;gt;get("firstName"), '%' + firstName + '%'));&lt;br /&gt;}&lt;br /&gt;String lastName = this.search.getLastName();&lt;br /&gt;if (lastName != null &amp;&amp; !"".equals(lastName)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;predicatesList.add(builder.like(root.&amp;lt;String&amp;gt;get("lastName"), '%' + lastName + '%'));&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Please give it a try!&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Download &lt;a href="https://repository.jboss.org/nexus/service/local/artifact/maven/redirect?r=releases&amp;g=org.jboss.forge&amp;a=forge-distribution&amp;v=1.0.0.Beta4&amp;e=zip"&gt;Forge Beta4&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="https://docs.jboss.org/author/display/FORGE/Installation"&gt;Install&lt;/a&gt; it&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Run it&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Copy and execute this command:&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;$ run-url https://raw.github.com/forge/core/master/showcase/posale.fsh&lt;/tt&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;For the lazy, I've uploaded the project that Forge generates. You can &lt;a href="https://docs.google.com/open?id=0Bz-3d0tCrobHYWIyMzBlYmYtNzg1YS00NTViLWFkMWItYmIyMTA1NDVkMjE2"&gt;download it here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-5468267606522235517?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/5468267606522235517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=5468267606522235517' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5468267606522235517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5468267606522235517'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/12/you-cant-spell-forge-without-metawidget.html' title='You Can&apos;t Spell Forge Without Metawidget'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-nLXy1bl12OE/Tu5sJ0spX4I/AAAAAAAAAjM/HJJd8okglBs/s72-c/forge2.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-3743740176094357065</id><published>2011-12-04T19:25:00.005+11:00</published><updated>2011-12-04T19:35:03.749+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wicket'/><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Pleasing Dick Wall</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 199px; height: 200px;" src="http://2.bp.blogspot.com/-XqXBNn3TIhY/TtsvbmeiSUI/AAAAAAAAAi0/1dWiHuQOap4/s200/untitled.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5682187506089609538" /&gt;In &lt;a href="http://www.javaposse.com/webpage/java-posse-371-roundup-11-future-of-the-java-programmer"&gt;Episode 371&lt;/a&gt; of the Java Posse, &lt;a href="http://www.escalatesoft.com/home"&gt;Dick Wall&lt;/a&gt; has this to say about &lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;D.R.Y.&lt;/a&gt; (at 47m.30s):&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;"That actually, I hate to say, but it's an affliction that's very very bad in the Java world. And you see developers drop it as soon as they see another programming environment and really grok the idea of Don't Repeat Yourself. A lot of the flagship libraries in Java are really bad for this.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://wicket.apache.org"&gt;Wicket&lt;/a&gt; is one that springs to mind... everybody loves Wicket, [but] now I've been exposed to a bunch of different stuff I look at it and you have to repeat things 3, 4 or 5 times sometimes. When you're adding a field on to a Web page you've gotta name it on the page and then you come into the code and you write your handle on it with the exact same kind of component that is, and the name, and even worse, you know, taking the current Java mindset of 'you should be working for the compiler' and not the other way around.&lt;br /&gt;&lt;br /&gt;If you get it wrong, &lt;em&gt;it&lt;/em&gt; complains at &lt;em&gt;you&lt;/em&gt;. It doesn't try and fix it for you."&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;This is, of course, exactly the problem that &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; is designed to address. I talk about it in my &lt;a href="http://blog.kennardconsulting.com/2011/12/metawidget-javaone-2011-jboss-booth.html"&gt;JavaOne video here&lt;/a&gt; (at 5m.30s).&lt;br /&gt;&lt;br /&gt;Unfortunately work has stalled on the Wicket version while I've been working on &lt;a href="http://jboss.org/forge"&gt;JBoss Forge&lt;/a&gt; integration. Wicket actually makes completely dynamic controls, like Metawidget, tricky because of its approach of 'a Java file and a static HTML file'.&lt;br /&gt;&lt;br /&gt;However, I was fortunate to have lunch with Wicket guru &lt;a href="http://www.logicstyle.com"&gt;Juliano Viana&lt;/a&gt; at &lt;a href="http://www.oracle.com/javaone/index.html"&gt;JavaOne 2011&lt;/a&gt;. He deep dived into the Wicket internals and found &lt;a href="http://wicket.apache.org/apidocs/1.4/org/apache/wicket/MarkupContainer.html#getAssociatedMarkupStream(boolean)"&gt;MarkupContainer.getAssociatedMarkupStream&lt;/a&gt; for me. It looks like this can free up the requirement of a static HTML file. So hopefully there is a way to get around this Wicket limitation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-3743740176094357065?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/3743740176094357065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=3743740176094357065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3743740176094357065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3743740176094357065'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/12/pleasing-dick-wall.html' title='Pleasing Dick Wall'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-XqXBNn3TIhY/TtsvbmeiSUI/AAAAAAAAAi0/1dWiHuQOap4/s72-c/untitled.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-3029235995275330764</id><published>2011-12-01T12:58:00.015+11:00</published><updated>2011-12-01T23:59:15.985+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget @ JavaOne 2011: JBoss Booth Video</title><content type='html'>&lt;a href="http://www.jboss.org/events/javaone"&gt;JBoss have posted videos&lt;/a&gt; from sessions at their mini-theater in the JavaOne Exhibition Hall. This includes our talk on &lt;a href="http://blog.kennardconsulting.com/2011/09/metawidget-javaone-2011-updated.html"&gt;DRY UIs: Let the metadata do the work&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;iframe style="margin: auto" src="http://player.vimeo.com/video/30746629?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="600" height="338" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen&gt;&lt;/iframe&gt;&lt;/center&gt;&lt;br /&gt;The video is available in High Definition, so please try the Full Screen mode if you find the coding examples difficult to read.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-3029235995275330764?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/3029235995275330764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=3029235995275330764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3029235995275330764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3029235995275330764'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/12/metawidget-javaone-2011-jboss-booth.html' title='Metawidget @ JavaOne 2011: JBoss Booth Video'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1432794075165247105</id><published>2011-11-08T10:04:00.031+11:00</published><updated>2011-11-08T16:01:28.016+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><title type='text'>Should HTML.next Have A Higher Level of Abstraction?</title><content type='html'>&lt;a href="http://dev.w3.org/html5/spec"&gt;HTML&lt;/a&gt; brings a lot of great features to the table. One of them is &lt;a href="http://en.wikipedia.org/wiki/Device_independence"&gt;device independence&lt;/a&gt;. The HTML author gets to write:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" style="padding-left: 25px"&gt;&lt;tt&gt;&amp;lt;button value="OK"/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;And the device gets to choose how to render that using a native widget:&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://4.bp.blogspot.com/-TaaGBbylrMA/TrhkOeDE2KI/AAAAAAAAAiE/4gbeZ0b_K_I/s400/button.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5672393930420050082" /&gt;I think this is a great level of abstraction. But &lt;strong&gt;in my opinion the W3C made a mistake&lt;/strong&gt; when they specified:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" style="padding-left: 25px"&gt;&lt;tt&gt;&amp;lt;input type="checkbox"/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;See that &lt;tt&gt;type&lt;/tt&gt; attribute? It's referring to the &lt;em&gt;widget&lt;/em&gt; type. But it really should be referring to the &lt;em&gt;data&lt;/em&gt; type. Then we could write:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" style="padding-left: 25px"&gt;&lt;tt&gt;&amp;lt;input type="boolean"/&amp;gt;&lt;br /&gt;&amp;lt;input type="date"/&amp;gt;&lt;br /&gt;&amp;lt;input type="integer"/&amp;gt;&lt;br /&gt;&amp;lt;input type="color"/&amp;gt;&lt;br /&gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;And the device gets to choose how to render that. If it were a simple device, or it didn't understand the data type, it could just render a text box. But better implementations could offer nicer UIs. Date pickers. Spinners. Color pickers. Browsers could compete by offering better widgets.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Think how much time our industry has wasted re-implementing HTML date pickers and spinners&lt;/strong&gt;. Hundreds of widget libraries across all development platforms (PHP libraries, Java libraries, .NET libraries, etc).&lt;br /&gt;&lt;br /&gt;I came to this realisation while using &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;. Typically you tell Metawidget to generate an entire form, composed of many widgets:&lt;br /&gt;&lt;br /&gt;&lt;table width="100%"&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;div class="code" style="padding-left: 25px"&gt;&lt;tt&gt;&amp;lt;m:metawidget value="#{myForm}"/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;div style="text-align: right; padding-top: 5px"&gt;...which gives...&lt;/div&gt;&lt;/td&gt;&lt;td align="left"&gt;&lt;img style="display:block; border: 1px solid #cccccc; padding: 1px" src="http://3.bp.blogspot.com/-0euo6jFxx_I/TrhmborS3ZI/AAAAAAAAAiQ/LoilR2_ghEE/s400/form.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5672396355634650514" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;But I've found it suprisingly useful to still use Metawidget even when dealing with single widgets:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" style="padding-left: 25px"&gt;&lt;tt&gt;&amp;lt;m:metawidget value="#{myForm.name}"/&amp;gt;&lt;br /&gt;&amp;lt;m:metawidget value="#{myForm.age}"/&amp;gt;&lt;br /&gt;&amp;lt;m:metawidget value="#{myForm.dateOfBirth}"/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Here we are deferring the actual widget choice to Metawidget. So Metawidget can &lt;strong&gt;choose it for us based on the best widgets available on the target device, our locale, our accessibility requirements etc&lt;/strong&gt;. Maybe that's a plain text box. Or maybe it's a &lt;a href="http://jboss.org/richfaces"&gt;RichFaces date picker&lt;/a&gt;. Or an &lt;a href="http://sencha.com/products/extgwt"&gt;ExtGWT spinner&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's nice to defer that choice, because &lt;strong&gt;now all the widgets can automatically upgrade over time&lt;/strong&gt; as the platform improves. If this were in HTML too, it'd save an enormous amount of re-implementing. And it would provide a new battleground for browser competition.&lt;br /&gt;&lt;br /&gt;&lt;strong style="display: block; text-align: center"&gt;Better for developers. Better for browser vendors. Better for consumers.&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1432794075165247105?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1432794075165247105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1432794075165247105' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1432794075165247105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1432794075165247105'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/11/should-htmlnext-have-higher-level-of.html' title='Should HTML.next Have A Higher Level of Abstraction?'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-TaaGBbylrMA/TrhkOeDE2KI/AAAAAAAAAiE/4gbeZ0b_K_I/s72-c/button.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-6049245730427753908</id><published>2011-10-30T21:06:00.005+11:00</published><updated>2011-10-30T21:24:16.602+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget Quotes</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 250px; height: 250px;" src="http://4.bp.blogspot.com/-IjGyxA2pD1s/Tq0lkuAezXI/AAAAAAAAAh4/1chYVu0ZtGs/s320/punctuation-marks-quotation-marks.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5669228818684890482" /&gt;A collection of quotes people have said about &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li style="font-weight: bold"&gt;"I finally had a chance to try out Metawidget on an example of my own and it is quite amazing"&lt;br /&gt;  &lt;a href="http://mojavelinux.com" target="_blank"&gt;Dan Allen (author, Seam In Action)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Looks impressive... the author of this library has evidently put some real thought into this"&lt;br /&gt;  &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=51572" target="_blank"&gt;Michael Klaene (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"I spun up the SwingMetawidget, very impressive. Love the annotations, too. Thanks a lot for this API! I am going to try one of the web widgets next"&lt;br /&gt;  &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=51572" target="_blank"&gt;i k (Swing Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"We have a large GWT app it could certainly do with this for the forms. The documentation looks very good. I also really like the 'don't take over the GUI' principle" &lt;br /&gt;  &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=51572" target="_blank"&gt;David Tinker (GWT Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"This looks like a very interesting project!"&lt;br /&gt;  &lt;a href="http://blog.kennardconsulting.com/2008/04/declarative-user-interface-generator.html#comments"&gt;Johan Andries (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"I strongly agree that UI duplication is mindless, error-prone code that should have been solved years ago. I am so glad someone is addressing this"&lt;br /&gt;  &lt;a href="/survey.html"&gt;Survey respondent&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li style="font-weight: bold"&gt;"On my todo list is to develop an integration with Metawidget. I'm impressed by the work they're doing here"&lt;br /&gt;  &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=58283" target="_blank"&gt;Dan Haywood (author, Domain-Driven Design using Naked Objects)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Metawidget is worth taking a look at"&lt;br /&gt;  &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=52466" target="_blank"&gt;Eric Rich (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"I have taken a look at it, and found it's a wonderful tool. When coding with SWT, I always wanted to find such kind of tool..."&lt;br /&gt;  &lt;a href="http://old.nabble.com/Re%3A-Metawidget-has-added-SWT-support-p28442101.html" target="_blank"&gt;Zhong Nanhai (SWT Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Sounds impressive. I was infact looking for such a utility for a while"&lt;br /&gt;  &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=51572" target="_blank"&gt;Shashi Ayachitam (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Developers no longer have to spend too much time to bind UI with POJO"&lt;br /&gt;  &lt;a href="http://vinaytech.wordpress.com/2008/10/18/metawidget-adds-supports-for-google-web-toolkit" target="_blank"&gt;Vinay Saintantonyar (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"The strength of Metawidget is it allows the developer flexibility to change how the front-end is rendered because Metawidget does not exclusively own the front-end like many other frameworks"&lt;br /&gt;  &lt;a href="http://markashworth.blogspot.com/2008/02/metawidget-introduction-background.html" target="_blank"&gt;Mark Ashworth (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li style="font-weight: bold"&gt;"Metawidget is very interesting... I will try to use it in one of my projects"&lt;br /&gt;  &lt;a href="http://blog.adam-bien.com" target="_blank"&gt;Adam Bien (author, Oracle Java Developer of the Year)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Think of a configurable form widget driven off of your beans through runtime inspection of properties, getters and setters, annotations, etc"&lt;br /&gt;  &lt;a href="http://www.pathf.com/blogs/2008/07/metawidget-convention-over-configuration-ui" target="_blank"&gt;Dietrich Kappe (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Our app has over 300 screens and UI duplication is a huge maintenance issue for us. You are definitely on to something here and I like the fact that your framework integrates with others and does not try to 'own' the UI"&lt;br /&gt;  &lt;a href="/survey.html"&gt;Survey respondent&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"I think Object Interface Mapper (OIM) is a very good 'concept' for this domain. I usually call it 'domain model framework' or something like that, but now I think OIM is more clear"&lt;br /&gt;  &lt;a href="http://blog.kennardconsulting.com/2008/09/generate-user-inteface-automatically.html#comments" target="_blank"&gt;wangzx (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"In the past I used [other frameworks] but their approach is too invasive and unfittable. Metawidget is very flexible and integrates an environment already in production. Great great great framework!!!"&lt;br /&gt;  &lt;a href="http://blog.kennardconsulting.com/2008/12/better-than-free-metawidget-v065.html" target="_blank"&gt;Nicola (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Here's something different... it builds on your underlying framework and so is not competing with it"&lt;br /&gt;  &lt;a href="http://devsac.blogspot.com/2008/10/must-have-tools-for-every-smart-java.html" target="_blank"&gt;Sachin (Java Developer)&lt;/a&gt;&lt;/li&gt; &lt;br /&gt; &lt;li style="font-weight: bold"&gt;"I have long held the reason for the incessant churn in how we best complete the UI architecture task is due to the continued quest for economic value. [Your work] shows there are benefits to separating the elements of that task from that churn"&lt;br /&gt;  &lt;a href="http://java.net/blog/edburns" target="_blank"&gt;Ed Burns (author, JSF specification lead)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"I have been using Metawidget (which is a really cool library by the way) on a project lately..."&lt;br /&gt;  &lt;a href="http://blog.singingwizard.org/2009/05/metawidget-beanutils-auto-update-binding" target="_blank"&gt;Arthur Peters (Swing Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Metawidget not only provides a nice UI framework but offers realistically implemented connections to backends"&lt;br /&gt;  &lt;a href="http://mobilebytes.wordpress.com/2009/06/10/an-android-ui-widgetkit" target="_blank"&gt;Fred Grott (Android Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"It works, beautifully! Thanks for bringing us this powerful stuff&lt;br /&gt;  &lt;a href="https://sourceforge.net/projects/metawidget/forums/forum/747623/topic/3788210/index/page/1" target="_blank"&gt;Phaderm (Swing Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Metawidget concept is the way to go.... you can exploit multiple UI targets with minimal code rewrite and take advantage of native widgets when required"&lt;br /&gt;  &lt;a href="http://java.dzone.com/news/%E2%80%9Cperfect-web-framework%E2%80%9D-there" target="_blank"&gt;Steven Goldsmith (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"I'd like to thank you for what you've done with Metawidget. It's a really great framework and is proving especially useful in a model driven architecture we are implementing"&lt;br /&gt;  &lt;a href="https://sourceforge.net/projects/metawidget/forums/forum/747623/topic/4024359/index/page/1"&gt;Ashlin Eldridge (Java Developer)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li style="font-weight: bold"&gt;"Metawidget is a super-cool project"&lt;br /&gt; &lt;a href="http://jbaruch.wordpress.com"&gt;Baruch Sadogursky (author, Spring in a Nutshell)&lt;/a&gt;&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/5950537015062599287-6049245730427753908?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/6049245730427753908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=6049245730427753908' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6049245730427753908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6049245730427753908'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/10/metawidget-quotes.html' title='Metawidget Quotes'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-IjGyxA2pD1s/Tq0lkuAezXI/AAAAAAAAAh4/1chYVu0ZtGs/s72-c/punctuation-marks-quotation-marks.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-7052238940815057425</id><published>2011-10-10T10:26:00.010+11:00</published><updated>2011-10-23T09:08:34.492+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><category scheme='http://www.blogger.com/atom/ns#' term='JavaOne'/><title type='text'>Metawidget @ JavaOne 2011 (Epilogue)</title><content type='html'>I had a great time presenting &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; at &lt;a href="http://blog.kennardconsulting.com/2011/09/metawidget-javaone-2011-updated.html"&gt;JavaOne 2011&lt;/a&gt;. We had a good turn out (about sixty people) with lots of good questions at the end. My thanks to all who attended, and to my co-speaker &lt;a href="http://mojavelinux.com"&gt;Dan Allen&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/-DWQjZ6VKC38/TpIuvyjGbBI/AAAAAAAAAho/ohZPuPC9jDc/s1600/javaone2011-2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 278px; height: 320px;" src="http://2.bp.blogspot.com/-DWQjZ6VKC38/TpIuvyjGbBI/AAAAAAAAAho/ohZPuPC9jDc/s320/javaone2011-2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5661639080115858450" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://4.bp.blogspot.com/-1PjLUx8S4XQ/TpIuv3qoxOI/AAAAAAAAAhg/dtHCUaR1sN8/s1600/javaone2011-1.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 207px;" src="http://4.bp.blogspot.com/-1PjLUx8S4XQ/TpIuv3qoxOI/AAAAAAAAAhg/dtHCUaR1sN8/s320/javaone2011-1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5661639081489646818" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The full talk should be available on &lt;a href="http://www.parleys.com/#st=4&amp;id=102979"&gt;Parleys&lt;/a&gt; in the next few weeks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-7052238940815057425?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/7052238940815057425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=7052238940815057425' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7052238940815057425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7052238940815057425'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/10/metawidget-javaone-2011-epilogue.html' title='Metawidget @ JavaOne 2011 (Epilogue)'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-DWQjZ6VKC38/TpIuvyjGbBI/AAAAAAAAAho/ohZPuPC9jDc/s72-c/javaone2011-2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-3438294396145181703</id><published>2011-09-13T11:40:00.029+10:00</published><updated>2011-09-21T12:14:00.347+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget @ JavaOne 2011 (Updated)</title><content type='html'>&lt;div style="float: right; text-align: right"&gt;&lt;img border="0" height="250" width="250" src="http://3.bp.blogspot.com/-0I6Z-5JRrNY/Tm6yWATeXLI/AAAAAAAAAhQ/ByEKubzJjO4/s400/11053828-j1-imspeaking-250x250-427822.gif" style="padding: 0px"/&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-_AXrLl3jULc/TnlD5RXimxI/AAAAAAAAAhY/5DwFuj0-RgI/s1600/flyer.png"&gt;&lt;img style="cursor:pointer; cursor:hand;padding:0px;margin-top: 5px;border: 1px solid #cccccc" src="http://3.bp.blogspot.com/-_AXrLl3jULc/TnlD5RXimxI/AAAAAAAAAhY/5DwFuj0-RgI/s400/flyer.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5654625458334112530"/&gt;&lt;/a&gt;&lt;/div&gt;The time and venue for the &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; technical session at &lt;a href="http://www.oracle.com/javaone"&gt;JavaOne 2011&lt;/a&gt; have now been confirmed:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td colspan="2"&gt;&lt;span style="font-weight: bold; font-size: 130%"&gt;DRY UIs: Let the metadata do the work&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Date:&lt;/th&gt;&lt;td&gt;Wednesday 5th October 2011&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Time:&lt;/th&gt;&lt;td&gt;1:00 PM&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Speakers:&amp;nbsp;&lt;/th&gt;&lt;td&gt;Dan Allen, Richard Kennard&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Venue:&lt;/th&gt;&lt;td&gt;Parc 55 - Market Street&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Length:&lt;/th&gt;&lt;td&gt;1 hour&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Track:&lt;/th&gt;&lt;td&gt;&lt;em&gt;Emerging Languages, Tools, and Techniques&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;How many times have you sat in a dark office after hours hand editing forms, page after page? Software teams spend a lot of time developing the UI. To speed up the process, developers resort to drag-and-drop widget solutions or model-based static generation tools. These approaches only change the appearance of the problem.&lt;br /&gt;&lt;br /&gt;This talk presents Metawidget as a solution to keep your UIs DRY. Metawidget is a smart UI processor that populates itself, at runtime, with UI components that match properties of your model. Rather than introduce new technologies, it reads existing metadata (e.g. JavaBeans, annotations, XML) to create native UI widgets (e.g. JSF, Android, Swing).&lt;br /&gt;&lt;br /&gt;Stop hand-coding your forms! Come learn how to break out of the rut!&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;I'll also be doing a supplemental session at the &lt;a href="http://www.jboss.com/events"&gt;JBoss booth&lt;/a&gt; at 11.30am on Tuesday 4th, as well as being on-hand to answer questions and give live demonstrations.&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;My thanks to &lt;a href="http://www.lisandrojudaya.com/"&gt;Lee Judaya&lt;/a&gt; who put together a cool looking promotional flyer for the sessions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-3438294396145181703?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/3438294396145181703/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=3438294396145181703' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3438294396145181703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3438294396145181703'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/09/metawidget-javaone-2011-updated.html' title='Metawidget @ JavaOne 2011 (Updated)'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-0I6Z-5JRrNY/Tm6yWATeXLI/AAAAAAAAAhQ/ByEKubzJjO4/s72-c/11053828-j1-imspeaking-250x250-427822.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-420058086900154468</id><published>2011-08-30T10:15:00.003+10:00</published><updated>2011-08-30T10:19:10.106+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>OIM: Metawidget v1.30</title><content type='html'>&lt;img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 0px 10px 10px; WIDTH: 188px; FLOAT: right; HEIGHT: 400px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id="BLOGGER_PHOTO_ID_5428305152285105858" border="0" alt="" src="http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s400/box.png" /&gt;Version 1.30 of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, the &lt;a href="http://metawidget.org"&gt;OIM&lt;/a&gt; is now available! This release includes the following enhancements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/08/metawidget-125-to-130-migration-guide.html"&gt;Refactored InspectionResultProcessors&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/08/metawidget-125-to-130-migration-guide.html"&gt;Harmonized JSF EL&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/08/metawidget-125-to-130-migration-guide.html"&gt;Improved Proxy Support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/08/metawidget-moving-to-github.html"&gt;Migration to GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Bug fixes, documentation and unit tests&lt;/li&gt;&lt;/ul&gt;This release contains breaking changes. We apologise for the disruption and provide this &lt;a href="http://blog.kennardconsulting.com/2011/08/metawidget-125-to-130-migration-guide.html"&gt;Metawidget 1.25 to 1.30 Migration Guide&lt;/a&gt;. Special thanks to &lt;a href="http://gastaldi.wordpress.com"&gt;George Gastaldi&lt;/a&gt; for his help with this release!&lt;br /&gt;&lt;br /&gt;As always, the best place to start is the Reference Documentation:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;a href="http://metawidget.org/doc/reference/en/pdf/metawidget.pdf"&gt;http://metawidget.org/doc/reference/en/pdf/metawidget.pdf&lt;br /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Your continued feedback is invaluable to us. Please &lt;a href="http://metawidget.org/download.html"&gt;download it&lt;/a&gt; and &lt;a href="http://metawidget.org/forums.html"&gt;let us know what you think&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-420058086900154468?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/420058086900154468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=420058086900154468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/420058086900154468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/420058086900154468'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/08/oim-metawidget-v130.html' title='OIM: Metawidget v1.30'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s72-c/box.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-2869827913550964361</id><published>2011-08-28T18:57:00.010+10:00</published><updated>2011-08-28T19:26:25.439+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>What Good is an OIM?</title><content type='html'>&lt;span style="font-size: 130%; font-weight: bold"&gt;1.  Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Metawidget has coined the term &lt;a href="http://metawidget.org"&gt;Object User Interface Mapper&lt;/a&gt; (&lt;a href="http://metawidget.org"&gt;OIM&lt;/a&gt;). It's a new take on an old problem. Like any new approach, it can sometimes be difficult to identify where it can be applied. This blog entry outlines a number of use cases for an OIM, citing examples of real world implementations. In short, it helps answer the question: what good is an OIM?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;2.  Generate User Interfaces from Existing Business Objects&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OIMs excel at generating widgets based on your &lt;em&gt;existing&lt;/em&gt; UI framework, matched to your &lt;em&gt;existing&lt;/em&gt; application business objects. Whether the application is a government tool for transaction processing or a pharmaceutical tool for database maintenance&lt;sup&gt;&lt;a href="#references"&gt;1&lt;/a&gt;&lt;/sup&gt;, OIMs are ideally suited (Figure 1).&lt;br /&gt;&lt;br /&gt;One lead developer summarised: "Many frameworks or tools enforce the [tool] designer's vision on how solutions should be architected. What I liked about Metawidget is that I could drop it in whatever architecture I was using"&lt;sup&gt;&lt;a href="#references"&gt;1&lt;/a&gt;&lt;/sup&gt;. Another concluded: "In 10 years of software development, I can't count the number of times I've needed a simple form for users to enter or update data... no one has extended [a solution] in a general way to apply to a broad audience. Certainly there have been 'form code generators', but creating the form at runtime from metadata is a far more elegant approach in my opinion"&lt;sup&gt;&lt;a href="#references"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;br /&gt; &lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://4.bp.blogspot.com/-ku5fFwTkJ1M/TloDQIfjpcI/AAAAAAAAAgY/zfxvXeKEiJw/s1600/Figure1a.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 138px; height: 200px;" src="http://4.bp.blogspot.com/-ku5fFwTkJ1M/TloDQIfjpcI/AAAAAAAAAgY/zfxvXeKEiJw/s200/Figure1a.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645828658554971586" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://1.bp.blogspot.com/-gJmAJ0JjhRE/TloDQW5PxCI/AAAAAAAAAgg/jqA3y2rPwNY/s1600/Figure1b.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 154px;" src="http://1.bp.blogspot.com/-gJmAJ0JjhRE/TloDQW5PxCI/AAAAAAAAAgg/jqA3y2rPwNY/s200/Figure1b.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5645828662420816930" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" align="center"&gt;&lt;strong&gt;Figure 1: Transaction processing and database maintenance&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;OIMs are less cumbersome than visual IDE designers such as &lt;a href="http://netbeans.org"&gt;NetBeans Matisse&lt;/a&gt; (Figure 2), or modelling languages such as &lt;a href="http://facelets.java.net"&gt;Facelets&lt;/a&gt;. They require no repetitive definitions between UI and business objects. Such definitions are laborious to define and error-prone to maintain. OIMs are also more flexible than language-based tools such as &lt;a href="http://nakedobjects.org/"&gt;Naked Objects&lt;/a&gt;. OIMs have an explicit focus on generating the &lt;em&gt;same&lt;/em&gt; UI you would previously have coded by hand.&lt;br /&gt;&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/-KSWD6sQGF-M/TloDQXHUhmI/AAAAAAAAAgo/gTELNocYafU/s1600/Figure2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 174px;" src="http://2.bp.blogspot.com/-KSWD6sQGF-M/TloDQXHUhmI/AAAAAAAAAgo/gTELNocYafU/s200/Figure2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5645828662479849058" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align="center"&gt;&lt;strong&gt;Figure 2: NetBeans Matisse&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The introduction of an OIM can reduce the amount of repetitive, error-prone UI code in an architecture by up to 70%&lt;sup&gt;&lt;a href="#references"&gt;2&lt;/a&gt;&lt;/sup&gt;. One architect remarked: "it's a fairly established software engineering principle that the more you have to repeat something the higher the error is, the higher the chances there's going to be an error in the code"&lt;sup&gt;&lt;a href="#references"&gt;3&lt;/a&gt;&lt;/sup&gt;. Another: "We had an experience in our last project, that a lot of view related bugs would come from missing required fields, wrong formatting and changing the model and not changing the view. Also, keeping those in synch, required a lot of effort, not complex, but we had most of our junior programmers dedicated to fixing those silly problems. [After we introduced Metawidget] it simplified a lot and this category of bug has simply disappeared"&lt;sup&gt;&lt;a href="#references"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;3.  Generate User Interfaces from Unconventional Sources&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Beyond conventional UI generation, the five characteristics of an OIM&lt;sup&gt;&lt;a href="#references"&gt;2&lt;/a&gt;&lt;/sup&gt; allow it to generate UIs from arbitrary sources. This opens new possibilities for functionality.&lt;br /&gt;&lt;br /&gt;The Telef&amp;oacute;nica Health Portal allowed users to describe portions of their required UI themselves, using a simplified Domain Specific Language. The generated portion was then inserted into the application dynamically, based on the logged in user's roles and permissions. The team reflected: "With our requirements Metawidget was basically the only option. Our usual techniques would not have done the job"&lt;sup&gt;&lt;a href="#references"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;br /&gt;&lt;br /&gt;Another theatre system application exposed a plugin API that generated UIs for each plugin on-demand, at runtime. The team lead stressed: "One of the really important reasons I used Metawidget for this was that I have plug-ins that provide data objects for, and I/O support for, different types of [theatre] systems. I wanted to be able to just add [plug-ins] and have them be immediately editable without [them] needing to implement any UI code at all"&lt;sup&gt;&lt;a href="#references"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;br /&gt;&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://3.bp.blogspot.com/-7_xj8JkxU3g/TloDQTDp_UI/AAAAAAAAAgw/Qo7msNdGsFk/s1600/Figure3a.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 127px;" src="http://3.bp.blogspot.com/-7_xj8JkxU3g/TloDQTDp_UI/AAAAAAAAAgw/Qo7msNdGsFk/s200/Figure3a.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5645828661390736706" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://4.bp.blogspot.com/-Mdk0TI6eD_M/TloDQwFgqEI/AAAAAAAAAg4/b42mRuIEoXQ/s1600/Figure3b.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://4.bp.blogspot.com/-Mdk0TI6eD_M/TloDQwFgqEI/AAAAAAAAAg4/b42mRuIEoXQ/s200/Figure3b.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5645828669183141954" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" align="center"&gt;&lt;strong&gt;Figure 3: Health application and theatre system&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The ability of OIMs to inspect, and collate, metadata from arbitrary back-end sources permits a new level of dynamically generated UIs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;4.  Generate User Interfaces with Consistent Behaviour&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OIMs integrate with your existing back-end architecture, and deliver results integrated to your existing front-end framework. They provide a consistency of behaviour and layout across all the screens of your application. This goes far beyond traditional technologies such as CSS or Swing Look and Feels.&lt;br /&gt;&lt;br /&gt;OIMs generate widgets at runtime from centralised code, ensuring: consistent choice of widgets for data types (i.e. date pickers for all dates, spinners for all integers); consistent insertion of validators and converters (i.e. for currency); consistent enforcing of data limits (i.e. minimum values for integers, maximum lengths for strings); and consistent layout of sub-entities (i.e. separated by section headings, or separated into tabs). UIs created by an OIM are more consistent and more robust than those created by hand. For example, few developers bother to put &lt;tt&gt;maxlength&lt;/tt&gt; attributes on every one of their text fields: it is too laborious and likely to change over time, requiring error-prone maintenance. With an OIM, such limits are enforced automatically.&lt;br /&gt;&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://4.bp.blogspot.com/-4hvWvlPVv4w/TloDvJNX6KI/AAAAAAAAAhA/ZHpppcGrlqI/s1600/Figure4a.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 144px;" src="http://4.bp.blogspot.com/-4hvWvlPVv4w/TloDvJNX6KI/AAAAAAAAAhA/ZHpppcGrlqI/s200/Figure4a.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645829191323084962" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://1.bp.blogspot.com/-TIx9FW46TIA/TloDvTIXohI/AAAAAAAAAhI/GsHMmD0-qLQ/s1600/Figure4b.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 112px;" src="http://1.bp.blogspot.com/-TIx9FW46TIA/TloDvTIXohI/AAAAAAAAAhI/GsHMmD0-qLQ/s200/Figure4b.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5645829193986449938" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" align="center"&gt;&lt;strong&gt;Figure 4: Superannuation application and ERP application&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;One ERP application (Figure 4) used Metawidget to ensure consistent behaviour across a large number of screens in a large team. The team remarked: "Metawidget is really useful in the way it is the foundation to build your solution... A great advantage [it offers] is UI standards. It is really hard to keep consistency, visual or functional standards when building UI in a large team. However when it is generated dynamically, the rules are centred and even the customisation is somehow controlled"&lt;sup&gt;&lt;a href="#references"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;5.  A Platform for Adopting New Technologies&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OIMs provide a common platform for technologies participating in UI development. Vendors can leverage this to lower the barrier of entry in adopting their technology, or to open their technology to a new market.&lt;br /&gt;&lt;br /&gt;The Bean Validation plugin allows Metawidget to inspect Bean Validation annotations and translate them into UI data limits. This automatically allows Bean Validation to be applied to diverse UI frameworks including Swing, SWT, Spring and Java Server Faces.&lt;br /&gt;&lt;br /&gt;The RichFaces plugin allows Metawidget to generate RichFaces components for arbitrary back-end architectures. This automatically allows RichFaces to bind to technologies such as Drools and jBPM. If an application is already using Metawidget, adding the RichFaces plugin will automatically upgrade &lt;em&gt;every&lt;/em&gt; widget in the application across &lt;em&gt;every&lt;/em&gt; screen to use rich UI widgets such as date pickers and spinners.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;6.  Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This blog entry has outlined a number of use cases for an OIM, and cited examples of real world implementations. We hope this will help you identify areas Metawidget could be used within your own applications. You can then apply the new approach of an OIM to the old problem of repetitive, error-prone UI code - saving both you and your organisation time and money.&lt;br /&gt;&lt;br /&gt;&lt;a label="references"/&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;References&lt;/span&gt;&lt;br /&gt;&lt;em&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://metawidget.org/media/whitepaper/MetawidgetWhitePaper-AdoptionStudies.pdf"&gt;Kennard, R. 2011, 'Adoption Studies'&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://metawidget.org/media/downloads/Towards%20a%20General%20Purpose%20Architecture%20for%20UI%20Generation.pdf"&gt;Kennard, R. &amp; Leaney, J. 2010, Towards a General Purpose Architecture for UI Generation. Journal of Systems and Software.&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://metawidget.org/media/downloads/Separation%20Anxiety%20-%20stresses%20of%20developing%20a%20modern%20day%20Separable%20User%20Interface.pdf"&gt;Kennard, R., Edmonds, E. &amp; Leaney, J. 2009, Separation Anxiety: stresses of developing a modern day Separable User Interface. 2nd International Conference on Human System Interaction.&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://metawidget.org/media/whitepaper/MetawidgetWhitePaper-TelefonicaHealthPortal.pdf"&gt;Kennard, R. 2011, 'Case Study: Telefónica Health Portal'&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-2869827913550964361?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/2869827913550964361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=2869827913550964361' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2869827913550964361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2869827913550964361'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/08/what-good-is-oim.html' title='What Good is an OIM?'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-ku5fFwTkJ1M/TloDQIfjpcI/AAAAAAAAAgY/zfxvXeKEiJw/s72-c/Figure1a.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-3249225252299026121</id><published>2011-08-26T20:55:00.004+10:00</published><updated>2011-08-26T20:58:11.310+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget 1.25 to 1.30 Migration Guide</title><content type='html'>The next release of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; (v1.30) contains some breaking changes. We apologise for the disruption and provide this Migration Guide to help in moving from v1.25 to v1.30. All of the existing documentation and examples have already been migrated, as a reference point.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%; font-weight: bold"&gt;Refactored InspectionResultProcessor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Inspired by &lt;a href="http://sourceforge.net/projects/metawidget/forums/forum/747623/topic/4612394"&gt;this forum post&lt;/a&gt;, a suggestion by &lt;a href="http://mojavelinux.com"&gt;Dan Allen&lt;/a&gt;, and &lt;a href="http://www.pushing-pixels.org/2008/05/15/party-of-one-maintain.html"&gt;Kirill's advice&lt;/a&gt; we have refactored InspectionResultProcessors to reduce internal complexity. By adding 3 extra parameters to their interface...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;String processInspectionResult( String inspectionResult, M metawidget, &lt;strong&gt;Object toInspect, String type, String... names&lt;/strong&gt; );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...we can use them to consolidate other mechanisms. Specifically, we can:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;remove &lt;tt&gt;FacesXmlInspector&lt;/tt&gt; and simplify &lt;tt&gt;FacesInspector&lt;/tt&gt;, replacing them with a &lt;tt&gt;FacesInspectionResultProcessor&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;remove &lt;tt&gt;JexlInspector&lt;/tt&gt; and &lt;tt&gt;JexlXmlInspector&lt;/tt&gt;, replacing them with a &lt;tt&gt;JexlInspectionResultProcessor&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;simplify &lt;tt&gt;JspInspector&lt;/tt&gt;, replacing it with a &lt;tt&gt;JspInspectionResultProcessor&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;reduce our dependency on &lt;tt&gt;ThreadLocal&lt;/tt&gt;s (which can be brittle)&lt;/li&gt;&lt;/ul&gt;&lt;tt&gt;FacesInspectionResultProcessor&lt;/tt&gt;, &lt;tt&gt;JexlInspectionResultProcessor&lt;/tt&gt; and &lt;tt&gt;JspInspectionResultProcessor&lt;/tt&gt; combine and extend the previous functionality of their Inspectors. Specifically they can now:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Evaluate expressions from arbitrary attributes. There is no longer any need for &lt;tt&gt;UiFacesAttribute&lt;/tt&gt;, &lt;tt&gt;UiJexlAttribute&lt;/tt&gt; or &lt;tt&gt;UiJspAttribute&lt;/tt&gt;. You can just use &lt;tt&gt;UiAttribute&lt;/tt&gt; directly:&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;@UiAttribute( name = LABEL, value = "#{person.readOnly ? 'Back' : 'Cancel'}" )&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Even better, you can use &lt;tt&gt;UiLabel&lt;/tt&gt; directly:&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;@UiLabel( "#{person.readOnly ? 'Back' : 'Cancel'}" )&lt;/tt&gt;&lt;/div&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Evaluate embedded expressions, such as:&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;@UiSection( "#{person.name}'s Details As At #{today}" )&lt;/tt&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:130%; font-weight: bold"&gt;Harmonized JSF EL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We took this opportunity to remove use of &lt;tt&gt;this&lt;/tt&gt; in JSF EL expressions, in favour of &lt;tt&gt;_this&lt;/tt&gt;. The former has been made a reserved word in EL 2.2 and beyond. You still declare &lt;tt&gt;injectThis&lt;/tt&gt; in much the same way as before:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;facesInspectionResultProcessor xmlns="java:org.metawidget.inspectionresultprocessor.faces" config="FacesInspectionResultProcessorConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;injectThis&amp;gt;&amp;lt;javaBeanPropertyStyle refId="myPropertyStyle" /&amp;gt;&amp;lt;/injectThis&amp;gt;&lt;br /&gt;&amp;lt;/facesInspectionResultProcessor&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%; font-weight: bold"&gt;Improved Proxy Support&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The rise of &lt;a href="http://jcp.org/en/jsr/summary?id=299"&gt;dependency injection frameworks&lt;/a&gt; has made it increasingly common that the object Metawidget is inspecting is, in fact, a proxy. This is troublesome because many proxied classes do not maintain annotation and/or generics information. We've refactored the way we deal with proxies to support this. Specifically:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;We've enhanced &lt;tt&gt;BaseXmlInspectorConfig.setRestrictAgainstObject&lt;/tt&gt; so that XML-based inspectors can align with Object-based inspectors in the face of proxies. However this is disabled by default so you may need to enable &lt;tt&gt;setRestrictAgainstObject&lt;/tt&gt; if you are mixing XML and Object-based inspectors in your app.&lt;br /&gt;&lt;li&gt;The inspectors no longer try and determine whether a class is a proxy by pattern matching its class name. Instead, they traverse up the class hierarchy. The API names have changed slightly to reflect this.&lt;/li&gt;&lt;/ul&gt;Again, we apologise for the disruption but believe these changes will help make Metawidget cleaner and more robust than ever before.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-3249225252299026121?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/3249225252299026121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=3249225252299026121' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3249225252299026121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3249225252299026121'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/08/metawidget-125-to-130-migration-guide.html' title='Metawidget 1.25 to 1.30 Migration Guide'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-2918976764130860377</id><published>2011-08-23T12:08:00.014+10:00</published><updated>2011-08-26T20:54:03.407+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GitHub'/><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget Moving To GitHub</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 320px; height: 282px;" src="http://1.bp.blogspot.com/-voUIdksL0yY/TlMNljTF8zI/AAAAAAAAAgI/LdFFbENWKao/s320/github-logo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5643869696807007026" /&gt;After months of gentle nudging from folks like &lt;a href="http://programmer-monk.net"&gt;Greedy&lt;/a&gt; and &lt;a href="http://ocpsoft.com"&gt;Lincoln Baxter&lt;/a&gt;, and finally a big push from &lt;a href="http://gastaldi.wordpress.com"&gt;George Gastaldi&lt;/a&gt;, I'm thrilled to announce &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; has now made the move to &lt;a href="https://github.com/metawidget/metawidget"&gt;GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The master repository is at &lt;a href="https://github.com/metawidget/metawidget"&gt;https://github.com/metawidget/metawidget&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/metawidget/metawidget"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 278px;" src="http://4.bp.blogspot.com/-bH3NsTJ6h5I/Tld6n4Yzp_I/AAAAAAAAAgQ/Zi2N-AoQuaA/s320/github.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5645115483502127090" /&gt;&lt;/a&gt;&lt;br /&gt;I'll be migrating all my internal tools over the next few days, and then it'll be social coding and pull requests ahoy!&lt;br /&gt;&lt;br /&gt;My thanks to George, Lincoln and Greedy for their help.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-2918976764130860377?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/2918976764130860377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=2918976764130860377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2918976764130860377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2918976764130860377'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/08/metawidget-moving-to-github.html' title='Metawidget Moving To GitHub'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-voUIdksL0yY/TlMNljTF8zI/AAAAAAAAAgI/LdFFbENWKao/s72-c/github-logo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-2117326588307074292</id><published>2011-07-22T17:25:00.020+10:00</published><updated>2011-07-25T17:07:13.107+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Case Study: Telefónica Health Portal</title><content type='html'>&lt;span style="font-size: 130%; font-weight: bold"&gt;1. Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This blog entry presents a case study of using &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; to provide automatic UI generation for the &lt;a href="http://telefonica.com"&gt;Telefónica&lt;/a&gt; &lt;a href="http://salud.telefonica.es"&gt;Health Portal&lt;/a&gt; system. The Health Portal is a Web-based application designed around a Service Oriented Architecture and built using &lt;a href="http://code.google.com/webtoolkit"&gt;Google Web Toolkit&lt;/a&gt;. It serves the &lt;a href="http://en.wikipedia.org/wiki/Spanish_National_Health_System"&gt;Spanish National Health System&lt;/a&gt; and is deployed to some 3,000 hospitals and health clinics across Spain. The integration of Metawidget allowed  Telefónica to reduce development and ongoing maintenance costs. It further allowed the Health Portal to offer a level of flexibility and functionality not possible in previous products.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;2. Organisation and Product Overview&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Telefónica (&lt;a href="http://uk.finance.yahoo.com/q?s=TDE.L"&gt;LSE: TDE.L&lt;/a&gt;) is one of the largest fixed-line and mobile telecommunications companies in the world. It operates globally across Europe and Latin America with headquarters in Madrid, Spain (figure 1). Telefónica was founded in 1924, and was originally government owned until being privatised in 1997. Since then it has grown to over 260,000 employees with an annual revenue in excess of 60 billion Euros.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-ggFtl5QiUP8/Tik5LSidX7I/AAAAAAAAAfA/eTfzHoK_aqQ/s1600/figure1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/-ggFtl5QiUP8/Tik5LSidX7I/AAAAAAAAAfA/eTfzHoK_aqQ/s320/figure1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5632095675121229746" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 1: Telefónica headquarters in Madrid, Spain&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The company was looking to develop a product for the Spanish National Health System (NHS). The Spanish NHS is similar to that found in many European countries. It consists of a network of health clinics and hospitals across different states and territories. Each centre employs multiple healthcare workers with an array of specialities including &lt;a href="http://en.wikipedia.org/wiki/General_practitioner"&gt;General Practitioners&lt;/a&gt; (GP), &lt;a href="http://en.wikipedia.org/wiki/Pediatrics"&gt;paediatricians&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Physiotherapists"&gt;physiotherapists&lt;/a&gt;. They are funded through both public, government healthcare and private healthcare insurers.&lt;br /&gt;&lt;br /&gt;The Telefónica Health Portal was to be an online platform providing a range of services to health clinics. The Health Portal's functionality would include administering a clinic (see figure 2) and scheduling physicians (see figure 3). Most relevant to this case study, the Health Portal could also serve as an intermediary between clinics and healthcare insurers. Such an intermediary would provide three key benefits compared to existing manual processes. First, it would provide interactivity: if additional documentation or authorisation codes were required during submission of an insurance claim, the insurer could request them at the time the claim was being lodged. Second, it would provide immediacy: after the claim was lodged, the Health Portal would report back a status such as approved, rejected or pending validation. Finally, it would improve processing times: claims could be lodged and payments made more quickly, and clinics could see real-time reports of settled payments against their accounts as they approached month end.&lt;br /&gt;&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/-whANlsrTLbw/TikmZeDNV6I/AAAAAAAAAeA/IbPRHipx67A/s1600/figure2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 219px;" src="http://2.bp.blogspot.com/-whANlsrTLbw/TikmZeDNV6I/AAAAAAAAAeA/IbPRHipx67A/s320/figure2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075028008621986" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 2: Health Portal administration&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/-pDygeIp7-vc/TikmaLE-UWI/AAAAAAAAAeI/xw7sR5fm3vQ/s1600/figure3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 216px;" src="http://2.bp.blogspot.com/-pDygeIp7-vc/TikmaLE-UWI/AAAAAAAAAeI/xw7sR5fm3vQ/s320/figure3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075040095621474" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 3: Health Portal scheduler&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;This description of the Health Portal, simplified for the purposes of this case study, is depicted visually in figure 4.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-Ao-GsBMNoH0/TikmahbGisI/AAAAAAAAAeQ/H-zoyhek2x4/s1600/figure4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 202px;" src="http://4.bp.blogspot.com/-Ao-GsBMNoH0/TikmahbGisI/AAAAAAAAAeQ/H-zoyhek2x4/s320/figure4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075046094015170" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 4: Simplified UML diagram of Health Portal&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;However, business analysis showed that the data needed in order to lodge a claim varied for each private healthcare insurer. Within each insurer, it further varied by speciality (GP, paediatrician, etc.). And within each speciality, it further varied by type of activity (initial consultation, follow-up visit etc.). The Health Portal would need one insurance claim form per insurer, per speciality and per activity. Worse, as new insurance companies signed on to the service, new forms would need to be developed. This ongoing development cost would threaten the economic viability of the Health Portal. Instead, Telefónica decided they needed a way to dynamically define portions of each insurance screen. Indeed, they wanted the insurer to be able to dynamically define their forms themselves. This was where Metawidget came in.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;3. Integration of Metawidget&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This case study interviewed members of the project team, including the project manager.&lt;br /&gt;&lt;br /&gt;The discussion opened around the Health Portal's requirement to dynamically define portions of each insurance form. The project manager explained: "We had a need to dynamically create input data screens, we searched the different alternatives available in the market, and the one that fitted best was Metawidget". He explained they considered several alternatives but "after an exhaustive analysis of available tools we decided that the tool that best fitted our needs was Metawidget".&lt;br /&gt;&lt;br /&gt;The Health Portal needed to provide a range of functionality. This required a rich UI with several different types of screens and aesthetics. There was no requirement to automatically generate the entire UI. Indeed for many screens doing so would have been impractical. For example figures 2 and 3 show screens that were manually tuned for usability. It would not have suited the project to impose a generic, stylized CRUD UI (or OOUI) across every screen. The team only wanted to use automatic generation for selected portions of their application. In addition, they had already chosen their preferred UI framework and tools (GWT 2011) and developed several screens using traditional techniques. It would not have suited them if the UI generator had tried to dictate their technology choices. Together, these observations validated Metawidget's approach to defining 'useful bounds' around UI generation (Kennard &amp; Steele 2008).&lt;br /&gt;&lt;br /&gt;The team wanted the dynamic portions of their insurance claim forms to be definable by the insurer. They built a UI to allow the insurer to specify their particular fields, including the name, data type and other metadata (such as whether they were optional fields). The team then needed these fields to be reflected on the clinic's screens. The application was built around a rich, Web-based UI making extensive use of JavaScript and client-side AJAX calls to Web services. The design was that, upon initiating an insurance claim, the UI would first invoke a Web service and supply the id of the insurer. The Web service would respond with an XML definition of the insurer's form requirements, including portions that described the dynamic fields. A typical response would be:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;mensaje co_op="R00210"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;R00210&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;cif-aseguradora&amp;gt;00000000X&amp;lt;/cif-aseguradora&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;co-facturador&amp;gt;00000000X&amp;lt;/co-facturador&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;respuesta&amp;gt;&amp;lt;/respuesta&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;timestamp&amp;gt;0000000000000000&amp;lt;/timestamp&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;agrupaciones&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;agrupacion codigo="0001"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;nombre&amp;gt;AGRUPACION&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;especialidades&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;especialidad codigo="01"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;nombre&amp;gt;&lt;strong&gt;MEDICINA GENERAL&lt;/strong&gt;&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;actos&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;acto codigo="0001"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;nombre&amp;gt;&lt;strong&gt;CONSULTA&lt;/strong&gt;&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;...GP initial consult dynamic fields...&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/acto&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;acto codigo="0002"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;nombre&amp;gt;&lt;strong&gt;REVISION&lt;/strong&gt;&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;...GP follow-up visit dynamic fields...&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/acto&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/actos&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/especialidad&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;especialidad codigo="02"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;nombre&amp;gt;&lt;strong&gt;PEDIATRIA&lt;/strong&gt;&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;actos&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;acto codigo="0001"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;nombre&amp;gt;&lt;strong&gt;CONSULTA&lt;/strong&gt;&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;...pediatrician initial consult dynamic fields...&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/acto&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;acto codigo="0002"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;nombre&amp;gt;&lt;strong&gt;REVISION&lt;/strong&gt;&amp;lt;/nombre&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;...pediatrician follow-up visit dynamic fields...&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/campos-variables&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/acto&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/actos&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/especialidad&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...more especialidad...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/especialidades&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/agrupacion&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...more agrupacion...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/agrupaciones&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/R00210&amp;gt;&lt;br /&gt;&amp;lt;/mensaje&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The UI generator would extract those portions of the XML response related to dynamic fields and use them to generate its UI. This requirement validated Metawidget's approach to performing generation at runtime. It is a scenario where a system's input is itself source code - adding new functionality and screens to an application. Runtime analysis is needed to accommodate such a scenario.&lt;br /&gt;&lt;br /&gt;Because the fields were to be defined declaratively, visual IDE tools such as &lt;a href="http://netbeans.org"&gt;NetBeans Matisse&lt;/a&gt; were not applicable. And because the screens must be generated dynamically at runtime, rather than statically at development time, model-based tools such as &lt;a href="http://www.jcp.org/en/jsr/detail?id=314"&gt;JSF&lt;/a&gt; were not suitable either. What was needed was a runtime generator that could source its metadata from arbitrary sources, in this case embedded in an XML response from a web service. As the project manager commented: "The main feature [of Metawidget] for us was the possibility to dynamically, based on rules stored in our database [and exposed via a Web service], create input screens based on user selections". The team were able to plug in a custom inspector to suit their needs. But they did not require multiple inspectors, as the web service provided a single source of metadata, so they did not require collation. This validated Metawidget's approach to making collation pluggable via CompositeInspector.&lt;br /&gt;&lt;br /&gt;Once the UI had been generated and the data captured, it was to be written back into the same XML structure and returned via a second web service. This was an interesting design decision. Its rationale was that there would then be a single piece of XML containing both field names, data types and values. This XML could be stored directly in the database. Screens using it could then be recreated and redisplayed at a later time, even if the insurer's original XML definition changed. For example if, having used the Health Portal for a few months, the insurer decided they needed to alter the fields on their form, the previous several months worth of claims and associated invoices could still be rendered in their original format. This was an unusual requirement because it meant the UI data was not to be stored back to a domain object. Indeed, there was no domain object to store back to. Rather, data values had to be read and written into a fragment of XML. The team were able to plug in a custom widget processor to achieve this, validating Metawidget's approach to pluggable processing.&lt;br /&gt;&lt;br /&gt;Finally, the presentation of the dynamic portions was required to be different for different screens, so as to blend with the non-dynamic portions. For the 'lodge individual claim' and 'lodge multiple claims' screens a three column layout was required, as shown in figures 5 and 6. The bottom of each dialog box is generated by Metawidget. For the invoice screen a single column layout was preferred, as shown in figure 7. The centre of the dialog box is generated by Metawidget. These differences in layout validated Metawidget's approach to pluggable layouts.&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/-AN0hcOqxOww/TikmbGvOyaI/AAAAAAAAAeY/lr5hYGxXc7c/s1600/figure5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 203px;" src="http://2.bp.blogspot.com/-AN0hcOqxOww/TikmbGvOyaI/AAAAAAAAAeY/lr5hYGxXc7c/s320/figure5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075056110553506" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 5: Metawidget is used while lodging individual claims&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://3.bp.blogspot.com/-U6OSCI_8ZL4/TikmoUfaP2I/AAAAAAAAAe4/xMQ2UkENuFk/s1600/figure6.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 172px;" src="http://3.bp.blogspot.com/-U6OSCI_8ZL4/TikmoUfaP2I/AAAAAAAAAe4/xMQ2UkENuFk/s320/figure6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075283140591458" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 6: Metawidget is used while lodging multiple claims&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" align="center" style="padding-top: 20px"&gt;&lt;a href="http://1.bp.blogspot.com/-0jXzLQmphcg/TikmnJyZFFI/AAAAAAAAAeg/J4KrZ8jW8_Q/s1600/figure7.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 202px;" src="http://1.bp.blogspot.com/-0jXzLQmphcg/TikmnJyZFFI/AAAAAAAAAeg/J4KrZ8jW8_Q/s320/figure7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075263087547474" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 7: Metawidget is used while printing invoices&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Having detailed the organisation and product, and understood Metawidget's integration within it, the case study turned to validating Metawidget's effectiveness.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;4. Validation of Metawidget&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This case study validated Metawidget against four themes.&lt;br /&gt;&lt;br /&gt;The themes were derived from an overarching goal (GQM - Basili 1992) of Metawidget being a general purpose solution accepted by developers and applicable to industry. 'Acceptance' was considered a multi-faceted concern. First, a solution must have an obviousness to it: it must be approachable and straightforward to conceptualise, with a learning curve no steeper than necessary. Second, a solution should be convenient to use: it's API must be powerful but not cumbersome, and be more productive than developing the same application without it. Third, a solution must be adaptable: it must work well within a broad range of architectures, both front-end UI frameworks and back-end technologies. Finally, a solution must be performant: imposing reasonable processor time, bandwidth and memory constraints that do not outweigh its benefits.&lt;br /&gt;&lt;br /&gt;Such themes can be tested either quantitatively or qualitatively. There is appeal in the former, as metrics such as 'number of lines of UI code saved', 'hours required to update the UI following changes to the domain model' or 'number of API methods necessary to implement a UI'  have an impersonal, impartial character to them that conveys a sense of neutrality. However such thinking misses a critical point of Metawidget: its success is tied to the personal, to the partial. If Metawidget saves developers 25% of their UI code but they find it awkward and laborious to use, it will not achieve developer acceptance in significant numbers. If Metawidget can do more with fewer API calls but those calls are obtuse and inflexible, its long-term adoption in a project will be unlikely to survive handover from one developer to the next. If Metawidget can automatically update a UI in seconds, but that UI does not appear the way the designer intended, it will not pass usability tests.&lt;br /&gt;&lt;br /&gt;Rather, a more reliable measure arises from qualitative metrics. Metrics such as developer thoughts, preferences, and satisfaction. It is possible to give these an impersonal, quantitative flavour using techniques such as Likert scales (1932), but again doing so risks losing a critical essence. Given the fragile, elusive nature of a quality such as 'acceptance', it seemed prudent this case study remain qualitative. The next sections discuss Metawidget in the context of the four themes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;4.1. Obviousness&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Prior to encountering Metawidget did you have any preconceptions regarding UI generation? If so, how did Metawidget fit with those preconceptions? If not, could you identify with the gap Metawidget defines?&lt;/em&gt; One team member recalled: "In our case [it was] more than preconceptions. We had actual requirements. Requirements in concrete cases for generating UI, i.e. we needed a technology compatible with GWT, it had to work with XML, and it also had to be able to work dynamically". The team already had a product specification whose requirements included UI generation, so they were very clear about the gap they needed to fill.&lt;br /&gt;&lt;br /&gt;The team member elaborated: "The Health Portal acts like a broker between insurance companies and clinics/hospitals. When data flows between those two parts (e.g. a clinic sends a bill to the insurance company), certain parts are common to all the insurance companies (such as the structure of worker's 'profiles' and of the medical 'acts') and others are not (bill numbering can be different, some include authorisation number etc.). We wanted the insurance companies to be able to define and provide (through XML) themselves these variable data for the benefit of both parties". The team understood this was not a requirement they could fulfil using their existing technologies. It was an explicit requirement for UI generation. This is unusual. It is distinct from a team who, say, were already using manual techniques to construct their UIs and were looking for a way to automate their processes.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;As you were getting started with Metawidget, did you find its parts arranged roughly where you expected to find them? Were there any areas that stood out as being designed differently to you expected? If so, what were they and what were you expecting?&lt;/em&gt; The team member reflected: "we really didn't have so much expectation about that". Nevertheless, they were comfortable with what they found. The project manager confirmed: "The [Metawidget] concept makes sense, and it gives opportunities to create very flexible applications, where the input screens are easy to adapt to the user needs". Such input screens can be seen in figures 5, 6 and 7, described previously.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;4.2. Convenience&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Having determined what you wanted Metawidget to do, how difficult did you find getting Metawidget to do it?&lt;/em&gt; One team member responded: "Let's say the difficulty was medium. There were some features we wanted but which Metawidget did not have at that time, and that did require some customisation of the code". For these, the team were able to plug in their own inspectors and widget processors.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Were there scenarios where Metawidget demonstrated clear benefits over your usual techniques?&lt;/em&gt; The team member validated: "More than clear benefits. With our requirements Metawidget was basically the only option. Our usual techniques would not have done the job. The only other solution that came close to meet our requirements was TICBO [a Customer Relationship Management tool] but in end it did not meet all of them". Metawidget met all requirements because "it was compatible with GWT, could work with XML, and could work dynamically". This was a validation of Metawidget's mixture of useful bounds and runtime generation. They created a solution unlike any other available.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Were there scenarios where Metawidget was demonstrably worse than your usual techniques, or did not represent a compelling advantage? If so, what would have helped tip the balance?&lt;/em&gt; The project manager replied there were no demonstrably worse scenarios, but that "we think it would be nice to have conditional fields, so that [a field's] behaviour would depend on the user selections from other fields". Metawidget does support pluggable third-party expression languages for implementing conditional fields for different environments. However it did not cater for the particular combination of front-end and back-end this project chose. Specifically, Metawidget had no solution for client-side, browser-based (i.e. ECMAScript) conditional fields using GWT. More work was needed there, though there was good precedent for incorporating this kind of technology based on the other platforms.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;4.3. Adaptability&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;How did you find Metawidget initially fit with your existing architecture? Were there parts that 'just worked'?&lt;/em&gt; The team member responded: "As [I said] before, the use of Metawidget was somewhat concrete and, where we used it, it did meet our requirements and worked. [On top of that] the code was customised to include features not yet present at the time". There were two examples of such customisation. The first was a custom inspector, &lt;tt&gt;CamposVariablesInspector&lt;/tt&gt;. This was used to inspect fragments of the XML response returned by the insurer Web service, as shown in figure 8. This was different to Metawidget's standard inspectors, which generally inspected objects or whole XML configuration files. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-6M1WbfI7aFc/Tikmnb100oI/AAAAAAAAAeo/V18y7jWmarE/s1600/figure8.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 218px;" src="http://1.bp.blogspot.com/-6M1WbfI7aFc/Tikmnb100oI/AAAAAAAAAeo/V18y7jWmarE/s320/figure8.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075267933786754" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 8: Health Portal uses a custom inspector&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The second piece of customisation was a custom widget processor, &lt;tt&gt;CamposVariablesBinding&lt;/tt&gt;. This both extracted data values from the XML fragment and wrote them into the generated widgets, and also read them back from the generated widget and inserted them into the XML fragment, as shown in figure 9. Again this was different to Metawidget's standard binding, which bound data values to domain objects.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-I0rqbar0dT0/Tikmn_0NkAI/AAAAAAAAAew/ljfJxbZMe90/s1600/figure9.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 251px; height: 320px;" src="http://4.bp.blogspot.com/-I0rqbar0dT0/Tikmn_0NkAI/AAAAAAAAAew/ljfJxbZMe90/s320/figure9.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632075277590695938" /&gt;&lt;/a&gt;&lt;strong style="display: block; text-align: center"&gt;Figure 9: Health Portal uses a custom widget processor&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Were there areas where you had to write your own plugins, and if so how did you find writing them?&lt;/em&gt; The project manager explained: "Being able to incorporate Metawidget within an existing UI was important. It's fundamental for our project". Similarly to integrate with their existing back-end: "It was important it supported our back-end. Being able to plug-in our back-end inspectors gave us the flexibility needed, it is impossible for Metawidget to support everyone's requirements". The inverse of this statement is that it is unrealistic to expect everyone to change their application to suit Metawidget's requirements. This ability to integrate was so important, in fact, that the project manager summarised "It was critical Metawidget supported both our front-end and back-end, otherwise we probably would not have even tried it [for the Health Portal]".&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Were there areas where Metawidget couldn't be made to fit?&lt;/em&gt; The team member couldn't recall any: "No, where we used Metawidget it did fit".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;4.4. Performance&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;How did your application compare, both in terms of speed and memory, before and after the introduction of Metawidget?&lt;/em&gt; The team member replied: "In this case there was no before and after. No alternatives to Metawidget were ever developed, it was included from the beginning". However the team had encountered no performance problems, having deployed the Health Portal to thousands of clinics across Spain.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Did you find the before and after reasonable in terms of the costs and benefits of UI generation?&lt;/em&gt; The team member opined: "As [I said] before, there were no alternatives developed. However, we consider the choice reasonable in terms of cost and benefits; it was really the only option that met our requirements. If not, these requirements would have had to be changed. That would have meant less flexibility to all the parties of the project. Of course, another option would have been to develop some in-house solution similar to what Metawidget does, but that was never really an option considering the costs and benefits". This validated that UI generation is conceptually a common problem (Kennard, Leaney &amp; Edmonds 2009) that calls for a general purpose solution rather than an in-house one. "[It] did not add any business specific value if we could find a third-party solution that solved the same problem".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;5. Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In closing, I asked the project manager how he would sum up the team's experiences with Metawidget? "Since we use [Metawidget] as a dynamic information capture tool, it gives us great flexibility towards fulfilling customer requirements in record time. Even more of the information captured is almost as a black box where our application does not apply any business rules, [letting] our customers [the insurers] be the ones that define the business rules. Our application is a bridge between the user and our customer, and from that point of view Metawidget fits our needs perfectly, since it allows us to offer the customer [insurer] with a tool for him to decide and customise, without our help, the information that needs to be captured from the user [clinic]".&lt;br /&gt;&lt;br /&gt;This case study gathered responses that were pertinent to its qualitative metrics. In turn, these provided an understanding of its four themes and validated its goal. The case study found industry developers who had accepted, and successfully adopted, Metawidget for use in their application. At the time of writing, the Telefónica Health Portal has been in production for several months and deployed to some 3,000 health clinics across Spain. This presents strong validation of industry applicability and developer acceptance.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;References&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Basili, V. 1992, 'Software modeling and measurement: the Goal/Question/Metric paradigm'.&lt;br /&gt;Kennard, R., Edmonds, E. &amp; Leaney, J. 2009, Separation Anxiety: stresses of developing a modern day Separable User Interface. 2nd International Conference on Human System Interaction.&lt;br /&gt;Kennard, R. &amp; Steele, R. 2008, Application of Software Mining to Automatic User Interface Generation. 7th International Conference on Software Methodologies, Tools and Techniques.&lt;br /&gt;Likert, R. A. 1932. 'A technique for the measurement of attitudes', Archives of Psychology, New York, No. 140.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-2117326588307074292?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/2117326588307074292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=2117326588307074292' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2117326588307074292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2117326588307074292'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/07/case-study-telefonica-health-portal.html' title='Case Study: Telefónica Health Portal'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-ggFtl5QiUP8/Tik5LSidX7I/AAAAAAAAAfA/eTfzHoK_aqQ/s72-c/figure1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-7223874415998187203</id><published>2011-07-12T19:03:00.005+10:00</published><updated>2011-07-14T09:02:07.340+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><category scheme='http://www.blogger.com/atom/ns#' term='JavaOne'/><title type='text'>Metawidget @ JavaOne 2011</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 232px; height: 81px;" src="http://4.bp.blogspot.com/--8Ct2XQwwvI/ThwPfE_dq9I/AAAAAAAAAds/H4cMpZ0Wf-s/s400/JavaOne.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5628390660896566226" /&gt;&lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; has been accepted for a technical session at &lt;a href="http://www.oracle.com/javaone"&gt;JavaOne 2011&lt;/a&gt; (October 2nd-6th, San Francisco). My thanks to the selection committee and to &lt;a href="http://mojavelinux.com"&gt;Dan Allen&lt;/a&gt; for organizing this!&lt;br /&gt;&lt;br /&gt;Here's the abstract:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;DRY UIs: Let the metadata do the work&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;How many times have you sat in a dark office after hours hand editing forms, page after page? Software teams spend a lot of time developing the UI. To speed up the process, developers resort to drag-and-drop widget solutions or model-based static generation tools. These approaches only change the appearance of the problem.&lt;br /&gt;&lt;br /&gt;This talk presents Metawidget as a solution to keep your UIs DRY. Metawidget is a smart UI processor that populates itself, at runtime, with UI components that match properties of your model. Rather than introduce new technologies, it reads existing metadata (e.g. JavaBeans, annotations, XML) to create native UI widgets (e.g. JSF, Android, Swing).&lt;br /&gt;&lt;br /&gt;Stop hand-coding your forms! Come learn how to break out of the rut!&lt;br /&gt;&lt;br /&gt;&lt;em&gt;More details to follow as we get closer the time.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-7223874415998187203?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/7223874415998187203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=7223874415998187203' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7223874415998187203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7223874415998187203'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/07/metawidget-javaone-2011.html' title='Metawidget @ JavaOne 2011'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/--8Ct2XQwwvI/ThwPfE_dq9I/AAAAAAAAAds/H4cMpZ0Wf-s/s72-c/JavaOne.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4558737602405931163</id><published>2011-07-11T16:22:00.000+10:00</published><updated>2011-08-25T12:59:40.795+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget 1.20 to 1.25 Migration Guide</title><content type='html'>The next release of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; (v1.25) contains some breaking changes. We apologise for the disruption and provide this Migration Guide to help in moving from v1.20 to v1.25. All of the existing documentation and examples have already been migrated, as a reference point.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%; font-weight: bold"&gt;Refactor dependencies for JSF, JSP, Spring and Struts annotations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This change only affects those projects using &lt;a href="http://metawidget.sourceforge.net/doc/reference/en/html/ch09s05.html#section-howto-performance-jar"&gt;fine-grained Maven dependencies&lt;/a&gt; such as:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.metawidget.modules&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;&lt;strong&gt;metawidget-annotation&lt;/strong&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;version&amp;gt;1.25&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.metawidget.modules&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;&lt;strong&gt;metawidget-beanvalidation&lt;/strong&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;version&amp;gt;1.25&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Projects using &lt;tt&gt;metawidget-all.jar&lt;/tt&gt; are not affected.&lt;br /&gt;&lt;br /&gt;We have refactored the annotation-based Inspectors from the &lt;tt&gt;metawidget-faces&lt;/tt&gt;, &lt;tt&gt;metawidget-jsp&lt;/tt&gt;, &lt;tt&gt;metawidget-spring&lt;/tt&gt; and &lt;tt&gt;metawidget-struts&lt;/tt&gt; modules into corresponding &lt;tt&gt;metawidget-facesannotation&lt;/tt&gt;, &lt;tt&gt;metawidget-jspannotation&lt;/tt&gt;, &lt;tt&gt;metawidget-springannotation&lt;/tt&gt; and &lt;tt&gt;metawidget-strutsannotation&lt;/tt&gt; modules respectively. You will need to update your &lt;tt&gt;pom.xml&lt;/tt&gt; to add in these new dependencies.&lt;br /&gt;&lt;br /&gt;This was done for two reasons:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Most importantly, application environments where the Web tier is separated from the business tier may need the annotations to be deployed on the back-end and the UI widgets deployed on the front-end. Some frameworks and application servers have classpath issues if the two are not deployed separately.&lt;/li&gt;&lt;li&gt;Build environments like &lt;a href="http://m2eclipse.sonatype.org"&gt;m2eclipse&lt;/a&gt; do not properly support mixing JDK 1.4 and Java 5 targets in the same source tree, so separating them removes a hack we were using (Metawidget tries to target JDK 1.4 wherever possible).&lt;/li&gt;&lt;/ol&gt;Similarly, we have separated the Java 6-specific &lt;tt&gt;metawidget-grouplayout&lt;/tt&gt; from the JDK 1.4-compatible &lt;tt&gt;metawidget-swing&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Again, we apologise for the disruption. &lt;a href="http://metawidget.org/support.php"&gt;Feedback&lt;/a&gt; welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4558737602405931163?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4558737602405931163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4558737602405931163' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4558737602405931163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4558737602405931163'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/07/metawidget-120-to-125-migration-guide.html' title='Metawidget 1.20 to 1.25 Migration Guide'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-8272204780919345222</id><published>2011-07-05T13:47:00.016+10:00</published><updated>2011-07-05T20:15:53.655+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wi-Fi'/><title type='text'>Extend Your Wi-Fi The Easy Way: No Configuration Required</title><content type='html'>The proliferation of Wi-Fi enabled devices around my home (phones, tablet, games console) finally drove me to doing something about my Wi-Fi reception. Like most people my modem is under a desk in a corner of the house. The Wi-Fi router is beside it, and looks like this:&lt;a href="http://1.bp.blogspot.com/--RQ9ufSdBRY/ThKJnUB_PMI/AAAAAAAAAdk/PU20YRmWlZg/s1600/router.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 300px;" src="http://1.bp.blogspot.com/--RQ9ufSdBRY/ThKJnUB_PMI/AAAAAAAAAdk/PU20YRmWlZg/s320/router.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5625710193024122050" /&gt;&lt;/a&gt;Predictably &lt;strong&gt;Wi-Fi reception drops rapidly towards the back of the house&lt;/strong&gt;. I looked into getting a Wi-Fi Extender like this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-jn52MAvB0FY/ThKJnLQsdhI/AAAAAAAAAdc/YU33AcuAzok/s1600/extender.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 271px; height: 320px;" src="http://1.bp.blogspot.com/-jn52MAvB0FY/ThKJnLQsdhI/AAAAAAAAAdc/YU33AcuAzok/s320/extender.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5625710190669886994" /&gt;&lt;/a&gt;But apparently they can be tricky to configure. I also looked into a second Wi-Fi router, but I assume then you have two Wi-Fi hotspots? And have to configure your devices to connect to both? Icky.&lt;br /&gt;&lt;br /&gt;Then something occurred to me. See those 3 antennas on the back of the router? What are they doing exactly? I assume they're all receiving in a spherical (or perhaps conical) space, but seeing as &lt;strong&gt;all 3 are stuck under my desk&lt;/strong&gt; they're not achieving much. I noticed &lt;strong&gt;they unscrew easily&lt;/strong&gt; and you can buy a coaxial cable like this...&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-dbFxyChBDM0/ThKJm_xoinI/AAAAAAAAAdU/WgOYfIIQ11Q/s1600/cable.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 306px; height: 320px;" src="http://4.bp.blogspot.com/-dbFxyChBDM0/ThKJm_xoinI/AAAAAAAAAdU/WgOYfIIQ11Q/s320/cable.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5625710187586816626" /&gt;&lt;/a&gt;&lt;br /&gt;...from online stores like &lt;a href="http://www.rfshop.com.au"&gt;rfshop.com.au&lt;/a&gt;. Specifications are:&lt;br /&gt;&lt;br /&gt;&lt;table border="1" style="margin: auto"&gt;&lt;tr&gt;&lt;th&gt;Connector 1&lt;/th&gt;&lt;td&gt;RP SMA Plug (Female pin)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Connector 2&lt;/th&gt;&lt;td&gt;RP SMA Jack (Male pin)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Cable Type&lt;/th&gt;&lt;td&gt;240 series&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Length&lt;/th&gt;&lt;td&gt;10 metres&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Ohms&lt;/th&gt;&lt;td&gt;50 ohm (TV coaxial is 75 ohm)&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;So I ran one of the antenna up into the roof cavity and guess what? Now &lt;strong&gt;I get great Wi-Fi reception&lt;/strong&gt;, even out in the garden! I still have only one Wi-Fi hotspot, and there was no configuration required. A bit unconventional, perhaps, but an idea for all you &lt;a href="http://en.wikipedia.org/wiki/Do_it_yourself"&gt;Do-It-Yourself&lt;/a&gt;-ers out there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-8272204780919345222?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/8272204780919345222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=8272204780919345222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/8272204780919345222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/8272204780919345222'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/07/extend-your-wi-fi-easy-way-no.html' title='Extend Your Wi-Fi The Easy Way: No Configuration Required'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/--RQ9ufSdBRY/ThKJnUB_PMI/AAAAAAAAAdk/PU20YRmWlZg/s72-c/router.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4104857027750374952</id><published>2011-06-24T15:08:00.015+10:00</published><updated>2011-07-18T08:35:58.475+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Duplication'/><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>3 Out Of 4 Developers Could Benefit From Metawidget</title><content type='html'>I thought it was about time I posted the 'results to date' of the &lt;a href="http://metawidget.org/survey.php"&gt;Metawidget survey&lt;/a&gt; I've been running.&lt;br /&gt;&lt;br /&gt;I started the survey in response to the query '&lt;strong&gt;just how prevelant is the problem of duplication in User Interface development?&lt;/strong&gt;' By 'duplication' I mean code that you have to write, but that could be inferred using existing sources within your application. For example the maximum length of a UI text box could be inferred from a database schema; the correct format for an e-mail address could be inferred from a validation subsystem; the available navigation buttons could be inferred from a BPM engine. Such duplicated values must be declared identically, and must be kept identical throughout your project's lifetime. If they diverge, for example if the UI allows text to be input that is longer that the database can store, it's likely to cause an error.&lt;br /&gt;&lt;br /&gt;So how many developers have to do this error-prone sort of work, duplicating information throughout their applications? Apparently &lt;strong&gt;3 out of 4&lt;/strong&gt;. Every time they add a new field to their back-end, they also need to:&lt;br /&gt;&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/-H_n614YKwlo/TgQcf2WogUI/AAAAAAAAAc8/vkWOGyArCPE/s1600/results1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 314px; height: 400px;" src="http://2.bp.blogspot.com/-H_n614YKwlo/TgQcf2WogUI/AAAAAAAAAc8/vkWOGyArCPE/s400/results1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621649568357187906" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/-jra3cN5zP2k/TgQcgLYvUYI/AAAAAAAAAdE/pqHzMmiGQQ8/s1600/results2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 314px; height: 400px;" src="http://2.bp.blogspot.com/-jra3cN5zP2k/TgQcgLYvUYI/AAAAAAAAAdE/pqHzMmiGQQ8/s400/results2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621649574003167618" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;tr&gt;&lt;td colspan="2" align="center"&gt;&lt;a href="http://4.bp.blogspot.com/-a5EyuBngnP8/TgQcgeNMWlI/AAAAAAAAAdM/t4yr8FNhMiw/s1600/results3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 261px;" src="http://4.bp.blogspot.com/-a5EyuBngnP8/TgQcgeNMWlI/AAAAAAAAAdM/t4yr8FNhMiw/s400/results3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621649579055012434" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;This lends weight to the idea that a project like &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; has the potential to help a great many developers. I've previously blogged a more in-depth discussion on the &lt;a href="http://blog.kennardconsulting.com/2008/08/on-duplication-in-user-interfaces.html"&gt;problem of duplication in User Interfaces&lt;/a&gt;. The survey is still open, so please submit your votes!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4104857027750374952?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4104857027750374952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4104857027750374952' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4104857027750374952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4104857027750374952'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/06/3-out-of-4-developers-could-benefit.html' title='3 Out Of 4 Developers Could Benefit From Metawidget'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-H_n614YKwlo/TgQcf2WogUI/AAAAAAAAAc8/vkWOGyArCPE/s72-c/results1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4710264900399102945</id><published>2011-06-20T16:24:00.005+10:00</published><updated>2011-06-20T16:43:18.414+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPad'/><category scheme='http://www.blogger.com/atom/ns#' term='Asus'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>iPad vs Android: Do Consumers Really Want Flash?</title><content type='html'>Say what you will about &lt;a href="http://apple.com/hotnews/thoughts-on-flash"&gt;Apple not supporting Flash&lt;/a&gt;, consumer choice, and all that. But I know one thing: it completely rocks that I can run &lt;a href="http://readingeggs.com.au"&gt;ABC Reading Eggs&lt;/a&gt; as a full-screen Flash game on my Asus Eee Pad Transformer:&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-jokQn5H4O2s/Tf7oiR0OT8I/AAAAAAAAAc0/ykZXekOW1II/s1600/readingeggs.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 180px;" src="http://4.bp.blogspot.com/-jokQn5H4O2s/Tf7oiR0OT8I/AAAAAAAAAc0/ykZXekOW1II/s320/readingeggs.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5620185060600598466" /&gt;&lt;/a&gt;&lt;br /&gt;Now the kids can play it comfortably on the couch instead of stuck at a desk in the study! Android FTW!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4710264900399102945?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4710264900399102945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4710264900399102945' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4710264900399102945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4710264900399102945'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/06/ipad-vs-android-do-consumers-really.html' title='iPad vs Android: Do Consumers Really Want Flash?'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-jokQn5H4O2s/Tf7oiR0OT8I/AAAAAAAAAc0/ykZXekOW1II/s72-c/readingeggs.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-5191047856207213416</id><published>2011-06-17T13:58:00.005+10:00</published><updated>2011-06-17T14:38:54.571+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Asus'/><title type='text'>Price Gouging and the Asus Eee Pad Transformer</title><content type='html'>A few months ago Australian retailers (perhaps buoyed by the &lt;a href="http://abc.net.au/unleashed/35176.html"&gt;spectacular success of the Minining Industry&lt;/a&gt; doing a similar thing) tried to &lt;a href="http://abc.net.au/rn/breakfast/stories/2011/3106498.htm"&gt;lobby the government&lt;/a&gt; to add &lt;a href="http://en.wikipedia.org/wiki/Goods_and_Services_Tax_(Australia)"&gt;Goods and Sales Tax&lt;/a&gt; (10%) to overseas (i.e. online) purchases. They cited the usual "if we're hurting, we can't create as many jobs, and so &lt;em&gt;everybody suffers&lt;/em&gt;".&lt;br /&gt;&lt;br /&gt;Personally I enjoy supporting local retailers. I like brick and mortar stores. I like being sold to by an enthusiastic and informed sales person. And I like the comfort of knowing I can return a product and have my warranty serviced locally.&lt;br /&gt;&lt;br /&gt;I like all of this &lt;em&gt;more&lt;/em&gt; than 10%. &lt;strong&gt;But not more than 36%&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Recently I wanted to buy an &lt;a href="http://www.asus.com/Eee/Eee_Pad/Eee_Pad_Transformer_TF101"&gt;Asus Eee Pad Transformer&lt;/a&gt; so I could test &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; on a physical tablet. The Transformer is a great product at a great price: $399 USD for the base model, $149 USD for the keyboard add-on. So with the way the Aussie dollar is at the moment I figure that should be about $550 AUD, right? Wrong.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-N0EVhoA4les/TfrRMXO8dlI/AAAAAAAAAcs/1h8z-qmDbVQ/s1600/asus.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 250px;" src="http://2.bp.blogspot.com/-N0EVhoA4les/TfrRMXO8dlI/AAAAAAAAAcs/1h8z-qmDbVQ/s320/asus.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5619033495423448658" /&gt;&lt;/a&gt;&lt;br /&gt;The best &lt;a href="http://www.shopbot.com.au/m/?m=asus+transformer&amp;order=lh"&gt;I could find locally&lt;/a&gt; was $750 AUD. That's a 36% difference! So instead &lt;a href="http://www.amazon.com/Transformer-TF101-A1-10-1-Inch-Tablet-Computer/dp/B004U78J1G/ref=sr_1_1?ie=UTF8&amp;qid=1308282258&amp;sr=8-1"&gt;I got it from Amazon.com&lt;/a&gt; for $570 AUD &lt;em&gt;including international delivery&lt;/em&gt;. A good $180 cheaper than I could buy it locally. It's a little hard to find in stock at the moment, but &lt;a href="http://nowinstock.net"&gt;http://nowinstock.net&lt;/a&gt; took care of that.&lt;br /&gt;&lt;br /&gt;So yes, it comes with a U.S. plug which I'd rather not have. And yes, I'll have to ship it Stateside if anything goes wrong with it. And yes, I wish I could buy it locally at a price I felt wasn't &lt;a href="http://en.wikipedia.org/wiki/Price_gouging"&gt;price gouging&lt;/a&gt;. But I simply can't.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-5191047856207213416?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/5191047856207213416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=5191047856207213416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5191047856207213416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5191047856207213416'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/06/price-gouging-and-asus-eee-pad.html' title='Price Gouging and the Asus Eee Pad Transformer'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-N0EVhoA4les/TfrRMXO8dlI/AAAAAAAAAcs/1h8z-qmDbVQ/s72-c/asus.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-414863412871501787</id><published>2011-06-16T11:31:00.001+10:00</published><updated>2011-07-18T08:36:23.083+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HornetQ'/><title type='text'>HornetQ: I Want My... I Want My... I Want My MTV (um, JBM)</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 320px; height: 93px;" src="http://1.bp.blogspot.com/-qpZlx--lYOE/TecjMMt_mYI/AAAAAAAAAcQ/wEeSKEqzAns/s320/1516_450_130_cache.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5613494153020152194" /&gt;&lt;em&gt;(with apologies to &lt;a href="http://en.wikipedia.org/wiki/Money_for_Nothing_(song)"&gt;Dire Straits&lt;/a&gt;)&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Following on from &lt;a href="http://blog.kennardconsulting.com/2011/06/stung-by-hornetq-revenge.html"&gt;my previous two posts&lt;/a&gt; I've been wrapping up my migration from JBoss 5.1.0.GA (which used &lt;a href="http://www.jboss.org/jbossmessaging"&gt;JBoss Messaging (JBM)&lt;/a&gt;) to JBoss AS 6.0.0.Final (which uses &lt;a href="http://jboss.org/hornetq"&gt;HornetQ&lt;/a&gt;). As I said before &lt;strong&gt;the end result is well worth it: HornetQ is very fast&lt;/strong&gt;. But I've hit a few gotchas.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;8. Uneven Nodes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With JBM (and most messaging implementations) the 'natural' thing to do (i.e. if you're not thinking too hard) is store your JMS queue in a relational database. Then all your nodes consume off that single queue. Some disadvantages of this approach are: your database is a &lt;a href="http://en.wikipedia.org/wiki/Single_point_of_failure"&gt;Single Point of Failure&lt;/a&gt;; relational databases aren't great for implementing high performance queues.&lt;br /&gt;&lt;br /&gt;HornetQ doesn't support relational databases at all. Instead all queues are stored directly on the local file system. And &lt;strong&gt;you mustn't share that file system&lt;/strong&gt;. So now the 'natural' thing (i.e. again, if you're not thinking too hard) is for each node to have its own 'slice' of the overall queue.&lt;br /&gt;&lt;br /&gt;This change in the 'natural' order of things has a side effect. With JBM, your nodes would &lt;strong&gt;naturally consume off the overall queue as quickly as possible&lt;/strong&gt;. With HornetQ, they only ever &lt;strong&gt;naturally consume off their slice of the queue&lt;/strong&gt;. If, like us, you have grown your cluster over time and some of your nodes are on better spec hardware than others (more RAM, more CPU cores etc) this is a problem. Because your &lt;strong&gt;overall queue processing time will be limited to the time it takes the slowest node to finish its slice&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Really what you need is for HornetQ to either: at distribution time, give more messages to the fast nodes and fewer messages to the slow nodes. Or, at consumption time, redistribute messages from the slow nodes whenever the queues on the fast nodes are empty. HornetQ doesn't support either of these features yet (&lt;a href="https://issues.jboss.org/browse/HORNETQ-721"&gt;RFE here&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;In the meantime, HornetQ &lt;em&gt;can&lt;/em&gt; support the 'old JBM model' of a single queue. This is covered (in a slightly outdated JBoss 5 way) under &lt;a href="http://docs.jboss.org/hornetq/2.2.2.Final/user-manual/en/html/appserver-integration.html#d0e8389"&gt;32.5. Configuring the JBoss Application Server to connect to Remote HornetQ Server&lt;/a&gt;. Basically you need to:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;On all nodes, modify &lt;tt&gt;/server/all/deploy/jms-ra.rar/META-INF/ra.xml&lt;/tt&gt; to use NettyConnectorFactory (instead of InVMConnectorFactory) and supply a host and port (this is your MDB consumer):&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;resourceadapter&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;resourceadapter-class&amp;gt;org.hornetq.ra.HornetQResourceAdapter&amp;lt;/resourceadapter-class&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;description&amp;gt;The transport type&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property-name&amp;gt;ConnectorClassName&amp;lt;/config-property-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property-type&amp;gt;java.lang.String&amp;lt;/config-property-type&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;config-property-value&amp;gt;org.hornetq.core.remoting.impl.netty.NettyConnectorFactory&amp;lt;/config-property-value&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/config-property&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;description&amp;gt;The transport configuration. These values must be in the form of key=val;key=val;&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property-name&amp;gt;ConnectionParameters&amp;lt;/config-property-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property-type&amp;gt;java.lang.String&amp;lt;/config-property-type&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;config-property-value&amp;gt;host=${node.with.queue:localhost};port=${hornetq.remoting.netty.port:5445}&amp;lt;/config-property-value&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/config-property&amp;gt;&amp;lt;/tt&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;On all nodes, modify &lt;tt&gt;/server/all/deploy/hornetq/jms-ds.xml&lt;/tt&gt; to use NettyConnectorFactory (instead of InVMConnectorFactory implicitly) and supply a host and port (this is your producer):&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;tx-connection-factory&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;jndi-name&amp;gt;JmsXA&amp;lt;/jndi-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xa-transaction/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;rar-name&amp;gt;jms-ra.rar&amp;lt;/rar-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connection-definition&amp;gt;org.hornetq.ra.HornetQRAConnectionFactory&amp;lt;/connection-definition&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property name="SessionDefaultType" type="java.lang.String"&amp;gt;javax.jms.Topic&amp;lt;/config-property&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;config-property name="ConnectorClassName" type="java.lang.String"&amp;gt;org.hornetq.core.remoting.impl.netty.NettyConnectorFactory&amp;lt;/config-property&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property name="ConnectionParameters" type="java.lang.String"&amp;gt;host=${node.with.queue:localhost};port=${hornetq.remoting.netty.port:5445}&amp;lt;/config-property&amp;gt;&lt;/strong&gt;&lt;/tt&gt;&lt;/div&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;On all nodes, pass the same &lt;strong&gt;-Dnode.with.queue=192.xx.xx.xx&lt;/strong&gt; value&lt;/li&gt;&lt;/ul&gt;Now the MDBs on all nodes will both produce to, and consume from, &lt;tt&gt;node.with.queue&lt;/tt&gt;. You're back to a Single Point of Failure but you're &lt;em&gt;also&lt;/em&gt; back to supporting 'uneven' nodes (i.e. some faster than others). In addition may I suggest, in &lt;tt&gt;hornetq-configuration.xml&lt;/tt&gt;:&lt;ul&gt;&lt;li&gt;Set &lt;tt&gt;&amp;lt;clustered&amp;gt;false&amp;lt;/clustered&amp;gt;&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Remove all &lt;tt&gt;&amp;lt;connectors /&amp;gt;&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Leave just the Netty &lt;tt&gt;&amp;lt;acceptor /&amp;gt;&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Remove all &lt;tt&gt;&amp;lt;broadcast-groups /&amp;gt;&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Remove all &lt;tt&gt;&amp;lt;discovery-groups /&amp;gt;&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Remove all &lt;tt&gt;&amp;lt;cluster-connections /&amp;gt;&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Remove your cluster username/password&lt;/li&gt;&lt;/ul&gt;Because now you're no longer using any clustering (at the HornetQ level) so can remove that overhead.&lt;br /&gt;&lt;br /&gt;Hope that helps somebody!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-414863412871501787?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/414863412871501787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=414863412871501787' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/414863412871501787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/414863412871501787'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/06/hornetq-i-want-my-i-want-my-i-want-my.html' title='HornetQ: I Want My... I Want My... I Want My MTV (um, JBM)'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-qpZlx--lYOE/TecjMMt_mYI/AAAAAAAAAcQ/wEeSKEqzAns/s72-c/1516_450_130_cache.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-5268901741525976023</id><published>2011-06-14T11:09:00.005+10:00</published><updated>2011-07-18T08:36:58.729+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HornetQ'/><title type='text'>Stung by HornetQ: The Revenge</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 320px; height: 93px;" src="http://1.bp.blogspot.com/-qpZlx--lYOE/TecjMMt_mYI/AAAAAAAAAcQ/wEeSKEqzAns/s320/1516_450_130_cache.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5613494153020152194" /&gt;Following on from &lt;a href="http://blog.kennardconsulting.com/2011/06/stung-by-hornetq.html"&gt;my previous post&lt;/a&gt; I've been spending some more time with &lt;a href="http://jboss.org/hornetq"&gt;HornetQ&lt;/a&gt; and have discovered a few more gotchas:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;4. Stuck By Default&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There's some &lt;a href="http://hornetq.sourceforge.net/docs/hornetq-2.0.0.BETA5/user-manual/en/html/perf-tuning.html"&gt;advice here&lt;/a&gt; that says...&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Probably the most common messaging anti-pattern we see is users who create a new connection/session/producer for every message they send or every message they consume. This is a poor use of resources... Always re-use them"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;...couple that with &lt;a href="http://hornetq.sourceforge.net/docs/hornetq-2.0.0.GA/user-manual/en/html/flow-control.html"&gt;other advice&lt;/a&gt; that says...&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Please note the default value for address-full-policy [when the send buffer is full] is to PAGE [out to disk]"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;And you might think the Right Thing To Do is set up a single connection/session/producer and send all your messages to the queue. But if you're doing this in a transaction (most Web applications are) you'd be wrong. Why? Because there's &lt;a href="http://hornetq.sourceforge.net/docs/hornetq-2.0.0.GA/user-manual/en/html/paging.html"&gt;some conflicting advice&lt;/a&gt; that says...&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"By default, HornetQ does not page messages - this must be explicitly configured to activate it"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;And a setting in the JBoss/HornetQ integration (&lt;tt&gt;hornetq-configuration.xml&lt;/tt&gt;) that says...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;max-size-bytes&amp;gt;10485760&amp;lt;/max-size-bytes&amp;gt;&lt;br /&gt;&amp;lt;address-full-policy&amp;gt;BLOCK&amp;lt;/address-full-policy&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;So &lt;strong&gt;by default JBoss will get stuck&lt;/strong&gt; if you try sending more than 10MB of messages in a single transacted producer (ie. before your MDBs can start consuming them). 10MB is not a lot. For me it was about 1,000 messages of about 5,000 characters each (a Unicode XML string).&lt;br /&gt;&lt;br /&gt;Here are my suggestions:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;HornetQ should treat its JBoss JMS integration as more of a first class citizen&lt;/strong&gt;. It should be a primary use case, rather than relegated to a &lt;a href="http://docs.jboss.org/hornetq/2.2.2.Final/user-manual/en/html/appserver-integration.html"&gt;chapter at the back of the user guide&lt;/a&gt;. Why? Because most people that just dip into the User Guide are going to be doing so from a JBoss JMS mindset. So if you say something like "Please note the default value is to PAGE" then you need to also say, immediately afterwards, " (except on JBoss where the default value is to BLOCK)"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;BLOCKing is a poor default value&lt;/strong&gt;. Either &lt;a href="https://issues.jboss.org/browse/HORNETQ-581"&gt;make it fail&lt;/a&gt; (so the user gets an error) or make it PAGE (so the user gets an error when their disk is full). At least then the developer knows where to look. But blocking just results in the queue being 'stuck' - with no clue to the developer who has barely heard of their underlying JMS implementation, let alone blocking versus paging and &lt;tt&gt;&amp;lt;address-full-policy&amp;gt;&lt;/tt&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;5. Stuck By Bugs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;HornetQ is pretty new and there are a few bugs that can cause your JMS messages to get stuck. There's the fact that &lt;a href="https://issues.jboss.org/browse/JBAS-7950"&gt;MDBs will rollback/retry indefinitely&lt;/a&gt;, that &lt;a href="https://issues.jboss.org/browse/HORNETQ-705"&gt;messages with different JMS priorities may get forgotten&lt;/a&gt;, that &lt;a href="https://issues.jboss.org/browse/HORNETQ-716"&gt;messages can be forwarded to dead cluster nodes&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;When you have several different bugs interacting to produce an overall symptom (ie. a stuck queue) it can be very hard to separate them to understand their underlying causes. This causes a lot of pain!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;6. Stuck By Birth&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This one isn't really HornetQ's fault, but its behaviour seems different to JBoss Messaging. If your MDB uses &lt;tt&gt;@EJB&lt;/tt&gt; injection you really need to setup &lt;tt&gt;&amp;lt;depends ... &amp;gt;&lt;/tt&gt; blocks in your &lt;tt&gt;jboss.xml&lt;/tt&gt;...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;message-driven&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ejb-name&amp;gt;LongRunningProcessConsumerBean&amp;lt;/ejb-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;destination-jndi-name&amp;gt;queue/avant-ss.long-running-processes&amp;lt;/destination-jndi-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;!-- Stop MDB consuming too early --&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;depends&amp;gt;jboss.j2ee:ear=avant-ss-app.ear,jar=avant-ss-dev-ejb.jar,name=LongRunningProcessBean,service=EJB3&amp;lt;/depends&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;depends&amp;gt;jboss.j2ee:ear=avant-ss-app.ear,jar=avant-ss-dev-ejb.jar,name=BusinessRulesBean,service=EJB3&amp;lt;/depends&amp;gt;&lt;/strong&gt;&amp;lt;/message-driven&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...because HornetQ starts up and starts consuming very early. This is particularly bad because these errors go quietly into the &lt;tt&gt;boot.log&lt;/tt&gt;, not the regular &lt;tt&gt;system.log&lt;/tt&gt;, so you don't realise that your MDBs crashed on startup.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-5268901741525976023?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/5268901741525976023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=5268901741525976023' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5268901741525976023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5268901741525976023'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/06/stung-by-hornetq-revenge.html' title='Stung by HornetQ: The Revenge'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-qpZlx--lYOE/TecjMMt_mYI/AAAAAAAAAcQ/wEeSKEqzAns/s72-c/1516_450_130_cache.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-6829677538603676876</id><published>2011-06-03T09:53:00.019+10:00</published><updated>2011-06-03T16:32:19.853+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><title type='text'>Oracle and the Evil Alternative: Taking Java Private</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 260px; height: 320px;" src="http://1.bp.blogspot.com/-yOp0aREYQ-k/TegjsCpyI0I/AAAAAAAAAcg/cUakN1Is8fM/s320/burns.gif" border="0" alt="NOT an Oracle employee" id="BLOGGER_PHOTO_ID_5613776175050662722" /&gt;In &lt;a href="http://blogs.oracle.com/javaspotlight/entry/java_spotlight_episode_30_henrik"&gt;a recent episode&lt;/a&gt; of the &lt;a href="http://blogs.oracle.com/javaspotlight"&gt;Java Spotlight Podcast&lt;/a&gt;, &lt;a href="http://blogs.oracle.com/henrik"&gt;Henrik Ståhl&lt;/a&gt; (Oracle's Senior Product Director of Java Platform Development) is interviewed about Oracle's strategy for Java past and present.&lt;br /&gt; &lt;br /&gt;At 9 minutes 20 seconds he says "[Oracle] looked at the evil alternative, taking Java private". He then goes on to say "we determined it wasn't a good idea". But I was interested that Henrik didn't say "we determined it wasn't possible".&lt;br /&gt;&lt;br /&gt;I contacted Henrik and asked for clarification: how would 'taking Java private' work? &lt;br /&gt;&lt;br /&gt;&lt;h2 style="font-size: 130%; font-weight: bold"&gt;Relax, This Isn't Going To Happen&lt;/h2&gt;&lt;br /&gt;First, let's be clear. Henrik has been explicit about Oracle's strategy for Java (&lt;a href="http://blogs.oracle.com/henrik/entry/oracle_and_openjdk"&gt;here&lt;/a&gt;, &lt;a href="http://blogs.oracle.com/henrik/entry/oracles_jvm_strategy"&gt;here&lt;/a&gt;, &lt;a href="http://www.oracle.com/us/corporate/press/173782"&gt;here&lt;/a&gt; and &lt;a href="http://blogs.oracle.com/henrik/entry/jrockit_is_now_free_and"&gt;here&lt;/a&gt;): they have considered this evil alternative and rejected it. That's not what this blog is about. Let's not start a &lt;a href="http://en.wikipedia.org/wiki/Fear,_uncertainty_and_doubt"&gt;FUD&lt;/a&gt; storm.&lt;br /&gt;&lt;br /&gt;Rather I'm interested in how any company could, even hypothetically, take a GPL'd project private.&lt;br /&gt;&lt;br /&gt;&lt;h2 style="font-size: 130%; font-weight: bold"&gt;So, Hypothetically, How Would It Work?&lt;/h2&gt;&lt;br /&gt;Henrik explained the basic idea was that, given Oracle owns or co-owns all OpenJDK Intellectual Property (IP), they&lt;br /&gt;have the right to release it under a non-GPL license. &lt;strong&gt;The owner of the IP can retroactively apply any license he/she wants&lt;/strong&gt;, provided all prior modifications to the IP were made by that same owner. This appears to sidestep the &lt;a href="http://www.gnu.org/copyleft"&gt;GPL copyleft clause&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Of course you can't stop the community using the existing GPL'd version. Nor can you stop them forking it (though under a different name). But being able to un-GPL the code is a significant leg up from, say, having to build a &lt;a href="http://harmony.apache.org"&gt;clean room implementation&lt;/a&gt; before you can privatize it. It means you can have a &lt;strong&gt;100% compatible, closed source product from day one, built using modified GPL'd code&lt;/strong&gt;. And I assume if you rev the versions quick enough, most corporates will follow you rather than wait for the community version to catch up. Effectively you can close source a GPL project.&lt;br /&gt;&lt;br /&gt;So my question is: is this legitimate? Can a corporation take a piece of Open Source software, acquire all IP rights to it, then close source its future versions? Is this a risk of relying on Open Source software? Should steps be taken to mitigate this risk? For example, &lt;strong&gt;should an Open Source project ensure its IP is distributed between multiple neutral entities&lt;/strong&gt; (and avoid having Contributor Agreements that require handing over IP rights)?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-6829677538603676876?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/6829677538603676876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=6829677538603676876' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6829677538603676876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6829677538603676876'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/06/oracle-and-evil-alternative-taking-java.html' title='Oracle and the Evil Alternative: Taking Java Private'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-yOp0aREYQ-k/TegjsCpyI0I/AAAAAAAAAcg/cUakN1Is8fM/s72-c/burns.gif' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-5778860911487322087</id><published>2011-06-01T15:42:00.008+10:00</published><updated>2011-06-02T17:21:45.696+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HornetQ'/><title type='text'>Stung by HornetQ</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 320px; height: 93px;" src="http://1.bp.blogspot.com/-qpZlx--lYOE/TecjMMt_mYI/AAAAAAAAAcQ/wEeSKEqzAns/s320/1516_450_130_cache.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5613494153020152194" /&gt;I've recently been upgrading our &lt;a href="http://jboss.org/jbossas"&gt;JBoss 5.1.0.GA&lt;/a&gt; and &lt;a href="http://jboss.org/jbossmessaging/"&gt;JBoss Messaging&lt;/a&gt; based application to JBoss 6.0.0.Final and &lt;a href="http://jboss.org/hornetq"&gt;HornetQ&lt;/a&gt;. &lt;strong&gt;The end result has been positive: HornetQ is very fast&lt;/strong&gt;. But there were a few gotchas I thought I'd share:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;1. No More Database, Lots More Backups&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;HornetQ eschews the JBoss Messaging approach of storing messages in a shared database. Instead it uses the file system directly (and, on Linux, accelerated &lt;a href="http://en.wikipedia.org/wiki/Asynchronous_I/O"&gt;AIO&lt;/a&gt;). But note this doesn't mean a &lt;em&gt;shared&lt;/em&gt; file system. It means &lt;strong&gt;each cluster node has its own file system&lt;/strong&gt;, with peer-to-peer communication to distribute messages between them.&lt;br /&gt;&lt;br /&gt;The advantage of this approach is you no longer have a &lt;a href="http://en.wikipedia.org/wiki/Single_point_of_failure"&gt;Single Point of Failure&lt;/a&gt; (ie. the database). But it's quite a shift in mindset if you're used to thinking of your database as a heavy, fault-tolerant kind-of-thing and your nodes as lightweight, throwaway kind-of-things. Because now, each node stores a portion of your messages. So &lt;strong&gt;if you lose a node you lose some messages&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;The recommended solution to this is to have &lt;em&gt;backup nodes&lt;/em&gt;. Whereas before you might have one big backup instance for your database, and no backups for your nodes, now you need a backup for each node. See &lt;a href="http://community.jboss.org/thread/167181?tstart=0"&gt;this forum thread&lt;/a&gt;. Confusingly, when talking about backup nodes you may choose to use a shared file. But this is only for sharing between the 'backup' and 'live' instance of a single node.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;2. hornetq-jms.xml Is A Red Herring&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Out of the box, JBoss 6.0.0.Final includes a &lt;tt&gt;server/all/deploy/hornetq/hornetq-jms.xml&lt;/tt&gt; that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;configuration xmlns="urn:hornetq"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connection-factory name="NettyConnectionFactory"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connector-ref connector-name="netty"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entries&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="/ConnectionFactory"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="/XAConnectionFactory"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/entries&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connection-factory&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connection-factory name="NettyThroughputConnectionFactory"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connector-ref connector-name="netty-throughput"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entries&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="/ThroughputConnectionFactory"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="/XAThroughputConnectionFactory"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/entries&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connection-factory&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connection-factory name="InVMConnectionFactory"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connector-ref connector-name="in-vm"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entries&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="java:/ConnectionFactory"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="java:/XAConnectionFactory"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/entries&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connection-factory&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;queue name="DLQ"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="/queue/DLQ"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/queue&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;queue name="ExpiryQueue"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;entry name="/queue/ExpiryQueue"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/queue&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;To my mind this is very confusing, because &lt;strong&gt;if you're using JMS producers and MDBs all those &amp;lt;connection-factory&amp;gt; configurations aren't used!&lt;/strong&gt; I would recommend deleting them, for 3 reasons:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;You see the &lt;tt&gt;/ConnectionFactory&lt;/tt&gt; JNDI reference in there and think you should start using &lt;tt&gt;ic.lookup("/ConnectionFactory")&lt;/tt&gt; in your code. If you do, you'll get non-transacted queue sessions, duplicated messages, lost messages, and all sorts of other weirdness. Stick with &lt;tt&gt;ic.lookup("java:JmsXA")&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If using &lt;tt&gt;java:JmsXA&lt;/tt&gt;, those &amp;lt;connection-factory&amp;gt; configurations don't apply! You need to look instead in &lt;tt&gt;server/all/deploy/hornetq/jms-ds.xml&lt;/tt&gt;. This is using &lt;tt&gt;InVMConnectorFactory&lt;/tt&gt; implicitly, but you can &lt;a href="http://hornetq.sourceforge.net/docs/hornetq-2.1.0.Final/user-manual/en/html/appserver-integration.html#d0e7656"&gt;explicitly configure it&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If using MDBs, again those &amp;lt;connection-factory&amp;gt; configurations don't apply! MDBs are configured in &lt;tt&gt;server/all/deploy/jms-ra.rar/META-INF/ra.xml&lt;/tt&gt;. They use &lt;tt&gt;InVMConnectorFactory&lt;/tt&gt; by default.&lt;/li&gt;&lt;/ol&gt;This last point is a real doozey. Because if you want to simulate a heavyweight store of messages with lightweight consumers who read from it (like JBoss Messaging) you're going to want to use &amp;lt;consumer-window-size&amp;gt;0&amp;lt;/consumer-window-size&amp;gt;. You'll find lots of examples on the Web of putting this in &lt;tt&gt;hornetq-jms.xml&lt;/tt&gt;. &lt;strong&gt;But consumer-window-size won't work there&lt;/strong&gt;, because MDBs don't use &lt;tt&gt;hornetq-jms.xml&lt;/tt&gt;. Instead you need this in &lt;tt&gt;ra.xml&lt;/tt&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;config-property&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;description&amp;gt;The consumer window size&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;config-property-name&amp;gt;ConsumerWindowSize&amp;lt;/config-property-name&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property-type&amp;gt;java.lang.Integer&amp;lt;/config-property-type&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;config-property-value&amp;gt;0&amp;lt;/config-property-value&amp;gt;&lt;br /&gt;&amp;lt;/config-property&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;3. hornetq-configuration.xml Is Noisy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm a 'break it to learn it' kind of guy. So to my mind the connectors and acceptors section of &lt;tt&gt;hornetq-configuration.xml&lt;/tt&gt; is a bit noisy. Here's what you can reduce it to:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- Node to node communication --&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;connector name="netty"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;factory-class&amp;gt;org.hornetq.core.remoting.impl.netty.NettyConnectorFactory&amp;lt;/factory-class&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;param key="host" value="${jboss.bind.address:localhost}"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;param key="port" value="${hornetq.remoting.netty.port:5445}"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connector&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/connectors&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;acceptors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- Node to node communication --&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;acceptor name="netty"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;factory-class&amp;gt;org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory&amp;lt;/factory-class&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;param key="host" value="${jboss.bind.address:localhost}"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;param key="port" value="${hornetq.remoting.netty.port:5445}"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/acceptor&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- jms-ds.xml produces to, and ra.xml consumes from, InVMConnectorFactory by default --&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;acceptor name="in-vm"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;factory-class&amp;gt;org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory&amp;lt;/factory-class&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;param key="server-id" value="0"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/acceptor&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/acceptors&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Your Mileage May Vary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Of course, these tips aren't for everyone. But if you're like me they may save you a few hours banging your head against the desk!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-5778860911487322087?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/5778860911487322087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=5778860911487322087' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5778860911487322087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5778860911487322087'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/06/stung-by-hornetq.html' title='Stung by HornetQ'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-qpZlx--lYOE/TecjMMt_mYI/AAAAAAAAAcQ/wEeSKEqzAns/s72-c/1516_450_130_cache.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-807107188567529517</id><published>2011-05-20T21:29:00.016+10:00</published><updated>2011-07-18T08:37:15.514+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Is There Convergence in the Field of UI Generation?</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TON0leIPEKI/AAAAAAAAAUk/VWFuhqHAOWo/s400/package_graphics.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540400153687429282" /&gt;Kennard, R. &amp;amp; Leaney, J. 2011, Journal of Systems and Software&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;Abstract&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;For many software projects, the construction of the User Interface (UI) consumes a significant proportion of their development time. Any degree of automation in this area therefore has clear benefits. But it is difficult to achieve such automation in a way that will be widely adopted by industry because of the diversity of UIs, software architectures, platforms and development environments. In a previous article, the authors identified five key characteristics any UI generator would need in order to address this diversity. We asserted that, without these characteristics, a UI generator should not expect wide industry adoption or standardisation. We supported this assertion with evidence from industry adoption studies. A further source of validation would be to see if other research teams, who were also conducting industry field trials, were independently converging on this same set of characteristics. Conversely, it would be instructive if they were found to be converging on a different set of characteristics. In this article, the authors look for such evidence of convergence by interviewing the team behind one of the research community's most significant UI generators: Naked Objects. We observe strong signs of convergence, which we believe signal the beginning of a general purpose architecture for UI generation, one that both industry and the research community could standardise upon.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;1. Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For many software projects, the construction of the User Interface (UI) consumes a significant proportion of their development time. Research in the early 1990s found that some 48% of application code and 50% of application time was devoted to implementing UIs (Myers 1992). These figures are still considered relevant today, more so with the increased demands of richly graphical and web-based UIs (Jha 2005; Daniel et al. 2007), therefore any degree of automation in this area has clear benefits. But it is difficult to achieve such automation in a way that is useful and widely adopted by industry. In previous papers (Kennard &amp;amp; Steele 2008; Kennard, Edmonds &amp;amp; Leaney 2009) the authors explored the diversity of UIs, architectures, platforms and development environments that contribute to this difficulty. And in a &lt;a href="http://blog.kennardconsulting.com/2010/11/towards-general-purpose-architecture.html"&gt;recent article (Kennard &amp;amp; Leaney 2010)&lt;/a&gt; the authors identified five key characteristics any UI generator would need in order to address this diversity. The authors asserted that, without these five characteristics, a UI generator should not expect wide industry adoption or standardisation. We summarised these five characteristics as:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;em&gt;Inspecting existing, heterogeneous back-end architectures&lt;/em&gt;: the authors found many business systems are modelled using what Fowler (2002) calls "anaemic entities". These are surrounded in an arrangement that Firesmith (1996) describes as "dumb entity objects controlled by a number of controller objects". Such controller objects include persistence contexts, validation subsystems and Business Process Modelling (BPM) languages. As far as UI generation is concerned, there is a single source of truth (SSOT) but it is decentralised amongst these multiple subsystems. As Shan et al. (2006) enumerate, there are often competing implementations of the same subsystem. Furthermore as Rouvellou et al. (1999) shows, different types of subsystems become popular over time, such as rule engines. Any UI generator that seeks to dictate, rather than adapt to, a system's architecture therefore has limited practical value.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Appreciating different practices in applying inspection results&lt;/em&gt;: adoption studies (Kennard &amp;amp; Leaney 2010) showed the raw inspection result invariably needs post processing before it is suitable for consumption by a UI generator. For example, fields generally need to be arranged in a business defined order, or excluded based on business defined criteria. In some cases this processing can be performed independent of any particular UI screen. For example, globally excluding fields that represent database synthetic keys. In other cases it requires knowledge of which UI screen the user has navigated to. For example, a summary screen versus a detail screen. Furthermore, different practitioners had different preferences on how to perform such post processing. Some preferred  a 'comes after' approach, whereby each business field can specify the field that immediately precedes it. But some adoption studies reported "I would rather give the properties priorities so that I can say 'this one comes first' instead of 'this one comes after that other one'. It's just more natural to me".&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Recognising multiple, and mixtures of, UI widget libraries&lt;/em&gt;: practitioners discussed how industry UI libraries were diverging from any notion of a single, ubiquitous UI framework. They expressed the need to support a variety of front-end frameworks, including third-party and in-house widget libraries. In particular, they talked about the need to mix multiple third-party and in-house widget libraries within the same UI, in order to achieve a high quality user experience. Any UI generator that limits this choice compromises usability - the most determining factor of a UI - for the sake of automatic generation.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Supporting multiple, and mixtures of, UI adornments&lt;/em&gt;: in raw form, a widget is unlikely to be suitable for inclusion in a UI. For example, end users interacting with a raw text field are able to enter arbitrary text. However the business requirement may be for, say, a credit card number. Widgets therefore need to be further adorned with data validators, data binding frameworks and event handlers. Of particular note is that some of these mechanisms, such as a credit card validator, may come from a different third-party library than the raw widget.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Applying multiple, and mixtures of, UI layouts&lt;/em&gt;: a final characteristic was supporting multiple ways to arrange widgets on the screen. It significantly detracts from the practicality of automated generation if it in any way compromises the final product in usability, or even in aesthetics (Myers, Hudson &amp;amp; Pausch 2000, p. 13). Yet there is a formidable degree of variability. Fields may typically be arranged in a 'column', with the widget on the right and its label on the left. But other times the practitioner may want two or three such columns side by side. If so, they may need some widgets - such as large text areas - to span multiple columns. Or they may abandon columns altogether and want the fields arranged in a single, horizontal row. Furthermore, it is not difficult to posit other real world arrangements, such as right-to-left arrangements for the Arabic world. It is important to accommodate this variety if the generator is to achieve the exact look the practitioner desires.&lt;/li&gt;&lt;/ol&gt;Having defined these five characteristics, the authors supported them with evidence from industry adoption studies (Kennard &amp;amp; Leaney 2010). A further source of validation would be to see if other research teams, who were also conducting industry field trials, were independently converging on this same set of characteristics. If they were as fundamental as we believed, other teams should have been identifying similar constructs. Conversely, if they were found to be converging on a different set of characteristics, that would also be very instructive. In this article, the authors look for such evidence of convergence by interviewing the team behind one of the research community's most significant UI generators: &lt;a href="http://nakedobjects.net"&gt;Naked Objects&lt;/a&gt;. Clearly this is a qualitative measure, not quantitative, but has validity in conjunction with our previous work (Kennard &amp;amp; Leaney 2010) as a triangulation between industry and the research community. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;2. Related Work&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Research in the field of UI generation dates back over two decades. Projects including, though by no means limited to, COUSIN (Hayes, Szekely &amp;amp; Lerner 1985), TRIDENT (Bodart et al. 1995), UsiXML (Vanderdonckt et al. 2004), OliviaNOVA and OOWS (Valverd et al. 2006) and AUI (Xudong &amp;amp; Jiancheng 2007) have all explored a variety of techniques. The work was given increased urgency with the emergence of ubiquitous computing (Weiser 1993) and its proliferation of different UI devices with widely varying capabilities.&lt;br /&gt;&lt;br /&gt;However most approaches have not taken industry acceptance and adoption as a key driver for their work. This means they have tended to exhibit significant disadvantages from an industry perspective (Myers, Hudson &amp;amp; Pausch 2000). Many require developers laboriously restate information that is already encoded elsewhere in an application. "A common disadvantage of both [interactive graphical editing tools and UI modelling languages] is the fact that the user interface is defined explicitly and separately" (Jelinek &amp;amp; Slavik 2004). This makes them a source of errors should the application code and the UI model not stay synchronised. Other UI generation approaches have imposed generalised interfaces which appear quite differently from, and function less effectively than, those designed with consideration to their specific purpose (Falb et al. 2007).  Such disadvantages have led to limited adoption of these tools within industry.&lt;br /&gt;&lt;br /&gt;There have been some notable industry successes, however. The Cameleon reference framework (Calvary et al. 2003) defines a Unifying Reference Framework for diverse, ubiquitous devices. The team have worked closely with the World Wide Web Consortium (W3C) with a view to industry standardization. Cameleon introduces "the notions of multi-targeting and plasticity" and "serves as a reference for classifying user interfaces supporting multiple targets, or multiple contexts of use in the field of context-aware computing". It further incorporates UsiXML (Vanderdonckt et al. 2004), a common User Interface Description Language (UIDL), which has also been submitted to the W3C for standardization. In doing so, it hopes to address a shortcoming of "AUIML, UIML, XAML, XIML, XUL" in that they "result in many XML-compliant dialects that are not (yet) largely used and that do not allow interoperability between tools that have been developed around the[ir own] UIDL". &lt;br /&gt;&lt;br /&gt;As an approach gains acceptance and adoption within industry it generally inspires multiple implementations. These implementations first compete, then converge on a set of core characteristics with some additional features as a differentiator. This convergence ultimately leads industry to standardize upon the core characteristics, reflecting a pivotal moment in the maturity of the approach. This industry convergence can be evidenced in such projects as &lt;a href="http://hibernate.org"&gt;Hibernate&lt;/a&gt; and &lt;a href="http://www.oracle.com/technetwork/middleware/toplink"&gt;TopLink&lt;/a&gt; standardizing under &lt;a href="http://jcp.org/en/jsr/detail?id=220"&gt;JPA&lt;/a&gt;, and &lt;a href="http://springframework.org"&gt;Spring&lt;/a&gt;, &lt;a href="http://code.google.com/p/google-guice"&gt;Guice&lt;/a&gt; and &lt;a href="http://seamframework.org"&gt;Seam&lt;/a&gt; standardizing under &lt;a href="http://www.jcp.org/en/jsr/detail?id=330"&gt;JSR 330&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Convergence, therefore, requires the experience and validation that come from large scale adoption. One approach that has seen significant adoption, being used by large organisations such as the Irish Department of Social Protection and deployed to thousands of users, is the Naked Objects pattern (Pawson 2004). Given the authors' focus on industry applicability, Naked Objects presents as a forerunner in bridging the divide between the theoretical and the practical.&lt;br /&gt;&lt;br /&gt;The naked objects pattern considers "an application solely in terms of the [domain] objects. These objects are then rendered directly visible to the user by means of a generic presentation layer. The user undertakes all tasks by directly invoking methods on those [domain] objects. This approach has been dubbed ‘naked objects’, because as far as the user is concerned he or she is viewing and manipulating the ‘naked’ business domain objects". If there is any doubt as to the significance of Pawson's approach, one need look no further than the polarising effect it has had on the research community. It has been lauded by renowned pioneers such as Trygve Reenskaug, inventor of the Model-View-Controller (MVC) pattern: "In the quarter century since the inception of MVC, there has been little progress in empowering the users. This is where Pawson’s work comes as a fresh contribution in an otherwise drab market... Naked Objects represent a new beginning pointing towards a novel generation of human-centred information systems" (Pawson 2004, p. 3). It has been similarly praised by Dave Thomas, co-author of The Agile Manifesto: "Naked Objects is the embodiment of the Agile movement: lean, elegant, user-focused, and with testing built right in. Reduce a problem to its bare essentials, code it up with no extra fluff, then ship it out. Naked Objects brings programming back to its real purpose: expressing and solving business problems" (Pawson &amp;amp; Matthews 2002). But the Naked Objects pattern has also been derided by equally renowned pioneers such as Larry Constantine, expert in usage centred design: "The usability problems with [Naked Objects] interfaces under most conditions are too numerous to go into... Pawson and [framework implementer Robert] Matthews, who by their own admission are neither usability experts nor well-versed in user interface design, seem to be blissfully ignorant of the problems... Their book cites sources arguing for 'object oriented user interfaces' but ignores the critical literature that long ago discredited the concept" (Constantine 2002).&lt;br /&gt;&lt;br /&gt;The authors, too, have been critical of Naked Objects. When developing our own UI generator, called &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, we have expressed doubts over the practicality of the Naked Objects 'behaviourally-complete' methodology. This methodology dictates "all the functionality associated with a given entity [must be] encapsulated in that entity, rather than being provided in the form of external functional procedures that act upon the entities" (Pawson 2004). Yet Pawson himself recognises "most object-oriented designs, and especially object-oriented designs for business systems, do not match this ideal of behavioural-completeness". The authors believe this is not, as Pawson suggests, because they are poorly designed. Rather, they are seeking to leverage functionality provided by the large number of mature subsystems available in industry, in order to increase productivity and reduce development cost (Kennard &amp;amp; Leaney 2010). For Naked Objects to be applicable to such business systems, it needs to accommodate their approach rather than expect them to be re-architected as behaviourally-complete.&lt;br /&gt;&lt;br /&gt;However, all such criticisms are levelled at the version of Naked Objects last described by the academic literature (Pawson 2004). Like any good software project, Naked Objects has evolved over the intervening years. The team now have both Java and .NET implementations, have published several books (Pawson &amp;amp; Matthews 2002; Haywood 2009), and have continued to refine their approach. They have recently moved to standardise and increase adoption by moving Naked Objects for Java to the Apache Software Foundation under the name &lt;a href="http://incubator.apache.org/isis"&gt;Apache Isis&lt;/a&gt;. The frameworks implementing the naked objects pattern in 2010 have many differences to the original Naked Objects Framework of 2004.&lt;br /&gt;&lt;br /&gt;The authors contacted the Naked Objects team for an update on their work. What we discovered was a surprising amount of independent convergence with our own ideas.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;3. Methodology&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The authors interviewed &lt;a href="http://danhaywood.com"&gt;Dan Haywood&lt;/a&gt; over a series of e-mails in late 2010. Dan is a UK-based freelance consultant specialising in enterprise application development using domain driven design approaches and agile development. He is the project lead on the Apache Isis project (the effort to standard Naked Objects within the Apache Software Foundation), the author of &lt;a href="http://www.pragprog.com/titles/dhnako/domain-driven-design-using-naked-objects"&gt;Domain Driven Design using Naked Objects&lt;/a&gt; and a long-time advocate of the naked objects pattern.&lt;br /&gt;&lt;br /&gt;We chose a standardized, open-ended format for the interview (Valenzuela &amp;amp; Shrivastava 2002). This approach involves asking broadly framed questions to allow the candidate room to talk openly, avoiding leading the interviewee and therefore minimizing bias. The overarching theme of the interview was the current feature set of the Naked Objects architecture. The interviewee was asked to discuss, and contextualize, aspects of their approach. The goal was to draw out decisions underlying the original design and motivations that led to subsequent changes. We observed patterns of convergence, then posited probe questions (Dick 2005) to drill down and confirm our observations. Unlike our previous interviews (Kennard, Edmonds &amp;amp; Leaney 2009) we were not looking to generalise or codify. Rather every comment, even in isolation, was valuable to help understand the team's research.&lt;br /&gt;&lt;br /&gt;The authors and the Naked Objects team had worked independently up to this point, but learnt much about each other's work during the course of the exchange. Most notably, we discovered a surprising amount of convergence around the key characteristics we had previously identified (Kennard &amp;amp; Leaney 2010). In the next section, we record our findings, framed in the context of the five characteristics defined in section 1.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;4. Interview&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Dan started the discussion with an overview of the current design. Recap that Pawson (2004) had summarized: "Using the naked objects approach to designing a business system, the domain objects are exposed explicitly, and automatically, to the user, such that all user actions consist of viewing objects, and invoking behaviours that are encapsulated in those objects". This results in an Object Oriented User Interface (OOUI) as shown below:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-LHZOmF3JyT4/TdZQyHW9ffI/AAAAAAAAAbw/AE-R2npypUE/s1600/figure1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 215px;" src="http://2.bp.blogspot.com/-LHZOmF3JyT4/TdZQyHW9ffI/AAAAAAAAAbw/AE-R2npypUE/s320/figure1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5608759207835565554" /&gt;&lt;/a&gt;The UI is a direct representation of the domain objects, with UI actions explicitly creating and retrieving domain objects and invoking an object's methods. The advantage of this approach is that the UI can be built and reworked very rapidly from the domain.&lt;br /&gt;&lt;br /&gt;Dan then elaborated on the architecture. "First off, in terms of what Naked Objects/Apache Isis actually is, these days I think of it in terms of the hexagonal architecture:"&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-ugWyu8WPbVM/TdZQyfFqHHI/AAAAAAAAAb4/8T7ehzOcIN8/s1600/figure2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 234px;" src="http://4.bp.blogspot.com/-ugWyu8WPbVM/TdZQyfFqHHI/AAAAAAAAAb4/8T7ehzOcIN8/s320/figure2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5608759214205443186" /&gt;&lt;/a&gt;&lt;br /&gt;"The hexagon core has got two main bits to it - the metamodel (cf. a class) and the runtime (cf. an object). Plugging into the hexagon are the back-end object stores [labelled 'persistence'], and the front-end viewers [labelled 'main' and 'webapp']".&lt;br /&gt;&lt;br /&gt;"The metamodel [the hexagon] defines the ObjectSpecification which describes the class, its inheritance hierarchy, its class members. The runtime defines the ObjectAdapter, which wraps each [domain object]. This references the ObjectSpecification and also references an opaque Object Identifier (OID), basically an abstraction over primary keys (since it is assigned by the object store) though non-persisted objects also have an OID. The runtime also manages the identity of the (entity) object, each of which is identified in a multiway identity map of [domain object] &lt;-&gt; ObjectAdapter &lt;-&gt; OID. The back-end object store implementations deal mostly with the runtime; some use the metamodel (e.g. XML object store), some don't (e.g. JPA object store, because [JPA] builds its own metamodel). The front-end viewer implementations deal mostly with the metamodel in that they use it to render the [domain objects]".&lt;br /&gt;&lt;br /&gt;The interview then moved to discuss back-end object stores, the metamodel and front-end viewers in detail. The authors discovered a significant amount of convergence with our own key characteristics, identified previously (Kennard &amp;amp; Leaney 2010).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;4.1 Inspecting existing, heterogeneous back-end architectures&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The authors had previously identified (Kennard &amp;amp; Leaney 2010) that supporting a mixture of heterogeneous sources of UI metadata was an important characteristic for a practical UI generator. Many business systems are modelled as 'anaemic' (Fowler 2002) or 'dumb' (Firesmith 1996) entities surrounded by controller objects such as persistence contexts, validation subsystems and rule engines. This has implications for frameworks implementing the naked objects pattern, with its original tenet of 'behavioural-completeness' dictating that "all the functionality associated with a given entity [must be] encapsulated in that entity, rather than being provided in the form of external functional procedures that act upon the entities" (Pawson 2004). Our adoption studies showed practitioners resisted "many frameworks or tools [that] enforce the [framework] designer's vision on how solutions should be architected" (Kennard &amp;amp; Leaney 2010).&lt;br /&gt;&lt;br /&gt;Interestingly, however, the latest release of the naked objects frameworks include a concept called 'facets'. The authors wanted to clarify if these were in the original design? Dan Haywood responded: "No, they weren't". What was their background? "Up until 3.0 (late 2007) I had actually been working on my own [clean room implementation of a naked objects framework] based on Eclipse RCP. For various reasons, I wrote it off. But all was not lost: a lot of my thoughts on what the programming model should look like went into Naked Objects 4.0 (2009). I also had become enamoured with the extension object pattern, something used a lot in the Eclipse APIs. It was this that eventually evolved into facets".&lt;br /&gt;&lt;br /&gt;Dan explained that facets were a form of an extension object pattern, allowing capture of metadata from heterogeneous sources. How did this fit in to a naked objects architecture? Dan explained "Rob [Matthews] and I started refactoring the Naked Objects metamodel to bring in this idea [of the extension object pattern]. My original idea didn't go much beyond representing the [existing Naked Objects] annotations as facets... like all good collaborations, one of us (and I'm pretty sure it was Rob) realised that the imperative helper methods could also be captured as facets too". Is it one facet per technology? "No. It's one facet per piece of information to be captured. A collection of facets define the Naked Objects ProgrammingModel. Suppose there's a Java Persistence API (JPA) annotation (or bit of XML, it could be) to indicate that a field is nullable... that would correspond to a JpaMandatoryFacet.  And if we wanted to capture which property was the Id (which I do, to manufacture the framework's internal identifier) then there's also a JpaIdFacet. This is what I meant about a programming model: the JpaProgrammingModel is the collection of the FacetFactories for detecting these features/semantics/pieces of information and adding them to the code". Can a facet be targeted outside of the entity (i.e. XML files, database schemas, rule engines)? "Yes... a FacetFactory can pick up information from anywhere. We have a little example showing how names could be picked up from a flat file".&lt;br /&gt;&lt;br /&gt;In short, are facets close to Metawidget's Inspectors and its CompositeInspector? "Pretty similar, but more fine-grained. I think CompositeInspector = a Naked Objects ProgrammingModel = collection of Facets.  But it'd be good if we went closer to [Metawidget's] design, with an Inspector = a group of related facets that shouldn't be split apart. Our facets are too fine-grained and I think we should instead be dealing in an aggregation of facets, which I'm calling a ProgrammingModel, basically equivalent to your Inspector.  Then, another idea I intend to borrow is that of CompositeInspector which for us would be a CompositeProgrammingModel".&lt;br /&gt;&lt;br /&gt;The authors discovered that with their introduction of facets, particularly XML and flat file facets, the Naked Objects team had effectively extended their philosophy of behavioural-completeness (Pawson 2004) to go beyond just the semantics intrinsic within the code. They had converged on a need to support a mixture of heterogeneous sources of UI metadata. Their implementation differed a little from the authors' in that it was "more fine-grained". But the fundamental notion of opening up the naked objects frameworks to metadata from other subsystems, such as persistence contexts, rule engines and XML files, had close parity with our approach.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;4.2 Appreciating different practices in applying inspection results&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A second key characteristic the authors identified (Kennard &amp;amp; Leaney 2010) was to support a variety of ways to post process the UI metadata. For example, different practitioners had different preferences regarding how to sort or exclude business properties from the UI.&lt;br /&gt;&lt;br /&gt;The authors discovered the Naked Objects team had also perceived this need. Dan described: "our FacetFactorys can optionally implement various additional interfaces. To identify the properties and collections (i.e. identify the main scaffolding of the classes) we look for FacetFactorys (typically just one) that implements the PropertyOrCollectionIdentifyingFacetFactory interface. These are run through first.  I think it might be better to pull this out as a distinct phase of the metamodel building process. Similarly, after we've processed all the FacetFactories and added the facets then we go looking for MemberOrderFacets to sort the members; it's just a call to a method. Again, it might make sense to factor this out into a separate API".&lt;br /&gt;&lt;br /&gt;The Naked Objects team were clearly thinking about introducing post processing into their facets. They were already using multiple passes implicitly - "these are run through first... similarly, after we've processed all the [others]" - and were now seeing that separating this out into an explicit post processing phase may be advantageous. Metawidget had followed a similar evolution. The authors had originally had the Inspectors performing the sorting themselves, but factored this out into a separate InspectionResultProcessor API.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;4.3 Recognising multiple, and mixtures of, UI widget libraries&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another key characteristic the authors identified (Kennard &amp;amp; Leaney 2010) was supporting mixtures of widget libraries. This included mixing multiple third-party widget libraries, and the practitioner's own custom widget libraries, in addition to the UI platform's standard widget libraries.&lt;br /&gt;&lt;br /&gt;The authors wanted to gain an understanding of how this characteristic had been handled in the original naked objects pattern. Dan recounted: "the different viewers implement this differently. The original viewer had something similar, but restricted to just using AWT. That's fine, but it does mean that a developer wanting to extend the viewer has to learn all this new API".&lt;br /&gt;&lt;br /&gt;Had newer viewers tried to incorporate better support for third-party, or custom, widget libraries? "Talking about the Apache Wicket viewer, the API is actually called ComponentFactory. Part of the reason for using that terminology is to use a term that's already known by Wicket developers who might want to extend the UI generated by the Wicket viewer. I have a registry of ComponentFactories, which are asked in a chain-of-responsibility pattern to render model objects. They may use third party libraries if necessary". Can you compose multiple ComponentFactories in one project? "Yes. Basically the Wicket viewer is just a registered collection of ComponentFactories that can render any entity or collection of  entities. But the list is pluggable so that custom widgets can be provided if required". Can you specify precedence? "Yes, it's a first-come-first-served. So, any ComponentFactories picked up on the classpath are placed before the defaults. But our programmatic approach provides full control".&lt;br /&gt;&lt;br /&gt;In short, are they close to Metawidget's WidgetBuilders and its CompositeWidgetBuilder? "So, yes, kind of similar. But, as I say, [ComponentFactories are] an implementation detail of each viewer - the nature of the API is not standardised across viewers.  In theory that sounds like a good objective, and I think it's something you've managed to achieve with Metawidget. I'm hoping that within Apache Isis we'll be able to move some of this stuff into core, so that it can be reused more widely. It might also make sense to move the ComponentFactoryRegistry stuff there too, though I'd need to figure out how to remove any Wicket-specific stuff".&lt;br /&gt;&lt;br /&gt;The Naked Objects team had progressed from originally using a proprietary, low-level APIs to fully supporting pluggable third-party libraries via ComponentFactories. In the future they hoped to back port this approach from its current per-viewer implementation into the Naked Objects core proper. There was clear convergence in this characteristic.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;4.4 Supporting multiple, and mixtures of, UI adornments&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The authors further identified (Kennard &amp;amp; Leaney 2010) that supporting a variety of ways to post process UI widgets was an important characteristic for a practical UI generator. Once created, widgets may need to be adorned with such mechanisms as data validators, data binding frameworks and event handlers. Some of these mechanisms, such as validators, may come from a different third-party library to the widget itself.&lt;br /&gt;&lt;br /&gt;The latest release of Naked Objects included a concept called 'advisors'. Were these in the original design? "No; we introduced them in Naked Objects 4.0 (2009)". Dan explained advisors handled such operations as hiding, disabling, and validating components. "To clarify: some facets are also advisors, some facets aren't. There are no advisors that aren't also facets. Consider the [Naked Objects] @Disabled annotation. That is going to get picked up by the DisabledViaAnnotationFacetFactory, which installs a DisabledFacet on the property. When the viewer creates the text box [for the property] it doesn't go looking directly for a DisabledFacet.  What it does instead is call property.isDisabled which iterates through all installed facets looking for those that implement DisableInteractionAdvisor (of which the DisabledFacet will be one). If one of those advisors or facets vetoes, then it configures the text box accordingly".&lt;br /&gt;&lt;br /&gt;This results in the sequence diagram depicted below:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-NcJ9ZmXoTjo/TdZQygR22RI/AAAAAAAAAcA/y4d0GAs7i3c/s1600/figure3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 150px;" src="http://1.bp.blogspot.com/-NcJ9ZmXoTjo/TdZQygR22RI/AAAAAAAAAcA/y4d0GAs7i3c/s320/figure3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5608759214525045010" /&gt;&lt;/a&gt;&lt;br /&gt;The sequence has similarities with Metawidget's own pipeline (Kennard &amp;amp; Leaney 2010) depicted below:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-7wG61p1eLd4/TdZQy8xje4I/AAAAAAAAAcI/U6JjiB3MBvc/s1600/figure4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 263px;" src="http://3.bp.blogspot.com/-7wG61p1eLd4/TdZQy8xje4I/AAAAAAAAAcI/U6JjiB3MBvc/s320/figure4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5608759222174186370" /&gt;&lt;/a&gt;&lt;br /&gt;In particular, the similarities between facets and inspectors, component factories and widget builders, and advisors and widget processors. Considering neither facets, component factories nor advisors were part of the original naked objects pattern (Pawson 2004) this showed strong evidence of convergence.&lt;br /&gt;&lt;br /&gt;However, Dan's description was of a single object implementing both the Facet interface and the Advisor interface. These interfaces are roughly analogous to Metawidget's Inspector and WidgetProcessor interfaces, but Metawidget implements these as separate objects. This is because the former is tied to the back-end architecture whereas the latter is tied to the front-end UI. Is this something the Naked Objects team have considered? "[Yes] all the above said... I'm not entirely sure that there's any real need for a facet to be an advisor. Where at the moment a ObjectMember implements FacetHolder, it could perhaps be also an AdvisorHolder.  This would separate out these concerns, converging our two designs further".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;4.5 Applying multiple, and mixtures of, UI layouts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A final characteristic the authors identified (Kennard &amp;amp; Leaney 2010) was supporting multiple ways to arrange widgets on the screen. We pointed out that it significantly detracts from the practicality of automated generation if it in any way compromises the final product in usability, or even in aesthetics (Myers, Hudson &amp;amp; Pausch 2000, p. 13). This realisation exposes a myriad of small details around UI appearance, navigation, menu placement and so on. The problem is so difficult, in fact, we believe it insoluble.&lt;br /&gt;&lt;br /&gt;Metawidget sidesteps the issue by not attempting to generate the entire UI. Rather, it believes there are 'useful bounds' to UI generation: "as automatic UI generation moves away from [simply modelling fields as forms] it rapidly becomes highly speculative. Determining how to display a domain object is much more subjective than determining what fields to display. Determining how to represent relationships between multiple domain objects is more subjective still. The practical usefulness of UI generation diminishes once in these areas, because the generated UI bears less and less resemblance to how it would have appeared and functioned had it been designed manually, with consideration to its specific purpose" (Kennard &amp;amp; Steele 2008). As Constantine (2002) puts it "the greatest usability problem with Naked Objects is the one-size-fits-all premise on which the approach rests. Instead of tailoring the presentation of information and the operation of the UI to fit the unique aspects of the context, the application, and the user needs, one [generic presentation layer] is presumed to fit all problems". Instead, Metawidget focuses on generating only a small piece of the UI - the 'inside' of each page, the area around the fields themselves. The UI appearance, navigation, menu placement and overall usability are far more subjective and we explicitly keep these out of scope.&lt;br /&gt;&lt;br /&gt;Even after Metawidget has restricted its UI generation to just the area around fields, we find there is still a formidable degree of variability. Fields may typically be arranged in a 'column', with the widget on the right and its label on the left. But there are many other real world arrangements, such as all fields arranged in a single, horizontal row; or right-to-left arrangements for the Arabic world. It is important to accommodate this variability if the generator is to achieve the exact look the practitioner desires. Metawidget addresses this characteristic of supporting multiple ways to arrange widgets by defining pluggable layouts.&lt;br /&gt;&lt;br /&gt;In contrast, the original Naked Objects viewers did not admit this level of subjectivity. Dan explains: "there's lots of scepticism that a fully generic UI is sufficient [but] I don't think we recognise that... at least not for the enterprise applications that we have built thus far. In the Irish [Department of Social Protection] system there are about 5 or 6 transient entities [intermediate, subjective representations of domain objects] out of over 300 sovereign entities [direct representations of domain objects]. So, the point is... most entities don't need them". Dan summarised "[Metawidget] just provides, well, a widget (a rather large and clever one, but a widget nonetheless)". Naked Objects, on the other hand provides the full UI - "the scope of Naked Objects is larger than Metawidget".&lt;br /&gt;&lt;br /&gt;But Dan also noted that the naked objects frameworks provide a blunt level of pluggability so that entire viewers can be plugged in to provide different UIs: "the technology used by any given viewer is generally fixed (AWT, Wicket, JSF etc). But some viewers do provide pluggable layouts in a manner similar to that allowed by Metawidget. Rob's &lt;a href="http://nakedobjects.org/plugins/scimpi"&gt;Scimpi&lt;/a&gt; web viewer [a Naked Objects viewer that produces similar results to figure 1 but using a web-based platform], for example, provides a whole slew of tags that can be assembled onto a page to provide a rendering of an object, collection or action dialog [Scimpi 2010]. The only real assumption that Scimpi makes is what is being rendered is going to be one of these things (an object, collection or action dialog). Even then, Scimpi's tags allow other information to be 'mixed-into' the page (e.g. the name of the currently logged-on user)". Dan then went on to describe his Wicket viewer: "the Wicket viewer likewise looks for a page to render an object, collection or whatever. Where it differs from Scimpi is really just that its rendering is done not using tags but using Wicket components".&lt;br /&gt;&lt;br /&gt;The Scimpi and Wicket viewers therefore provide evidence of convergence. There is still a gap between approaches in that Metawidget places no expectations on the 'outside' of each page, whereas the naked objects viewers expect the entire page to map to an instance of something within their metamodel. Also, plugging in new viewer implementations is not something the Naked Objects team expects practitioners to undertake. Dan agreed: "it's a lot of work. Maybe in time we'll mature this somewhat and make it easier by pulling some common building blocks into the core (i.e. closer to how Metawidget works, I imagine), but for now that isn't the case".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;5. Convergence in Other Projects&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This article has explored convergence between our own work and that of the Naked Objects team. Given the intricacies and subtleties of the design decisions involved, it was necessary to cover their project in depth and in detail. Therefore this study focussed on only a single project.&lt;br /&gt;&lt;br /&gt;Clearly there are other UI generator projects that also demonstrate a significant industry presence. For example, UsiXML (Vanderdonckt et al. 2004) is a cross device, platform and modality UIDL that has been submitted to the W3C industry body for standardization. OlivaNOVA (Valverde et al. 2007) is a commercially available product that can generate UIs for both Java and Microsoft .NET environments. Such projects have differentiating characteristics beyond, though not necessarily mutually exclusive to, our own five. We have asserted that our five characteristics are fundamental for a UI generator to be useful to industry. The characteristics have been derived over successive iterations of Action Research cycles with industry practitioners, and validated by industry adoption studies and open-ended interviews (Kennard &amp;amp; Leaney 2010). Demonstrably, they are important enough that the Naked Objects team found the need to add them atop their original design.&lt;br /&gt;&lt;br /&gt;However ours are not the only characteristics by which UI generators may be assessed, nor the only ones by which they may converge. Examples of other generators and their differentiating characteristics are shown in the table below. This table shows a selection of features drawn both from our own five and from the feature sets of the generators as described in the literature. It can be seen there are differing approaches to implementing any given characteristic, and some can be left to the practitioner to implement manually without the UI generator's explicit support. This may or may not be enough for the generator to prove sufficiently useful to industry.&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 75%; margin: auto" border="1"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align="left"&gt;Feature/Generator&lt;/th&gt;&lt;th align="center"&gt;Metawidget&lt;/th&gt;&lt;th align="center"&gt;Naked Objects&lt;/th&gt;&lt;th align="center"&gt;UsiXML&lt;/th&gt;&lt;th align="center"&gt;OlivaNOVA&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th align="left"&gt;Inspecting existing, heterogeneous back-end architectures&lt;/th&gt;&lt;td align="center"&gt;Yes&lt;/td&gt;&lt;td align="center"&gt;Yes (see 4.1)&lt;/td&gt;&lt;td align="center"&gt;No, has its own UIDL&lt;/td&gt;&lt;td align="center"&gt;No, has its own UIDL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Appreciating different practices in applying inspection results&lt;/th&gt;&lt;td align="center"&gt;Yes&lt;/td&gt;&lt;td align="center"&gt;Yes (see 4.2)&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Recognising multiple, and mixtures of, UI widget libraries&lt;/th&gt;&lt;td align="center"&gt;Yes&lt;/td&gt;&lt;td align="center"&gt;Yes (see 4.3)&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Supporting multiple, and mixtures of, UI adornments&lt;/th&gt;&lt;td align="center"&gt;Yes&lt;/td&gt;&lt;td align="center"&gt;Yes (see 4.4)&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Applying multiple, and mixtures of, UI layouts&lt;/th&gt;&lt;td align="center"&gt;Yes&lt;/td&gt;&lt;td align="center"&gt;Partial (see 4.5)&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;td align="center"&gt;No, but can edit generated code&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Mode of operation&lt;/th&gt;&lt;td align="center"&gt;Runtime&lt;/td&gt;&lt;td align="center"&gt;Runtime&lt;/td&gt;&lt;td align="center"&gt;Static code generation&lt;/td&gt;&lt;td align="center"&gt;Static code generation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Translation to different devices, platforms, modalities&lt;/th&gt;&lt;td align="center"&gt;Manual (see 4.5)&lt;/td&gt;&lt;td align="center"&gt;Automatic&lt;/td&gt;&lt;td align="center"&gt;Automatic&lt;/td&gt;&lt;td align="center"&gt;Automatic&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th align="left"&gt;Object Oriented User Interface&lt;/th&gt;&lt;td align="center"&gt;No&lt;/td&gt;&lt;td align="center"&gt;Yes (see 4)&lt;/td&gt;&lt;td align="center"&gt;No&lt;/td&gt;&lt;td align="center"&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Research projects such as UsiXML and OlivaNOVA will require further exploration to look for signs of convergence. If our characteristics are as fundamental as we believe, these research teams should be identifying similar constructs through their own industry field trials. Conversely, if we find these teams to be converging on a different set of characteristics, that would also be very instructive.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;6. Conclusions and Future Work&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Through interviewing the Naked Objects team, the authors discovered there was broad agreement on four out of five of our key characteristics. None of these were considered an explicit feature of the original naked objects pattern and all had evolved independently within our two projects, so this represented good evidence of convergence. Our interview also established there were areas where our project philosophies differed, and were likely to remain in disagreement.&lt;br /&gt;&lt;br /&gt;In our previous article (Kennard &amp;amp; Leaney 2010) the authors reasoned that implementation of all five of our characteristics would lead to a notable emergent advantage: being able to retrofit an existing application that was not built with UI generation in mind. For example, one could retrofit a word processor: the main word processing area would be left untouched, but the numerous dialog boxes for application and formatting preferences could be retrofitted to use UI generation. Metawidget demonstrates this advantage but the naked objects frameworks do not, because there is still a gap around pluggable layouts which limits the categories of applications the naked objects pattern can be applied to. Dan agreed: "realistically, we aren't ever going to see a word processor written in naked objects....  but I'm interested in figuring out how many UI screens can be thought of as a rendering of an object, a collection or action dialog. The customisable UI then amounts to allowing the developer to specify which properties/collections/actions of that single object to appear where, and which to be omitted... the short answer is yes, we want naked objects to be more applicable. It's about removing objections from folks trying out the framework". Clearly there is room for future research and healthy competition between the two projects.&lt;br /&gt;&lt;br /&gt;In conclusion the authors consider it significant that a good many core, non-obvious characteristics have been established. These have been agreed upon both by our own industry adoption studies, and independently by the industry field trials of the Naked Objects team. We believe these signal the beginning of a general purpose architecture for UI generation, one that both industry and the research community could standardise upon. This standardisation could then be used to drive adoption and ultimately to realise the full potential of UI generation technology.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;References&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Bodart, F., Hennebert, A.M., Leheureux, J.M., Provot, I., Sacre, B. &amp;amp; Vanderdonckt, J. 1995, 'Towards a Systematic Building of Software Architectures: the TRIDENT Methodological Guide', Design, SpecCeification and Verification of Interactive Systems. Wien: Springer, pp. 262-278.&lt;br /&gt;Calvary, G., Coutaz, J., Thevenin, D., Limbourg, Q., Bouillon, L. &amp;amp; Vanderdonckt, J. 2003, 'A unifying reference framework for multi-target user interfaces', Interacting with Computers, vol. 15, no. 3, pp. 289-308.&lt;br /&gt;Constantine, L. 2002, 'The emperor has no clothes: Naked Objects meet the interface', Constantine Lockwood, http://www.foruse.com/articles.&lt;br /&gt;Daniel, F., Matera, M., Yu, J., Benatallah, B., Saint-Paul, R. &amp;amp; Casati, F. 2007, 'Understanding UI Integration: A Survey of Problems, Technologies, and Opportunities', IEEE INTERNET COMPUTING, pp. 59-66.&lt;br /&gt;Dick, B. 2005, 'Grounded theory: a thumbnail sketch', http://www.scu.edu.au/schools/gcm/ar/arp/grounded.html&lt;br /&gt;Falb, J., Popp, R., Rock, T., Jelinek, H., Arnautovic, E. &amp;amp; Kaindl, H. 2007, 'Fully-automatic generation of user interfaces for multiple devices from a high-level model based on communicative acts', System Sciences, 2007. HICSS 2007. 40th Annual Hawaii International Conference on, ed. P. Roman, p. 26.&lt;br /&gt;Firesmith, D.G. 1996, Use Cases: The Pros and Cons. Wisdom of the Gurus: A Vision for Object Technology.&lt;br /&gt;Fowler, M. 2002, Patterns of Enterprise Application Architecture. Addison Wesley.&lt;br /&gt;Hayes, P.J., Szekely, P.A. &amp;amp; Lerner, R.A. 1985, 'Design alternatives for user interface management sytems based on experience with COUSIN', Proceedings of the SIGCHI conference on Human factors in computing systems, pp. 169-175.&lt;br /&gt;Haywood, D. 2009, 'Domain Driven Design using Naked Objects', Pragmatic Bookshelf.&lt;br /&gt;Jelinek, J. &amp;amp; Slavik, P. 2004, 'GUI generation from annotated source code', Proceedings of the 3rd annual conference on Task models and diagrams, pp. 129-136.&lt;br /&gt;Jha, N.K. 2005, 'Low-power system scheduling, synthesis and displays', Computers and Digital Techniques, IEE Proceedings, vol. 152, no. 3, pp. 344-352.&lt;br /&gt;Kennard, R. &amp;amp; Steele, R. 2008, Application of Software Mining to Automatic User Interface Generation. 7th International Conference on Software Methodologies, Tools and Techniques.&lt;br /&gt;Kennard, R., Edmonds, E. &amp;amp; Leaney, J. 2009, Separation Anxiety: stresses of developing a modern day Separable User Interface. 2nd International Conference on Human System Interaction.&lt;br /&gt;Kennard, R. &amp;amp; Leaney, J. 2010, Towards a General Purpose Architecture for UI Generation. Journal of Systems and Software.&lt;br /&gt;Myers, B.A. &amp;amp; Rosson, M.B. 1992, Survey on user interface programming, ACM Press New York, NY, USA.&lt;br /&gt;Myers, B., Hudson, S.E. &amp;amp; Pausch, R. 2000, 'Past, present, and future of user interface software tools', ACM Transactions on Computer-Human Interaction (TOCHI), vol. 7, no. 1, pp. 3-28.&lt;br /&gt;Pawson, R. 2004, 'Naked Objects' thesis, Trinity College, Dublin.&lt;br /&gt;Pawson, R. &amp;amp; Matthews, R. 2002 'Naked Objects', Wiley.&lt;br /&gt;Rouvellou, I., Degenaro, L., Rasmus, K., Ehnebuske, D. &amp;amp; Mc Kee, B. 1999, 'Externalizing Business Rules from Enterprise Applications: An Experience Report', Practitioner Reports in the OOPSLA, vol. 99.&lt;br /&gt;Shan, T.C., Hua, W.W., Bank, W. &amp;amp; Wilmington, N.C., 2006. 'Taxonomy of java web application frameworks', pp. 378-385.&lt;br /&gt;Valenzuela, D. &amp;amp; Shrivastava, P. 2002, 'Interview as a Method for Qualitative Research', http://www.public.asu.edu/~kroel/www500/Interview%20Fri.pdf.&lt;br /&gt;Valverde, F., Valderas, P., Fons, J. &amp;amp; Pastor, O. 2007, 'A MDA-Based Environment for Web Applications Development: From Conceptual Models to Code', Citeseer.&lt;br /&gt;Vanderdonckt, J., Limbourg, Q., Michotte, B., Bouillon, L., Trevisan, D. &amp;amp; Florins, M. 2004, 'USIXML: a User Interface Description Language for Specifying Multimodal User Interfaces', W3C Workshop on Multimodal Interaction. Sophia Antipolis, pp. 19-20.&lt;br /&gt;Weiser, M. 1993, 'Hot topics-ubiquitous computing', Computer, vol. 26, no. 10, pp. 71-72.&lt;br /&gt;Xudong, L. &amp;amp; Jiancheng, W. 2007, 'User Interface Design Model', Software Engineering, Artificial Intelligence, Networking, and Parallel/Distributed Computing, 2007. SNPD 2007. Eighth ACIS International Conference on, vol. 3.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-807107188567529517?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/807107188567529517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=807107188567529517' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/807107188567529517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/807107188567529517'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/05/is-there-convergence-in-field-of-ui.html' title='Is There Convergence in the Field of UI Generation?'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/TON0leIPEKI/AAAAAAAAAUk/VWFuhqHAOWo/s72-c/package_graphics.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-8916126672518882507</id><published>2011-05-12T15:52:00.001+10:00</published><updated>2011-05-14T11:09:40.973+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>User Interface Generator: Metawidget v1.20</title><content type='html'>&lt;img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 0px 10px 10px; WIDTH: 188px; FLOAT: right; HEIGHT: 400px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id="BLOGGER_PHOTO_ID_5428305152285105858" border="0" alt="" src="http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s400/box.png" /&gt;Version 1.20 of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, the &lt;a href="http://metawidget.org"&gt;User Interface Generator&lt;/a&gt; is now available! This is a minor release, mainly to fix bugs in the examples. I discovered the 'initial experience' on the latest version of &lt;a href="http://tomcat.apache.org"&gt;Apache Tomcat&lt;/a&gt; (version 7) was pretty bad and may give a negative first impression to new users. The release includes the following enhancements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Improved examples to work better with Tomcat 7&lt;/li&gt;&lt;li&gt;Improved module POMs to work better with m2eclipse&lt;/li&gt;&lt;li&gt;Allow JavaBeanPropertyStyle to disable caching&lt;/li&gt;&lt;li&gt;Allow location of metawidget.xml to be configured in web.xml&lt;/li&gt;&lt;li&gt;Bug fixes, documentation and unit tests&lt;/li&gt;&lt;/ul&gt;As always, the best place to start is the Reference Documentation:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;a href="http://metawidget.org/doc/reference/en/pdf/metawidget.pdf"&gt;http://metawidget.org/doc/reference/en/pdf/metawidget.pdf&lt;br /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Your continued feedback is invaluable to us. Please &lt;a href="http://metawidget.org/download.html"&gt;download it&lt;/a&gt; and &lt;a href="http://metawidget.org/forums.html"&gt;let us know what you think&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-8916126672518882507?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/8916126672518882507/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=8916126672518882507' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/8916126672518882507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/8916126672518882507'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/05/user-interface-generator-metawidget.html' title='User Interface Generator: Metawidget v1.20'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s72-c/box.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1772447138101637035</id><published>2011-05-11T16:09:00.001+10:00</published><updated>2011-07-18T08:37:31.288+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget at Red Hat Summit 2011</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;border: 0;width: 400px; height: 84px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TAWOJpsiuxI/AAAAAAAAAQU/Bnznfoka9XQ/s400/summit.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5477940818228722450" /&gt;&lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; got a good showing at &lt;a href="http://redhat.com/summit"&gt;Red Hat Summit 2011&lt;/a&gt; this year, following on from our &lt;a href="http://blog.kennardconsulting.com/2010/06/metawidget-featured-at-jboss-world-2010.html"&gt;campground session&lt;/a&gt; in 2010.&lt;br /&gt;&lt;br /&gt;Metawidget was included in 3 sessions:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Seam Forge: Forge New Ground in Rapid Enterprise Java Development (&lt;a href="http://vimeo.com/23280944"&gt;Video&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Bean Validation: Best practices for real life (&lt;a href="http://www.redhat.com/summit/2011/presentations/jbossworld/in_the_weeds/thursday/bernard_t_420_hibernate_validator.pdf"&gt;PDF&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Seam Catch: Handling the Unexpected (&lt;a href="https://www.jboss.org/dms/judcon/presentations/Boston2011/JUDConBoston2011_day1track1session5.pdf"&gt;PDF&lt;/a&gt;, &lt;a href="https://github.com/LightGuard/catch-demo"&gt;Source Code&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;My thanks to all the presenters for their support!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1772447138101637035?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1772447138101637035/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1772447138101637035' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1772447138101637035'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1772447138101637035'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/05/metawidget-at-judcon.html' title='Metawidget at Red Hat Summit 2011'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__YNTBm_fS_I/TAWOJpsiuxI/AAAAAAAAAQU/Bnznfoka9XQ/s72-c/summit.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-2067936764721220164</id><published>2011-04-30T20:37:00.004+10:00</published><updated>2011-07-18T08:38:10.280+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Object User Interface Mapper (OIM): Metawidget v1.15</title><content type='html'>&lt;img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 0px 10px 10px; WIDTH: 188px; FLOAT: right; HEIGHT: 400px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id="BLOGGER_PHOTO_ID_5428305152285105858" border="0" alt="" src="http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s400/box.png" /&gt;Version 1.15 of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, the &lt;a href="http://metawidget.org"&gt;Object User Interface Mapping tool (OIM)&lt;/a&gt; is now available! This release includes the following enhancements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/03/metawidget-full-speed-to-maven.html"&gt;Maven support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/04/metawidget-streamlined-configuration.html"&gt;Streamlined Configuration&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/04/metawidget-richfaces-4-support.html"&gt;RichFaces 4 support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Bug fixes, documentation and unit tests&lt;/li&gt;&lt;/ul&gt;As always, the best place to start is the Reference Documentation:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;a href="http://metawidget.org/doc/reference/en/pdf/metawidget.pdf"&gt;http://metawidget.org/doc/reference/en/pdf/metawidget.pdf&lt;br /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;Special thanks to Renato Garcia and Lincoln Baxter III for their help with this release!&lt;br /&gt;&lt;br /&gt;Your continued feedback is invaluable to us. Please &lt;a href="http://metawidget.org/download.html"&gt;download it&lt;/a&gt; and &lt;a href="http://metawidget.org/forums.html"&gt;let us know what you think&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-2067936764721220164?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/2067936764721220164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=2067936764721220164' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2067936764721220164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2067936764721220164'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/04/object-user-interface-mapper-oim.html' title='Object User Interface Mapper (OIM): Metawidget v1.15'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s72-c/box.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-5768308616574619149</id><published>2011-04-28T17:10:00.009+10:00</published><updated>2011-04-28T17:20:09.624+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><category scheme='http://www.blogger.com/atom/ns#' term='RichFaces'/><title type='text'>Metawidget: RichFaces 4 support</title><content type='html'>The next release of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; (v1.15) will include support for &lt;a href="http://jboss.org/richfaces"&gt;RichFaces&lt;/a&gt; 4 (previously we only supported 3.3.3.Final). Code and unit tests are already available in SVN, and here are some screenshots:&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td align="center"&gt;&lt;a href="http://2.bp.blogspot.com/-W63kC0t-75E/TbkTXlJoPnI/AAAAAAAAAbo/oFi16kRxaHU/s1600/richfaces3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 234px;" src="http://2.bp.blogspot.com/-W63kC0t-75E/TbkTXlJoPnI/AAAAAAAAAbo/oFi16kRxaHU/s320/richfaces3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5600528907442339442" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td align="center"&gt;&lt;a href="http://2.bp.blogspot.com/-EuCbiN6JSLs/TbkTXT4F6gI/AAAAAAAAAbg/QTK9eMoELs0/s1600/richfaces2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 234px;" src="http://2.bp.blogspot.com/-EuCbiN6JSLs/TbkTXT4F6gI/AAAAAAAAAbg/QTK9eMoELs0/s320/richfaces2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5600528902805383682" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" align="center"&gt;&lt;a href="http://4.bp.blogspot.com/-AAh5-zmf3Z8/TbkTXA2ctWI/AAAAAAAAAbY/HBMheMk5jlo/s1600/richfaces1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 234px;" src="http://4.bp.blogspot.com/-AAh5-zmf3Z8/TbkTXA2ctWI/AAAAAAAAAbY/HBMheMk5jlo/s320/richfaces1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5600528897698215266" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;This support requires &lt;a href="http://myfaces.apache.org/"&gt;MyFaces 2.0.5&lt;/a&gt; or above, or a version of &lt;a href="http://javaserverfaces.java.net"&gt;Mojarra&lt;/a&gt; that includes &lt;a href="http://java.net/jira/browse/JAVASERVERFACES-1826"&gt;this fix&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-5768308616574619149?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/5768308616574619149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=5768308616574619149' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5768308616574619149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5768308616574619149'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/04/metawidget-richfaces-4-support.html' title='Metawidget: RichFaces 4 support'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-W63kC0t-75E/TbkTXlJoPnI/AAAAAAAAAbo/oFi16kRxaHU/s72-c/richfaces3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-2656825299961892359</id><published>2011-04-20T11:39:00.004+10:00</published><updated>2011-04-20T11:41:35.847+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Streamlined Configuration</title><content type='html'>The next release of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; (v1.15) will include a small enhancement to the &lt;tt&gt;metawidget.xml&lt;/tt&gt; syntax used by &lt;tt&gt;ConfigReader&lt;/tt&gt;. &lt;tt&gt;ConfigReader&lt;/tt&gt; has always been designed to &lt;strong&gt;automatically recognise and reuse immutable instances&lt;/strong&gt;. This works both when configuring multiple Metawidgets, and configuring multiple settings for a single Metawidget. So if you did...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;inspectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;array&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;java5Inspector xmlns="java:org.metawidget.inspector.java5" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;propertyStyle&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;javaBeanPropertyStyle xmlns="java:org.metawidget.inspector.impl.propertystyle.javabean" config="JavaBeanPropertyStyleConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;supportPublicFields&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;boolean&amp;gt;false&amp;lt;/boolean&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/supportPublicFields&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;privateFieldConvention&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;format&amp;gt;'m'{1}&amp;lt;/format&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/privateFieldConvention&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/javaBeanPropertyStyle&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/propertyStyle&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/java5Inspector&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;metawidgetAnnotationInspector xmlns="java:org.metawidget.inspector.annotation" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;propertyStyle&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;javaBeanPropertyStyle xmlns="java:org.metawidget.inspector.impl.propertystyle.javabean" config="JavaBeanPropertyStyleConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;supportPublicFields&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;boolean&amp;gt;false&amp;lt;/boolean&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/supportPublicFields&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;privateFieldConvention&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;format&amp;gt;'m'{1}&amp;lt;/format&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/privateFieldConvention&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/javaBeanPropertyStyle&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/propertyStyle&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/metawidgetAnnotationInspector&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/array&amp;gt;&lt;br /&gt;&amp;lt;/inspectors&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...&lt;tt&gt;ConfigReader&lt;/tt&gt; would be smart enough to reuse the same &lt;tt&gt;javaBeanPropertyStyle&lt;/tt&gt; instance. But you still had to specify all &lt;tt&gt;javaBeanPropertyStyle&lt;/tt&gt;'s configuration options twice. In v1.15 you can instead use &lt;tt&gt;id&lt;/tt&gt; and &lt;tt&gt;refId&lt;/tt&gt; to refer from one setting to another:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;inspectors&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;array&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;java5Inspector xmlns="java:org.metawidget.inspector.java5" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;propertyStyle&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;javaBeanPropertyStyle xmlns="java:org.metawidget.inspector.impl.propertystyle.javabean" config="JavaBeanPropertyStyleConfig" &lt;strong&gt;id="myPropertyStyle"&lt;/strong&gt;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;supportPublicFields&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;boolean&amp;gt;false&amp;lt;/boolean&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/supportPublicFields&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;privateFieldConvention&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;format&amp;gt;'m'{1}&amp;lt;/format&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/privateFieldConvention&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/javaBeanPropertyStyle&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/propertyStyle&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/java5Inspector&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;metawidgetAnnotationInspector xmlns="java:org.metawidget.inspector.annotation" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;propertyStyle&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;javaBeanPropertyStyle refId="myPropertyStyle" /&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/propertyStyle&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/metawidgetAnnotationInspector&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/array&amp;gt;&lt;br /&gt;&amp;lt;/inspectors&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;It's a small thing, but can shorten your &lt;tt&gt;metawidget.xml&lt;/tt&gt; in a big way. &lt;br /&gt;&lt;br /&gt;Feedback welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-2656825299961892359?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/2656825299961892359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=2656825299961892359' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2656825299961892359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2656825299961892359'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/04/metawidget-streamlined-configuration.html' title='Metawidget: Streamlined Configuration'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-665737894352627417</id><published>2011-04-11T17:13:00.009+10:00</published><updated>2011-07-18T08:38:31.670+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Maven Snapshot Releases</title><content type='html'>I'm thrilled to say that the first snapshot releases of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; 1.15 are now available in the JBoss Snapshot Repository at &lt;a href="https://repository.jboss.org/nexus/content/repositories/snapshots/org/metawidget"&gt;https://repository.jboss.org/nexus/content/repositories/snapshots/org/metawidget&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;repository&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;id&amp;gt;&lt;strong&gt;jboss-snapshots&lt;/strong&gt;&amp;lt;/id&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;url&amp;gt;&lt;strong&gt;https://repository.jboss.org/nexus/content/repositories/snapshots&lt;/strong&gt;&amp;lt;/url&amp;gt;&lt;br /&gt;&amp;lt;/repository&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;&lt;strong&gt;org.metawidget.modules&lt;/strong&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;&lt;strong&gt;metawidget-all&lt;/strong&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;version&amp;gt;&lt;strong&gt;1.15-SNAPSHOT&lt;/strong&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;I plan to be staging the modules here for a few weeks before the final 1.15 release. I'd be most grateful to anybody who could download them and take the &lt;a href="http://blog.kennardconsulting.com/2011/03/metawidget-full-speed-to-maven.html"&gt;new fine-grained module system&lt;/a&gt; for a spin.&lt;br /&gt;&lt;br /&gt;My thanks to Renato Garcia for his help with the Maven migration.&lt;br /&gt;&lt;br /&gt;Feedback most welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-665737894352627417?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/665737894352627417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=665737894352627417' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/665737894352627417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/665737894352627417'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/04/metawidget-maven-snapshot-releases.html' title='Metawidget: Maven Snapshot Releases'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-669120759597495864</id><published>2011-04-01T19:59:00.008+11:00</published><updated>2011-07-18T08:38:47.350+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seam Forge'/><title type='text'>Grokking Seam Forge: Part 3</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 300px; height: 89px;" src="http://4.bp.blogspot.com/-9wI1AV-g9wM/TXcRdGNqyDI/AAAAAAAAAaw/jKjeXWPmOIE/s400/139594.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5581949454730840114" /&gt;JBoss have just released &lt;a href="http://in.relation.to/Bloggers/Seam300CR2Released"&gt;Seam 3.0.0.Final&lt;/a&gt;, which includes Alpha 3 of Seam Forge. So I thought I'd improve my &lt;a href="http://blog.kennardconsulting.com/2011/03/grokking-seam-forge-part-2.html"&gt;previous blog entry&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First, download Seam from &lt;a href="http://sourceforge.net/projects/jboss/files/Seam/3/3.0.0.Final"&gt;here&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Unzip to a folder of your choosing&lt;/li&gt;&lt;li&gt;Run &lt;tt&gt;bin\forge&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;Type the following commands and press &lt;tt&gt;ENTER&lt;/tt&gt; after each one. Accept any defaults you are prompted for, and remember to use &lt;tt&gt;TAB&lt;/tt&gt; and &lt;tt&gt;UP ARROW&lt;/tt&gt; autocomplete:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;new-project --named MyApp --topLevelPackage com.myapp&lt;br /&gt;persistence setup --provider HIBERNATE --container JBOSS_AS6&lt;br /&gt;new-entity --named Person&lt;br /&gt;new-field string --named firstname&lt;br /&gt;new-field string --named surname&lt;br /&gt;new-field int --named age&lt;br /&gt;new-field string --named notes&lt;br /&gt;new-field custom --named homeAddress&lt;br /&gt;[type=The qualified Class to be used as this field's type (of type java.lang.String)]: com.myapp.Address&lt;br /&gt;new-field custom --named workAddress&lt;br /&gt;[type=The qualified Class to be used as this field's type (of type java.lang.String)]: com.myapp.Address&lt;br /&gt;new-entity --named Address&lt;br /&gt;new-field string --named street&lt;br /&gt;new-field string --named suburb&lt;br /&gt;new-field string --named state&lt;br /&gt;new-field string --named postcode&lt;br /&gt;scaffold from-entity com.myapp.domain.Person.java&lt;br /&gt;exit&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Next:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Open Eclipse (with &lt;a href="http://m2eclipse.sonatype.org"&gt;m2eclipse&lt;/a&gt; installed)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Choose &lt;tt&gt;File &amp;gt; Import &amp;gt; Existing Maven Projects&lt;/tt&gt; and import the &lt;tt&gt;pom.xml&lt;/tt&gt; at &lt;tt&gt;\seam-3.0.0.Final\forge\MyApp\pom.xml&lt;/tt&gt;&lt;a href="http://1.bp.blogspot.com/-oZYfvEgLS9w/TXcPfO4Xa8I/AAAAAAAAAaY/r6pNLmC6cQQ/s1600/import-pom.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 242px; height: 185px;" src="http://1.bp.blogspot.com/-oZYfvEgLS9w/TXcPfO4Xa8I/AAAAAAAAAaY/r6pNLmC6cQQ/s320/import-pom.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5581947292393892802" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Right click the &lt;tt&gt;pom.xml&lt;/tt&gt; and choose &lt;tt&gt;Run As &amp;gt; Maven package&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Take the WAR it generates under &lt;tt&gt;target/MyApp-1.0.0-SNAPSHOT.war&lt;/tt&gt; and deploy it under &lt;a href="http://www.jboss.org/jbossas/downloads"&gt;JBoss AS 6.0.0.Final&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Open your browser at &lt;a href="http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf"&gt;http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf&lt;/a&gt;:&lt;a href="http://3.bp.blogspot.com/-fc5RQi9Oazw/TZWrwtXhpjI/AAAAAAAAAbI/UnCmEuGgDsQ/s1600/before.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 225px;" src="http://3.bp.blogspot.com/-fc5RQi9Oazw/TZWrwtXhpjI/AAAAAAAAAbI/UnCmEuGgDsQ/s320/before.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5590563365750679090" /&gt;&lt;/a&gt;&lt;br /&gt;Now, let's play around a bit! These are things that soon Forge will be able to do for you, but for now edit &lt;tt&gt;Person.java&lt;/tt&gt; and add the lines in bold:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;package com.myapp.domain;&lt;br /&gt;&lt;br /&gt;import javax.persistence.Column;&lt;br /&gt;import javax.persistence.Entity;&lt;br /&gt;import javax.persistence.GeneratedValue;&lt;br /&gt;import javax.persistence.GenerationType;&lt;br /&gt;import javax.persistence.Id;&lt;br /&gt;import javax.persistence.Lob;&lt;br /&gt;import javax.persistence.Version;&lt;br /&gt;&lt;br /&gt;import org.metawidget.inspector.annotation.UiComesAfter;&lt;br /&gt;import org.metawidget.inspector.annotation.UiSection;&lt;br /&gt;&lt;br /&gt;@Entity&lt;br /&gt;public class Person&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;implements java.io.Serializable {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Id&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private @GeneratedValue( strategy = GenerationType.AUTO )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column( name = "id", updatable = false, nullable = false )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;long&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;= 0;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Version&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private @Column( name = "version" )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;version&amp;nbsp;&amp;nbsp;&amp;nbsp;= 0;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public long getId() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.id;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setId( final long id ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.id = id;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int getVersion() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.version;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setVersion( final int version ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.version = version;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String&amp;nbsp;&amp;nbsp;&amp;nbsp;firstname;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getFirstname() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.firstname;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setFirstname( final String firstname ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.firstname = firstname;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String&amp;nbsp;&amp;nbsp;&amp;nbsp;surname;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "firstname" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getSurname() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.surname;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setSurname( final String surname ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.surname = surname;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private int&amp;nbsp;&amp;nbsp;&amp;nbsp;age;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "surname" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int getAge() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.age;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setAge( final int age ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.age = age;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String&amp;nbsp;&amp;nbsp;&amp;nbsp;notes;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "workAddress" )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Lob&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@UiSection( "Other" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getNotes() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.notes;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setNotes( final String notes ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.notes = notes;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Address&amp;nbsp;&amp;nbsp;&amp;nbsp;homeAddress&lt;strong&gt; = new Address()&lt;/strong&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "age" )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@UiSection( "Details" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Address getHomeAddress() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.homeAddress;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setHomeAddress( final Address homeAddress ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.homeAddress = homeAddress;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Address&amp;nbsp;&amp;nbsp;&amp;nbsp;workAddress&lt;strong&gt; = new Address()&lt;/strong&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "homeAddress" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Address getWorkAddress() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.workAddress;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setWorkAddress( final Address workAddress ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.workAddress = workAddress;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String toString() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.getClass().getSimpleName() + "[" + id + ", " + version + ", " + firstname + ", " + surname + ", " + age + ", " + notes + ", " + homeAddress + ", " + workAddress + "]";&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Similarly for &lt;tt&gt;Address.java&lt;/tt&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;package com.myapp.domain;&lt;br /&gt;&lt;br /&gt;import javax.persistence.Column;&lt;br /&gt;import javax.persistence.Entity;&lt;br /&gt;import javax.persistence.GeneratedValue;&lt;br /&gt;import javax.persistence.GenerationType;&lt;br /&gt;import javax.persistence.Id;&lt;br /&gt;import javax.persistence.Version;&lt;br /&gt;&lt;br /&gt;import org.metawidget.inspector.annotation.UiComesAfter;&lt;br /&gt;&lt;br /&gt;@Entity&lt;br /&gt;public class Address&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;implements java.io.Serializable {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Id&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private @GeneratedValue( strategy = GenerationType.AUTO )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column( name = "id", updatable = false, nullable = false )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;long&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;= 0;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Version&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private @Column( name = "version" )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;version&amp;nbsp;&amp;nbsp;&amp;nbsp;= 0;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public long getId() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.id;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setId( final long id ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.id = id;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int getVersion() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.version;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setVersion( final int version ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.version = version;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String&amp;nbsp;&amp;nbsp;&amp;nbsp;street;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getStreet() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.street;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setStreet( final String street ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.street = street;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String&amp;nbsp;&amp;nbsp;&amp;nbsp;suburb;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "street" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getSuburb() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.suburb;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setSuburb( final String suburb ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.suburb = suburb;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String&amp;nbsp;&amp;nbsp;&amp;nbsp;state;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "suburb" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getState() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.state;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setState( final String state ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.state = state;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Column&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String&amp;nbsp;&amp;nbsp;&amp;nbsp;postcode;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;@UiComesAfter( "state" )&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String getPostcode() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.postcode;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setPostcode( final String postcode ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.postcode = postcode;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Then tell &lt;tt&gt;metawidget.xml&lt;/tt&gt; we'd like to use &lt;a href="http://richfaces.org"&gt;RichFaces&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;htmlMetawidget xmlns="java:org.metawidget.faces.component.html"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;widgetBuilder&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;compositeWidgetBuilder xmlns="java:org.metawidget.widgetbuilder.composite" config="CompositeWidgetBuilderConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;widgetBuilders&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;array&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;overriddenWidgetBuilder xmlns="java:org.metawidget.faces.component.widgetbuilder"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;readOnlyWidgetBuilder xmlns="java:org.metawidget.faces.component.html.widgetbuilder"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;richFacesWidgetBuilder xmlns="java:org.metawidget.faces.component.html.widgetbuilder.richfaces"/&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;htmlWidgetBuilder xmlns="java:org.metawidget.faces.component.html.widgetbuilder" config="HtmlWidgetBuilderConfig"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/array&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/widgetBuilders&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/compositeWidgetBuilder&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/widgetBuilder&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;tabPanelLayoutDecorator xmlns="java:org.metawidget.faces.component.html.layout.richfaces" config="TabPanelLayoutDecoratorConfig"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;simpleLayout xmlns="java:org.metawidget.faces.component.layout"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/tabPanelLayoutDecorator&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/layout&amp;gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/htmlMetawidget&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;And tell &lt;tt&gt;web.xml&lt;/tt&gt; the same &lt;em&gt;(update: this can be done using the richfaces-forge-plugin, see the comments below)&lt;/em&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;web-app &amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;filter&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;display-name&amp;gt;RichFaces Filter&amp;lt;/display-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;filter-name&amp;gt;richfaces&amp;lt;/filter-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;filter-class&amp;gt;org.ajax4jsf.Filter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;filter-mapping&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;filter-name&amp;gt;richfaces&amp;lt;/filter-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;servlet-name&amp;gt;Faces Servlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dispatcher&amp;gt;REQUEST&amp;lt;/dispatcher&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dispatcher&amp;gt;FORWARD&amp;lt;/dispatcher&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dispatcher&amp;gt;INCLUDE&amp;lt;/dispatcher&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;servlet&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;servlet-name&amp;gt;Faces Servlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;servlet-class&amp;gt;javax.faces.webapp.FacesServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;servlet-name&amp;gt;Faces Servlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;url-pattern&amp;gt;*.jsf&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/servlet-mapping&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;And finally &lt;tt&gt;pom.xml&lt;/tt&gt; too &lt;em&gt;(update: this can be done using add-dependency, see the comments below)&lt;/em&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;dependencies&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.richfaces.ui&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;richfaces-ui&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;version&amp;gt;3.3.3.Final&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;scope&amp;gt;compile&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.richfaces.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;richfaces-impl&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;version&amp;gt;3.3.3.Final&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;scope&amp;gt;compile&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/dependency&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;lt;/dependencies&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Then redeploy your app and hit &lt;a href="http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf"&gt;http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf&lt;/a&gt; again:&lt;a href="http://4.bp.blogspot.com/-gtCrSnSj4nc/TZWrw-6p1KI/AAAAAAAAAbQ/YO111jfl4OA/s1600/after.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 220px;" src="http://4.bp.blogspot.com/-gtCrSnSj4nc/TZWrw-6p1KI/AAAAAAAAAbQ/YO111jfl4OA/s320/after.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5590563370461418658" /&gt;&lt;/a&gt;&lt;br /&gt;Of course, Seam Forge is still in alpha so not everything works yet. But hopefully this has whetted your appetite for things to come!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-669120759597495864?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/669120759597495864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=669120759597495864' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/669120759597495864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/669120759597495864'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/04/grokking-seam-forge-part-3.html' title='Grokking Seam Forge: Part 3'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-9wI1AV-g9wM/TXcRdGNqyDI/AAAAAAAAAaw/jKjeXWPmOIE/s72-c/139594.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4067954375779573702</id><published>2011-03-25T16:41:00.007+11:00</published><updated>2011-03-25T16:58:04.120+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><title type='text'>Metawidget: Full Speed To Maven</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 307px; height: 105px;" src="http://2.bp.blogspot.com/-GykeVo8KJoY/TYwrb5Y8QUI/AAAAAAAAAa4/yPMwgk-CVUM/s400/maven-logo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5587888995921838402" /&gt;The next release of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; (v1.15) represents a significant rearrangement of our source tree, as we migrate the codebase from &lt;a href="http://ant.apache.org"&gt;Ant&lt;/a&gt; to &lt;a href="http://maven.apache.org"&gt;Maven&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'm not going to knock Ant: it's been a great build tool for us, and it's much more flexible than Maven in many regards. But there are some compelling reasons for us to switch:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Metawidget wires up &lt;em&gt;existing&lt;/em&gt; technologies, and there are lots of them.&lt;/strong&gt;&lt;br /&gt;I really like the idea of a single &lt;tt&gt;metawidget.jar&lt;/tt&gt; that's easy to deploy and get running, but there are some use cases where this isn't sufficient. For example, perhaps you want to save space by deploying only those Metawidget plugins you actually use. Or perhaps you need to deploy different plugins on different application tiers.&lt;br /&gt;&lt;br /&gt;We need a path from the easy-to-use but monolithic &lt;tt&gt;metawidget.jar&lt;/tt&gt; to this 'fine-grained' use case. Maven gives us this path. So with v1.15 you'll be able to do either...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.metawidget.modules&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;&lt;strong&gt;metawidget-all&lt;/strong&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Or you can specify fine-grained dependencies...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.metawidget.modules.faces&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;&lt;strong&gt;metawidget-richfaces&lt;/strong&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.metawidget.modules&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;&lt;strong&gt;metawidget-jpa&lt;/strong&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;groupId&amp;gt;org.metawidget.modules&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;artifactId&amp;gt;&lt;strong&gt;...other modules...&lt;/strong&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Maven will automatically drag in related dependencies for you, such as &lt;tt&gt;org.metawidget.modules:metawidget-core&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Metawidget needs lots of high quality examples.&lt;/strong&gt;&lt;br /&gt;Whether it's examples on how to run Metawidget on Android, or in GWT Hosted Mode, or with JSF 2, or how to write custom Inspectors or WidgetBuilders - high quality examples are critical. Maven lets us compose each small piece of Metawidget (every example, every plugin) as a standalone project. This makes it easy to use tools such as &lt;a href="http://m2eclipse.sonatype.org"&gt;m2eclipse&lt;/a&gt; to open the individual &lt;tt&gt;pom.xml&lt;/tt&gt; in your IDE and start experimenting!&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt; Some great tools play nicer with Maven.&lt;/strong&gt;&lt;br /&gt;Tools such as &lt;a href="http://jenkins-ci.org"&gt;Jenkins&lt;/a&gt; and &lt;a href="http://www.sonarsource.org"&gt;Sonar&lt;/a&gt;, which should have a direct bearing on maintaining our code quality.&lt;/li&gt;&lt;/ul&gt;&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://2.bp.blogspot.com/-CjysxNv-Sfo/TYwuywJs7AI/AAAAAAAAAbA/9dNVwbSzSPo/s400/amor.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5587892687113874434" /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Don't Panic!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To ally any concerns, allow me to stress:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Metawidget v1.15 will be backwards compatible with v1.10.&lt;/strong&gt;&lt;br /&gt;In fact, the binaries will be almost identical. Only the build system has been rewritten.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Metawidget will not require Maven to use.&lt;/strong&gt;&lt;br /&gt;We will still be packaging &lt;tt&gt;metawidget-1.15.zip&lt;/tt&gt; and &lt;tt&gt;metawidget-1.15-src.zip&lt;/tt&gt; distributions that you can download, just as before.&lt;/li&gt;&lt;/ul&gt;All up, I don't think anything will be lost (apart from sweat and tears rearranging the code) and hopefully a lot will be gained. I've branched the old v1.10 codebase in SVN and checked in an early copy of the Maven version. I'd say it's about 75% done (and has nearly 100 POMs!)&lt;br /&gt;&lt;br /&gt;I'd be most grateful to anybody who could check it out and provide feedback.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4067954375779573702?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4067954375779573702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4067954375779573702' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4067954375779573702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4067954375779573702'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/03/metawidget-full-speed-to-maven.html' title='Metawidget: Full Speed To Maven'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-GykeVo8KJoY/TYwrb5Y8QUI/AAAAAAAAAa4/yPMwgk-CVUM/s72-c/maven-logo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4707082104287658097</id><published>2011-03-09T16:23:00.009+11:00</published><updated>2011-03-10T08:11:32.408+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seam Forge'/><title type='text'>Grokking Seam Forge: Part 2</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 300px; height: 89px;" src="http://4.bp.blogspot.com/-9wI1AV-g9wM/TXcRdGNqyDI/AAAAAAAAAaw/jKjeXWPmOIE/s400/139594.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5581949454730840114" /&gt;JBoss have just released &lt;a href="http://in.relation.to/Bloggers/Seam300CR2Released"&gt;Seam 3.0.0.CR2&lt;/a&gt;, which includes Alpha 2 of Seam Forge. It's an alpha, so expect pain, but let's take it for a spin!&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First, download Seam Forge from &lt;a href="http://sourceforge.net/projects/jboss/files/Forge/1.0.0"&gt;here&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Unzip to a folder of your choosing&lt;/li&gt;&lt;li&gt;Run &lt;tt&gt;bin\forge&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;Seam Forge is command-line driven, similar to &lt;a href="http://rubyonrails.org"&gt;Rails&lt;/a&gt; and &lt;a href="http://springsource.org/roo"&gt;Roo&lt;/a&gt; (though with loftier goals :). Type the sections in bold:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;[no project] forge-1.0.0.Alpha2 $ &lt;strong&gt;new-project --named MyApp --topLevelPackage com.myapp&lt;/strong&gt;&lt;br /&gt;Use [/forge-1.0.0.Alpha2/MyApp] as project directory? [Y/n] &lt;strong&gt;y&lt;/strong&gt;&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/resources/META-INF/forge.xml&lt;br /&gt;***SUCCESS*** Created project [MyApp] in new working directory [/forge-1.0.0.Alpha2/MyApp]&lt;br /&gt;&lt;br /&gt;[MyApp] MyApp $ &lt;strong&gt;persistence setup --provider HIBERNATE --container JBOSS_6&lt;/strong&gt;&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/resources/META-INF/persistence.xml&lt;br /&gt;***SUCCESS*** Installed [forge.spec.jpa] successfully.&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/resources/META-INF/persistence.xml&lt;br /&gt;&lt;br /&gt;[MyApp] MyApp $ &lt;strong&gt;new-entity --named Person&lt;/strong&gt;&lt;br /&gt;In which package you'd like to create this @Entity, or enter for default: [com.myapp.domain]&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java&lt;br /&gt;Created @Entity [com.myapp.domain.Person]&lt;br /&gt;Picked up type &lt;JavaResource&gt;: com.myapp.domain.Person&lt;br /&gt;&lt;br /&gt;[MyApp] Person.java $ &lt;strong&gt;new-field string --fieldName firstName&lt;/strong&gt;&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java&lt;br /&gt;Added field to com.myapp.domain.Person: @Column private String firstName;&lt;br /&gt;[MyApp] Person.java $ &lt;strong&gt;new-field string --fieldName surname&lt;/strong&gt;&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java&lt;br /&gt;Added field to com.myapp.domain.Person: @Column private String surname;&lt;br /&gt;[MyApp] Person.java $ &lt;strong&gt;cd ..&lt;/strong&gt;&lt;br /&gt;[MyApp] domain $ &lt;strong&gt;scaffold from-entity com.myapp.domain.Person.java&lt;/strong&gt;&lt;br /&gt;The [forge.maven.WebResourceFacet] facet requires the following packaging type [war], but is currently [jar], would you like to change the packaging to [war]? (Note: this could break other plugins in your project.) [Y/n] &lt;strong&gt;y&lt;/strong&gt;&lt;br /&gt;Packaging updated to [war]&lt;br /&gt;***SUCCESS*** Installed [forge.maven.WebResourceFacet] successfully.&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/beans.xml&lt;br /&gt;***SUCCESS*** Installed [forge.spec.cdi] successfully.&lt;br /&gt;The [forge.spec.jsf] facet depends on the following missing facets: [forge.spec.servlet]. Would you like to attempt installation of these facets as well? [Y/n] &lt;strong&gt;y&lt;/strong&gt;&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/web.xml&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/index.html&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/faces-config.xml&lt;br /&gt;***SUCCESS*** Installed [forge.spec.jsf] successfully.&lt;br /&gt;***SUCCESS*** Scaffolding installed.&lt;br /&gt;No scaffold type was provided, use Forge default? [Y/n] &lt;strong&gt;y&lt;/strong&gt;&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/beans.xml&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/org/jboss/seam/forge/persistence/DatasourceProducer.java&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/org/jboss/seam/forge/persistence/PersistenceUtil.java&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/resources/forge-template.xhtml&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/resources/forge.css&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/resources/favicon.ico&lt;br /&gt;***INFO*** [/forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java] File exists, re-run with `--overwrite` to replace existing files.&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/view/PersonBean.java&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/scaffold/person/view.xhtml&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/scaffold/person/create.xhtml&lt;br /&gt;Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/scaffold/person/list.xhtml&lt;br /&gt;***SUCCESS*** Generated UI for [com.myapp.domain.Person]&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Next:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Open Eclipse (with &lt;a href="http://m2eclipse.sonatype.org"&gt;m2eclipse&lt;/a&gt; installed)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Choose &lt;tt&gt;File &amp;gt; Import &amp;gt; Existing Maven Projects&lt;/tt&gt; and import the &lt;tt&gt;pom.xml&lt;/tt&gt; at &lt;tt&gt;\forge-1.0.0.Alpha2\MyApp\pom.xml&lt;/tt&gt;&lt;a href="http://1.bp.blogspot.com/-oZYfvEgLS9w/TXcPfO4Xa8I/AAAAAAAAAaY/r6pNLmC6cQQ/s1600/import-pom.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 242px; height: 185px;" src="http://1.bp.blogspot.com/-oZYfvEgLS9w/TXcPfO4Xa8I/AAAAAAAAAaY/r6pNLmC6cQQ/s320/import-pom.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5581947292393892802" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Edit &lt;tt&gt;src/main/resources/META-INF/persistence.xml&lt;/tt&gt; and remove the line that says &lt;tt&gt;&amp;lt;non-jta-data-source/&amp;gt;&lt;/tt&gt;&lt;/li&gt; (a bug)&lt;br /&gt;&lt;li&gt;Right click the &lt;tt&gt;pom.xml&lt;/tt&gt; and choose &lt;tt&gt;Run As &amp;gt; Maven package&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Take the WAR it generates under &lt;tt&gt;target/MyApp-1.0.0-SNAPSHOT.war&lt;/tt&gt; and deploy it under &lt;a href="http://www.jboss.org/jbossas/downloads"&gt;JBoss AS 6.0.0.Final&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Open your browser at &lt;a href="http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf"&gt;http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf&lt;/a&gt;:&lt;a href="http://2.bp.blogspot.com/-NODz4PGxcis/TXcPfSXDz2I/AAAAAAAAAag/8G1nmxI3xBQ/s1600/screenshot1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 295px;" src="http://2.bp.blogspot.com/-NODz4PGxcis/TXcPfSXDz2I/AAAAAAAAAag/8G1nmxI3xBQ/s320/screenshot1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5581947293327937378" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;tt&gt;Create&lt;/tt&gt;:&lt;a href="http://3.bp.blogspot.com/-3t2-nr-OYWQ/TXcPfSpspaI/AAAAAAAAAao/17TpqM9yuJE/s1600/screenshot2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 295px;" src="http://3.bp.blogspot.com/-3t2-nr-OYWQ/TXcPfSpspaI/AAAAAAAAAao/17TpqM9yuJE/s320/screenshot2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5581947293406111138" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;And that's it! Seam Forge &lt;strong&gt;has created a full web application for you, complete with JPA back-end and JSF front-end, without you having to write a single line of code&lt;/strong&gt;. Of course there's much more to it than that, but hopefully this gives you a taste for what JBoss and the Seam Team are cooking up!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4707082104287658097?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4707082104287658097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4707082104287658097' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4707082104287658097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4707082104287658097'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/03/grokking-seam-forge-part-2.html' title='Grokking Seam Forge: Part 2'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-9wI1AV-g9wM/TXcRdGNqyDI/AAAAAAAAAaw/jKjeXWPmOIE/s72-c/139594.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1757556178211112428</id><published>2011-03-07T18:14:00.020+11:00</published><updated>2011-03-09T11:02:19.951+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><title type='text'>MySQL Performance: Leveraging SQL_CALC_FOUND_ROWS and FOUND_ROWS inside JPA-QL</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://3.bp.blogspot.com/-t_ZerK0P2rQ/TXSF-t4iGCI/AAAAAAAAAaQ/Rhcn1kbl9AU/s400/database.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5581233150733981730" /&gt;There are lots of articles on the Web about how to optimize paginated displays. The basic problem is: in order to paginate well, you must display the total number of hits to the user:&lt;br /&gt;&lt;br /&gt;&lt;div class="code" style="text-align: center"&gt;&lt;tt&gt;1...30 (of 54,342)&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;But finding that total number of hits can be slow. In particular doing &lt;tt&gt;select count(*)&lt;/tt&gt; in MySQL is &lt;a href="http://mysqlha.blogspot.com/2009/08/fast-count-for-innodb.html"&gt;notoriously slow&lt;/a&gt;. There are &lt;a href="http://www.mysqlperformanceblog.com/2008/09/24/four-ways-to-optimize-paginated-displays"&gt;lots&lt;/a&gt; of possible solutions. A promising, MySQL-specific one is &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows"&gt;select FOUND_ROWS()&lt;/a&gt;. Using this via native SQL is easy. But exposing it inside JPA-QL (which generates its SQL automatically) is tricky. The rules for using it are:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Clients must run a normal query, using &lt;tt&gt;LIMIT&lt;/tt&gt; for pagination, and prefix it as: &lt;strong&gt;&lt;tt&gt;select SQL_CALC_FOUND_ROWS * from myTable&lt;/tt&gt;&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Immediately afterwards, &lt;em&gt;before any other SQL statements are run&lt;/em&gt;, clients call &lt;strong&gt;&lt;tt&gt;select FOUND_ROWS()&lt;/tt&gt;&lt;/strong&gt; to obtain the number of rows there would have been if no &lt;tt&gt;LIMIT&lt;/tt&gt; had been set&lt;/li&gt;&lt;/ol&gt;A further advantage of &lt;code&gt;SQL_CALC_FOUND_ROWS&lt;/code&gt; is that it can be used with &lt;code&gt;having&lt;/code&gt; queries, whereas &lt;code&gt;count()&lt;/code&gt; cannot.&lt;br /&gt;&lt;br /&gt;Here's one way to leverage this inside Hibernate-based JPA. We'll be using &lt;a href="http://www.oreillynet.com/onjava/blog/2007/05/interceptors_in_hibernate.html"&gt;Interceptors&lt;/a&gt;. Like all the solutions to this problem, this one isn't perfect, but it may suit your purposes:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;package com.kennardconsulting.core.hibernate.interceptor;&lt;br /&gt;&lt;br /&gt;import org.hibernate.EmptyInterceptor;&lt;br /&gt;import org.hibernate.HibernateException;&lt;br /&gt;import org.hibernate.SessionFactory;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Hibernate interceptor to make use of MySQL's proprietary &amp;lt;code&amp;gt;SQL_CALC_FOUND_ROWS&amp;lt;/code&amp;gt; hint.&lt;br /&gt; * The &amp;lt;code&amp;gt;count()&amp;lt;/code&amp;gt; method in MySQL is notoriously slow&lt;br /&gt; * (http://mysqlha.blogspot.com/2009/08/fast-count-for-innodb.html) as it scans the entire index.&lt;br /&gt; * &amp;lt;code&amp;gt;SQL_CALC_FOUND_ROWS&amp;lt;/code&amp;gt; was introduced to allow clients to obtain a &amp;lt;code&amp;gt;count()&amp;lt;/code&amp;gt;&lt;br /&gt; * in a more performant way.&lt;br /&gt; * &amp;lt;p&amp;gt;&lt;br /&gt; * The rules are:&lt;br /&gt; * &amp;lt;p&amp;gt;&lt;br /&gt; * &amp;lt;ol&amp;gt;&lt;br /&gt; * &amp;lt;li&amp;gt;Clients must run a normal query, using &amp;lt;code&amp;gt;LIMIT&amp;lt;/code&amp;gt; for pagination, and prefix it with&lt;br /&gt; * &amp;lt;code&amp;gt;SQL_CALC_FOUND_ROWS&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; * &amp;lt;li&amp;gt;Immediately afterwards, &amp;lt;em&amp;gt;before any other SQL statements are run&amp;lt;/em&amp;gt;, clients call&lt;br /&gt; * &amp;lt;code&amp;gt;FOUND_ROWS()&amp;lt;/code&amp;gt; to obtain the number of rows there &amp;lt;em&amp;gt;would&amp;lt;/em&amp;gt; have been, if no&lt;br /&gt; * limit had been set&amp;lt;/li&amp;gt;&lt;br /&gt; * &amp;lt;/ol&amp;gt;&lt;br /&gt; * &amp;lt;p&amp;gt;&lt;br /&gt; * A further advantage of &amp;lt;code&amp;gt;SQL_CALC_FOUND_ROWS&amp;lt;/code&amp;gt; is that it can be used with&lt;br /&gt; * &amp;lt;code&amp;gt;having&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;count()&amp;lt;/code&amp;gt; cannot.&lt;br /&gt; * &amp;lt;p&amp;gt;&lt;br /&gt; * Other approaches we tried:&lt;br /&gt; * &amp;lt;p&amp;gt;&lt;br /&gt; * &amp;lt;ul&amp;gt;&lt;br /&gt; * &amp;lt;li&amp;gt;Hibernate supports ScrollableResults, but on MySQL that seems to just bring back the entire&lt;br /&gt; * results and is very slow&amp;lt;/li&amp;gt;&lt;br /&gt; * &amp;lt;li&amp;gt;You can try embedding count(*) as an extra column in the query, but that negates the indexes&amp;lt;/li&amp;gt;&lt;br /&gt; * &amp;lt;li&amp;gt;You can try 'show table status where name = Member' but that varies wildly and is&lt;br /&gt; * disconcerting for the user (for 60,000 rows, +/- 3,000 rows)&amp;lt;/li&amp;gt;&lt;br /&gt; * &amp;lt;li&amp;gt;You can make 'count()' setCacheable( true )&amp;lt;/li&amp;gt;&lt;br /&gt; * &amp;lt;/ul&amp;gt;&lt;br /&gt; * &amp;lt;strong&amp;gt;Note: this is not a general purpose Interceptor. It assumes it will be used to execute a&lt;br /&gt; * single select (possibly with secondary selects) and then thrown away. It cannot be&lt;br /&gt; * re-used.&amp;lt;/strong&amp;gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;public class MySQLCalcFoundRowsInterceptor&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;extends EmptyInterceptor {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Private statics&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final static String&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT_PREFIX&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;= "select ";&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final static String&amp;nbsp;&amp;nbsp;&amp;nbsp;CALC_FOUND_ROWS_HINT&amp;nbsp;&amp;nbsp;&amp;nbsp;= "SQL_CALC_FOUND_ROWS ";&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final static String&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT_FOUND_ROWS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;= "select FOUND_ROWS()";&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Private members&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private SessionFactory&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mSessionFactory;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private byte&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mSQLStatementsPrepared;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Long&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mFoundRows;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Constructor&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public MySQLCalcFoundRowsInterceptor( SessionFactory sessionFactory ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mSessionFactory = sessionFactory;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Public methods&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String onPrepareStatement( String sql ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;switch ( mSQLStatementsPrepared ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 0: {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mSQLStatementsPrepared++;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// First time, prefix CALC_FOUND_ROWS_HINT&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringBuilder builder = new StringBuilder( sql );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int indexOf = builder.indexOf( SELECT_PREFIX );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( indexOf == -1 ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new HibernateException( "First SQL statement did not contain '" + SELECT_PREFIX + "'" );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;builder.insert( indexOf + SELECT_PREFIX.length(), CALC_FOUND_ROWS_HINT );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return builder.toString();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 1: {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mSQLStatementsPrepared++;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Before any secondary selects, capture FOUND_ROWS. If no secondary selects are&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ever executed, getFoundRows() will capture FOUND_ROWS just-in-time when called&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// directly&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;captureFoundRows();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return sql;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;default:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Pass-through untouched&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return sql;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public long getFoundRows() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( mFoundRows == null ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;captureFoundRows();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return mFoundRows;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Private methods&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void captureFoundRows() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Sanity checks&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( mFoundRows != null ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new HibernateException( "'" + SELECT_FOUND_ROWS + "' called more than once" );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( mSQLStatementsPrepared &amp;lt; 1 ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new HibernateException( "'" + SELECT_FOUND_ROWS + "' called before '" + SELECT_PREFIX + CALC_FOUND_ROWS_HINT +"'" );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Fetch the total number of rows&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mFoundRows = ( (Number) mSessionFactory.getCurrentSession().createSQLQuery( SELECT_FOUND_ROWS ).uniqueResult() ).longValue();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To use this Interceptor inside JPA-QL:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;SessionFactory sessionFactory = ((org.hibernate.Session) mEntityManager.getDelegate()).getSessionFactory();&lt;br /&gt;MySQLCalcFoundRowsInterceptor foundRowsInterceptor = new MySQLCalcFoundRowsInterceptor( sessionFactory );&lt;br /&gt;Session session = sessionFactory.openSession( foundRowsInterceptor );&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;org.hibernate.Query query = session.createQuery( ... )&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;em&gt;// Note: JPA-QL, not createNativeQuery!&lt;/em&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;query.setFirstResult( ... );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;query.setMaxResults( ... );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;List entities = query.list();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;long foundRows = foundRowsInterceptor.getFoundRows();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;} finally {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Disconnect() is good practice, but close() causes problems. Note, however, that&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// disconnect could lead to lazy-loading problems if the returned list of entities has&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// lazy relations&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;session.disconnect();&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Hope that helps!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1757556178211112428?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1757556178211112428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1757556178211112428' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1757556178211112428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1757556178211112428'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/03/mysql-performance-leveraging.html' title='MySQL Performance: Leveraging SQL_CALC_FOUND_ROWS and FOUND_ROWS inside JPA-QL'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-t_ZerK0P2rQ/TXSF-t4iGCI/AAAAAAAAAaQ/Rhcn1kbl9AU/s72-c/database.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1226975689713966896</id><published>2011-03-03T10:21:00.009+11:00</published><updated>2011-03-03T10:42:56.234+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Eclipse Helios: Missing semicolon JavaScript Warnings</title><content type='html'>If your Eclipse &lt;tt&gt;Problems&lt;/tt&gt; tab looks like this after upgrading to 3.6.2 (Helios)...&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-6Uaznk6IzV0/TW7RIC_1NZI/AAAAAAAAAaA/6BSGg7HT1m8/s1600/pic.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 237px;" src="http://2.bp.blogspot.com/-6Uaznk6IzV0/TW7RIC_1NZI/AAAAAAAAAaA/6BSGg7HT1m8/s400/pic.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5579626924532381074" /&gt;&lt;/a&gt;...and you're having a hard time turning that off, here's what appears to be the answer:&lt;br /&gt;&lt;br /&gt;The &lt;strong&gt;Suspend all validators&lt;/strong&gt; checkbox on the &lt;tt&gt;Window &amp;gt; Preferences &amp;gt; Validation&lt;/tt&gt; screen is broken (or partially broken, its behaviour is a bit erratic). So ignore it.&lt;br /&gt;&lt;br /&gt;Instead, uncheck that box (and &lt;strong&gt;leave it unchecked&lt;/strong&gt;) and explictly turn off &lt;tt&gt;Client-side Javascript&lt;/tt&gt; validation in the box underneath:&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-prdcMSGTAwA/TW7R3ukkRAI/AAAAAAAAAaI/iAqbVnhjIuU/s1600/pic2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 343px;" src="http://3.bp.blogspot.com/-prdcMSGTAwA/TW7R3ukkRAI/AAAAAAAAAaI/iAqbVnhjIuU/s400/pic2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5579627743683036162" /&gt;&lt;/a&gt;&lt;br /&gt;Hope that helps somebody! I've reported this as &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=338759"&gt;bug 338759&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1226975689713966896?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1226975689713966896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1226975689713966896' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1226975689713966896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1226975689713966896'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/03/eclipse-helios-missing-semicolon.html' title='Eclipse Helios: Missing semicolon JavaScript Warnings'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-6Uaznk6IzV0/TW7RIC_1NZI/AAAAAAAAAaA/6BSGg7HT1m8/s72-c/pic.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1946820930689030932</id><published>2011-03-01T21:11:00.013+11:00</published><updated>2011-03-01T21:37:57.152+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><category scheme='http://www.blogger.com/atom/ns#' term='Drools'/><title type='text'>Metawidget and Drools</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 254px; height: 85px;" src="http://4.bp.blogspot.com/-mkDAL5ycJtc/TWzKnJIdvvI/AAAAAAAAAZw/nZAoAKCGRIQ/s400/drools-banner.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5579056812220333810" /&gt;Blogger &lt;a href="http://lisbor.blogspot.com/2011/02/exploring-metawidget.html"&gt;Sergiy&lt;/a&gt; has put together a terrific example of integrating &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; with &lt;a href="http://www.jboss.org/drools"&gt;JBoss Drools&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;He uses Metawidget to render a Drools ViewDefiniton for use in a weather forecasting application. To quote:&lt;br /&gt;&lt;br /&gt;&lt;em style="margin-left: 30px; margin-right: 30px; display: block"&gt;"One of the key aspects of Metawidget is its concept of inspectors that are responsible for extracting meaningful metadata from business objects. Metawidget comes with a number of default inspectors that allow extracting metadata based on Java reflection, annotations, etc. But what if we want something special? :)&lt;br /&gt;&lt;br /&gt;For instance, how about &lt;strong&gt;using business rules as the source of meaningful metadata for a UI?&lt;/strong&gt;"&lt;/em&gt;&lt;br /&gt;He then describes in detail the steps necessary to create an application like this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-dK5iMctmhpg/TWzK5pLK4DI/AAAAAAAAAZ4/2dd6WjrtPEM/s1600/pic1.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 299px; height: 320px;" src="http://3.bp.blogspot.com/-dK5iMctmhpg/TWzK5pLK4DI/AAAAAAAAAZ4/2dd6WjrtPEM/s320/pic1.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5579057130059259954" /&gt;&lt;/a&gt;&lt;br /&gt;Read the full blog post &lt;a href="http://lisbor.blogspot.com/2011/02/exploring-metawidget.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Thanks Sergiy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1946820930689030932?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1946820930689030932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1946820930689030932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1946820930689030932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1946820930689030932'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/03/metawidget-and-drools.html' title='Metawidget and Drools'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-mkDAL5ycJtc/TWzKnJIdvvI/AAAAAAAAAZw/nZAoAKCGRIQ/s72-c/drools-banner.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1404734269681991655</id><published>2011-02-24T12:02:00.004+11:00</published><updated>2011-05-21T22:05:41.765+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>User Interface Generation Tools: JAXenter Metawidget interview</title><content type='html'>&lt;img style="MARGIN: 0px 0px 10px 10px; WIDTH: 297px; FLOAT: right; HEIGHT: 123px; border: 0" id="BLOGGER_PHOTO_ID_5408207982146337410" border="0" alt="" src="http://4.bp.blogspot.com/__YNTBm_fS_I/Sw3QgX9DuoI/AAAAAAAAAMo/pS4w39JEE5w/s320/logo.jpg" /&gt;I did a &lt;a href="http://jaxenter.com/what-s-new-in-metawidget-1-10-35008.html"&gt;short interview with JAXenter&lt;/a&gt; about the recent v1.10 release of Metawidget, the &lt;a href="http://metawidget.org"&gt;user interface generation tool&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Thanks for the shout-out guys!&lt;br /&gt;&lt;br /&gt;JAXenter have previously done &lt;a href="http://it-republik.de/jaxenter/artikel/Metawidget-King-of-the-Hill-2681.html"&gt;an in-depth article on Metawidget here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1404734269681991655?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1404734269681991655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1404734269681991655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1404734269681991655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1404734269681991655'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/02/user-interface-generation-tools.html' title='User Interface Generation Tools: JAXenter Metawidget interview'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__YNTBm_fS_I/Sw3QgX9DuoI/AAAAAAAAAMo/pS4w39JEE5w/s72-c/logo.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1069264221737112444</id><published>2011-02-10T20:57:00.003+11:00</published><updated>2011-07-18T08:39:16.305+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>User Interface Generation: Metawidget v1.10</title><content type='html'>&lt;img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 0px 10px 10px; WIDTH: 188px; FLOAT: right; HEIGHT: 400px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id="BLOGGER_PHOTO_ID_5428305152285105858" border="0" alt="" src="http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s400/box.png" /&gt;Version 1.10 of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, the &lt;a href="http://metawidget.org"&gt;user interface generation&lt;/a&gt; tool is now available! This release includes the following enhancements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://metawidget.org/doc/reference/en/htmlsingle/metawidget.html#section-introduction-part2-web-primefaces"&gt;PrimeFaces support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2011/02/metawidget-icefaces-paneltabset-support.html"&gt;Improved ICEfaces support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://metawidget.org/doc/reference/en/htmlsingle/metawidget.html#section-inspectors-jpa"&gt;JpaInspector.setHideVersions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://metawidget.org/doc/reference/en/htmlsingle/metawidget.html#section-widgetprocessors-web-gwt-stylename"&gt;Refactored GWT StyleNameProcessor&lt;/a&gt;&lt;/li&gt;&lt;li&gt;JSF2 version of AddressBook&lt;/li&gt;&lt;li&gt;Upgrade to Seam 2.2.1.GA&lt;/li&gt;&lt;li&gt;Bug fixes, documentation and unit tests&lt;/li&gt;&lt;/ul&gt;As always, the best place to start is the Reference Documentation:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;a href="http://metawidget.org/doc/reference/en/pdf/metawidget.pdf"&gt;http://metawidget.org/doc/reference/en/pdf/metawidget.pdf&lt;br /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;Special thanks to Ronald van Kuijk and Leon E for their help with this release!&lt;br /&gt;&lt;br /&gt;Your continued feedback is invaluable to us. Please &lt;a href="http://metawidget.org/download.html"&gt;download it&lt;/a&gt; and &lt;a href="http://metawidget.org/forums.html"&gt;let us know what you think&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1069264221737112444?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1069264221737112444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1069264221737112444' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1069264221737112444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1069264221737112444'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/02/user-interface-generation-metawidget.html' title='User Interface Generation: Metawidget v1.10'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s72-c/box.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-6117710176419795657</id><published>2011-02-08T20:40:00.012+11:00</published><updated>2011-07-18T09:04:18.639+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PrimeFaces'/><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: PrimeFaces TabView support</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 125px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TVERmT5tzHI/AAAAAAAAAZo/Bh0IdD6Vh5A/s400/autobot.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5571253563909065842" /&gt;In a similar fashion to &lt;a href="http://blog.kennardconsulting.com/2011/02/metawidget-icefaces-paneltabset-support.html"&gt;my previous blog&lt;/a&gt;, the next release of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; (v1.10) will add support for the &lt;a href="http://primefaces.org"&gt;PrimeFaces&lt;/a&gt; TabView component.&lt;br /&gt;&lt;br /&gt;I have updated the &lt;a href="http://metawidget.sourceforge.net/doc/reference/en/html/ch01s02.html#section-introduction-part2-web"&gt;AddressBook Example&lt;/a&gt; included in the distribution to demonstrate swapping in PrimeFaces support. So now you can add...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;metawidget&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;tabViewLayoutDecorator xmlns="java:org.metawidget.faces.component.html.layout.primefaces"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config="org.metawidget.layout.decorator.LayoutDecoratorConfig"&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;simpleLayout xmlns="java:org.metawidget.faces.component.layout"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;/tabViewLayoutDecorator&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/layout&amp;gt;&lt;br /&gt;&amp;lt;/metawidget&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...and you auto-magically get (note the PrimeFaces TabView and the PrimeFaces Slider)...&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TVEREGZrUgI/AAAAAAAAAZg/740TZtD7at8/s1600/web-addressbook-primefaces.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 322px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TVEREGZrUgI/AAAAAAAAAZg/740TZtD7at8/s400/web-addressbook-primefaces.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5571252976169472514" /&gt;&lt;/a&gt;&lt;br /&gt;Early access code now available in SVN.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-6117710176419795657?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/6117710176419795657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=6117710176419795657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6117710176419795657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6117710176419795657'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/02/metawidget-primefaces-tabview-support.html' title='Metawidget: PrimeFaces TabView support'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/TVERmT5tzHI/AAAAAAAAAZo/Bh0IdD6Vh5A/s72-c/autobot.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4710988615140292896</id><published>2011-02-08T16:48:00.010+11:00</published><updated>2011-02-08T20:56:35.333+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><category scheme='http://www.blogger.com/atom/ns#' term='ICEfaces'/><title type='text'>Metawidget: ICEfaces PanelTabSet support</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TVDaBWO6PSI/AAAAAAAAAZQ/326A_aJeR48/s400/tux.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5571192455740144930" /&gt;The next release (v1.10) of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; improves our &lt;a href="http://icefaces.org"&gt;ICEfaces&lt;/a&gt; support by adding &lt;tt&gt;PanelTabSetLayoutDecorator&lt;/tt&gt;. So now you can do:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;metawidget&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;panelTabSetLayoutDecorator xmlns="java:org.metawidget.faces.component.html.layout.icefaces" config="org.metawidget.layout.decorator.LayoutDecoratorConfig"&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;simpleLayout xmlns="java:org.metawidget.faces.component.layout"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/layout&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;&amp;lt;/panelTabSetLayoutDecorator&amp;gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/layout&amp;gt;&lt;br /&gt;&amp;lt;/metawidget&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;I have updated the &lt;a href="http://metawidget.sourceforge.net/doc/reference/en/html/ch01s03.html#section-introduction-part3-icefaces"&gt;ICEfaces PenguinColony Example&lt;/a&gt; included in the distribution to include tabs inside the dialog:&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/__YNTBm_fS_I/TVDZr85a7TI/AAAAAAAAAYw/mTjzirY26-Y/s1600/Penguin1.jpg"&gt;&lt;img style="display:block; margin: auto; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 218px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TVDZr85a7TI/AAAAAAAAAYw/mTjzirY26-Y/s320/Penguin1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5571192088161873202" /&gt;&lt;/a&gt;The full ICEfaces AJAX experience of dynamically creating components still works as normal inside the tabs:&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/__YNTBm_fS_I/TVDZsG4781I/AAAAAAAAAY4/VXvHO1G3UUM/s1600/Penguin2.jpg"&gt;&lt;img style="display:block; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 218px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TVDZsG4781I/AAAAAAAAAY4/VXvHO1G3UUM/s320/Penguin2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5571192090844197714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TVDZsRzbt6I/AAAAAAAAAZA/_7G3Uhn1vqc/s1600/Penguin3.jpg"&gt;&lt;img style="display:block; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 218px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TVDZsRzbt6I/AAAAAAAAAZA/_7G3Uhn1vqc/s320/Penguin3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5571192093773903778" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2"&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TVDZs4L1wPI/AAAAAAAAAZI/5jpkhvP1UvQ/s1600/Penguin4.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 218px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TVDZs4L1wPI/AAAAAAAAAZI/5jpkhvP1UvQ/s320/Penguin4.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5571192104076820722" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;Early access code now available in SVN.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4710988615140292896?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4710988615140292896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4710988615140292896' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4710988615140292896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4710988615140292896'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/02/metawidget-icefaces-paneltabset-support.html' title='Metawidget: ICEfaces PanelTabSet support'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/TVDaBWO6PSI/AAAAAAAAAZQ/326A_aJeR48/s72-c/tux.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-5413340085047955098</id><published>2011-02-07T17:31:00.009+11:00</published><updated>2011-02-07T17:53:14.706+11:00</updated><title type='text'>Cluster Ointment: JBoss, JGroups and Shunning</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TU-SGCpG2VI/AAAAAAAAAYo/VA4zmpwrvqo/s400/Community%2BHelp.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5570831896566749522" /&gt;For some months now we've been having intermittent problems with our &lt;a href="http://jboss.org"&gt;JBoss&lt;/a&gt; cluster. Whenever a cluster node died and restarted, sometimes it would fail to rejoin the cluster. The log would just keep saying:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;WARN  [org.jgroups.protocols.pbcast.GMS] join(&amp;lt;IP address&amp;gt;) sent to &amp;lt;IP address&amp;gt; timed out (after 3000 ms), retrying&lt;br /&gt;WARN  [org.jgroups.protocols.pbcast.GMS] join(&amp;lt;IP address&amp;gt;) sent to &amp;lt;IP address&amp;gt; timed out (after 3000 ms), retrying&lt;br /&gt;WARN  [org.jgroups.protocols.pbcast.GMS] join(&amp;lt;IP address&amp;gt;) sent to &amp;lt;IP address&amp;gt; timed out (after 3000 ms), retrying&lt;br /&gt;WARN  [org.jgroups.protocols.pbcast.GMS] join(&amp;lt;IP address&amp;gt;) sent to &amp;lt;IP address&amp;gt; timed out (after 3000 ms), retrying&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;This happened on JBoss 4.0.3, 4.2, 5.0 and 5.1. But today I found some interesting tidbits:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;When a [JGroups] member [defined by its IP and port number] is expelled from the group, e.g. because it didn't respond to are-you-alive messages, and later comes back, then it is shunned&lt;/strong&gt; &lt;a href="http://www.jgroups.org/manual/html/user-advanced.html"&gt;(source)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;JGroups relies on the fact that the assignment of ports by the OS is always (not necessarily monotonically) increasing across a single machine... [but this may not hold] for TCP ... because we're defining the &lt;tt&gt;start_port&lt;/tt&gt; for a member, and so that member will always reuse the same port when restarted [the term is 'reincarnated'] &lt;a href="https://issues.jboss.org/browse/JGRP-130"&gt;(source)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;In [JGroups] 2.8, shunning has been removed, so the sections below only apply to versions up to 2.7 &lt;a href="http://www.jgroups.org/manual/html/user-advanced.html"&gt;(source)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;So any version of JBoss using JGroups 2.7 or earlier (which includes JBoss 5.1) will see this problem if you're explictly defining the &lt;tt&gt;start_port&lt;/tt&gt; for a node. The solution is to edit &lt;tt&gt;jgroups-channelfactory-stacks.xml&lt;/tt&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;FD_SOCK/&amp;gt;&lt;br /&gt;&amp;lt;FD timeout="6000" max_tries="5" &lt;strong&gt;shun="false"&lt;/strong&gt;/&amp;gt;&lt;br /&gt;&amp;lt;VERIFY_SUSPECT timeout="1500"/&amp;gt;&lt;br /&gt;&amp;lt;pbcast.NAKACK use_mcast_xmit="false" gc_lag="0"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;retransmit_timeout="300,600,1200,2400,4800"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;discard_delivered_msgs="true"/&amp;gt;&lt;br /&gt;&amp;lt;UNICAST timeout="300,600,1200,2400,3600"/&amp;gt;&lt;br /&gt;&amp;lt;pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_bytes="400000"/&amp;gt;&lt;br /&gt;&amp;lt;pbcast.GMS print_local_addr="true" join_timeout="3000"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;shun="false"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;reject_join_from_existing_member="false"&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;view_bundling="true"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;view_ack_collection_timeout="5000"/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;This has shown an immediate improvement in our cluster. Hope it works for you too!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-5413340085047955098?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/5413340085047955098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=5413340085047955098' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5413340085047955098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/5413340085047955098'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/02/cluster-ointment-jboss-jgroups-and.html' title='Cluster Ointment: JBoss, JGroups and Shunning'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__YNTBm_fS_I/TU-SGCpG2VI/AAAAAAAAAYo/VA4zmpwrvqo/s72-c/Community%2BHelp.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-972380331269638436</id><published>2011-02-02T13:35:00.008+11:00</published><updated>2011-07-18T08:40:29.361+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Defining Business Objects Using Maps (JSF Version)</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TUitMkv7XfI/AAAAAAAAAYc/a9X0Z06BTJk/s400/tutorials.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5568891370778353138" /&gt;I thought I'd do a JSF 2 version of &lt;a href="http://blog.kennardconsulting.com/2011/02/metawidget-defining-business-objects.html"&gt;my previous blog entry&lt;/a&gt;. Doing it in JSF is a litte more difficult to grok, because the all important methods...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;metawidget.setToInspect( values );&lt;br /&gt;metawidget.setPath( "person" );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...are obscured behind JSF's standard syntax:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;m:metawidget value="#{...}"/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;There are a number of ways you could &lt;em&gt;un&lt;/em&gt;obscure them, but so as not to be confusing I'll just talk about one here. Basically I will wrap the 'toInspect' values and the 'path' type in &lt;tt&gt;MyManagedBean&lt;/tt&gt; so that I can pass them both in a single &lt;tt&gt;ValueExpression&lt;/tt&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;m:metawidget value="#{myManagedBean}"/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Regardless, the crucial point - as with the Swing version - is that there's a &lt;tt&gt;MapInspector&lt;/tt&gt; and a &lt;tt&gt;MapWidgetProcessor&lt;/tt&gt; and &lt;em&gt;they operate on different Maps&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;You can &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHNmQ3ODRkNDgtNDc3YS00MjdiLWJkM2ItZDljM2Q4MmFkNGEx&amp;export=download&amp;hl=en"&gt;download the complete project here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-972380331269638436?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/972380331269638436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=972380331269638436' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/972380331269638436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/972380331269638436'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/02/metawidget-defining-business-objects_02.html' title='Metawidget: Defining Business Objects Using Maps (JSF Version)'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__YNTBm_fS_I/TUitMkv7XfI/AAAAAAAAAYc/a9X0Z06BTJk/s72-c/tutorials.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-7493326939501135821</id><published>2011-02-02T12:00:00.007+11:00</published><updated>2011-07-18T08:42:00.413+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Defining Business Objects Using Maps</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TUitMkv7XfI/AAAAAAAAAYc/a9X0Z06BTJk/s400/tutorials.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5568891370778353138" /&gt;I was &lt;a href="https://sourceforge.net/projects/metawidget/forums/forum/747623/topic/4075874"&gt;recently asked&lt;/a&gt; whether &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; could inspect, load and save business objects based not on a JavaBean (or GroovyBean, ScalaBean etc) but on a &lt;tt&gt;Map&lt;/tt&gt; of names and attributes. The answer is &lt;strong&gt;yes&lt;/strong&gt;!&lt;br /&gt;&lt;br /&gt;I've &lt;a href="http://blog.kennardconsulting.com/2008/06/metawidget-and-namevalue-pairs.html"&gt;sort of covered this before&lt;/a&gt; but last time I only blogged about &lt;em&gt;inspecting&lt;/em&gt; the &lt;tt&gt;Map&lt;/tt&gt;, not loading and saving the values.We already have a GWT version of this in the Metawidget distribution (see the &lt;a href="http://metawidget.sourceforge.net/doc/reference/en/html/ch01s03.html#section-introduction-part3-gwt-clientside"&gt;GWT Client Side example&lt;/a&gt;) but now &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHZjRjMmJkZGUtOWU2Yy00NDBmLWFhNTAtN2RmZGU1N2NkMWQz&amp;export=download&amp;hl=en"&gt;I've put together a Swing project you can download too&lt;/a&gt;. It's very similar to the &lt;a href="http://blog.kennardconsulting.com/2008/06/metawidget-and-namevalue-pairs.html"&gt;previous blog&lt;/a&gt; but adds a &lt;tt&gt;MapWidgetProcessor&lt;/tt&gt; that loads and saves values back into a &lt;tt&gt;Map&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;An important point to grok is that the 'Map of properties' (used by &lt;tt&gt;MapInspector&lt;/tt&gt;) is different to the 'Map of values' (used by &lt;tt&gt;MapWidgetProcessor&lt;/tt&gt;). This is in the same way that a 'Class' is different to an 'Object': one defines the type, one defines the instance values. So in the code you will see:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;metawidget.setToInspect( values );&lt;br /&gt;metawidget.setPath( "person" );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;We call both &lt;tt&gt;setToInspect&lt;/tt&gt; (to tell Metawidget where the values are coming from) &lt;em&gt;and&lt;/em&gt; &lt;tt&gt;setPath&lt;/tt&gt; (to tell Metawidget what the type is). Normally when using a JavaBean (or GroovyBean, ScalaBean etc) you don't need to do this, because Metawidget will internally call...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;metawidget.setPath( metawidget.getToInspect().getClass() )&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...on your behalf. But if you want to start using &lt;tt&gt;Maps&lt;/tt&gt;, these two concepts need to be explictly separate.&lt;br /&gt;&lt;br /&gt;Take a &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHZjRjMmJkZGUtOWU2Yy00NDBmLWFhNTAtN2RmZGU1N2NkMWQz&amp;export=download&amp;hl=en"&gt;look for yourself here&lt;/a&gt;. Or, for the impatient, here's the most important piece of code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;/**&lt;br /&gt; * MapWidgetProcessor uses the Metawidget's &amp;lt;code&amp;gt;toInspect&amp;lt;/code&amp;gt; to retrieve/store values.&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;public class &lt;strong&gt;MapWidgetProcessor&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;implements AdvancedWidgetProcessor&amp;lt;JComponent, SwingMetawidget&amp;gt; {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Public methods&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void onStartBuild( SwingMetawidget metawidget ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;getWrittenComponents( metawidget ).clear();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;/**&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * Retrieve the values from the Map and put them in the Components.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public JComponent processWidget( JComponent component, String elementName, Map&amp;lt;String, String&amp;gt; attributes, SwingMetawidget metawidget ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String attributeName = attributes.get( NAME );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;getWrittenComponents( metawidget ).put( attributeName, component );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;// Fetch the value...&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Map&amp;lt;String, Object&amp;gt; toInspect = metawidget.getToInspect();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object value = toInspect.get( attributeName );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( value == null ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return component;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;// ...and apply it to the component. For simplicity, we won't worry about converters&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String componentProperty = metawidget.getValueProperty( component );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ClassUtils.setProperty( component, componentProperty, value );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return component;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void onEndBuild( SwingMetawidget metawidget ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Do nothing&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;/**&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * Store the values from the Components back into the Map.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void save( SwingMetawidget metawidget ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Map&amp;lt;String, Object&amp;gt; toInspect = metawidget.getToInspect();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( Map.Entry&amp;lt;String,JComponent&amp;gt; entry : getWrittenComponents( metawidget ).entrySet() ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JComponent component = entry.getValue();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String componentProperty = metawidget.getValueProperty( component );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object value = ClassUtils.getProperty( component, componentProperty );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;toInspect.put( entry.getKey(), value );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Private methods&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;/**&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * During load-time we keep track of all the components. At save-time we write them all back&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * again.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Map&amp;lt;String,JComponent&amp;gt; getWrittenComponents( SwingMetawidget metawidget ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@SuppressWarnings( "unchecked" )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Map&amp;lt;String,JComponent&amp;gt; writtenComponents = (Map&amp;lt;String,JComponent&amp;gt;) metawidget.getClientProperty( MapWidgetProcessor.class );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( writtenComponents == null ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writtenComponents = CollectionUtils.newHashMap();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metawidget.putClientProperty( MapWidgetProcessor.class, writtenComponents );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return writtenComponents;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-7493326939501135821?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/7493326939501135821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=7493326939501135821' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7493326939501135821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7493326939501135821'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/02/metawidget-defining-business-objects.html' title='Metawidget: Defining Business Objects Using Maps'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__YNTBm_fS_I/TUitMkv7XfI/AAAAAAAAAYc/a9X0Z06BTJk/s72-c/tutorials.png' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-7291375525015387439</id><published>2011-01-28T22:29:00.004+11:00</published><updated>2011-01-28T22:40:57.784+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PrimeFaces'/><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: PrimeFaces support</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 200px; height: 157px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TUKrAvgq6jI/AAAAAAAAAYQ/I_t3DsAzyi8/s400/50272_206606616332_2668696_n.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5567200118625200690" /&gt;The guys over at &lt;a href="http://activiti.org"&gt;Activiti&lt;/a&gt; recently &lt;a href="http://forums.activiti.org/en/viewtopic.php?t=946&amp;p=3896"&gt;expressed an interest&lt;/a&gt; in integrating &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; into their BPM product. They had a few concerns, most notably &lt;a href="http://primefaces.org"&gt;PrimeFaces&lt;/a&gt; support, so I thought I'd have a go at implementing it.&lt;br /&gt;&lt;br /&gt;I'm delighted to say that, thanks to PrimeFaces' solid build quality and outstanding &lt;a href="http://primefaces.googlecode.com/files/primefaces_users_guide_260710.pdf"&gt;User Guide (over 400 detailed pages!)&lt;/a&gt; integration went very smoothly. There were a few minor glitches related to Mojarra which I will be working with that team to get resolved. But MyFaces works great.&lt;br /&gt;&lt;br /&gt;I have checked the code into SVN ready for the Metawidget v1.10 release. I have also put together a sample project demonstrating PrimeFaces support which &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHNWYyZDhkZDAtNzFlNC00MjcwLWJhNTgtNTM5NTU3NTE1YzJh&amp;export=download&amp;hl=en"&gt;you can download here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-7291375525015387439?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/7291375525015387439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=7291375525015387439' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7291375525015387439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7291375525015387439'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/01/metawidget-primefaces-support.html' title='Metawidget: PrimeFaces support'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__YNTBm_fS_I/TUKrAvgq6jI/AAAAAAAAAYQ/I_t3DsAzyi8/s72-c/50272_206606616332_2668696_n.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1029087784504767693</id><published>2011-01-27T13:59:00.016+11:00</published><updated>2011-01-31T08:48:38.967+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HttpClient'/><title type='text'>HttpClient 4: Want To Make It 250x Faster?</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TUDhsx7FNDI/AAAAAAAAAYI/oe9BFqONj9E/s400/agt_runit.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5566697298861569074" /&gt;I just spent a few hours debugging a performance problem with my app. It came down to a default setting inside &lt;a href="http://hc.apache.org/httpcomponents-client-ga"&gt;Apache HttpClient 4.0.3&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Don't get me wrong, &lt;strong&gt;HttpClient is an awesome piece of work and a fantastic contribution to the community&lt;/strong&gt; - I use it in lots of my projects and it's very useful. So my thanks to the HttpClient team for all their hard work.&lt;br /&gt;&lt;br /&gt;However, by default HttpClient 4.0.3 adds a...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;Expect: 100-continue&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...header to every &lt;tt&gt;POST&lt;/tt&gt; request. This appears to interact badly with Tomcat's (and JBoss', and possibly other containers) &lt;tt&gt;FormAuthenticator&lt;/tt&gt;. Specifically somewhere around...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;request.getParameter( Constants.FORM_USERNAME )&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...&lt;tt&gt;FormAuthenticator&lt;/tt&gt; disappears into a hole (during &lt;tt&gt;Request.parseParameters&lt;/tt&gt;) for some 2 seconds before emerging with the parameters. It appears to be 'lazy loading' the request body during this time? According to the &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3"&gt;HTTP spec&lt;/a&gt; the header "allows a client that is sending a request message with a request body to determine if the origin server is willing to accept the request before the client sends the request body".&lt;br /&gt;&lt;br /&gt;If you're using HttpClient to log in to your Java EE server (say, for &lt;a href="http://en.wikipedia.org/wiki/Black-box_testing"&gt;black box testing&lt;/a&gt;) this can be a significant performance hit. Removing the &lt;tt&gt;Expect&lt;/tt&gt; header logs you in in about 8ms, &lt;strong&gt;some 250 times faster&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;You can remove the &lt;tt&gt;Expect&lt;/tt&gt; header by doing:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;client.removeRequestInterceptorByClass( RequestExpectContinue.class );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;I've put together a sample WAR to reproduce the problem, along with deployment instructions, under &lt;a href="https://issues.apache.org/jira/browse/HTTPCLIENT-1048"&gt;this issue here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update: it appears this is actually a bug in Tomcat 6. Now tracking &lt;a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=50689"&gt;under this issue here&lt;/a&gt;.&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1029087784504767693?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1029087784504767693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1029087784504767693' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1029087784504767693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1029087784504767693'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/01/httpclient-4-want-to-make-it-250x.html' title='HttpClient 4: Want To Make It 250x Faster?'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/__YNTBm_fS_I/TUDhsx7FNDI/AAAAAAAAAYI/oe9BFqONj9E/s72-c/agt_runit.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4043323934094588637</id><published>2011-01-19T13:10:00.010+11:00</published><updated>2011-07-18T08:43:01.880+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Dynamic Layouts</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TOxbEicYLSI/AAAAAAAAAVk/NtIjkDbZKlQ/s400/linuxconf.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5542905374909672738" /&gt;I was &lt;a href="http://blog.kennardconsulting.com/2010/11/metawidget-collections-support-part-2_25.html?showComment=1295386100758#c1231344887190616134"&gt;recently asked&lt;/a&gt; whether Metawidget can change layouts dynamically, say from a tab-based layout to a panel-based layout?&lt;br /&gt;&lt;br /&gt;The answer is &lt;strong&gt;yes!&lt;/strong&gt; You can call...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;metawidget.setLayout( myLayout );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...at any time to dynamically update the layout. The questioner was asking in relation to JSF, and the hardest bit in JSF is actually getting programmatic access to the Metawidget. This requires the &lt;a href="http://blog.kennardconsulting.com/2010/10/metawidget-neat-trick-configuring-jsf.html"&gt;binding attribute I've blogged about previously&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;But once past that, you can put together something like this:&lt;br /&gt;&lt;table style="margin: auto"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TTZJ4igAlXI/AAAAAAAAAX4/RdXkt_uPM0Y/s1600/LayoutSwitch1.png"&gt;&lt;img style="display:block; text-align:center;cursor:pointer; cursor:hand;width: 178px; height: 320px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TTZJ4igAlXI/AAAAAAAAAX4/RdXkt_uPM0Y/s320/LayoutSwitch1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5563715625345389938" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/__YNTBm_fS_I/TTZIODWBypI/AAAAAAAAAXw/5vidzOLHX1c/s1600/LayoutSwitch.png"&gt;&lt;img style="display:block; text-align:center;cursor:pointer; cursor:hand;width: 178px; height: 320px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TTZIODWBypI/AAAAAAAAAXw/5vidzOLHX1c/s320/LayoutSwitch.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5563713795915893394" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://2.bp.blogspot.com/__YNTBm_fS_I/TTZJ4ljjIII/AAAAAAAAAYA/DAP2HF0VeSg/s1600/LayoutSwitch3.png"&gt;&lt;img style="display:block; text-align:center;cursor:pointer; cursor:hand;width: 178px; height: 320px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TTZJ4ljjIII/AAAAAAAAAYA/DAP2HF0VeSg/s320/LayoutSwitch3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5563715626165543042" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Note the buttons at the buttom that allow you to select which layout to use. I have put together the &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHMWU2Njg0MWMtMjA5Ny00MmY1LWI2NmEtN2MyMTE2YjUxMzJj&amp;export=download&amp;hl=en"&gt;complete project you can download from here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4043323934094588637?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4043323934094588637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4043323934094588637' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4043323934094588637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4043323934094588637'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/01/metawidget-dynamic-layout.html' title='Metawidget: Dynamic Layouts'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__YNTBm_fS_I/TOxbEicYLSI/AAAAAAAAAVk/NtIjkDbZKlQ/s72-c/linuxconf.png' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-2564384919088261930</id><published>2011-01-03T11:01:00.010+11:00</published><updated>2011-01-03T11:23:41.599+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seam Forge'/><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Grokking Seam Forge: Part 1</title><content type='html'>JBoss have just released &lt;a href="http://community.jboss.org/people/lincolnthree/blog/2010/12/31/forge-100alpha1-kitten-released--rad-java"&gt;Alpha 1 of Seam Forge&lt;/a&gt;, their framework for rapid-application development that includes &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; support.&lt;br /&gt;&lt;br /&gt;You can read more about the release and how to use it &lt;a href="http://community.jboss.org/people/lincolnthree/blog/2010/12/31/forge-100alpha1-kitten-released--rad-java"&gt;here&lt;/a&gt;. After that, for those wanting to dive into the code (either out of curiosity or to start contributing) here's a step-by-step guide that may save some trial and error:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Install JBoss Tools&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Download &lt;a href="http://www.eclipse.org/downloads/packages/release/galileo/sr2"&gt;Eclipse 3.5 SR2&lt;/a&gt; (just the 'Eclipse IDE for Java Developers' version)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Download &lt;a href="http://www.jboss.org/tools/download/stable/3_1_GA.html"&gt;JBoss Tools 3.1.GA&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Unzip Eclipse, and run &lt;tt&gt;eclipse.exe&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Select a workspace (I'd recommend starting a new one)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Use &lt;strong&gt;Help &amp;gt; Install New Software&lt;/strong&gt;. Click &lt;strong&gt;Add&lt;/strong&gt; then &lt;strong&gt;Archive&lt;/strong&gt; (see screenshot):&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/__YNTBm_fS_I/TSESBLokI6I/AAAAAAAAAWg/VqbRGixfBwU/s1600/step1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TSESBLokI6I/AAAAAAAAAWg/VqbRGixfBwU/s400/step1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743226664002466" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Check &lt;strong&gt;All JBoss Tools - 3.1.1&lt;/strong&gt;. Click &lt;strong&gt;Next&lt;/strong&gt; and &lt;strong&gt;Next&lt;/strong&gt; again&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Choose &lt;strong&gt;I accept the terms of the license agreements&lt;/strong&gt; and click &lt;strong&gt;Finish&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;(NB. there seems to be a bug here: the &lt;strong&gt;Finish&lt;/strong&gt; button will not always be enabled? I found clicking back to the start of the wizard fixed it)&lt;/em&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wait for the install to complete. Accept any signing certificates. Restart the IDE&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Install EGit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;strong&gt;Help &amp;gt; Install New Software&lt;/strong&gt; and click &lt;strong&gt;Add&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Enter a &lt;strong&gt;Location&lt;/strong&gt; of &lt;a href="http://download.eclipse.org/egit/updates"&gt;http://download.eclipse.org/egit/updates&lt;/a&gt; (see screenshot):&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/__YNTBm_fS_I/TSESBO7qymI/AAAAAAAAAWo/5nQmNYC19N8/s1600/step2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TSESBO7qymI/AAAAAAAAAWo/5nQmNYC19N8/s400/step2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743227549436514" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Check &lt;strong&gt;Eclipse Git Team Provider&lt;/strong&gt;. Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Click &lt;strong&gt;Finish&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wait for the install to complete. Accept any signing certificates. Restart the IDE&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Clone the Seam Forge Repository&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;strong&gt;File &amp;gt; Import&lt;/strong&gt; and choose &lt;strong&gt;Projects from Git&lt;/strong&gt; (see screenshot):&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TSESBXviIiI/AAAAAAAAAWw/SQbrEFiqof8/s1600/step3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TSESBXviIiI/AAAAAAAAAWw/SQbrEFiqof8/s400/step3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743229914456610" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Clone...&lt;/strong&gt; and enter a &lt;strong&gt;URI&lt;/strong&gt; of &lt;a href="git://github.com/seam/forge.git"&gt;git://github.com/seam/forge.git&lt;/a&gt; (see screenshot):&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/__YNTBm_fS_I/TSESBumzDhI/AAAAAAAAAW4/QZe3uVkBO-s/s1600/step4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TSESBumzDhI/AAAAAAAAAW4/QZe3uVkBO-s/s400/step4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743236051832338" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;, choose the &lt;strong&gt;Master&lt;/strong&gt; branch, click &lt;strong&gt;Next&lt;/strong&gt; (see screenshot):&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TSESBiGlC2I/AAAAAAAAAXA/zKUdnyo5Re8/s1600/step5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TSESBiGlC2I/AAAAAAAAAXA/zKUdnyo5Re8/s400/step5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743232695470946" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Finish&lt;/strong&gt;. Wait for the Git repository to clone (may take a while). See screenshot:&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/__YNTBm_fS_I/TSESfNAEmxI/AAAAAAAAAXI/xnhk6x1T4aM/s1600/step6.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TSESfNAEmxI/AAAAAAAAAXI/xnhk6x1T4aM/s400/step6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743742427110162" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Cancel&lt;/strong&gt; (not &lt;strong&gt;Next&lt;/strong&gt;!)&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Install Maven&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;strong&gt;Help &amp;gt; Install New Software&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Choose to &lt;strong&gt;Work with&lt;/strong&gt; the 'Maven Integration for Eclipse Update Site'&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Check the 'Maven Integration for Eclipse' box (see screenshot):&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/__YNTBm_fS_I/TSESfNhRmLI/AAAAAAAAAXQ/nPHTx5D4etE/s1600/step7.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TSESfNhRmLI/AAAAAAAAAXQ/nPHTx5D4etE/s400/step7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743742566373554" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;, &lt;strong&gt;Next&lt;/strong&gt;, accept the license terms and &lt;strong&gt;Finish&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wait for the install to complete. Accept any signing certificates. Close the IDE (don't restart it)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Edit &lt;tt&gt;eclipse/eclipse.ini&lt;/tt&gt; and add the lines in bold:&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;--launcher.XXMaxPermSize&lt;br /&gt;256m&lt;br /&gt;&lt;strong&gt;-vm&lt;br /&gt;&amp;lt;path to your JDK&amp;gt;\bin\javaw.exe&lt;/strong&gt;&lt;br /&gt;-vmargs&lt;br /&gt;-Dosgi.requiredJavaVersion=1.5&lt;br /&gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;(Maven needs Eclipse running under a JDK, not a JRE)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Relaunch the IDE&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: 130%; font-weight: bold"&gt;Import Maven Projects&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;strong&gt;File &amp;gt; Import&lt;/strong&gt;. Choose &lt;strong&gt;Maven &amp;gt; Existing Maven Projects&lt;/strong&gt; (see screenshot):&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/__YNTBm_fS_I/TSESfSLUW4I/AAAAAAAAAXY/T7iy2WaI2Dw/s1600/step8.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TSESfSLUW4I/AAAAAAAAAXY/T7iy2WaI2Dw/s400/step8.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743743816457090" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Browse&lt;/strong&gt; to the location of the Git clone (see screenshot):&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/__YNTBm_fS_I/TSESfoG2cVI/AAAAAAAAAXg/A_hengQ9FNU/s1600/step9.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TSESfoG2cVI/AAAAAAAAAXg/A_hengQ9FNU/s400/step9.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557743749703299410" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;Finish&lt;/strong&gt;. Wait for import of Maven projects (may take a while)&lt;/li&gt;&lt;/ul&gt;All Seam Forge sub-projects should now be listed under the &lt;strong&gt;Package Explorer&lt;/strong&gt;. There should be no compile errors under the &lt;strong&gt;Problems&lt;/strong&gt; tab, though there may be warnings (as this is still an alpha release). See screenshot:&lt;a href="http://1.bp.blogspot.com/__YNTBm_fS_I/TSEWYvi_xPI/AAAAAAAAAXo/CxWQhyRiLS4/s1600/step10.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TSEWYvi_xPI/AAAAAAAAAXo/CxWQhyRiLS4/s400/step10.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5557748029487826162" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-2564384919088261930?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/2564384919088261930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=2564384919088261930' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2564384919088261930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/2564384919088261930'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2011/01/groking-seam-forge-part-1.html' title='Grokking Seam Forge: Part 1'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__YNTBm_fS_I/TSESBLokI6I/AAAAAAAAAWg/VqbRGixfBwU/s72-c/step1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-3073285110714496674</id><published>2010-12-28T13:08:00.001+11:00</published><updated>2011-05-18T21:57:02.152+10:00</updated><title type='text'>We're Hiring Again!</title><content type='html'>Here's the job ad we're posting. Following a successful first hire earlier this year, and increased investment from a leading Australian financial institution, we're hiring again. A chance to work from home, and work for me! What a dream job :)&lt;br /&gt;&lt;br /&gt;&lt;img style="float:right; margin:0 0 10px 10px;border: 0;width: 128px; height: 128px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/SwMcum-f5LI/AAAAAAAAAMQ/1bDL3YzNvD8/s320/folder_home.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405195564836971698" /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight: bold"&gt;Senior Java EE 5 (J2EE) Developer: $120,000 AUD + super&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Small, focused team&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Modern, well-crafted software&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Work in city or from home&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;A rare opportunity to join our small consultancy team.&lt;/strong&gt; We have recently received substantial investment from a leading Australian financial institution and we must grow to meet demand.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;You will work side-by-side with one of Australia's premier Java EE developers&lt;/strong&gt;, and be intimately involved in all design decisions.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;You will be a pragmatic programmer. Software development will be in your blood:&lt;/strong&gt; a natural instinct. You must be passionate about Open Source and Java EE. You will demonstrate advanced analytical skills; an eye for elegance and craftmanship; a passion for refactoring, unit testing, and delivering secure and robust code.&lt;br /&gt;&lt;br /&gt;Your skills will include many of the following:&lt;br /&gt;&lt;img style="float:right; margin:0 0 10px 10px;border: 0;width: 128px; height: 128px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/SwMdf4iTwYI/AAAAAAAAAMg/ylIYM1sRv08/s320/java.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405196411364163970" /&gt;&lt;ul&gt;&lt;li&gt;JBoss&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JSF/RichFaces&lt;/li&gt;&lt;br /&gt;&lt;li&gt;XSL (T and FO) and XPath&lt;/li&gt;&lt;br /&gt;&lt;li&gt;EJB 3/JMS&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JPA/SQL&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Metawidget&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HtmlUnit&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HTML/CSS&lt;/li&gt;&lt;/ul&gt;In addition, you will have excellent communication skills and be comfortable interacting with stakeholders at all levels.&lt;br /&gt;&lt;br /&gt;Work from home will be offered providing that you can demonstrate an appropriate working environment. &lt;strong&gt;You must be a citizen or permanent resident of Australia&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;To help us sort applicants, include your CV and a 1 page overview highlighting your suitability for the role. Links to examples of your work (eg. web sites you have built, blogs you have written, Open Source contributions etc) will be highly regarded.&lt;br /&gt;&lt;br /&gt;Please send your application to &lt;a href="mailto:jobs@kennardconsulting.com"&gt;jobs@kennardconsulting.com&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-3073285110714496674?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/3073285110714496674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=3073285110714496674' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3073285110714496674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/3073285110714496674'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/12/were-hiring-again.html' title='We&apos;re Hiring Again!'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/__YNTBm_fS_I/SwMcum-f5LI/AAAAAAAAAMQ/1bDL3YzNvD8/s72-c/folder_home.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-6381925843430735094</id><published>2010-12-17T12:20:00.028+11:00</published><updated>2011-07-18T08:43:38.481+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Retrofitting a UI: GatewayWarDeployment example</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 224px; height: 224px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TQrE0TdcnPI/AAAAAAAAAWM/BNBua8zdoRs/s400/netbeans-logo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5551465893543582962" /&gt;&lt;a href="http://www.adam-bien.com"&gt;Adam Bien&lt;/a&gt; recently asked me to create a &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt; example for his &lt;a href="http://kenai.com/projects/javaee-patterns"&gt;Java EE Patterns and Best Practices Kenai Repository&lt;/a&gt;, based on his &lt;a href="http://press.adam-bien.com"&gt;Real World Java EE Patterns&lt;/a&gt; book.&lt;br /&gt;&lt;br /&gt;In order to demonstrate the changes typically required to incorporate Metawidget into a project (and the code savings it typically brings) I retrofitted one of Adam's original projects, his &lt;a href="http://www.adam-bien.com/roller/abien/entry/building_perfect_anti_facades_almost"&gt;GatewayWarDeployment&lt;/a&gt; example. I've called mine &lt;tt&gt;GatewayWarDeploymentWithMetawidget&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;To view the new example:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Ensure you have Metawidget installed at its default location (&lt;tt&gt;/metawidget-1.05/metawidget.jar&lt;/tt&gt;)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Get sources for the &lt;a href="http://kenai.com/projects/javaee-patterns"&gt;Java EE Patterns Kenai project&lt;/a&gt; in NetBeans using &lt;strong&gt;Team &gt; Team Server &gt; Get Sources...&lt;/strong&gt; (see &lt;a href="http://netbeans.org/kb/docs/ide/kenai-open-project-screencast.html"&gt;this screencast&lt;/a&gt; for detailed instructions)&lt;/li&gt;&lt;li&gt;Open the &lt;a href="http://kenai.com/projects/javaee-patterns/sources/hg/show/GatewayWarDeploymentWithMetawidget"&gt;GatewayWarDeploymentWithMetawidget&lt;/a&gt; project&lt;/li&gt;&lt;/ol&gt;The example works &lt;a href="http://www.adam-bien.com/roller/abien/entry/building_perfect_anti_facades_almost"&gt;just as before&lt;/a&gt;, but two files have been changed. The first is the managed bean, &lt;tt&gt;LoadView.java&lt;/tt&gt;, which now includes Metawidget annotations and is therefore longer. The second is the UI page, &lt;tt&gt;createorder.xhtml&lt;/tt&gt;, which now uses a &lt;tt&gt;&amp;lt;m:metawidget&amp;gt;&lt;/tt&gt; tag and is therefore shorter:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TQrEnRT1W4I/AAAAAAAAAWE/h1fDQXOsIPY/s1600/LoadView%2Bcompare.png"&gt;&lt;img style="border: 1px solid #888888; display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 212px; height: 320px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TQrEnRT1W4I/AAAAAAAAAWE/h1fDQXOsIPY/s320/LoadView%2Bcompare.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5551465669628091266" /&gt;&lt;/a&gt;LoadView.java&lt;/th&gt;&lt;th&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TQrElqjUahI/AAAAAAAAAV8/Toup4FuFU7Q/s1600/createorder%2BCompare.png"&gt;&lt;img style="border: 1px solid #888888; display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 164px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TQrElqjUahI/AAAAAAAAAV8/Toup4FuFU7Q/s320/createorder%2BCompare.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5551465642044189202" /&gt;&lt;/a&gt;createorder.xhtml&lt;/th&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/center&gt;&lt;br /&gt;In such a small example there is no overall saving in lines of code (larger examples have &lt;a href="http://blog.kennardconsulting.com/2009/05/metawidget-and-seam-saying-goodbye-to.html"&gt;more dramatic savings&lt;/a&gt;). But there is still a significant reduction in duplicated declarations (field names, types, action names etc) and therefore reduced possibility of error when building (and maintaining) the UI. Note Metawidget is handling both the input boxes &lt;em&gt;and&lt;/em&gt; the buttons, including enabling/disabling the buttons in line with the business logic. This is declared by the code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;@UiAction&lt;br /&gt;@UiFacesAttribute( name = "read-only", expression = "#{load.emptyLoad}" )&lt;br /&gt;public void dropLightest(){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Of course, this is not a great demonstration of all the features of Metawidget. More extensive examples can be found under the &lt;tt&gt;/examples&lt;/tt&gt; folder of the &lt;a href="http://metawidget.org/download.html"&gt;Metawidget distribution&lt;/a&gt;. But hopefully it's enough to get people excited without confusing them with lots of code.&lt;br /&gt;&lt;br /&gt;My thanks to Adam for his help and encouragement in developing this example!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-6381925843430735094?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/6381925843430735094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=6381925843430735094' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6381925843430735094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/6381925843430735094'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/12/retrofitting-ui-gatewaywardeployment.html' title='Retrofitting a UI: GatewayWarDeployment example'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/TQrE0TdcnPI/AAAAAAAAAWM/BNBua8zdoRs/s72-c/netbeans-logo.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-8742718760111308067</id><published>2010-12-15T20:12:00.005+11:00</published><updated>2011-07-18T08:44:05.092+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Automatic Form Generator: Metawidget v1.05</title><content type='html'>&lt;img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 0px 10px 10px; WIDTH: 188px; FLOAT: right; HEIGHT: 400px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id="BLOGGER_PHOTO_ID_5428305152285105858" border="0" alt="" src="http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s400/box.png" /&gt;Version 1.05 of &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;, the &lt;a href="http://metawidget.org"&gt;automatic form generator&lt;/a&gt; is now available! This release includes the following enhancements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2010/10/safely-manipulating-component-tree-with.html"&gt;Improved JSF 2 support (Mojarra 2.1 and MyFaces 2.0.3)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.kennardconsulting.com/2010/10/javabean-convention-relating-public.html"&gt;Support for annotating private fields&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://sourceforge.net/tracker/?func=detail&amp;aid=3076516&amp;group_id=208482&amp;atid=1005872"&gt;char support&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://metawidget.sourceforge.net/doc/reference/en/html/ch07s02.html#section-widgetprocessors-web-faces-ajax"&gt;JSF2 AjaxProcessor&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Read-only actions now display as disabled buttons (rather than not displaying at all)&lt;/li&gt;&lt;li&gt;Bug fixes, documentation and unit tests&lt;/li&gt;&lt;/ul&gt;As always, the best place to start is the Reference Documentation:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;a href="http://metawidget.org/doc/reference/en/pdf/metawidget.pdf"&gt;http://metawidget.org/doc/reference/en/pdf/metawidget.pdf&lt;br /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;Your continued feedback is invaluable to us. Please &lt;a href="http://metawidget.org/download.html"&gt;download it&lt;/a&gt; and &lt;a href="http://metawidget.org/forums.html"&gt;let us know what you think&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-8742718760111308067?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/8742718760111308067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=8742718760111308067' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/8742718760111308067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/8742718760111308067'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/12/automatic-form-generator-metawidget.html' title='Automatic Form Generator: Metawidget v1.05'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/S1U2xo5gXsI/AAAAAAAAANo/GtMUveZRhTA/s72-c/box.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-234830600746250551</id><published>2010-12-14T07:31:00.000+11:00</published><updated>2010-12-15T20:12:55.977+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seam'/><title type='text'>SeamForge: Latest Update</title><content type='html'>I'm growing a little uncomfortable with the direction &lt;a href="http://seamframework.org/Documentation/SeamForge"&gt;SeamForge&lt;/a&gt; is taking. Here's an output from the latest build:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&lt;strong&gt;$ forge&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;____&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_____&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;/&amp;nbsp;___|&amp;nbsp;&amp;nbsp;___&amp;nbsp;&amp;nbsp;__&amp;nbsp;_&amp;nbsp;_&amp;nbsp;__&amp;nbsp;___&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;&amp;nbsp;___|__&amp;nbsp;&amp;nbsp;_&amp;nbsp;__&amp;nbsp;__&amp;nbsp;_&amp;nbsp;&amp;nbsp;___&lt;br /&gt;&amp;nbsp;&amp;nbsp;\___&amp;nbsp;\&amp;nbsp;/&amp;nbsp;_&amp;nbsp;\/&amp;nbsp;_`&amp;nbsp;|&amp;nbsp;'_&amp;nbsp;`&amp;nbsp;_&amp;nbsp;\&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;|_&amp;nbsp;/&amp;nbsp;_&amp;nbsp;\|&amp;nbsp;'__/&amp;nbsp;_`&amp;nbsp;|/&amp;nbsp;_&amp;nbsp;\&amp;nbsp;&amp;nbsp;\\&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;___)&amp;nbsp;|&amp;nbsp;&amp;nbsp;__/&amp;nbsp;(_|&amp;nbsp;|&amp;nbsp;|&amp;nbsp;|&amp;nbsp;|&amp;nbsp;|&amp;nbsp;|&amp;nbsp;&amp;nbsp;|&amp;nbsp;&amp;nbsp;_|&amp;nbsp;(_)&amp;nbsp;|&amp;nbsp;|&amp;nbsp;|&amp;nbsp;(_|&amp;nbsp;|&amp;nbsp;&amp;nbsp;__/&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;|____/&amp;nbsp;\___|\__,_|_|&amp;nbsp;|_|&amp;nbsp;|_|&amp;nbsp;&amp;nbsp;|_|&amp;nbsp;&amp;nbsp;\___/|_|&amp;nbsp;&amp;nbsp;\__,&amp;nbsp;|\___|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|___/&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;[no project] $ new-project&lt;br /&gt;&lt;br /&gt;Greetings, Professor Falken. Would you like to play a game?&lt;/strong&gt;&lt;/tt&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-234830600746250551?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/234830600746250551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=234830600746250551' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/234830600746250551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/234830600746250551'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/12/seamforge-latest-update.html' title='SeamForge: Latest Update'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1552504397475583029</id><published>2010-12-01T19:02:00.016+11:00</published><updated>2010-12-07T15:27:44.042+11:00</updated><title type='text'>Rant: Who Designs These UI Frameworks Anyway?</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TPYBrCE-WcI/AAAAAAAAAV0/hLIdGN43EHo/s400/irc_protocol.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5545621829957081538" /&gt;I started a lively discussion over on &lt;a href="http://java.dzone.com/announcements/rant-who-designs-these-ui"&gt;Javalobby&lt;/a&gt; ranting about UI framework APIs.&lt;br /&gt;&lt;br /&gt;Specifically: &lt;strong&gt;how come hardly any UI frameworks define their widgets in terms of interfaces, as opposed to abstract base classes?&lt;/strong&gt; I &lt;a href="http://java.dzone.com/announcements/rant-who-designs-these-ui"&gt;listed off a dozen mainstream UI frameworks&lt;/a&gt; that do this, and was fortunate to get dozens of people responding with their thoughts. The key outcomes were:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Some UI frameworks (albeit a minority) &lt;em&gt;are&lt;/em&gt; interface-based. Examples include &lt;a href="http://itsnat.sourceforge.net"&gt;ItsNat&lt;/a&gt;, &lt;a href="http://vaadin.com"&gt;Vaadin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Other frameworks have considered being interface-based (Swing), but on balance decided to use abstract classes. Neither is optimal: &lt;em&gt;"when I was working on the Swing team at Sun Microsystems back in the early days of Java. Some people on the team were of the opinion that Component should be an interface and others that it was best as an abstract class. But really, neither sounded like a good choice"&lt;/em&gt;&lt;/li&gt;&lt;li&gt;Abstract base classes limit future use cases. This is dangerous because &lt;em&gt;"anything of strategic importance will be used in ways that the original designer cannot anticipate"&lt;/em&gt;&lt;/li&gt;&lt;li&gt;The problem with a 'monolithic' interface is that it is cumbersome to evolve: &lt;em&gt;"You will soon have IComponent, IComponent_v2, IComponent_v3"&lt;/em&gt;&lt;/li&gt;&lt;li&gt;The problem with 'granular' interfaces is that you often have to pass around many of them together: &lt;em&gt;"I found it to get problematic as I'd pass around something like (Sizable, Locatable) and then deep in the heart of the framework I realised I needed Focusable also, and I then had to go back up the stack chain and add it to all parameters"&lt;/em&gt;&lt;/li&gt;&lt;li&gt;Java does not have a good way to bundle several 'granular' interfaces together, but other languages may (&lt;a href="http://www.scala-lang.org"&gt;Scala&lt;/a&gt; traits): &lt;em&gt;"It's not yet possible to write Component the way I really want to write it. To do that, you'd have to change Java."&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;Finally, I would like to apologise to any who were offended by the somewhat incendiary tone of my article. It was pitched as a 'rant' in order to encourage responses, but in no way was I suggesting the UI frameworks I listed were anything but successful - or that their creators were anything but intelligent, brilliant people.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-1552504397475583029?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/1552504397475583029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=1552504397475583029' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1552504397475583029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/1552504397475583029'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/12/rant-who-designs-these-ui-frameworks.html' title='Rant: Who Designs These UI Frameworks Anyway?'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/__YNTBm_fS_I/TPYBrCE-WcI/AAAAAAAAAV0/hLIdGN43EHo/s72-c/irc_protocol.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4669940683720374860</id><published>2010-11-25T15:19:00.006+11:00</published><updated>2011-07-18T08:44:32.874+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Collections Support Part 2 (More Advanced)</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TO3kTeYZrFI/AAAAAAAAAVs/8L_5jH6eeIE/s400/knotes.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5543337739587005522" /&gt;In &lt;a href="http://blog.kennardconsulting.com/2010/11/metawidget-collections-support-part-2_24.html"&gt;my last post&lt;/a&gt; I looked at some quirks of using the &lt;a href="http://icefaces.org"&gt;ICEfaces&lt;/a&gt; &lt;tt&gt;PanelTabSet&lt;/tt&gt; with &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;. Specifically, because &lt;tt&gt;PanelTabSet&lt;/tt&gt; stores the &lt;tt&gt;selectedIndex&lt;/tt&gt; of the current tab &lt;em&gt;inside&lt;/em&gt; the component, the component cannot succesfully be destroyed and recreated.&lt;br /&gt;&lt;br /&gt;To work around this we looked at using Metawidget's &lt;tt&gt;COMPONENT_ATTRIBUTE_NOT_RECREATABLE&lt;/tt&gt; to preserve the &lt;tt&gt;selectedIndex&lt;/tt&gt; at the expense of some dynamicism. We further looked at using JSF's &lt;tt&gt;binding&lt;/tt&gt; attribute to try and claw back some of that dynamicism.&lt;br /&gt;&lt;br /&gt;However, a different approach entirely would be to stop &lt;tt&gt;PanelTabSet&lt;/tt&gt; storing &lt;tt&gt;selectedIndex&lt;/tt&gt; internally! It turns out ICEfaces provides an API for this. The only question is where &lt;em&gt;else&lt;/em&gt; to store &lt;tt&gt;selectedIndex&lt;/tt&gt;, but keeping it inside the current &lt;tt&gt;request&lt;/tt&gt; seems to work nicely. So:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Forget all about &lt;tt&gt;COMPONENT_ATTRIBUTE_NOT_RECREATABLE&lt;/tt&gt; and the &lt;tt&gt;binding&lt;/tt&gt; attribute (and related &lt;tt&gt;mMetawidget&lt;/tt&gt; inside the managed bean)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Change the line in the &lt;tt&gt;IceFacesTabsWidgetBuilder&lt;/tt&gt; that says...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;panelTabSet.getAttributes().put( UIMetawidget.COMPONENT_ATTRIBUTE_NOT_RECREATABLE, true );&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;...to say...&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;panelTabSet.setValueExpression( "selectedIndex", expressionFactory.createValueExpression( elContext, "#{param['tab-" + attributes.get( NAME ) + "']}", Object.class ) );&lt;/tt&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;So now you get fully dynamic tabs at the same time as tab switching working! This technique only applies in those cases where the &lt;tt&gt;UIComponent&lt;/tt&gt; thoughtfully exposes such an API, but in such cases it's very useful.&lt;br /&gt;&lt;br /&gt;Hope that helps!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4669940683720374860?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4669940683720374860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4669940683720374860' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4669940683720374860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4669940683720374860'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/11/metawidget-collections-support-part-2_25.html' title='Metawidget: Collections Support Part 2 (More Advanced)'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__YNTBm_fS_I/TO3kTeYZrFI/AAAAAAAAAVs/8L_5jH6eeIE/s72-c/knotes.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-7405218008757386962</id><published>2010-11-24T11:16:00.015+11:00</published><updated>2011-07-18T08:44:44.413+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Collections Support Part 2 (Advanced)</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TOxbEicYLSI/AAAAAAAAAVk/NtIjkDbZKlQ/s400/linuxconf.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5542905374909672738" /&gt;In &lt;a href="http://blog.kennardconsulting.com/2010/11/metawidget-collections-support-part-2.html"&gt;my previous post&lt;/a&gt;, I showed how to render a Collection as one item per tab. This is pretty easy in most frameworks, but &lt;a href="http://www.icefaces.org"&gt;ICEfaces&lt;/a&gt; presents a challenge because:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The ICEfaces &lt;tt&gt;PanelTabSet&lt;/tt&gt; &lt;strong&gt;doesn't have an option to switch tabs on the client-side&lt;/strong&gt;, using just JavaScript and CSS to show/hide the tabs (&lt;a href="http://jboss.org/richfaces"&gt;RichFaces&lt;/a&gt; has &lt;tt&gt;switchType="client"&lt;/tt&gt;)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The ICEfaces &lt;tt&gt;PanelTabSet&lt;/tt&gt; stores its tab state inside the component, so &lt;strong&gt;when doing server-side switching you cannot destroy and recreate the component or the tabs won't switch&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;In my last post I resolved this by setting &lt;tt&gt;COMPONENT_ATTRIBUTE_NOT_RECREATABLE&lt;/tt&gt; on the &lt;tt&gt;PanelTabSet&lt;/tt&gt;. I noted this would allow the user to switch tabs, at the expense of making the tabs themselves less dynamic. But a couple people wanted to know how to get the best of both worlds: how to switch tabs &lt;em&gt;and&lt;/em&gt; have them be dynamic.&lt;br /&gt;&lt;br /&gt;There are a few answers to this question:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;There is still quite a lot of dynamicism, even with &lt;tt&gt;COMPONENT_ATTRIBUTE_NOT_RECREATABLE&lt;/tt&gt; set. Metawidget is smart enough to work around the &lt;tt&gt;COMPONENT_ATTRIBUTE_NOT_RECREATABLE&lt;/tt&gt; components, and still recreates their siblings and even their children. As the &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHNzhkYzk0NDMtM2E5MS00MGU3LWJmOWMtZWUzMzI1ZWY1N2Qw&amp;export=download&amp;hl=en"&gt;project from the previous post&lt;/a&gt; shows, you can have an 'Edit' button that makes the components (both inside and outside the tab) turn from read-only labels into input boxes&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The &lt;tt&gt;COMPONENT_ATTRIBUTE_NOT_RECREATABLE&lt;/tt&gt; only applies during &lt;tt&gt;POST&lt;/tt&gt; requests. Re-rendering the page afresh as a &lt;tt&gt;GET&lt;/tt&gt; request works fine. So if your user clicks a link to navigate into the page with the &lt;tt&gt;TabPanelSet&lt;/tt&gt; on it, no problem&lt;/li&gt;&lt;/ol&gt;But there is a further case: what if I want to be able to add tabs with a &lt;tt&gt;POST&lt;/tt&gt; request? Here we need something new. We need to be able to tell Metawidget: don't recreate the tabs normally (else we won't be able to switch between them), but &lt;em&gt;do&lt;/em&gt; recreate them when I click 'add tab'.&lt;br /&gt;&lt;br /&gt;I have put together a &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHZmExMzNlNDAtZDFmMy00NmQyLTgwMjEtYzJiMzc1Njc1NWJh&amp;export=download&amp;hl=en"&gt;complete project you can download from here&lt;/a&gt;. It'll produce something that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TOxat6up2DI/AAAAAAAAAVU/secIAlDX0es/s1600/screen.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 261px; height: 320px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TOxat6up2DI/AAAAAAAAAVU/secIAlDX0es/s320/screen.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5542904986291787826" /&gt;&lt;/a&gt;&lt;br /&gt;The trick is to use JSF's &lt;tt&gt;binding&lt;/tt&gt; attribute. As &lt;a href="http://blog.kennardconsulting.com/2010/10/metawidget-neat-trick-configuring-jsf.html"&gt;I blogged previously&lt;/a&gt;, this is a little-used but very useful feature of JSF that allows programmatic control over your components. So in your page you do:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;&amp;lt;m:metawidget value="#{headerDemo}" &lt;strong&gt;binding="#{headerDemo.metawidget}"&lt;/strong&gt;/&amp;gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;And in your managed bean you do:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;public UIMetawidget getMetawidget() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;return mMetawidget;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setMetawidget( UIMetawidget metawidget ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;mMetawidget = metawidget;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@UiAction&lt;br /&gt;@UiComesAfter( "details" )&lt;br /&gt;public void addTab() {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;mDetails.add( new Detail( mDetails.size(), "Detail #" + mDetails.size() ) );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;mMetawidget.getChildren().clear();&lt;/strong&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;/div&gt;&lt;br /&gt;Hope that helps!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-7405218008757386962?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/7405218008757386962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=7405218008757386962' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7405218008757386962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/7405218008757386962'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/11/metawidget-collections-support-part-2_24.html' title='Metawidget: Collections Support Part 2 (Advanced)'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__YNTBm_fS_I/TOxbEicYLSI/AAAAAAAAAVk/NtIjkDbZKlQ/s72-c/linuxconf.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-4801854889091609104</id><published>2010-11-19T08:55:00.006+11:00</published><updated>2011-07-18T08:44:55.536+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Metawidget: Collections Support Part 2</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TOTptBvOIQI/AAAAAAAAAVM/WvJqOTMUkHM/s400/xchat.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540810401342431490" /&gt;I was &lt;a href="https://sourceforge.net/projects/metawidget/forums/forum/747623/topic/3949870"&gt;recently asked&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"I would like to create a widget that displays each item contained in a List using an ICEfaces PanelTabSet. I would like the widget inside each panelTab to be generated through Metawidget. How can I accomplish this?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;This represents (yet) another aesthetic preference for rendering Collections. Namely, rendering one item per tab. Some other preferences, such as rendering one item per row of a table, have been covered &lt;a href="http://blog.kennardconsulting.com/2010/10/metawidget-collections-support.html"&gt;in a previous blog entry&lt;/a&gt;). As I said in that entry:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;To support this, Metawidget provides WidgetBuilders.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;So it's a case of writing a WidgetBuilder that will return a PanelTabSet for the List. I have put together a &lt;a href="https://docs.google.com/uc?id=0Bz-3d0tCrobHNzhkYzk0NDMtM2E5MS00MGU3LWJmOWMtZWUzMzI1ZWY1N2Qw&amp;export=download&amp;hl=en"&gt;complete project you can download here&lt;/a&gt;. It'll produce something that looks like this:&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/__YNTBm_fS_I/TOTpbfHJfgI/AAAAAAAAAVE/Ob0ON5WI6NI/s1600/Image1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 355px; height: 372px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TOTpbfHJfgI/AAAAAAAAAVE/Ob0ON5WI6NI/s400/Image1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540810099989773826" /&gt;&lt;/a&gt;&lt;br /&gt;Code for the WidgetBuilder part below:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;tt&gt;package com.myapp;&lt;br /&gt;&lt;br /&gt;import static org.metawidget.inspector.InspectionResultConstants.*;&lt;br /&gt;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;import javax.el.ELContext;&lt;br /&gt;import javax.el.ExpressionFactory;&lt;br /&gt;import javax.el.ValueExpression;&lt;br /&gt;import javax.faces.component.UIComponent;&lt;br /&gt;import javax.faces.context.FacesContext;&lt;br /&gt;&lt;br /&gt;import org.metawidget.faces.FacesUtils;&lt;br /&gt;import org.metawidget.faces.component.UIMetawidget;&lt;br /&gt;import org.metawidget.faces.component.UIStub;&lt;br /&gt;import org.metawidget.faces.component.html.HtmlMetawidget;&lt;br /&gt;import org.metawidget.util.ClassUtils;&lt;br /&gt;import org.metawidget.util.simple.StringUtils;&lt;br /&gt;import org.metawidget.widgetbuilder.iface.WidgetBuilder;&lt;br /&gt;&lt;br /&gt;import com.icesoft.faces.component.paneltabset.PanelTab;&lt;br /&gt;import com.icesoft.faces.component.paneltabset.PanelTabSet;&lt;br /&gt;&lt;br /&gt;public class IceFacesTabsWidgetBuilder&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;implements WidgetBuilder&amp;lt;UIComponent, UIMetawidget&amp;gt; {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Public methods&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public UIComponent buildWidget( String elementName, Map&amp;lt;String, String&amp;gt; attributes, UIMetawidget metawidget ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Not for us?&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String type = attributes.get( TYPE );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( type == null ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Class&amp;lt;?&amp;gt; clazz = ClassUtils.niceForName( type );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !List.class.isAssignableFrom( clazz ) ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Create a Stub to wrap around the PanelTabSet.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// This is because:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 1. PanelTabSet will not switch tabs if it is destroyed/recreated. We must set&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// COMPONENT_ATTRIBUTE_NOT_RECREATABLE on it (see&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// http://metawidget.sourceforge.net/doc/reference/en/html/ch02s04.html#section-architecture-widgetbuilders-implementing-your-own-faces).&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// This limits some dynamicism, such as being able to dynamically add tabs, but there are&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// further ways around that&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 2. COMPONENT_ATTRIBUTE_NOT_RECREATABLE only works if there is a 'value' expression that&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// OverriddenWidgetBuilder can match against&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 3. PanelTabSet is a little unusual in how it treats its 'value' expression (binding it to&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// a UI mechanism, rather than a model mechanism) so we need to avoid using it. We use the&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Stub's 'value' expression instead&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UIStub stub = new UIStub();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FacesContext context = FacesContext.getCurrentInstance();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ELContext elContext = context.getELContext();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ValueExpression metawidgetValueExpression = metawidget.getValueExpression( "value" );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String metawidgetValueExpressionString = FacesUtils.unwrapExpression( metawidgetValueExpression.getExpressionString() );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String tabSetValueExpressionString = metawidgetValueExpressionString + StringUtils.SEPARATOR_DOT_CHAR + attributes.get( NAME );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ValueExpression tabSetValueExpression = expressionFactory.createValueExpression( elContext, FacesUtils.wrapExpression( tabSetValueExpressionString ), Object.class );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stub.setValueExpression( "value", tabSetValueExpression );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Create tab set&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PanelTabSet panelTabSet = new PanelTabSet();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;panelTabSet.getAttributes().put( UIMetawidget.COMPONENT_ATTRIBUTE_NOT_RECREATABLE, true );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stub.getChildren().add( panelTabSet );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;List&amp;lt;UIComponent&amp;gt; tabs = panelTabSet.getChildren();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Lookup the List from the parent Metawidget to see how many items it has&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;List&amp;lt;?&amp;gt; list = (List&amp;lt;?&amp;gt;) tabSetValueExpression.getValue( elContext );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Create one tab per item...&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( int loop = 0, length = list.size(); loop &amp;lt; length; loop++ ) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PanelTab tab = new PanelTab();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tabs.add( tab );&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ...with each tab itself containing a Metawidget.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// The 'value' expression of each Metawidget uses the EL #{foo.bar[0]} notation for&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// accessing arrays&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HtmlMetawidget tabMetawidget = new HtmlMetawidget();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ValueExpression tabValueExpression = expressionFactory.createValueExpression( elContext, FacesUtils.wrapExpression( tabSetValueExpressionString + '[' + loop + ']' ), Object.class );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tabMetawidget.setValueExpression( "value", tabValueExpression );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tabMetawidget.setValueExpression( "readOnly", metawidget.getValueExpression( "readOnly" ) );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tab.getChildren().add( tabMetawidget );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Return tab set&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return stub;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/tt&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5950537015062599287-4801854889091609104?l=blog.kennardconsulting.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.kennardconsulting.com/feeds/4801854889091609104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5950537015062599287&amp;postID=4801854889091609104' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4801854889091609104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5950537015062599287/posts/default/4801854889091609104'/><link rel='alternate' type='text/html' href='http://blog.kennardconsulting.com/2010/11/metawidget-collections-support-part-2.html' title='Metawidget: Collections Support Part 2'/><author><name>Richard</name><uri>http://www.blogger.com/profile/11191015489042575122</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/__YNTBm_fS_I/R8U28ZqxB9I/AAAAAAAAADM/mBDbekiHnVI/S220/Richard+Kennard+(square).png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__YNTBm_fS_I/TOTptBvOIQI/AAAAAAAAAVM/WvJqOTMUkHM/s72-c/xchat.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5950537015062599287.post-1491571800821710415</id><published>2010-11-17T17:08:00.011+11:00</published><updated>2011-07-18T08:45:48.068+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metawidget'/><title type='text'>Towards a General Purpose Architecture for User Interface Generation</title><content type='html'>&lt;img style="float:right; margin:0 0 10px 10px;width: 128px; height: 128px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TON0leIPEKI/AAAAAAAAAUk/VWFuhqHAOWo/s400/package_graphics.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540400153687429282" /&gt;&lt;a href="http://dx.doi.org/10.1016/j.jss.2010.05.079"&gt;Kennard, R. &amp; Leaney, J. 2010, Journal of Systems and Software&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;Abstract&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Many software projects spend a significant proportion of their time developing the User Interface (UI), therefore any degree of automation in this area has clear benefits. Such automation is difficult due principally to the diversity of architectures, platforms and development environments. Attempts to  automate UI generation to date have contained restrictions which did not accommodate this diversity, leading to a lack of wide industry adoption or standardisation. The authors set out to understand and address these restrictions. We studied the issues of UI generation (especially duplication) in practice, using action research cycles guided by interviews, adoption studies and close collaboration with industry practitioners. In addressing the issues raised in our investigation, we identified five key characteristics any UI generation technique would need before it should expect wide adoption or standardisation. These can be summarised as: inspecting existing, heterogeneous back-end architectures; appreciating different practices in applying inspection results; recognising multiple, and mixtures of, UI widget libraries; supporting multiple, and mixtures of, UI adornments; applying multiple, and mixtures of, UI layouts. Many of these characteristics seem ignored by current approaches. In addition, we discovered an emergent feature of these characteristics that opens the possibility of a previously unattempted goal - namely, retrofitting UI generation to an existing application.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;1. Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Many software projects spend a significant proportion of their time developing the User Interface (UI). Research in the early 1990s found that some 48% of application code and 50% of application time was devoted to implementing UIs (Myers 1992). These figures are still considered relevant today, more so with the increased demands of richly graphical and web-based UIs (Jha 2005; Daniel et al. 2007), therefore any degree of automation in this area has clear benefits. This automation is difficult because UIs bring together many qualities of a system that are not formally specified in any one place, or are not specified in a machine-readable form. For example, a dropdown widget on a UI screen may have a data type specified in a database schema, a range of choices drawn from within application code, and a look and feel specified by a human-readable design document. Bringing these diverse characteristics together to enable automatic UI generation is a significant challenge and research in this field dates back over two decades. The work was given increased urgency with the emergence of ubiquitous computing (Weiser 1993) and its proliferation of different UI devices with widely varying capabilities. Approaches to date can be broadly grouped into three categories: interactive graphical specification tools, model-based generation tools, or language-based tools (Myers 1995). Each has significant disadvantages which have limited its success in industry (Myers, Hudson &amp;amp; Pausch 2000).&lt;br /&gt;&lt;br /&gt;The main disadvantage of the first two approaches - interactive graphical specification tools and model-based generation tools - is that they inherently require software developers to restate information that is already encoded elsewhere in the application. This duplication is both laborious and a source of errors, as the developer must take care that the application code and the UI model stay synchronised (Jelinek &amp;amp; Slavik 2004). The main disadvantage of the third approach - language-based tools - is that generally programming languages "are not sufficient enough for complex UI modelling. To completely and formally depict the UI composition and behaviour, new attributes and properties are needed to describe the object data members" (Xudong &amp;amp; Jiancheng 2007, p. 540). Without these new attributes and properties, language-based tools must resort to generalised heuristics when generating their UIs. These generalisations invariably mean "the generated User Interfaces [are] not as good as those created with conventional programming techniques" (Myers, Hudson &amp;amp; Pausch 2000, p. 13).&lt;br /&gt;&lt;br /&gt;UI generation has not experienced the same wide industry adoption and standardisation as, say, Object Relational Mapping (ORM) (JPA 2008). We claim that this is because existing approaches are impractical, not because the issue itself lacks urgency. A series of interviews conducted with practitioners across industry segments and software platforms (Kennard, Edmonds &amp;amp; Leaney 2009) found common experiences of duplication (Jelinek &amp;amp; Slavik 2004), common experiences of bugs caused by it, and a common desire for it to be addressed. One interviewee confirmed "the problem definitely exists. It's more from the business layer forward to the screen is the biggest problem because there are things out there like [ORM] which do from, sort of, business layer down". Another lamented that, when making a typical change to an enterprise system "the drudgery at the moment is adding the UI code, and adding the validation and giving that feedback. That's really quite unpleasant. It's the most complex of all the steps, actually, depending on the magnitude of the change". Some practitioners gave concrete examples "we've got a BigDecimal (Gosling 2005), and [the back-end has] set the scale to 8 but the GUI puts through 10, it [gets silently rounded and] passes all the way through. That becomes a real issue because it's really hard to find. That's caused us huge problems before". One developer reflected "it's a fairly established software engineering principle that the more you have to repeat something [defining fields in both the business layer and the UI layer] the higher the chances there's going to be an error in the code". Finally one engineer summarised "every developer who writes anything more than a Hello World application will have this problem. Most developers encounter this problem on a daily basis as a constant friction in their daily work". During publication of our 2009 paper, reviewers reframed our interviews in an academic context "the work is exceptionally well motivated... it is important for the [research] community to hear... nobody in a senior position in a software company today is going to not be aware of this problem and the various hacks, workarounds, and band-aids used to cover up the pain that it causes (at least not in a successful software company). Again, academics may be surprised by some of the comments and the gravity of the concerns, but I wasn't; this is a serious problem and there are partial solutions out there that various people employ with varying degrees of success".&lt;br /&gt;&lt;br /&gt;Having established the urgency of the problem, the authors set out to address the impracticalities with existing UI generation approaches. We sought a well-motivated, well-justified approach guided by practice based research and human centred design approaches. These included open ended interviews, adoption studies and close collaboration with industry practitioners, as described in section 2. In doing so we identified five key characteristics we believe are necessary for any UI generation technique to achieve wide adoption or standardisation. Many of these characteristics seem ignored by current approaches. The full adoption studies will be published at a later date, but we discuss each characteristic in detail in section 3. In addition, we discovered an emergent feature of these characteristics is that they open the possibility of retrofitting - a previously unattempted goal - which we explore in section 4. Finally, we discuss future work in section 5.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;2. Methodology&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Given our strong focus on industry practice, and ensuring any UI generation is practical, it was important to engage our target audience early and often. One industry-based approach effective in doing this is iterative development. There are various definitions of iterative development, but all are common in trying to avoid a single-pass, document-driven, gated-step approach (Larman &amp;amp; Basil 2003). The iterative development methodology has interesting parallels to the research methodology of action research (Dick 2000). Indeed, action research's definition of a cycle of 'plan, act, observe, reflect, then plan again' (Kemmis &amp;amp; McTaggart 1988) would be a fitting description for iterative development. The outcomes from each cycle drive the planning for the next cycle, both in terms of expanding those areas that worked well and revisiting those that were less successful. This is particularly effective when either the problem or the solution are not well defined, as they afford the work the agility to change as its goals become clearer.&lt;br /&gt;&lt;br /&gt;Our research methodology employed action research as a framework within which to formalise iterative development, allowing the work to be both accessible to, and guided by, observations from both industry and the research community. Observations were gathered through forum messages, open-ended interviews using simplified grounded theory (Dick 2005) and adoption studies1. Adoption studies were gathered retroactively from companies who had independently discovered and decided to apply our work, of their own volition, based on publicity from previous action research cycles. Companies were discovered through message forums then contacted to solicit a study of their experiences. We conducted seven such studies in all, ranging from private biotechnology and telecommunications companies, to government departments and academic institutions.&lt;br /&gt;&lt;br /&gt;The last phase of each action research cycle reflected upon the observations from interviews and adoption studies as drivers for the next cycle. Action research delineates an explicit 'reflect' phase (Kemmis &amp;amp; McTaggart 1988) so as to bring academic rigour to the proceedings. During the 'plan', 'act' and 'observe' phases, reflection happens 'in action' (Schön 1983) with the 'action present' measured in minutes or hours. During the 'reflect' phase, however, the 'action present' is much more deliberate, being measured in days or weeks, which lends more diligence and formality to the Validity, Verification and Testing (VVT) of the research. It facilities the reconsideration of all design decisions, implementation details and observations from the preceding action research cycle in a holistic light, leading to key new insights.&lt;br /&gt;&lt;br /&gt;This practice based methodology, conducted across three action research cycles over a period of three years, afforded us a breakthrough in our understanding of the problem domain. Our most significant finding is the identification of five key characteristics any UI generation technique needs before it can be practical in an industry setting. Notably, many of these characteristics seem ignored by current UI generators, which we believe is hindering their widespread adoption. The next section presents our action research results in detail.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;3. Characteristics of a Practical User Interface Generator&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This section explains the five characteristics we believe, based on our action research cycles, are key to a practical UI generator. We have derived these characteristics through interviews, adoption studies and close collaboration with industry practitioners. They can be summarised as: inspecting existing, heterogeneous back-end architectures; appreciating different practices in applying inspection results; recognising multiple, and mixtures of, UI widget libraries; supporting multiple, and mixtures of, UI adornments; applying multiple, and mixtures of, UI layouts. We will justify each of these characteristics in turn in the following sections. We will begin each section by first framing the characteristic within the literature and within observations from our discovery research. We will then move to justify each characteristic and discuss its technical details. Because of our strong focus on a practical &lt;a href="http://metawidget.org"&gt;user interface generator&lt;/a&gt;, we will discuss these technical details in the context of our own implementation, which we have called &lt;a href="http://metawidget.org"&gt;Metawidget&lt;/a&gt;. This implementation is the outcome of our action research, and the proof of our work. &lt;br /&gt;&lt;br /&gt;Before we begin, however, it is important to first frame how the five characteristics fit together. There are a number of ways they could be designed into a UI generator, though we would caution against any approach based on presenting practitioners with multiple options or 'flags' - such approaches likely underestimate the sheer volume of variations and combinations the characteristics need to accommodate. In our particular implementation we have implemented the five characteristics as a pluggable pipeline (Vermeulen, Beged-Dov &amp;amp; Thompson 1995) as shown in below. Practitioners can plug in alternate implementations, or custom implementations, of each characteristic. This allows our implementation to accommodate the volume of variability while avoiding the performance overhead and maintenance  cost of an exponential combination of 'flags'.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/__YNTBm_fS_I/TONx1ct4zEI/AAAAAAAAAT8/OYl8nD9rSiY/s1600/Figure1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 263px;" src="http://3.bp.blogspot.com/__YNTBm_fS_I/TONx1ct4zEI/AAAAAAAAAT8/OYl8nD9rSiY/s320/Figure1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540397129651506242" /&gt;&lt;/a&gt;&lt;br /&gt;The leftmost 'lifeline' in the UML sequence diagram (the Metawidget) serves to coordinate the others and is not considered part of the pipeline. The remaining five UML lifelines correspond to the five key characteristics we have identified from our action research. The UI generation proceeds in a well-defined fashion along each stage of the pipeline, from left to right. Each stage is pluggable. As an implementation detail, each stage is also immutable. This helps with memory consumption and performance when multiple Metawidgets are used in the same UI.&lt;br /&gt;&lt;br /&gt;Each of the UML lifelines and their corresponding characteristic is discussed in turn in the sections to follow. We begin with the first UML lifeline, the 'inspector'.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;3.1. Pluggable Inspectors&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Most UI generation solutions dictate that practitioners provide the generator with a centralised, single source of truth (SSOT). The solutions do this by defining their own UI modelling language or graphical builder tool, then require the practitioner to use their tool to define the UI. For example, UsiXML (Vanderdonckt et al. 2004) consists of "a User Interface Description Language (UIDL) that is a declarative language capturing the essence of what a UI is or should be independently of physical characteristics. UsiXML describes at a high level of abstraction the constituting elements of the UI of an application: widgets, controls, containers". GUMMY (Meskens 2008) is designed "in a similar way to traditional GUI builders in order to allow designers to reuse their knowledge of single-platform user interface design tools... there is a toolbox showing the available user interface elements, a canvas to build the actual user interface and a properties panel to change the properties of the user interface elements on the canvas". Internally, "GUMMY builds a platform-independent representation of the user interface and updates it as the designer makes changes. This allows for an abstract specification of the user interface" which it then uses to drive UI generation for multiple physical devices. However as Jelinek and Slavik (2004) observe, "a common disadvantage [of modelling languages and graphical builder tools] is the fact that the user interface is defined explicitly and separately" and therefore "the application and the corresponding [UI] model need to be kept consistent". Prat et. al (1990) agree, finding that in practical application design "the [back-end] requires a considerable amount of knowledge [much of which is] similar to that required by the [UI] modules".&lt;br /&gt;&lt;br /&gt;Some UI generation solutions acknowledge this shortcoming and seek to reuse existing information already embedded in an application's architecture. Unfortunately they still require this to be rigidly centralised. For example, Naked Objects dictates "all the functionality associated with a given entity [must be] encapsulated in that entity, rather than being provided in the form of external functional procedures that act upon the entities" (Pawson 2004). Most industry systems do not adhere to such a 'behaviourally-complete' methodology. Rather, they use what Firesmith (1996) calls "dumb entity objects controlled by a number of controller objects". They do this in order to benefit from a rich ecosystem of technologies. What Firesmith terms 'controller objects' industry practitioners would term, but not be limited to, validation subsystems, workflow subsystems, rule engines and Business Process Modelling (BPM) languages. Indeed, as Pawson himself later concedes "most object-oriented (OO) designs, and especially object-oriented designs for business systems, do not match this ideal of behavioural-completeness". It is important to appreciate this is not because most business systems are poorly designed. Rather, they are seeking to leverage functionality provided by the large number of mature subsystems available in industry, in order to increase productivity and reduce development cost. It is still possible to have an SSOT whilst being decentralised amongst multiple subsystems, provided there is no overlap in the decentralisation (i.e. the workflow subsystem is concerned with different aspects of the application to the validation subsystem).&lt;br /&gt;&lt;br /&gt;Our adoption studies underscored this point with industry practitioners. One commented "many frameworks or tools enforce the designer's vision on how solutions should be architected. What I liked about [your implementation] is that I could drop it in whatever architecture I was using". The phrase 'whatever architecture I am using' turned out to be critical, because real world architectures were found to vary widely - dependent on both hard, business requirements and softer, aesthetic judgements.&lt;br /&gt;&lt;br /&gt;As an example of a business requirement, many architectures abstract their UI data into OO classes. It is certainly possible to generate UIs based on instances of those classes - indeed, this is the approach Naked Objects mandates. But business requirements often prevent this approach and it was found that being able to plug in a company's own back-end inspector was fundamental to the usefulness of a UI generator. One adoption study had defined the UI in their own, proprietary XML.   "[Being able to write our own] inspector that knows our XML schema and can find all restrictions of the currently inspected field and add that to the attributes returned [was a key strength]". Another study had used rules in a database: "The main feature for us was the possibility to dynamically, based on rules stored in our database, create input screens based on user selections... it was important it supported our back-end. Being able to plug-in our back-end inspectors gave us the flexibility needed, it is impossible to support everyone's requirements [out of the box]... otherwise we probably would not have even tried it". Another adoption study used a mixture of third-party libraries: "we work with JDO, OVal, and some custom annotations, so being able to extend was a must for us". Another adoption study "we did not want to place view stuff into the model, and we did not want to place it in an [external] XML file either, because we would have to replicate the property name. [Instead] we built [an inspector] based on our properties files". By 'properties files' the team is referring to reading UI information from localization (internationalization) resource bundles. These examples demonstrate there are a multiplicity of sources of UI metadata. Furthermore, it is not difficult to posit other useful sources, such as Web Services Description Language files (WSDL 2001).&lt;br /&gt;&lt;br /&gt;A common example of an aesthetic judgement revolved around the mixing of presentation information with business logic. Some adoption studies reported "there was some spirited debate [in the development team], since [annotating the business objects can] degrade gracefully if not in use. It still, to us, seemed cleaner to put UI-specific code outside of our business objects [in XML files]". Another said "business objects should be neutral regarding presentation - I am a supporter of separated tiers". But other adoption studies disagreed "while I appreciate the power within the XML inspectors, I used annotations to configure [my business objects]". Another "I don't mind [annotating], an annotation is just metadata". Interestingly, one study considered it a matter of scale: "for small projects it might not be a concern, so we find [the fact that it is supported] valid, but for larger projects where the architecture is more important, usually we want to keep a clear separation between layers, and it is not desirable to 'pollute' the model".&lt;br /&gt;&lt;br /&gt;It is important to note practitioners are not simply talking about supporting many different back-end technologies. Rather, they are talking about being able to mix technologies, including custom subsystems and alternate implementations of the same subsystem. The latter is less an issue in 'full stack' proprietary software environments such as the Microsoft application stack, but in Open Source enterprise ecosystems such as Java EE there are often dozens of competing implementations of the same subsystem (Shan et al. 2006). There are even competing implementations of the core language (e.g. Java versus Groovy versus Scala). Software architecture therefore involves a myriad of choices, many of which have no 'right' or 'wrong', and opinions on which evolve over time. For example, business rule engines are becoming increasingly popular (Rouvellou et al. 1999). Any UI generator that seeks to dictate, rather than adapt to, a system's architecture therefore has limited practical value.&lt;br /&gt;&lt;br /&gt;Our implementation addresses this characteristic of supporting mixtures of back-end technologies by defining pluggable 'inspectors'. It defines a minimal 'Inspector' interface and ships with a number of implementations of this interface to support extracting metadata from different, heterogeneous subsystems. The parent Metawidget (leftmost lifeline in UML diagram) requests information regarding a particular business object and it is the responsibility of each individual inspector to gather as much information as possible about that business object from its particular subsystem. A current limitation and open question of this approach is how to validate the completeness of the inspection. The issue of completeness is ongoing work. &lt;br /&gt;&lt;br /&gt;Returning to our theme of an SSOT, our implementation also supplies a CompositeInspector, named after the composite design pattern (Gamma et al. 1995), to support combining the inspection results from multiple inspectors into a more detailed whole result, as shown below. This more detailed whole result forms a temporary centralised SSOT from the subsystems it is split across, so that it can be used to drive UI generation. This extraction and collation of metadata from multiple, heterogeneous subsystems is commonly referred to as software mining.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/__YNTBm_fS_I/TONx2ZC2SxI/AAAAAAAAAUE/ucsXPVsIYRU/s1600/Figure2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 219px;" src="http://1.bp.blogspot.com/__YNTBm_fS_I/TONx2ZC2SxI/AAAAAAAAAUE/ucsXPVsIYRU/s320/Figure2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540397145845549842" /&gt;&lt;/a&gt;&lt;br /&gt;It is often said in software development that each design decision should "pull its weight" (Bloch 2001). That is to say, it is a validation of good design if each decision provides multiple advantages that demonstrably outweigh the inevitable disadvantage of its added complexity. Encouragingly, several of our five characteristics demonstrate such emergent advantages. For inspectors, an emergent advantage of CompositeInspector is that it becomes possible to run remote inspections. Multiple groups of inspections can be run remotely on different application tiers, passing the inspection results back to the UI in a well-defined, secure manner, where they can be recombined. This is important in real world architectures where often the UI layer is prohibited from, say, directly accessing the database schema.&lt;br /&gt;&lt;br /&gt;To reiterate, throughout section 3 we are referencing our own particular implementation of each characteristic in order to provide a deeper analysis. Clearly, however, ours is not the only approach. For example, the Naked Objects team report (Haywood 2008.1) they are introducing pluggable 'facets' as a method of supporting mixtures of back-end technologies, including XML and database sources. This somewhat relaxes their 'behaviourally-complete' methodology and suggests some convergence (Haywood 2009).&lt;br /&gt;&lt;br /&gt;This section has demonstrated that supporting a mixture of heterogeneous sources of UI metadata is an important characteristic for a practical UI generator. Having retrieved and collated all available  metadata from the back-end subsystems, it is generally necessary to post process it. This characteristic is discussed in the next section.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;3.2. Pluggable Inspection Result Processors&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The raw inspection result returned from the inspector invariably needs post processing before it is suitable for consumption. For example, the fields generally need to be arranged in a business-defined order. There are various ways to achieve this, dependent on the metadata source. For example, if the data is sourced from an XML document its nodes are inherently ordered (XML 2008). But if the data comes from JavaBean properties in Java class files then it will not retain any ordering information (Gosling 2005) so one must be imposed. In the latter case, our adoption studies showed that the method used to impose ordering is open to practitioner taste. By default our implementation uses a 'comes after' approach, whereby each business field can specify the field that immediately precedes it. But some adoption studies reported "I would rather give the properties priorities so that I can say 'this one comes first' instead of 'this one comes after that other one'. It's just more natural to me". Equally, the Naked Objects team reports "by way of comparison (and as an alternative idea), the Naked Objects programming model uses an annotation called @MemberOrder, which takes an ordering in Dewey decimal notation. So, we have @MemberOrder("1.1")" (Haywood 2008.2).&lt;br /&gt;&lt;br /&gt;Such explicit field ordering at the business model-level has disadvantages, however, as one practitioner noted "adding [field ordering information] to basically every field of your business model strongly reduces clarity... one of the key principles of [pluggable inspectors] is the possibility to directly use your unchanged domain objects [but this] doesn't really follow that principle". It is also less flexible in cases where "one wants to automatically create many different views based on a single business object with components of different sequence and visibility". The alternative, ordering the fields at the UI-level, introduces duplication - re-stating the fields used in a business object (Jelinek &amp;amp; Slavik 2004) - and compromises polymorphism - the UI needs to statically know the fields in advance - but practitioners advocated both sides: "I agree, the default behaviour [model-level ordering] should be as it is now... still, I see [UI-level ordering] as an advantageous option for cases with specific concerns such as flexibility".&lt;br /&gt;&lt;br /&gt;Field ordering, then, whether specified by the back-end or the front-end, must be pluggable. Another example of an inspection result post processing operation, open to similar interpretations of practitioner taste, is excluding fields: should the model-level dictate which fields are to be excluded from the UI, or should this be decided on a per-screen basis? Most likely, a combination of both would be required - some clearly inappropriate fields, such as database primary keys, should be excluded from the UI at the model-level whereas other fields may need excluding on a per-screen, or per-user-role basis. Such post processing requirements are commonplace and a UI generator that does not accommodate different practitioners' preferred approaches would limit its appeal.&lt;br /&gt;&lt;br /&gt;Our implementation addresses this characteristic of supporting multiple ways to post process the UI data by defining pluggable 'inspection result processors'. It defines a minimal 'InspectionResultProcessor' interface and ships with a number of implementations of this interface to support post processing metadata. Distinct from inspectors, which are designed to be detached from the UI and executable on application tiers inaccessible to the UI, InspectionResultProcessors maintain a reference to the current UI page. This is required for the aforementioned ability to implement UI-level ordering and exclusion.&lt;br /&gt;&lt;br /&gt;This section has demonstrated that supporting a variety of ways to post process UI metadata is an important characteristic for a practical UI generator. Once post processing is complete, the inspection result is ready to drive the UI generation, as discussed in the remaining three sections.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;3.3. Pluggable Widget Builders&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;An SSOT acts as a valuable starting point for UI generation. We have discussed how, in industry, this metadata is seldom centralised but rather must be brought together from disparate sources. There does not appear to be any movement among industry systems to converge this situation. On the contrary, the movement is generally towards additional types of subsystems, such as business rule engines (Rouvellou et al. 1999). Similarly, and despite research community ideals to the contrary, industry UI frameworks continue to diverge. Most notably, the Web browser does not appear to be the ubiquitous UI for which many were hoping.&lt;br /&gt;&lt;br /&gt;For example, when Apple debuted their iPhone in 2007, they originally advocated their Safari Web browser as the recommended way to develop applications for the mobile device. A year later, however, the pressure for native UIs was recognised and a traditional SDK was released. This allowed better performance and access to device-specific hardware such as accelerometers and third-party peripherals (Square 2010). The Google Android mobile platform similarly supports native UI applications in addition to browser-based ones. Even if the browser were to become the ubiquitous UI, the plethora of Web frameworks and approaches to Web development (Shan et al. 2006) suggest there will not be a convergence of UI platforms in the near future.&lt;br /&gt;&lt;br /&gt;This need to support a variety of front-end frameworks was apparent in several adoption studies. One reported: "We needed to integrate with a Spring MVC app, and in the future we may want to integrate with some existing Swing applications... also possibly Java Server Faces (JSF)". Another: "if I'd had to [design my architecture] differently because of [your implementation] I would have been unhappy. As things are I was just able to treat it as a normal Swing widget which was nice".&lt;br /&gt;&lt;br /&gt;Another important requirement for a UI generator is that it support third-party, or custom, widgets.  This is important not only for flexibility but also robustness. For example, a frequent problem when developing Web applications is ensuring compatibility across browsers. By leveraging existing widget libraries, rather than attempting to generate HTML directly, a UI generator can delegate all issues of browser incompatibility to the widget library - which has typically already been vetted in a variety of production environments. An adoption study from an earlier action research cycle criticised "if you have a more exotic GUI component used for certain properties, [your implementation requires] more work needed to get that to render, as opposed to simply creating the component in your GUI layer". After we improved this, adoption studies from later action research cycles reported: "We wrote our own widget builder.... [to use custom] components we developed and Metawidget instantiates them".&lt;br /&gt;&lt;br /&gt;Implicit to this requirement to support third-party widget libraries is the ability to mix multiple third-party widget libraries in the same UI. Most third-party libraries only specialise on a certain set of widgets, rather than trying to replace every widget the platform provides.&lt;br /&gt;&lt;br /&gt;Our implementation addresses this characteristic of supporting mixtures of widget libraries by defining pluggable 'widget builders'. It defines a minimal 'WidgetBuilder' interface and ships with a number of implementations of this interface to support popular UI frameworks, such as the aforementioned Spring MVC, Swing and Java Server Faces. Notably, our implementation also supplies a CompositeWidgetBuilder, named after the composite design pattern (Gamma et al. 1995), to support combining the widget libraries from multiple WidgetBuilders. The ordering of the WidgetBuilders is significant, so that widget choice can prefer one third-party library's widgets over another, or fall back to the default platform widgets, as shown below.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/__YNTBm_fS_I/TONx3pSclZI/AAAAAAAAAUM/cU5Lm9qLoyQ/s1600/Figure4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 121px;" src="http://4.bp.blogspot.com/__YNTBm_fS_I/TONx3pSclZI/AAAAAAAAAUM/cU5Lm9qLoyQ/s320/Figure4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540397167385810322" /&gt;&lt;/a&gt;&lt;br /&gt;As with inspectors, widget builders demonstrate emergent advantages. Specifically, they present a compelling use case for practitioners to adopt UI generation. Once the developer has delegated their widget creation to a widget builder, it becomes possible to plug in new widget libraries as they become available - either new versions of existing libraries, or competing libraries offering more desirable widgets. For example, a third-party widget library may be released that offers a 'colour picker' widget with a user-friendly colour wheel. Imagine a practitioner has an application whose existing approach is to present a text field constrained to only accept hexadecimal input in RGB format (e.g. #ff00ff). The text field works, but the practitioner decides the colour wheel is more usable (it doesn't require the user understand hexadecimal, for one). Using widget builders, the practitioner would simply need to insert a WidgetBuilder for this new widget library as the first in a CompositeWidgetBuilder's list of priorities. Every screen in the application that previously used the hexadecimal text field would be immediately upgraded to use the colour picker, and this would happen automatically across the entire application - a significant saving in practitioner time over upgrading each screen manually. Notably, the WidgetBuilder itself could be provided by the widget library author, their incentive being to increase ease-of-adoption of their library. This reasoning extends to other areas of our pipeline too, such as inspectors, widget processors and layouts (covered in subsequent sections): an author of a new product, such as a business rules engine, a validation subsystem, or a layout manager, could increase its install base by providing UI generator plugins for it - alleviating the need for a practitioner to learn much of their product's API and significantly easing its adoption. Such plugins are not unprecedented, and grow the ecosystem of a product segment by levelling the playing field for new entrants. For example, database vendors  typically provide plugins to popular ORMs so as to ease adoption amongst practitioners using those ORMs.&lt;br /&gt;&lt;br /&gt;This section has demonstrated that supporting mixtures of widget libraries is an important characteristic for a practical UI generator. Widget builders simplify the process of choosing the most appropriate widget for a business field. Simply choosing the widget is rarely sufficient, however. There are generally a host of supporting technologies that also need to be attached, such as data validators, data binding frameworks, and event handlers. This characteristic is discussed in the next section.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;3.4. Pluggable Widget Processors&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In raw form, a widget is not likely to be suitable for inclusion in a UI. For example, end users interacting with a raw text field are able to enter arbitrary text. However the business requirement may be for, say, a credit card number. Widgets therefore need to be further adorned with data validators, data binding frameworks and event handlers. Of particular note is that some of these mechanisms, such as validators, may come from a different third-party library than the raw widget.&lt;br /&gt;&lt;br /&gt;Processing such adornments is made difficult because of a general problem with automatic generation of any kind, not just UI generation: generated code is opaque to the practitioner. It is difficult to reference and attach mechanisms to objects that are not well-known in advance. One early adoption study identified this as "when you want to customise [the generated widgets], like replacing or adding more info to [them] you have to refer to them by property names. We have this problem not only for [UI generation], but when you have a lot of dynamic stuff [such as ORM frameworks]. It would be nice to either solve this or offer a solution for that". Another gave a concrete example, needing "a way to attach event handlers to widget value changes. This would allow you to respond to change... not just do a bi-directional binding (for example you could enable a save button that starts disabled)". A third adoption study had custom mechanisms they wanted to attach: "[we'd like to be] able to integrate our own validation and custom rendering of components".&lt;br /&gt;&lt;br /&gt;Practitioners require a pluggable mechanism that allows post processing of a built widget. Critically, this mechanism must expose the same richness of metadata as the original widget building did, so that widgets may be identified not just by their name but also by their type, their constraints, their labels or any amount of other metadata.&lt;br /&gt;&lt;br /&gt;Our implementation addresses this characteristic by defining pluggable 'widget processors'. It defines a minimal 'WidgetProcessor' interface and ships with a number of implementations of this interface to support popular adornments, such as the aforementioned data validators and data bindings, as shown below. Many of these implementations are defined by third-party libraries, not by the same base UI library as the raw widget. Notably the list of widget processors is maintained not by an immutable CompositeWidgetProcessor, as with CompositeWidgetBuilder, but by a mutable list. This is important so that individual UI screens can dynamically add widget processors that, say, attach event handlers. The methods these event handlers call are, by definition, tied to a particular UI screen rather than being immutable across the entire application. If we were to implement an immutable CompositeWidgetProcessor we would be unable to add such event handler processors without invalidating the immutability of the overall composite. Equally however many other types of widget processor, such as data validators and data bindings, are not tied to a particular screen and are immutable. We do not want to unnecessarily instantiate multiple instances of such processors. Designing the widget processors as a mutable list, therefore, allows us the best of both approaches.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/__YNTBm_fS_I/TONx4pW60jI/AAAAAAAAAUU/n3uvRIxxc5Q/s1600/Figure5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 216px;" src="http://2.bp.blogspot.com/__YNTBm_fS_I/TONx4pW60jI/AAAAAAAAAUU/n3uvRIxxc5Q/s320/Figure5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5540397184584438322" /&gt;&lt;/a&gt;&lt;br /&gt;This section has demonstrated that supporting a variety of ways to post process UI widgets is an important characteristic for a practical UI generator. Following post processing, the widget is robust enough to be placed in front of the user. However, it still remains to lay it out appropriately among its siblings. This final characteristic is discussed in the next section.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;3.5. Pluggable Layouts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Having inspected, built and processed the final widget its layout on the screen is perhaps the most intractable issue in UI generation. In particular, it significantly detracts from the practicality of automated generation if it in any way compromises the final product in usability, or even in aesthetics (Myers, Hudson &amp;amp; Pausch 2000, p. 13). This realisation exposes a myriad of small details around UI appearance, navigation, menu placement and so on. The problem is so difficult, in fact, we believe it insoluble.&lt;br /&gt;&lt;br /&gt;Our implementation sidesteps the issue by sharply restricting the bounds of its generation (Kennard &amp;amp; Steele 2008). Specifically, it does not attempt to generate the entire UI. Rather, it focuses on generating only a small piece of it - the 'inside' of each page, the area around the fields themselves. Ultimately, this is the only piece that is actually constrained by the back-end architecture. The UI appearance, navigation, menu placement and overall usability are far more device-specific, not to mention specific to the aesthetic taste of the UI designer. We explicitly keep these out of scope. Our adoption studies confirmed: "I think that although it is theoretically possible to solve this [automatically], in practice, it is generally not feasible to re-write the view into different technologies [automatically]. Even in scenarios where you have to design, for instance, the same screen with different versions for desktop and mobile, the screen cannot fit/support the same functionality". Human-based, aesthetic judgements must be made as to what can fit, what can be supported, and what is most usable.&lt;br /&gt;&lt;br /&gt;As testament to how impractical generation of an entire UI is, even after restricting UI generation to just the area around fields we find there is still a formidable degree of variability. Fields may typically be arranged in a 'column', with the widget on the right and its label on the left. But other times the practitioner may want two or three such columns side by side. If so, they may need some widgets - such as large text areas - to span multiple columns. Or they may abandon columns altogether and want the fields arranged in a single, horizontal row. Furthermore, it is not difficult to posit other real world arrangements, such as right-to-left arrangements for the Arabic world. It is important to accommodate this variety if the generator is to achieve the exact look the practitioner desires. If it cannot achieve that exact look, the practitioner is compromising usability - the most determining factor of a UI - for the sake of automatic generation (Myers, Hudson &amp;amp; Pausch 2000, p. 13).&lt;br /&gt;&lt;br /&gt;Our implementation addresses this characteristic of supporting multiple ways to arrange widgets by defining pluggable 'layouts'. It defines a minimal 'Layout' interface and ships with a number of implementations of this interface to support different layouts. Notably, our implementation also supplies a LayoutDecorator, named after the decorator design pattern (Gamma et al. 1995), to support decorating one layout with another. For example, fields may need to be divided into sections separated by headings, or sections divided into tabs in a tab panel. Such concerns should be orthogonal to the field arrangement themselves (i.e. one column or two columns, labels to the left of the widgets or the right) to curb a combinatorial explosion of UI options.&lt;br /&gt;&lt;br /&gt;Adoption studies informed and agree the benefits of achieving parity between the UI designer's intent and the automatically generated UI are invaluable: "It is really hard to keep consistency, visual or functional standards when building [a] GUI in a large team. However, when it is generated dynamically, the rules are centred and even the customisation is somehow controlled".&lt;br /&gt;&lt;br /&gt;As with inspectors and widget builders, layouts further demonstrate emergent advantages. Specifically, it becomes possible to mix layouts from third party widget libraries. Third party libraries often supply 'layout widgets' in addition to their data entry widgets. For example they may provide collapsible panels. If the practitioner is accustomed to using these layout widgets, the UI generator must support them or it will not be able to achieve parity with the original UI design. In addition, leveraging layout widgets affords the inherent robustness of delegating Web browser incompatibility issues, as discussed in section 3.3.&lt;br /&gt;&lt;br /&gt;This section has demonstrated that supporting multiple ways to arrange widgets is an important characteristic for a practical UI generator. This, combined with the other four characteristics demonstrated in previous sections, results in a richly flexible UI generator. As shown, many of these five characteristics individually exhibit emergent advantages. However, when all five are combined there is a further emergent advantage - one that appears unique in the literature. We turn to this advantage in the next section.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;font-weight:bold"&gt;4. Retrofitting&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The previous section demonstrated five characteristics that are necessary for a practical UI generator. In addition, it showed how these characteristics give rise to a number of emergent advantages, which in themselves are an encouraging validation of their value. However there is a further notable advantage that emerges when all five characteristics are present in a UI generator - an advantage that is seldom even discussed, much less targeted, in the literature. Specifically, these five characteristics combined make it possible to retrofit UI generation into existing applications.&lt;br /&gt;&lt;br /&gt;Retrofitting is a laudable but largely unpursued goal. It is laudable because the number of existing applications, both mature and currently under development, far outweighs the number of 'green field' applications that could reasonably be expected to adopt a new UI generator. The ability to remove boilerplate code from existing applications, in addition to preventing boilerplate code in new ones, has potential savings of many orders of magnitude. Retrofitting is largely unpursued presumably because it requires a level of UI generator flexibility, particularly flexibility towards back-end architectures, that is difficult to target. However several adoption studies successfully applied our implementation to existing applications. This included them being able to partially migrate applications one screen, or even one piece of a screen, at a time. This prompted us to conduct internal experiments retrofitting our implementation to other projects. For example, we chose three applications from the samples included with the Open Source JBoss Seam distribution (JBoss Seam 2010). We discovered the retrofitting activity encompassed three main areas.&lt;br /&gt;&lt;br /&gt;First was to explore what existing metadata could be leveraged from the application's back-end architecture. For example the Seam Hotel Booking sample contained some UI metadata embedded within its persistence subsystem, some within its validation subsystem, and some within a scripting language. Conversely, the Seam DVD Store sample contained UI metadata embedded within its BPM subsystem. We were able to plug in inspectors for each of these. The second activity was to introduce UI metadata that did not exist in the application but was required for generation. For example business field ordering information had to be incorporated. The final activity was to replicate the application's original UI appearance. We were able to plug in  widget builders for this. In particular, we were able to plug in a mixture of widget builders to replicate the application's original choice of two third-party widget libraries.&lt;br /&gt;&lt;br /&gt;Overall there was a significant amount of existing code that could be removed, though notably some new code also had to be introduced - such as field ordering information and configuration files. Nevertheless, when comparing aggregate sizes of the files in the sample projects before and after retrofitting, we realised between a 30% to 40% reduction in UI code through the introduction of our implementation. For some individual files this metric was as high as 70%, as shown below. On the left is the original XHTML source code for a single UI screen, and on the right the retrofitted version (the source code is not me
