<?xml version="1.0" encoding="utf-8"?>
<!-- generator="Joomla! 1.5 - Open Source Content Management" -->
<?xml-stylesheet href="/site/components/com_jcomments/tpl/default/style.css?v=10" type="text/css"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Unorganized Machines</title>
		<description>Software development</description>
		<link>http://www.unorganizedmachines.com/site/component/content/frontpage</link>
		<lastBuildDate>Tue, 18 Feb 2014 22:12:47 +0000</lastBuildDate>
		<generator>Joomla! 1.5 - Open Source Content Management</generator>
		<language>en-gb</language>
		<item>
			<title>Moving!</title>
			<link>http://www.unorganizedmachines.com/site/other-stuff/41-general/128-moving</link>
			<guid>http://www.unorganizedmachines.com/site/other-stuff/41-general/128-moving</guid>
			<description><![CDATA[<p>Long story short, I'm moving my blog to a new home.&nbsp; All of the content that is here will remain here for reference, but I have disabled comments on any published articles.&nbsp; I have finally had enough of the "c1@lis!!!&nbsp; V1@gra!!!&nbsp; Cheap prices, shady vendors, get your credit card stolen!!!" spam that is posted multiple times a day.&nbsp; Does anybody actually click that crap?&nbsp;</p>
<p> </p>
<p>My new home on the web can be found at <a target="_self" href="http://nathanmcminn.com">nathanmcminn.com</a>, and will launch in the next few days.&nbsp; So if you want to keep in touch, or find my latest articles on brewing, technology, Alfresco or anything else that catches my attention, check the new site.</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Mon, 25 Jun 2012 17:41:22 +0000</pubDate>
		</item>
		<item>
			<title>Robust Porter Recipe</title>
			<link>http://www.unorganizedmachines.com/site/beer-and-brewing/43-brewing/126-robust-porter-recipe</link>
			<guid>http://www.unorganizedmachines.com/site/beer-and-brewing/43-brewing/126-robust-porter-recipe</guid>
			<description><![CDATA[<p>It's no secret that I love dark beers (<a target="_blank" href="http://www.unorganizedmachines.com/site/beer-and-brewing/43-brewing/118-belgian-stout-recipe">mmm, Belgian stout!</a>), especially during the dark days of winter.&nbsp; When the weather turns cold nothing else comes close to a hearty dark beer in a warm pub with friends.&nbsp; One of my personal favorite styles is a porter.&nbsp; <a target="_blank" href="http://www.bjcp.org/2008styles/style12.php">Porters come in several styles</a>, ranging from sweet to dry, with roasty, malty and chocolatey flavors being common across the range.&nbsp;</p>
<p> </p>
<p>One of my favorite styles of porter is the robust porter, BJCP style 12B.&nbsp; I put together this recipe for a competition, and like it enough that it has become a staple in my brewing rotation.&nbsp; Like any good English style of ale, it starts with a generous helping of Maris Otter pale malt.&nbsp; A few lbs of speciality grains layer on the roast flavors in abundance.&nbsp; Finally, I like to toss in a little sour (acidified) malt.&nbsp; It isn't needed to lower the mash pH, as the roasted malts will do a fine job of that.&nbsp; I just like the slightly lactic character that it adds to the finished beer.&nbsp; Here's the total grain bill:</p>
<p> </p>
<p>9.5lb Maris Otter pale malt</p>
<p>2lb biscuit malt</p>
<p>1lb chocolate malt</p>
<p>1lb black malt</p>
<p>0.5lb sour (acidified) malt</p>
<p> </p>
<p>I dough this in at 1.25qt/lb with a target mash temp of ~150F.&nbsp; 60 or 70 minutes is more than enough time to complete conversion.&nbsp; Sparge with your choice of method until you get about 6.5 gallons of wort.&nbsp; Sticking with the English theme, the hops in this recipe are all traditional English fare:</p>
<p> </p>
<p>1oz East Kent Goldings (5% AA) - 80 mins</p>
<p>1oz East Kent Goldings (5% AA) - 20 mins</p>
<p>1.25oz East Kent Goldings (5% AA) - 5 mins</p>
<p> </p>
<p>The boil time is a little longer than the usual 60 minutes for a homebrew recipe.&nbsp; I think this helps darken the beer a bit more (not that it needs it!) and helps develop the flavor a bit more.&nbsp; Once the sweet wort is cooled down, pitch an appropriately English yeast strain.&nbsp; I've brewed this with Wyeast 1275 Thames Valley and White Labs WLP004 Irish Ale, and both turned out great.&nbsp; Just find something fairly neutral with good attenuation.&nbsp; On my brewing rig the starting gravity usually comes out between 1.065 and 1.070.&nbsp; After fermentation it gets down to around 1.015, yielding an ABV of 6.5%- 7%.&nbsp; Keeping with the traditional theme, carbonate to about 2 volumes of CO2.&nbsp; I've done this beer force carbonated in the keg and bottle conditioned and it turns out fine either way.&nbsp; The beer will come out inky black, and should raise a firm mocha colored head.&nbsp; For a fun variation, use this as the base recipe for some porter   exploration.&nbsp; I've brewed this with black licorice added, with some   smoked malt and even with a couple handfuls of ground coffee.&nbsp; Just the thing for a break from the snowball fights and sledding!</p>
<p> </p>
<p>Happy brewing!</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Wed, 11 Jan 2012 03:02:56 +0000</pubDate>
		</item>
		<item>
			<title>Storing and Retrieving Images in MySQL</title>
			<link>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/125-storing-and-retrieving-images-in-mysql</link>
			<guid>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/125-storing-and-retrieving-images-in-mysql</guid>
			<description><![CDATA[<p>One of my ongoing projects is a rich client application written in Java. &nbsp;A recent request from the users was the ability to add handwritten notes or drawings to some of their records. &nbsp;It's simple enough to give the users a simple canvas on which they can draw and store that data as an image. &nbsp;However, we want these notes to be available to the companion web application that runs on our server. &nbsp;The clients synchronize their databases with the server fairly regularly using a database sync tool called <a target="_blank" href="http://www.pervasync.com/">Pervasync</a>, so it should be possible to store the images as a BLOB in the MySQL database on the client and have them sent to the server when the client and server databases are synchronized. &nbsp;As with any vendor claim, I wanted to test whether or not Pervasync could synchronize BLOB data properly. &nbsp;</p>
<p> </p>
<p>To test this, I needed to import a binary file of an image into a test client database, synchronize it to the server, export the BLOB to a file and make sure the image was intact. &nbsp;After a little digging around, it turns out that the SQL to accomplish this is fairly simple. &nbsp;I created a table called "image_test", with two fields. &nbsp;The first is a simple numeric ID field, the second a MEDIUMBLOB. &nbsp;Inserting an image from a file on disk is just this simple:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="sql">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> image_test <span style="color: #66cc66;">(</span>id<span style="color: #66cc66;">,</span> image<span style="color: #66cc66;">)</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">(</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> LOAD_FILE<span style="color: #66cc66;">(</span><span style="color: #ff0000;">'c:/test/test.png'</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span>;</span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>After running the data synchronization, I needed to get the BLOB data back out and into a file. &nbsp;MySQL makes this easy. &nbsp;The output from any query can be dumped to a file by using the INTO OUTFILE/DUMPFILE syntax in a select statement. &nbsp;This is very handy for scheduled jobs that take data from a MySQL database and make it available to other systems. &nbsp;For example:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="sql">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> table_name <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #993333; font-weight: bold;">OUTFILE</span> <span style="color: #ff0000;">'c:/test/outfile.txt'</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>The SQL statement above will take all of the data in the table_name table and dump it out to a text file. &nbsp;This statement can also take the same export_options parameters used while importing a file to set things such as the field and line delimiters. &nbsp;But wait, aren't we dealing with binary data? &nbsp;Wouldn't field and line delimiters just muck things up? &nbsp;Yep, and that's why <a target="_blank" href="http://dev.mysql.com/doc/refman/5.0/en/select.html">MySQL provides the DUMPFILE</a> option instead. &nbsp;Using INTO DUMPFILE instead of INTO OUTFILE, all of the returned data is dumped to a file as a single line. &nbsp;This is just the ticket for fetching my image data and storing it in a local file for verification. &nbsp;The SQL looks like this:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="sql">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
2
3
4
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #993333; font-weight: bold;">SELECT</span> image </span>
<span style="vertical-align: top;"><span style="color: #993333; font-weight: bold;">INTO</span> DUMPFILE <span style="color: #ff0000;">'C:/test/test2.png'</span></span>
<span style="vertical-align: top;"><span style="color: #993333; font-weight: bold;">FROM</span> image_test </span>
<span style="vertical-align: top;"><span style="color: #993333; font-weight: bold;">WHERE</span> id <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span>;</span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>When I first tried to run this under the MySQL workbench it kept choking with an error code 1064, complaining about the syntax. &nbsp;By default, the MySQL workbench inserts a LIMIT 0, 1000 statement into queries before they run. &nbsp;This causes the statement above to fail. &nbsp;To turn off the limit, go to the "edit" menu in MySQL workbench and select "preferences". &nbsp;In the SQL Editor tab, uncheck the "limit rows" option and the query should run, outputting the BLOB data to a file.</p>
<p> </p>
<p>Happy Coding!</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Tue, 10 Jan 2012 18:43:09 +0000</pubDate>
		</item>
		<item>
			<title>Adding a User to an Alfresco Share Site via the Javascript API</title>
			<link>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/124-adding-a-user-to-an-alfresco-share-site-via-the-javascript-api</link>
			<guid>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/124-adding-a-user-to-an-alfresco-share-site-via-the-javascript-api</guid>
			<description><![CDATA[<p>As much as I love working with Alfresco (and I do, really), there are some things about it that still make me scratch my head and say "huh?". &nbsp;One of these things is the way Alfresco Share handles adding users to sites. &nbsp;Typically, a site manager simply invites a user to a Share site via the invite mechanism. &nbsp;95% of the time this is exactly how I want it to work. &nbsp;Sometimes, however, I need to add a user directly without going through the invite process. &nbsp;Strangely, Alfresco admin users cannot simply add users to an arbitrary site. &nbsp;Under older versions of Alfresco (3.1), there was a simple workaround. &nbsp;A user could be added directly to a site group, and thus the site, through the Alfresco Explorer admin interface. &nbsp;In newer versions of Alfresco (3.3.3, in my case), this no longer works. &nbsp;The site manager, collaborator, contributor and consumer groups no longer show up in the admin interface's group search. &nbsp;Aaaaarrrrgh!!!</p>
<p> </p>
<p>Thankfully, there is another way. &nbsp;It takes a little more work. &nbsp;I have written a <a href="http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/97-calling-web-services-from-alfresco-web-scripts" target="_blank">few articles</a> before about the <a href="http://wiki.alfresco.com/wiki/JavaScript_API" target="_blank">Alfresco Javascript API</a>, and we're going to dive into it again to accomplish the task at hand. &nbsp;</p>
<p> </p>
<p>So, let's get started! &nbsp;To add a user directly to a Share site using the Javascript API, two things are required:</p>
<p> </p>
<ol>
<li>Valid Alfresco user credentials. &nbsp;The account needs to either have SiteManager access to the site to which the user will be added, or it need to be an admin account.</li>
<li>A good REST client. &nbsp;There are quite a few to choose from. &nbsp;Depending on the task, I either use the <a href="http://code.google.com/p/rest-client/" target="_blank">WizTools.org RESTClient</a>, or the <a href="http://code.google.com/a/eclipselabs.org/p/restclient-tool/" target="_blank">Eclipse restclient-tool</a>. &nbsp;Either one will work just fine.</li>
</ol>
<p> </p>
<p>The first step is to fire up your REST client or a browser and get an Alfresco authentication ticket. &nbsp;This is done via a simple HTTP GET operation. &nbsp;Just hit the following URL:</p>
<p> </p>
<p><strong>http://&lt;your_alfresco_host&gt;/alfresco/service/api/login?u=username&amp;pw=password</strong></p>
<p> </p>
<p>This will return an authentication ticket that can be appended to all of your future requests. &nbsp;The exact response will look something like this:</p>
<p> </p>
<div class="rj_insertcode">
<div class="rj_insertcode_xml" style="overflow: auto; width: 100%; height: auto; border: 1px solid #054b6e; background: #f8f8f8;">
<table class="xml" style="border-collapse: collapse; width: 100%;">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1<br /></pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ticket<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>TICKET_ce2ffccb238802825af8ae7632160dd87aa234e7b<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ticket<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></pre>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p> </p>
<p>The part of the ticket that should be appended to the URL is the content of the &lt;ticket&gt; element. &nbsp;Make a note of the ticket, it will be required in a moment. &nbsp;Now, fire up your REST client if you haven't already. &nbsp;The client will be used to send a POST to the site membership web service. &nbsp;This web service is used by Alfresco Share internally to (duh) add a user to a site with a specified role. &nbsp;You can browse all of the available web scripts on your system at this URL:</p>
<p> </p>
<p><strong>http://&lt;your_alfresco_host&gt;/alfresco/service/index</strong></p>
<p> </p>
<p>The script we're looking for is in the package /org/alfresco/repository/site/membership, and is called the "Add Site Membership" script. &nbsp;A full description of the script and its parameters can be found here:</p>
<p> </p>
<p><b><span style="font-size: 8pt;"><strong>http://&lt;your_alfresco_host&gt;</strong></span></b></p>
<p><b><span style="font-size: 8pt;"><strong><your_alfresco_host>/alfresco/service/script/org/alfresco/repository/site/membership/memberships.post</your_alfresco_host></strong></span><br /></b></p>
<p> </p>
<p>The script itself is pretty simple. &nbsp;Take a moment to read the description, go over the associated Javascript and get a feel for what it is going to do. &nbsp;I'll wait. &nbsp;Done? &nbsp;Good. &nbsp;If you look at the URL that will accept the POST, you'll see it has a pretty simple signature. &nbsp;Only one part of the URL needs to be changed. &nbsp;You'll need the short name of the site to which you want to add a user. &nbsp;The short name is the "URL name" that you used when you created the site. &nbsp;It's a part of every URL in the site. &nbsp;For this example we'll assume I have created a site called My Test Site with a URL name (short name) of "mytestsite". &nbsp;The URL specified by the script looks like this:</p>
<p> </p>
<p><strong>http://&lt;your_alfresco_host&gt;/alfresco/service/api/sites/{shortname}/memberships</strong></p>
<p> </p>
<p>Looking at the URL template above, it's pretty clear what to do. &nbsp;Substitute the shortname of your site for {shortname}. &nbsp;The last part of the URL is the Alfresco authentication ticket created earlier. &nbsp;Simply append it as a URL parameter named "alf_ticket". &nbsp;</p>
<p> </p>
<p><strong>http://&lt;your_alfresco_host&gt;/alfresco/service/api/sites/mytestsite/memberships?alf_ticket=TICKET_dc233f7e8212825ef8fa8f945762ee24df53bcd7b</strong></p>
<p> </p>
<p>When I first started working on this I tried to use the authentication built into my REST client, but Alfresco constantly complained about HTTP authentication. &nbsp;Appending the ticket in this manner seems to work nicely with every web script I have tried. &nbsp;The last step in this process is to create a JSON object that will go into the body of the POST request. &nbsp;A quick look at the Javascript for the memberships script shows that it expects a JSON object that contains a role (SiteManager, SiteCollaborator, SiteContributor or SiteConsumer, corresponding to the Share site roles), and a person object with a username property. &nbsp;Here's what such a request looks like:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="javascript">
<thead> 
<tr>
<td style="background: #dddddd; color: #054b6e; padding: 2px 0px; text-align: center; font: bold italic 12px Verdana, Geneva, Arial, Helvetica, sans-serif;" colspan="2">JSON Body</td>
</tr>
</thead> 
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1<br />2<br />3<br />4<br />5<br />6<br />7<br /></pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;"><span style="color: #3366cc;">"role"</span><span style="color: #339933;">:</span><span style="color: #3366cc;">"SiteManager"</span><span style="color: #339933;">,</span>	</span><br /><span style="vertical-align: top;"><span style="color: #3366cc;">"person"</span><span style="color: #339933;">:</span></span><br /><span style="vertical-align: top;">	<span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;">		<span style="color: #3366cc;">"userName"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"username"</span></span><br /><span style="vertical-align: top;">	<span style="color: #009900;">}</span></span><br /><span style="vertical-align: top;"><span style="color: #009900;">}</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>Note that this isn't everything that Alfresco includes in a person object, but it's enough to get the job done in this case. &nbsp;Once you have entered this JSON into the body of your POST request, there is one more task and we're ready to send the request. &nbsp;Alfresco is expecting a certain content type for JSON requests. &nbsp;A proper REST client will let you set any additional HTTP headers that the request requires. &nbsp;Add a header called "Content-type" and set its value to "application/json". &nbsp;Once the header is set and your request body is ready go ahead and send the request. &nbsp;You should get back an HTTP OK response, with a body that contains another JSON object with a bit of detail about what was done. &nbsp;For the request and test site in this example, the response should look something like this:</p>
<p> </p>
<table class="javascript" style="border-collapse: collapse; width: 100%;">
<thead> 
<tr>
<td colspan="2" style="background: #dddddd; color: #054b6e; padding: 2px 0px; text-align: center; font: bold italic 12px Verdana, Geneva, Arial, Helvetica, sans-serif;">JSON Response</td>
</tr>
</thead> 
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;">	<span style="color: #3366cc;">"role"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"SiteManager"</span><span style="color: #339933;">,</span></span><br /><span style="vertical-align: top;">&nbsp;</span><br /><span style="vertical-align: top;">	<span style="color: #3366cc;">"authority"</span><span style="color: #339933;">:</span></span><br /><span style="vertical-align: top;">	<span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;">		<span style="color: #3366cc;">"authorityType"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"USER"</span><span style="color: #339933;">,</span></span><br /><span style="vertical-align: top;">		<span style="color: #3366cc;">"fullName"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"User Name"</span><span style="color: #339933;">,</span></span><br /><span style="vertical-align: top;">		<span style="color: #3366cc;">"userName"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"username"</span><span style="color: #339933;">,</span></span><br /><span style="vertical-align: top;">		<span style="color: #3366cc;">"firstName"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"User"</span><span style="color: #339933;">,</span></span><br /><span style="vertical-align: top;">		<span style="color: #3366cc;">"lastName"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"Name"</span><span style="color: #339933;">,</span></span><br /><span style="vertical-align: top;">		<span style="color: #3366cc;">"url"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"<span style="color: #000099; font-weight: bold;">\/</span>alfresco<span style="color: #000099; font-weight: bold;">\/</span>service<span style="color: #000099; font-weight: bold;">\/</span>api<span style="color: #000099; font-weight: bold;">\/</span>people<span style="color: #000099; font-weight: bold;">\/</span>username"</span></span><br /><span style="vertical-align: top;">	<span style="color: #009900;">}</span><span style="color: #339933;">,</span></span><br /><span style="vertical-align: top;">	<span style="color: #3366cc;">"url"</span> <span style="color: #339933;">:</span> <span style="color: #3366cc;">"<span style="color: #000099; font-weight: bold;">\/</span>alfresco<span style="color: #000099; font-weight: bold;">\/</span>service<span style="color: #000099; font-weight: bold;">\/</span>api<span style="color: #000099; font-weight: bold;">\/</span>sites<span style="color: #000099; font-weight: bold;">\/</span>mytestsite<span style="color: #000099; font-weight: bold;">\/</span>memberships<span style="color: #000099; font-weight: bold;">\/</span>username"</span></span><br /><span style="vertical-align: top;">&nbsp;</span><br /><span style="vertical-align: top;"><span style="color: #009900;">}</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>It's entirely possible that there was an easier way to do this that I completely missed. &nbsp;Even if there is, it never hurts to get more familiar with the Javascript API. &nbsp;The Alfresco Javascript API is a powerful tool for Alfresco users. &nbsp;It doesn't matter if you are a developer or admin, learning the Javascript API is essential.</p>
<p> </p>
<p>Happy coding!</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Sun, 14 Aug 2011 19:46:22 +0000</pubDate>
		</item>
		<item>
			<title>Groovy, RCP, JasperReports and Code Reuse</title>
			<link>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/123-groovy-rcp-jasper-reuse</link>
			<guid>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/123-groovy-rcp-jasper-reuse</guid>
			<description><![CDATA[<p>One of my many responsibilities at my day job is guiding the architecture of and helping to develop a fairly large <a href="http://www.eclipse.org/home/categories/rcp.php" target="_blank">Eclipse RCP</a> application. &nbsp;The RCP is a pretty good platform for a desktop Java app. &nbsp;<a href="http://www.eclipse.org/swt/" target="_blank">SWT</a> keeps the look and feel mostly native, and you get a lot of freebies like a help system and update engine that would have to be developed if one were to build a Java application from scratch. &nbsp;Recently I was getting frustrated with the reusability of the service layer of this application and started looking for a new way. &nbsp;The service layer of this application is a set of POJOs that implement the business logic of the application, mostly importantly a complex set of calculations. &nbsp;The idea here was that we could reuse the same objects in the web version, ensuring that the calculations were performed consistently across both the client application and the web application (which serve different audiences, but a very similar purpose).&nbsp;</p>
<p> </p>
<p>This approach worked well, but it did turn out to have some drawbacks. &nbsp;The service objects had dependencies that make it difficult to work with our reports (based on <a href="http://jasperforge.org/index.php?q=project/jasperreports" target="_blank">JasperReports</a>). &nbsp;The result is that the reports end up with their own code for handling the calculations, either in the field expression or in the report query itself. &nbsp;This doubles the amount of work we have to do when a calculation is altered. &nbsp;The service layer objects themselves are compiled and are part of the RCP plugin, meaning that an update to the calculation logic required an update to the plugins. &nbsp;The update process, while very powerful and useful, can be cumbersome to the user community. &nbsp;I don't like forcing a big update on the community any more often than I have to. &nbsp;Finally, we want to have our analysts (who define the calculations) more involved in the development and maintenance of the service layer. &nbsp;These folks are bright, but they aren't coders. &nbsp;Java's syntax is a bit too verbose and obtuse for them to work with directly.</p>
<p> </p>
<p>So, there are few problems to solve. &nbsp;How can I build a service layer for this RCP app that can easily be reused in both a set of web services and a web application, and can also be easily called from JasperReports? &nbsp;How can I deploy this layer in such a way that I don't have to push out a bulky RCP feature update every time an analyst wants to change a calculation? &nbsp;How can I bake-in unit testing? &nbsp;How can I get my analysts more involved in maintaining the calculations and double-checking them for correctness?</p>
<p> </p>
<p><a href="http://groovy.codehaus.org/">Groovy</a>!</p>
<p> </p>
<p>Groovy neatly fits all of my requirements. &nbsp;It runs on the JVM, so it should play nicely alongside both the RCP and our existing web environment. &nbsp;Groovy also can be used to develop scriptlets for JasperReports (with a little work). &nbsp;It's a simple matter to have the RCP application download the latest scripts from the server when it has a chance, and the scripts are tiny making this a very quick operation and much less disruptive to the users (we do it via an embedded Subversion client). &nbsp;Finally, Groovy's syntax is simple and clean enough that the analysts will be able to at least read it, if not write it. &nbsp;As an added bonus, Groovy is also very well suited to <a target="_blank" href="http://docs.codehaus.org/display/GROOVY/Writing+Domain-Specific+Languages">writing a DSL</a> (Domain Specific Language). &nbsp;While this isn't planned for the first go, this capability could be handy in the future if we decide to define a DSL for this app.</p>
<p> </p>
<p>Enough about the "why", time for the "how". &nbsp;Let's look at some code! &nbsp;The simplest way to embed Groovy in an existing Java application of any sort is by using the <a target="_blank" href="http://groovy.codehaus.org/api/groovy/util/GroovyScriptEngine.html">GroovyScriptEngine</a>. &nbsp;This class handles finding, loading, compiling and running a Groovy script. &nbsp;Almost all of the complexity is hidden from the developer. &nbsp;It's a simple as giving the script engine one or more paths to search, binding some variables (if you need them) and telling it which script to run.</p>
<p> </p>
<p>Let's create a simplified example in which we take the unit price for an item and the quantity, using these values to calculate an extended price. &nbsp;For this example we'll assume a working directory of /home/groovytest/scripts. &nbsp;Here's what the Groovy script might look like:</p>
<p> </p>
<table class="groovy" style="border-collapse: collapse; width: 100%;">
<thead> 
<tr>
<td colspan="2" style="background: #dddddd; color: #054b6e; padding: 2px 0px; text-align: center; font: bold italic 12px Verdana, Geneva, Arial, Helvetica, sans-serif;">ExtendedPrice.groovy</td>
</tr>
</thead> 
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
2
3
4
5
6
7
8
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20def"><span style="color: #000000; font-weight: bold;">def</span></a> ep <span style="color: #66cc66;">=</span> <a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20new"><span style="color: #000000; font-weight: bold;">new</span></a> ExtendedPriceService<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">;</span></span>
<span style="vertical-align: top;">extended_price <span style="color: #66cc66;">=</span> ep.<span style="color: #006600;">calcExtended</span><span style="color: #66cc66;">(</span>unit_price, qty<span style="color: #66cc66;">)</span><span style="color: #66cc66;">;</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;"><a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20class"><span style="color: #000000; font-weight: bold;">class</span></a> ExtendedPriceService <span style="color: #66cc66;">{</span></span>
<span style="vertical-align: top;">	<a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20double"><span style="color: #993333;">double</span></a> calcExtended<span style="color: #66cc66;">(</span><a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20double"><span style="color: #993333;">double</span></a> unit_price, <a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20int"><span style="color: #993333;">int</span></a> qty<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></span>
<span style="vertical-align: top;">		<a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20return"><span style="color: #000000; font-weight: bold;">return</span></a> unit_price <span style="color: #66cc66;">*</span> qty<span style="color: #66cc66;">;</span></span>
<span style="vertical-align: top;">	<span style="color: #66cc66;">}</span></span>
<span style="vertical-align: top;"><span style="color: #66cc66;">}</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>Pretty simple stuff. &nbsp;We're creating a new extended_price variable and assigning it the value of unit_price multiplied by quantity. &nbsp;You might be asking yourself, why define the calculation in a class and not just do it in the script and return the result? &nbsp;We'll get to that later. &nbsp;Now, here's how we might call that script from the Java application:</p>
<p> </p>
<table class="java" style="border-collapse: collapse; width: 100%;">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">groovy.lang.Binding</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">groovy.util.GroovyScriptEngine</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ScriptEngineTest <span style="color: #009900;">{</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">(</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> args<span style="color: #009900;">[</span><span style="color: #009900;">]</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span></span>
<span style="vertical-align: top;">    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">{</span></span>
<span style="vertical-align: top;">      <span style="color: #666666; font-style: italic;">//set the paths the script engine will use to find the script</span></span>
<span style="vertical-align: top;">      <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">[</span><span style="color: #009900;">]</span> paths <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a><span style="color: #009900;">[</span><span style="color: #009900;">]</span> <span style="color: #009900;">{</span><span style="color: #0000ff;">"/home/groovytest/scripts"</span><span style="color: #009900;">}</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">      GroovyScriptEngine engine <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> GroovyScriptEngine<span style="color: #009900;">(</span>paths<span style="color: #009900;">)</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;">      <span style="color: #666666; font-style: italic;">//create a Binding object to hold the variables</span></span>
<span style="vertical-align: top;">      <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Abinding+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Binding</span></a> binding <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Abinding+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Binding</span></a><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">      binding.<span style="color: #006633;">setVariable</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"unit_price"</span>, <span style="color: #cc66cc;">3.50</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">      binding.<span style="color: #006633;">setVariable</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"qty"</span>, <span style="color: #cc66cc;">10</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;">      <span style="color: #666666; font-style: italic;">//execute the script</span></span>
<span style="vertical-align: top;">      engine.<span style="color: #006633;">run</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"ExtendedPrice.groovy"</span>, binding<span style="color: #009900;">)</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;">      <span style="color: #666666; font-style: italic;">//print the returned result</span></span>
<span style="vertical-align: top;">      <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">System</span></a>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"Ext Price: "</span> <span style="color: #339933;">+</span> binding.<span style="color: #006633;">getVariable</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"extended_price"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">    <span style="color: #000000; font-weight: bold;">catch</span><span style="color: #009900;">(</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Exception</span></a> ex<span style="color: #009900;">)</span> <span style="color: #009900;">{</span></span>
<span style="vertical-align: top;">      <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">System</span></a>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"Exception: "</span> <span style="color: #339933;">+</span> ex<span style="color: #009900;">)</span><span style="color: #339933;">;</span></span>
<span style="vertical-align: top;">    <span style="color: #009900;">}</span></span>
<span style="vertical-align: top;">  <span style="color: #009900;">}</span></span>
<span style="vertical-align: top;"><span style="color: #009900;">}</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>Looking at the code, it should be pretty clear what is happening here. &nbsp;First, we're setting up an array of Strings that lists all the paths in which scripts are located. &nbsp;Next, we instantiate the script engine and give it the list. &nbsp;Once the script engine is ready, we create a Binding object to hold the variables that we will pass to the script as arguments and give us access to variables in the script itself. &nbsp;Finally, we run the script and get the results back from the Binding object. &nbsp;Simple, simple, simple, and this approach works for both the RCP application and our J2EE web app. &nbsp;Of course our actual calculations are much more complex, but conceptually it's the same thing.</p>
<p> </p>
<p>It's worth noting that you can pass ANY Java object to your Groovy script using the Binding object. &nbsp;Using Hibernate? &nbsp;Just pass in your mapped objects. &nbsp;Alternately, you can pass in the db connection details and use <a target="_blank" href="http://groovy.codehaus.org/Database+features">Groovy's built in database features</a> to pull whatever data you need.</p>
<p> </p>
<p>So we've seen how Groovy can be used to externalize calculations (or any other logic, really) from an RCP application. &nbsp;Now what about that promise of reuse? &nbsp;Now that I've gone through all the effort of embedding Groovy and externalizing my calculations into Groovy scripts, how can I reuse these, say, in a web service? &nbsp;There are a couple of options. &nbsp;Probably the simplest way to reuse the scripts as a service is to use the <a target="_blank" href="http://groovy.codehaus.org/GroovyWS">GroovyWS</a> module to expose the script as a WS-I compliant service. &nbsp;How easy is this? &nbsp;Surprisingly easy.</p>
<p> </p>
<div class="rj_insertcode">
<div style="overflow: auto; width: 100%; height: auto; border: 1px solid #054b6e; background: #f8f8f8;" class="rj_insertcode_groovy">
<table style="border-collapse: collapse; width: 100%;" class="groovy">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
2
3
4
5
6
7
8
9
10
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20import"><span style="color: #000000; font-weight: bold;">import</span></a> <span style="color: #a1a100;">groovyx.net.ws.WSServer</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;"><span style="color: #808080; font-style: italic;">//define a new WSServer</span></span>
<span style="vertical-align: top;"><a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20def"><span style="color: #000000; font-weight: bold;">def</span></a> server <span style="color: #66cc66;">=</span> <a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20new"><span style="color: #000000; font-weight: bold;">new</span></a> WSServer<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;"><span style="color: #808080; font-style: italic;">//set a server node to point to the extended price class created earlier</span></span>
<span style="vertical-align: top;">server.<span style="color: #006600;">setNode</span><span style="color: #66cc66;">(</span><span style="color: #ff0000;">"ExtendedPriceService"</span>, <span style="color: #ff0000;">"http://localhost:80/ExtendedPriceService"</span><span style="color: #66cc66;">)</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;"><span style="color: #808080; font-style: italic;">//crank up the server!</span></span>
<span style="vertical-align: top;">server.<a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20start"><span style="color: #993399;">start</span></a><span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span></span></pre>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p> </p>
<p>Earlier, when we defined the ExtendedPrice class, it would have been visibly simpler to just create a script that took the two variables and returned a calculated value. &nbsp;The reason that we put the calculation in a class is so that we could reference it here and easily expose its methods as a service. &nbsp;It is also pretty simple to take the class defined in ExtendedPrice and <a target="_blank" href="http://grails.org/doc/1.0.x/guide/13.%20Web%20Services.html">use it in a server framework like Grails</a>. &nbsp;It's nice to have options, right?</p>
<p> </p>
<p>Now, what about JasperReports? &nbsp;The whole point of this exercise is to build a single set of scripts that encapsulate my complex calculations and make them available to all of the parts of this application including the RCP app, web app / services and reporting. &nbsp;This part is a bit trickier. &nbsp;While JasperReports supports <a target="_blank" href="http://jasperforge.org/uploads/publish/ireportwebsite/IR%20Website/iReport_groovy.html">Groovy as an expression language</a> (which greatly simplifies report development, IMHO), there is no direct support for scriptlets written in Groovy. &nbsp;However, all is not lost. &nbsp;It just takes a little extra work. &nbsp;Since Groovy can be compiled to a regular old Java class (via groovyc), there's nothing stopping you from writing your scriptlets in Groovy, compiling them and using them in JasperReports. &nbsp;Or, write the scriptlets in Java and call the calculation scripts via the GroovyScriptEngine. &nbsp;Either way works. &nbsp;It's not a perfect solution, but it's pretty simple to whip up an Ant script to compile the Groovy scriptlet wrappers and jar 'em up. &nbsp;I'll have another article coming soon that details exactly how this works with an extended <a target="_blank" href="http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/JRDefaultScriptlet.html">JRDefaultScriptlet</a> that works nicely with Groovy.</p>
<p> </p>
<p>Now that the service script can be used in the RCP and web apps, as a web service, and in the reporting engine, there's just one last piece of the puzzle. &nbsp;Unit testing. &nbsp;Again, Groovy makes this very simple. &nbsp;<a target="_blank" href="http://groovy.codehaus.org/Unit+Testing">JUnit is baked into the Groovy runtime</a>. &nbsp;It's simply a matter of creating a class that extends GroovyTestCase. &nbsp;Here's a simple example that tests the calcExtended method of the ExtendedPriceService class that contains the calculation used throughout this article:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="groovy">
<thead> 
<tr>
<td style="background: #dddddd; color: #054b6e; padding: 2px 0px; text-align: center; font: bold italic 12px Verdana, Geneva, Arial, Helvetica, sans-serif;" colspan="2">ExtendedPriceTest.groovy</td>
</tr>
</thead> 
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
2
3
4
5
6
7
8
9
10
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #808080; font-style: italic;">//define the test case</span></span>
<span style="vertical-align: top;"><a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20class"><span style="color: #000000; font-weight: bold;">class</span></a> ExtendedPriceTest <a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20extends"><span style="color: #000000; font-weight: bold;">extends</span></a> GroovyTestCase <span style="color: #66cc66;">{</span></span>
<span style="vertical-align: top;">&nbsp;</span>
<span style="vertical-align: top;">	<span style="color: #808080; font-style: italic;">//test the extended price calculation</span></span>
<span style="vertical-align: top;">	<a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20void"><span style="color: #993333;">void</span></a> testExtendedPrice<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></span>
<span style="vertical-align: top;">		<span style="color: #808080; font-style: italic;">//create an instance of the extended price service</span></span>
<span style="vertical-align: top;">		<a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20def"><span style="color: #000000; font-weight: bold;">def</span></a> ep <span style="color: #66cc66;">=</span> <a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20new"><span style="color: #000000; font-weight: bold;">new</span></a> ExtendedPriceService<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">;</span></span>
<span style="vertical-align: top;">		<a href="http://www.google.de/search?q=site%3Adocs.codehaus.org/%20assert"><span style="color: #000000; font-weight: bold;">assert</span></a> <span style="color: #cc66cc;">350</span> <span style="color: #66cc66;">==</span> ep.<span style="color: #006600;">calcExtended</span><span style="color: #66cc66;">(</span><span style="color: #cc66cc;">3.5</span>, <span style="color: #cc66cc;">100</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">;</span></span>
<span style="vertical-align: top;">	<span style="color: #66cc66;">}</span></span>
<span style="vertical-align: top;"><span style="color: #66cc66;">}</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>That's all there is to it. &nbsp;Classes that extend GroovyTestCase can either be run directly from the command line, or they can be compiled and run like any other JUnit test case.</p>
<p> </p>
<p>Groovy is a relative newcomer (version 1.0 came out in 2007), but it's already finding a place in my toolbox. &nbsp;Java has its fair share of detractors, but languages like Groovy help make it fun again and can give some significant gains in productivity when applied properly.</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Tue, 05 Jul 2011 00:22:38 +0000</pubDate>
		</item>
		<item>
			<title>Alfresco - How to Find All Content Created by a User</title>
			<link>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/122-alfresco-how-to-find-all-content-created-by-a-user</link>
			<guid>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/122-alfresco-how-to-find-all-content-created-by-a-user</guid>
			<description><![CDATA[<p>I was recently approached with a request to find all the content that has been created by a particular user in our Alfresco repository. &nbsp;At first this seemed like a simple request, surely there is a way to view the user account through the Explorer or Share interface and see everything they have created. &nbsp;Not so, unfortunately. &nbsp;The Share interface will show you content created recently, but only goes back a short amount of time. &nbsp;The Explorer interface will allow an admin to see how much disk a user has consumed, but not all of their individual pieces of content. &nbsp;So, how do we find what we're looking for?</p>
<p> </p>
<p>The answer lies in Alfresco's robust search capabilities. &nbsp;Everything in Alfresco is a node, and you can search on any property of those nodes if you know the document model and the search syntax. &nbsp;To further complicate things Alfresco offers several search options, each with its own pros/cons and syntax. &nbsp;Perhaps the most powerful and useful of these is the Lucene search. &nbsp;There are a few ways to execute a Lucene search in Alfresco. &nbsp;In this case I chose to use the Alfresco Node Browser. &nbsp;This console can be accessed at the following URL on your Alfresco installation:</p>
<p> </p>
<p>https://&lt;your_server_name&gt;/alfresco/faces/jsp/admin/node-browser.jsp</p>
<p> </p>
<p>Once you have signed in and can see the node browser, one of the first things to take note of is the "Search" section at the top of the page. &nbsp;The drop down menu provided allows you to specify the type of search desired. &nbsp;For this example, select "Lucene". &nbsp;Lucene has its own search syntax, some of which is documented in the <a target="_blank" href="http://wiki.alfresco.com/wiki/Search_Documentation#Lucene_Language">Alfresco Wiki</a>. &nbsp; &nbsp;There is also an <a href="http://www.slideshare.net/JM.Pascal/alfresco-search-tutorial-presentation">excellent presentation</a> up on SlideShare that details the various Alfresco search options and has some great examples of how to search for Node aspects, properties, etc using Lucene.</p>
<p> </p>
<p>OK, so I know I want to use Lucene to search my repository, I know what property I am looking for (creator), I know what value I need that property to have (the user's login) and I have the Node Browser page loaded. &nbsp;What's the exact string to search for? &nbsp;In Lucene, the syntax for searching for nodes that have a certain property value is simple.</p>
<p> </p>
<div class="rj_insertcode">
<div style="overflow: auto; width: 100%; height: auto; border: 1px solid #054b6e; background: #f8f8f8;" class="rj_insertcode_xml">
<table style="border-collapse: collapse; width: 100%;" class="xml">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;">@<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property_qname<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>\:"property_value"</span></pre>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p> </p>
<p>So, back to my original request. &nbsp;I need all the documents created by user "John Q. Public", who has the login of "johnqpublic". &nbsp;</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="xml">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1
</pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;">@<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;creator<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>\:"johnqpublic"</span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>Pretty simple, right? &nbsp;This same syntax can be applied to search for nodes with any property value in the Alfresco Repository. &nbsp;</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Fri, 10 Jun 2011 14:55:00 +0000</pubDate>
		</item>
		<item>
			<title>Need a Resume Boost?  Get Involved with an Open Source Project - Part 1</title>
			<link>http://www.unorganizedmachines.com/site/software-and-technology/44-open-source/120-need-a-resume-boost-get-involved-with-an-open-source-project</link>
			<guid>http://www.unorganizedmachines.com/site/software-and-technology/44-open-source/120-need-a-resume-boost-get-involved-with-an-open-source-project</guid>
			<description><![CDATA[<p>There are a lot of excellent reasons to get involved with an open source project.&nbsp; You can learn a new language, improve your existing skills, be challenged by a community that is at the top of their field or even get better at managing complex distributed projects.&nbsp; There are also dozens of ways to participate.&nbsp; Open up a project's bug tracker and find an issue that needs to be fixed.&nbsp; Write a useful new extension or plugin.&nbsp; Even if you don't code, just about every open source project out there could use more testing, more documentation and tutorials and help handling the load on their support forums and mailing lists. If you are a heavy user of open source software it feels great to give something back to the community that has contributed so much.</p>
<p> </p>
<p>One of the most overlooked reasons to get involved with an open source project is career advancement.&nbsp; Developers, project managers, testers and technical writers are judged on their skills, and what better way to show off what you can do than to do it in public!&nbsp; I've always suspected that this is the case, but had no way to really quantify what open source participation means to potential job seekers.&nbsp; So, I set out to find out.&nbsp; This is the first of a series of articles about how employers, recruiters and other developers view open source contribution, how to get the most out of your work and how to couch it on your resume.</p>
<p> </p>
<p>If you are in a technology field, you probably hear from recruiters fairly regularly.&nbsp; It seems to be one of the more common ways for tech folk to find a new gig.&nbsp; This includes both corporate recruiters that work for a specific company and freelance recruiters that find candidates for a number of different clients.&nbsp; To find out how these professionals view open source experience I turned the tables on them a little bit.&nbsp; Over the last several months whenever a recruiter contacted me about a position I replied with a counter-proposal:&nbsp; I love my job and don't want to leave, but I'd like to interview you instead.&nbsp; Almost all of them were good sports and over a few months I was able to collect some interesting (if anecdotal) information about how open source is used at their client companies, how they view open source experience and even a little bit about how open source projects can be fertile hunting grounds for recruiters.</p>
<p> </p>
<p>What I found was mostly expected, but there were some surprises.&nbsp; Recruiters and their clients have a universally positive view of those that participate in open source projects at all levels.&nbsp; One corporate recruiter at a firm in Pennsylvania went so far as to say "I think people who are active in the open source  community are rock stars. &nbsp;The average employee works 8 hours a day, the  rock stars continue to do it after hours not because they have to but  because they want to. &nbsp;I don't think there is an employer in the world  that would look at that as anything but a positive.".&nbsp; While I myself am <a target="_blank" href="http://blog.hirelite.com/what-developers-think-when-you-say-rock-star">not a big fan of the "Rock Star" analogy</a>, the point is well taken.&nbsp; People that code, document, test and otherwise contribute outside of what is required for their career demonstrate a passion for the job that employers find very attractive.</p>
<p> </p>
<p>Companies that make use of open source technologies naturally gravitate toward people that are active in the ecosystem around those technologies.&nbsp; For example, if a company is looking for a good Drupal developer, it would be perfectly natural to scour the Drupal support forums, module contributors and even commit logs for active, competent candidates.&nbsp; Is this poaching?&nbsp; Maybe, but that is part of a recruiter's job.&nbsp; As <a target="_blank" href="http://www.infoq.com/news/2011/03/gartner-oss-survey">open source software continues to weave itself into the fabric of IT organizations large and small</a>, this trend will only continue.&nbsp; Recruiters know where to find people with experience in the technologies that they need, and those that are active in their project communities will have an edge when it comes to finding employment.</p>
<p> </p>
<p>On a slightly more cautionary note, don't think that casual open-source participation is equivalent to work experience.&nbsp; Based on my interviews it isn't viewed as such, except in some rare cases.&nbsp; If you are a core contributor to the Linux Kernel, for example, you can certainly claim equivalence.&nbsp; If you release a few bug fixes and write a plugin or two?&nbsp; Not so much.&nbsp; Employment means a lot more than your technical work.&nbsp; It means getting along with colleagues and working on a team.&nbsp; It means building what the customer needs or wants, not writing code that scratches your particular itch as is so often the case in the open source world.&nbsp; Writing code to satisfy yourself is awesome, but it isn't the same thing as writing it to a customer's specification.&nbsp; Also be very careful to stay positive and professional on project forums and mailing lists.&nbsp; The content posted to these forums is basically around forever and you have no control over the content retention, so make sure to put your best foot forward.&nbsp; You wouldn't want to have a potential employer Google your name and find a bunch of petty fighting and name calling.</p>
<p> </p>
<p>In part 2 of this series, I set out to interview a much more elusive group:&nbsp; The CIO.</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Sat, 26 Feb 2011 01:52:22 +0000</pubDate>
		</item>
		<item>
			<title>Apache Chemistry Graduation</title>
			<link>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/119-apache-chemistry-graduation</link>
			<guid>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/119-apache-chemistry-graduation</guid>
			<description><![CDATA[<p>The CMIS standard provides a vendor-neutral interface to content repositories.&nbsp; <a target="_blank" href="http://en.wikipedia.org/wiki/Content_Management_Interoperability_Services">CMIS</a> is well-supported by the likes of IBM, Alfresco, Nuxeo and Microsoft, among others.&nbsp; While the server side is important, a good set of client libraries will make it easier to take advantage of the new interface.</p>
<p> </p>
<p>Enter Apache Chemistry.&nbsp; Chemistry is a set of client and server libraries for applications written in Java, PHP, Python and now, .Net.&nbsp; Chemistry was in the Apache Incubator for a while but has now officially <a target="_blank" href="https://blogs.apache.org/foundation/entry/the_apache_software_foundation_announces11">graduated to a top-level Apache project</a>.&nbsp; Congrats to the project team and their continued success!</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Wed, 23 Feb 2011 22:30:32 +0000</pubDate>
		</item>
		<item>
			<title>Belgian Stout Recipe</title>
			<link>http://www.unorganizedmachines.com/site/beer-and-brewing/43-brewing/118-belgian-stout-recipe</link>
			<guid>http://www.unorganizedmachines.com/site/beer-and-brewing/43-brewing/118-belgian-stout-recipe</guid>
			<description><![CDATA[<p>I have a real love of Belgian beers, and I love what American brewers have done with Belgian inspiration.&nbsp; One of my favorite stateside breweries is<a target="_blank" href="http://www.allagash.com/brewery.htm"> Allagash</a>, in Portland, Maine.&nbsp; Allagash not only makes excellent examples of the typical Belgian-style White, Double, Tripel and Grand Cru styles, but they also do some slightly more esoteric barrel aged beers and experimental brews.&nbsp; One of my top picks from this Maine favorite is <a target="_blank" href="http://www.allagash.com/black.htm">Allagash Black</a>.&nbsp; This Belgian-style stout has big roast flavors reminiscent of chocolate and coffee layered on top of the slightly tart dark fruits that Belgian yeasts can produce in spades.&nbsp; In short, it's delicious.&nbsp;</p>
<p> </p>
<p>It's also expensive, and a prime candidate for a homebrew recipe!&nbsp; Allagash gives a hint of the grain bill on their web site, mentioning 2 row German malt, torrefied wheat and oats.&nbsp; Of course there has to be a healthy dose of dark roasted grains.&nbsp; I wanted a bit more of the dark fruit flavor, so I added a bit of Special B to the mix.&nbsp; Here's the grain bill:</p>
<p> </p>
<p>12lb Pale 2 row malt - I used a Belgian, but any would do fine.&nbsp;</p>
<p>1lb torrefied wheat</p>
<p>1lb Belgian chocolate malt</p>
<p>1lb roast barley</p>
<p>1lb <a href="http://www.specialtymalts.com/dingemans/descriptions.html">Dingeman's Special B</a></p>
<p>2lb Munich</p>
<p>1lb <a target="_blank" href="http://darkcandi.com/d.html">Belgian Dark Candi syrup</a></p>
<p> </p>
<p>One of my favorite adjuncts to add to a dark Belgian beer (especially in my Double) is a dark candi syrup.&nbsp; Not to be confused with the dark rocks sold in many shops, this stuff is a pungent dark caramelized sugar syrup and lends a great flavor to the finished beers.&nbsp; It's also an easy way to bump the gravity a touch.&nbsp; The Belgians tend to make digestible beers, with a high degree of attenuation.&nbsp; For this reason I mash at a pretty low temperature with a long mash.&nbsp; Usually around 150F for 75 or 80 minutes does the trick.&nbsp; I like a thick mash, around 1.25 qt/lb, and fly sparge until I have collected about 6 gallons.</p>
<p> </p>
<p>Allagash Black doesn't have a ton of hop bitterness or aromatics.&nbsp; It's definitely dominated by the dark grains.&nbsp; I use the following hop additions:</p>
<p> </p>
<p>1oz Galena (14.1%) - 60 mins</p>
<p>1oz East Kent Goldings (4.5%) - 30 mins</p>
<p>1oz East Kent Goldings (4.5%) - Flameout</p>
<p> </p>
<p>On my relatively inefficient setup I end up with 5 gallons of wort with a starting gravity of 1.080 or so.&nbsp; A Belgian-style beer calls for a Belgian yeast strain, and I usually use WLP530 here.&nbsp; 3 weeks in the fermenter in the mid 70s gets the gravity down to about 1.010, yielding a beer that comes out around 7.5%.&nbsp; As is traditional, I like to bottle condition this beer instead of kegging.&nbsp; 6 oz of corn sugar gets the carbonation to 3 volumes at 75F.&nbsp; To add a little extra complexity, use a fresh dose of a different Belgian yeast strain for the bottle fermentation.</p>
<p> </p>
<p>Brew it up and enjoy!&nbsp;</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Tue, 15 Feb 2011 00:19:58 +0000</pubDate>
		</item>
		<item>
			<title>What's New in HTML5 Forms</title>
			<link>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/117-whats-new-in-html5-forms</link>
			<guid>http://www.unorganizedmachines.com/site/software-and-technology/34-software-development/117-whats-new-in-html5-forms</guid>
			<description><![CDATA[<p>HTML5 has been getting a lot of buzz, and for good reason. &nbsp;The next version of the ubiquitous web standard is currently winding its way through the W3C draft process and includes tons of long overdue improvements. &nbsp;Despite its draft status, browser vendors have been quickly adding support for the new standard. &nbsp;Based on my limited testing (Safari 5.0.3, Firefox 3.6.13, Chrome 8.0.552.231, all on Mac) Safari and Chrome have the best support for HTML5 at the moment. &nbsp;If you want to see how well your browser of choice supports HTML5, there is a <a href="http://html5test.com/" target="_blank">handy test page</a> that will give you the details of which parts of the standard your browser can / can't handle.</p>
<p> </p>
<p>There is a lot new in HTML5, including a ton of new elements such as the &lt;canvas&gt; and &lt;video&gt;, and &lt;audio&gt; elements, which have received a lot of attention. &nbsp;However, HTML5 also includes many useful changes to existing elements, adding new attributes and behaviors. &nbsp;Of these, some of the most significant involve the way that forms are built and handled.</p>
<p> </p>
<p>As in HTML4, all of the input fields in a form are built up using &lt;input&gt; elements. &nbsp;In HTML4 there were a fairly limited number of input element types. &nbsp;Buttons, text / password fields, radio buttons / checkboxes, images, hidden fields and files were pretty much it. &nbsp;We have all built additional functionality on top of these input types, such as date pickers, color pickers, etc. &nbsp;HTML5 adds a lot of new valid values for the input element's 'type' attribute, including types for URLs, phone numbers, colors, dates (and their constituent parts) and email addresses. &nbsp;The idea behind these new input types is for the user agent (that is, the browser) to be able to provide specialized controls for these specialized data types, freeing the developer from having to write them and giving users a more consistent experience across sites.</p>
<p> </p>
<p>The &lt;input&gt; element has also been endowed with quite a few totally new attributes. &nbsp;One of the ones that I am most exited about is the 'form' attribute (which has also been added to the &lt;textarea&gt;, &lt;select&gt;, &lt;fieldset&gt;, &lt;button&gt; and &lt;output&gt; elements). &nbsp;The 'form' attribute allows you to specify to which form a particular input element belongs, even if it is not a descendant of the &lt;form&gt; element. &nbsp;In HTML4, input elements must be nested within the form they belong to, as in this simple example:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="html4strict">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1<br />2<br />3<br />4<br /></pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/form.html"><span style="color: #000000; font-weight: bold;">form</span></a> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'mainForm'</span> <span style="color: #000066;">action</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'submit_url'</span> <span style="color: #000066;">method</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'POST'</span>&gt;</span></span><br /><span style="vertical-align: top;">	<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">input</span></a> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'text'</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'firstName'</span><span style="color: #66cc66;">/</span>&gt;</span></span><br /><span style="vertical-align: top;">	<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">input</span></a> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'text'</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'lastName'</span><span style="color: #66cc66;">/</span>&gt;</span></span><br /><span style="vertical-align: top;"><span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/form.html"><span style="color: #000000; font-weight: bold;">form</span></a>&gt;</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>In HTML5, you are freed from this constraint. &nbsp;Instead, you can specify to which form an input element belongs by using the 'form' attribute of the &lt;input&gt; element, like so:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="html4strict">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1<br />2<br />3<br />4<br /></pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/form.html"><span style="color: #000000; font-weight: bold;">form</span></a> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'mainForm'</span> <span style="color: #000066;">action</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'submit_url'</span> <span style="color: #000066;">method</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'POST'</span><span style="color: #66cc66;">/</span>&gt;</span></span><br /><span style="vertical-align: top;">&nbsp;</span><br /><span style="vertical-align: top;"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">input</span></a> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'text'</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'firstName'</span> form<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'mainForm'</span><span style="color: #66cc66;">/</span>&gt;</span></span><br /><span style="vertical-align: top;"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">input</span></a> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'text'</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'lastName'</span> form<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'mainForm'</span><span style="color: #66cc66;">/</span>&gt;</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>This will definitely make design simpler, especially for pages with multiple forms. &nbsp;It is unclear whether or not an element can belong to multiple forms, but I do not think that this is possible.</p>
<p> </p>
<p>Another neat feature of HTML5 is the way it handles form validation. &nbsp;We've all used JavaScript to do form validation either with a <a target="_blank" href="http://docs.jquery.com/Plugins/validation">framework like jQuery</a> or with a function that looks something like this:</p>
<p> </p>
<table style="border-collapse: collapse; width: 100%;" class="javascript">
<tbody>
<tr class="li1">
<td style="width: 1px; background: #f0f0f0; vertical-align: top; color: #676f73; border-right: 1px dotted #dddddd; font-size: 12px; text-align: right;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></pre>
</td>
<td style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;">
<pre style="margin: 0; background: none; vertical-align: top; padding: 0px 4px; font-size: 12px;"><span style="vertical-align: top;"><span style="color: #003366; font-weight: bold;">function</span> validate<span style="color: #009900;">(</span>field<span style="color: #009900;">)</span> <span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;">	<span style="color: #000066; font-weight: bold;">with</span> <span style="color: #009900;">(</span>field<span style="color: #009900;">)</span><span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;">  		<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">(</span>value<span style="color: #339933;">==</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">||</span>value<span style="color: #339933;">==</span><span style="color: #3366cc;">""</span><span style="color: #009900;">)</span><span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;">    			<span style="color: #000066;">alert</span><span style="color: #009900;">(</span><span style="color: #3366cc;">'please enter a value'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>return <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span></span><br /><span style="vertical-align: top;">  		<span style="color: #009900;">}</span><span style="color: #000066; font-weight: bold;">else</span><span style="color: #009900;">{</span></span><br /><span style="vertical-align: top;">    			<span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span></span><br /><span style="vertical-align: top;">  		<span style="color: #009900;">}</span></span><br /><span style="vertical-align: top;">	<span style="color: #009900;">}</span></span><br /><span style="vertical-align: top;"><span style="color: #009900;">}</span></span></pre>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>In HTML5 this sort of simple validation is no longer required. &nbsp;Instead of writing JavaScript to validate your forms, you can simply specify which &lt;input&gt; and &lt;textarea&gt; elements must have values provided by using the new 'required' attribute. &nbsp;If you set the 'required' attribute to 'true', the form to which the input element is attached will not submit unless a value is provided. &nbsp;This form-level validation can be easily turned off by setting the 'novalidate' attribute of the form to 'true'. &nbsp;This turns off validation for all the elements that are attached to the form.</p>
<p> </p>
<p>Disabling forms, or sections of forms, has also become much simpler. &nbsp;Using the &lt;fieldset&gt; element, you can group &lt;input&gt; elements together into logical field sets just like you can do in HTML4. &nbsp;However, HTML5 adds a 'disabled' attribute to the &lt;fieldset&gt; element. &nbsp;This allows you to disable all of the descendant &lt;input&gt; elements with a single attribute change. &nbsp;This is easier than having to go through and disable each individual &lt;input&gt; element separately.</p>
<p> </p>
<p>For a full list of what's new from HTML4 to HTML5, check the <a target="_blank" href="http://www.w3.org/TR/html5-diff/">W3C Working Draft</a>.</p>
<p> </p>
<p>Happy coding!</p>]]></description>
			<author>nmcminn@gmail.com (Nathan McMinn)</author>
			<category>frontpage</category>
			<pubDate>Thu, 30 Dec 2010 16:23:35 +0000</pubDate>
		</item>
	</channel>
</rss>
