<?xml version="1.0" encoding="utf-8"?>
			
			<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://web.resource.org/cc/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">

			<channel>
			<title>ArgumentCollection - Broadchoice Engineering - Tools and Technology</title>
			<link>http://blog.broadchoice.com/index.cfm</link>
			<description>The Broadchoice engineering team blog.</description>
			<language>en-us</language>
			<pubDate>Mon, 06 Sep 2010 13:56:42 -0400</pubDate>
			<lastBuildDate>Wed, 11 Mar 2009 19:04:00 -0400</lastBuildDate>
			<generator>BlogCFC</generator>
			<docs>http://blogs.law.harvard.edu/tech/rss</docs>
			<managingEditor>ac@broadchoice.com</managingEditor>
			<webMaster>ac@broadchoice.com</webMaster>
			<itunes:subtitle></itunes:subtitle>
			<itunes:summary></itunes:summary>
			<itunes:category text="Technology" />
			<itunes:category text="Technology">
				<itunes:category text="Podcasting" />
			</itunes:category>
			<itunes:category text="Technology">
				<itunes:category text="Tech News" />
			</itunes:category>
			<itunes:keywords></itunes:keywords>
			<itunes:author></itunes:author>
			<itunes:owner>
				<itunes:email>ac@broadchoice.com</itunes:email>
				<itunes:name></itunes:name>
			</itunes:owner>
			<itunes:image href="" />
			<image>
				<url></url>
				<title>ArgumentCollection - Broadchoice Engineering</title>
				<link>http://blog.broadchoice.com/index.cfm</link>
			</image>
			<itunes:explicit>no</itunes:explicit>
			
			
			
			
			
			<item>
				<title>Broadchoice Community Platform 2.0.11 Released</title>
				<link>http://blog.broadchoice.com/index.cfm/2009/3/11/Broadchoice-Community-Platform-2011-Released</link>
				<description>
				
				As I Twittered on Monday, the new release of the &lt;a
href=&quot;http://www.broadchoice.com/products/community_platform/&quot;&gt;Broadchoice Community Platform&lt;/a&gt; (our hosted content management system) was in QA and had hit zero bugs. QA completed successfully so today we pushed the new release to production. It&apos;s mostly a bug fix and minor enhancements release but it contains one new feature I wanted to talk about from a technical point of view.

The Community Platform has a number of &quot;modules&quot; (applications) that you can add to a page and one of those is a list of documents for download (or external links). You add the module to the page and then select documents (from your document library) to add to that module. In previous releases, authors had to add documents in the order that they wanted them to appear on the (generated) web page. We looked at a number of UI options for allowing authors to &quot;rank&quot; the documents within the module but felt most of them were fairly clunky, involving entering ranking numbers to reorder things or up/down arrows requiring authors to move documents one position at a time. Ugh!

Ray pointed me at one of the cool &lt;a href=&quot;http://jqueryui.com/&quot;&gt;jQuery UI&lt;/a&gt; interactions: sortable. It allows you to mark a &quot;container&quot; tag (e.g., a div) as sortable and then users can drag&apos;n&apos;drop the &quot;child&quot; elements into the order they want. You can attach event handlers that fire at various points in the drag&apos;n&apos;drop operation.

Here&apos;s how we do it:
&lt;code&gt;
&lt;div id=&quot;sortable&quot;&gt;
  &lt;cfloop query=&quot;documents&quot;&gt;
    &lt;div id=&quot;doctag_#documents.id#&quot; onMouseOver=&quot;setCursor(this,&apos;move&apos;)&quot; onMouseOut=&quot;setCursor(this,&apos;auto&apos;)&quot;&gt;
      #documents.name# ... etc ...
    &lt;/div&gt;
  &lt;/cfloop&gt;
&lt;/div&gt;
&lt;/code&gt;
That&apos;s all you need in the HTML. Then you add the following JavaScript:
&lt;code&gt;
$(&apos;#sortable&apos;).sortable({
  update: function(event,ui) {
    jQuery.get(&apos;/updateRank.cfm?&apos; + $(&apos;#sortable&apos;).sortable(&apos;serialize&apos;));
}
&lt;/code&gt;
This causes two things to happen:
&lt;ol&gt;
&lt;li&gt;jQuery marks the sortable div contents as being, well, sortable!&lt;/li&gt;
&lt;li&gt;jQuery adds an event handler for update - when the drag&apos;n&apos;drop operation completes - that invokes a URL on the server, passing in the serialized data from the children of the sortable div, i.e., the id values as a list in the new order: doctag[]=1,3,4,2. It assumes an underscore as a separator.&lt;/li&gt;
&lt;/ol&gt;
The server side code simply updates the module data to put the documents in the specified order.
				
				</description>
						
				
				<category>Tools and Technology</category>				
				
				<category>Broadchoice Shares Knowledge</category>				
				
				<pubDate>Wed, 11 Mar 2009 19:04:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2009/3/11/Broadchoice-Community-Platform-2011-Released</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Unit Testing Improves Your Love Life</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/11/26/Unit-Testing-Improves-Your-Love-Life</link>
				<description>
				
				Oh, sorry, that was the title of the BACFUG presentation by Bill Shelton and Marc Esher (of MXUnit fame)!

Unit testing has defined my working day. I&apos;ve been working on the licensing subsystem of the next build of the &lt;a href=&quot;http://www.broadchoice.com/what_is_workspace/&quot;&gt;Broadchoice Workspace&lt;/a&gt; today and because we practice Test-Driven Development (thanx Brian!), that means writing unit tests &quot;first&quot; or at least alongside the production code.

I started by writing the License bean and an accompanying LicenseTest. The bean has a handful of properties and two methods. The unit test has nine test methods.

Fairly confident that the bean was correct, I moved on to the data layer. Apart from encryption, this mostly follows our well-tested generic Hibernate DAO. That meant only a couple of unit tests.

Once those tests passed, I moved on to the service layer. Six unit tests for four service methods.

At this point I&apos;m ready to write the remote service facade (which implements user-level security) but I&apos;m fairly confident our licensing subsystem will work as expected. 623 lines of code, just over half of which is unit tests (327 lines to 296 production code). I&apos;ll probably add some more data layer unit tests since I have a couple of &quot;untested&quot; methods (they&apos;re used in the service layer tests).

Unit tests may seem dull and tedious but they really can make your life easier.
				
				</description>
						
				
				<category>Tools and Technology</category>				
				
				<category>Broadchoice Shares Knowledge</category>				
				
				<pubDate>Wed, 26 Nov 2008 04:06:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/11/26/Unit-Testing-Improves-Your-Love-Life</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Cocomo Post-MAX</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/11/24/Cocomo-PostMAX</link>
				<description>
				
				Adobe&apos;s Cocomo technology entered public beta at MAX and the day one keynote featured an extremely brief demo of a little of what Cocomo can do. Nigel Pegg (of the Cocomo team) did a couple of sessions during the conference which I had planned to attend but, as is usual with MAX, my schedule got derailed early and often so I didn&apos;t make either of them. I&apos;ll be writing up my MAX experience on my own blog shortly (and may contribute an extended version as an article for &lt;a href=&quot;http://fusionauthority.com/&quot;&gt;Fusion Authority&lt;/a&gt; as I have done with conferences in the past).

Now MAX is over, Nigel has &lt;a href=&quot;http://blogs.adobe.com/collabmethods/2008/11/cocomo_public_beta_max_and_exh.html&quot;&gt;blogged more about Cocomo&lt;/a&gt; and talks about what beta testers get access to in terms of source code, documentation and features. Nigel includes a nod to me for contributing the Groovy version of the provisioning script and and a mention of the Broadchoice Workspace which uses Cocomo behind the scenes - and which we demo&apos;d at both the Adobe Partner booth (Wednesday lunchtime) and on the &lt;a href=&quot;http://ribbit.com/&quot;&gt;Ribbit&lt;/a&gt; booth.

If you didn&apos;t get a chance to look at Ribbit, check out this &lt;a href=&quot;http://video.ribbit.com/developer_site/chuck/video1.html&quot;&gt;video of Joe and Rick (our CTO) talking about Ribbit integration&lt;/a&gt; into Broadchoice Workspace (as a proof of concept for now - would the ability to make phone calls from within the Workspace be valuable to you?).
				
				</description>
						
				
				<category>Tools and Technology</category>				
				
				<category>Workspace</category>				
				
				<pubDate>Mon, 24 Nov 2008 15:42:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/11/24/Cocomo-PostMAX</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Some Code Statistics for Broadchoice Workspace</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/11/14/Some-Code-Statistics-for-Broadchoice-Workspace</link>
				<description>
				
				Now that the &lt;a href=&quot;http://www.broadchoice.com/what_is_workspace/&quot; target=&quot;_blank&quot;&gt;Broadchoice Workspace&lt;/a&gt; has been officially released, I thought I&apos;d post a quick entry with some code statistics. I ran the codebase through a line counting tool that gives a breakdown by file, folder, language, etc. We all know that lines of code is not a very good way to judge quality or effort, but it is still interesting in a general way. This is only lines of code, all blank lines and comments were excluded:

&lt;ul&gt;
&lt;li&gt;Total Lines of Code: 50,125&lt;/li&gt;
&lt;li&gt;Total Files: 633&lt;/li&gt;
&lt;li&gt;Lines of MXML: 10,784&lt;/li&gt;
&lt;li&gt;Lines of ActionScript: 12,675&lt;/li&gt;
&lt;li&gt;Lines of CFML: 7,730&lt;/li&gt;
&lt;li&gt;Lines of Groovy: 8,878&lt;/li&gt;
&lt;li&gt;Lines of XML: 1,757&lt;/li&gt;
&lt;li&gt;Lines of CSS, HTML, JavaScript, etc.: 7,612&lt;/li&gt; 
&lt;li&gt;Lines of SQL: 1,089&lt;/li&gt;
&lt;li&gt;Lines excluded as comments or blank: 15,778&lt;/li&gt;
&lt;/ul&gt;
				
				</description>
						
				
				<category>Workspace</category>				
				
				<category>General</category>				
				
				<category>Tools and Technology</category>				
				
				<category>AIR</category>				
				
				<category>Broadchoice Shares Knowledge</category>				
				
				<pubDate>Fri, 14 Nov 2008 20:10:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/11/14/Some-Code-Statistics-for-Broadchoice-Workspace</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Is it ColdFusion or Groovy?</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/11/3/Is-it-ColdFusion-or-Groovy</link>
				<description>
				
				Here at &lt;a href=&quot;http://www.broadchoice.com&quot;&gt;Broadchoice&lt;/a&gt; we&apos;ve been working on our &lt;a href=&quot;http://blog.broadchoice.com/index.cfm/2008/9/7/Behind-The-Curtain&quot;&gt;new product&lt;/a&gt; for close to three months now. I&apos;ve gotten a crash course in Groovy, Spring, and Hibernate, all of which are slightly familiar to me from my time with ColdSpring, Transfer, and Java. I&apos;m really digging these new technologies, but of course, I&apos;m a die hard ColdFusion user at heart. A few weeks backs I needed to work on a quick iPhone web application prototype. Joe set up the connection and all I had to do was write CFML (lucky me). Little did I know that along with setting up basic CFML compatibility on the server, Joe also added one of the slickest things I&apos;ve seen ever in my life as a developer.

The application I&apos;m working on is pretty simple, but I wanted to use Model-Glue 3 for it since - well - you never know when a simple prototype will turn into a large, complex application. The following code snippet comes from a controller used to load bookmarks:

&lt;code&gt;
    &lt;cffunction name=&quot;getBookmarks&quot; output=&quot;false&quot;&gt;
        &lt;cfargument name=&quot;event&quot; /&gt;
        &lt;cfset var u = arguments.event.getValue(&quot;currentuser&quot;)&gt;
       
        &lt;!--- In theory currentuser should always exist, but... ---&gt;
        &lt;cfif not isSimpleValue(u)&gt;
            &lt;!--- space only? ---&gt;
            &lt;cfif arguments.event.valueExists(&quot;space&quot;)&gt;
                &lt;cfset arguments.event.setValue(&quot;bookmarks&quot;, beans.contentService.findContentBySpace(arguments.event.getValue(&quot;space&quot;),[&quot;Bookmark&quot;]))&gt;
            &lt;cfelse&gt;
                &lt;cfset arguments.event.setValue(&quot;bookmarks&quot;, beans.contentService.findUsersContent(u,[&quot;Bookmark&quot;]))&gt;
            &lt;/cfif&gt;
        &lt;/cfif&gt;
           
    &lt;/cffunction&gt;
&lt;/code&gt;
      
Nothing in the above code should be too odd or even that exciting really. I&apos;m using a service (injected via the beans scope in Model-Glue 3) to retrieve my content. My controller begins with...

&lt;code&gt;
&lt;cfcomponent output=&quot;false&quot; hint=&quot;I am a Model-Glue controller.&quot; extends=&quot;ModelGlue.gesture.controller.Controller&quot;
    beans=&quot;contentService,config&quot;
&gt;
&lt;/code&gt;

Note the beans value specifies which beans configured in ColdSpring should be passed to my controller. I love this new automation in Model-Glue 3. If you open up my ColdSpring.xml file, you will see my beans configured:

&lt;code&gt;
&lt;bean id=&quot;config&quot; class=&quot;ModelGlue.Bean.CommonBeans.SimpleConfig&quot;&gt;
    &lt;property name=&quot;config&quot;&gt;
        &lt;map&gt;
            &lt;entry key=&quot;profileimageroot&quot;&gt;&lt;value&gt;/some url you dont need to know&lt;/value&gt;&lt;/entry&gt;
            &lt;entry key=&quot;filesroot&quot;&gt;&lt;value&gt;/something else you dont need to worry about&lt;/value&gt;&lt;/entry&gt;
            &lt;entry key=&quot;perpage&quot;&gt;&lt;value&gt;10&lt;/value&gt;&lt;/entry&gt;           
        &lt;/map&gt;
    &lt;/property&gt;
&lt;/bean&gt;   
&lt;/code&gt;

Hmmm. Ok, there&apos;s my config bean, wheres my contentService bean? Oh yeah - here it is:

&lt;code&gt;
    &lt;bean id=&quot;contentService&quot; class=&quot;com.broadchoice.bcp.services.ContentService&quot;&gt;
        &lt;property name=&quot;dao&quot; ref=&quot;contentDAO&quot;/&gt;
        &lt;property name=&quot;sessionFacade&quot; ref=&quot;sessionFacade&quot; /&gt;
        &lt;property name=&quot;sharedFileGateway&quot; ref=&quot;sharedFileGateway&quot; /&gt;
        &lt;property name=&quot;eventMessageDispatcher&quot; ref=&quot;eventMessageDispatcherService&quot; /&gt;
    &lt;/bean&gt;
&lt;/code&gt;

You can find the above in our Spring file. Just in case the above didn&apos;t quite make get through, let me make it real nice and obvious:

&lt;code&gt;
&lt;cfset arguments.event.setValue(&quot;bookmarks&quot;, beans.contentService.findContentBySpace(arguments.event.getValue(&quot;space&quot;),[&quot;Bookmark&quot;]))&gt;
&lt;/code&gt;

The above line of CFML is using a bean injected from Spring, not ColdSpring, and points to a Groovy file. This is the same Groovy code used to drive the AIR application. No createObject(&quot;java&quot;) here baby. I&apos;m using the Groovy code just like it had come from a CFC. This is done using a ColdSpring/Spring adapter that Joe wrote. It lets ModelGlue get Java-based beans from Spring. (I&apos;m simplifying it here a bit, but hopefully you get the significance of that!) Once that connection is done, you can easily get beans from the Spring file and inject them into your controller. So for example, when my UserController wanted do handle login, I added: beans=&quot;userService,config&quot; and then simply ran a userService.validateAndLoad on the authentication information.

It&apos;s always been easy to use Java from CFML, but never has been so sexy! Now to be fair, I did have to use a JavaCast once or twice, but not nearly as much as I would have thought.
				
				</description>
						
				
				<category>Groovy</category>				
				
				<category>Broadchoice Shares Knowledge</category>				
				
				<category>ColdSpring</category>				
				
				<category>Spring</category>				
				
				<category>Model-Glue</category>				
				
				<category>Tools and Technology</category>				
				
				<pubDate>Mon, 03 Nov 2008 17:52:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/11/3/Is-it-ColdFusion-or-Groovy</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Behind The Curtain ... continued</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/9/12/Behind-The-Curtain--continued</link>
				<description>
				
				A few days back Sean gave us all a sneak peak of the Broadchoice Workspace. He also mentioned we&apos;re all very busy lately, and guess what ... the Broadchoice Workspace is not the only application we&apos;re working on. Today I&apos;m going to introduce the Broadchoice Workspace Analytics platform.

&lt;img src=&quot;http://blog.broadchoice.com/images/bba_dashr_m.jpg&quot;&gt;
				 [More]
				</description>
						
				
				<category>Flex</category>				
				
				<category>Beta</category>				
				
				<category>Tools and Technology</category>				
				
				<category>AIR</category>				
				
				<category>Analytics</category>				
				
				<pubDate>Fri, 12 Sep 2008 21:56:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/9/12/Behind-The-Curtain--continued</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>AIR File Download Gotcha</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/8/29/AIR-File-Download-Gotcha</link>
				<description>
				
				If you happen to work with Adobe AIR at some point, and you want to download a file from a server, you may run into this helpful error:

I/O error 2038

Not very helpful. After a lot of digging and trying out solutions, I think I&apos;ve figured it out. I was doing something like this in a Delegate object:

&lt;code&gt;
public function downloadFile( fileName:String ):void {
	var req:URLRequest = new URLRequest( this.sharedFileDownloadURL + fileName );
	var file = new File();
	file.addEventListener( Event.COMPLETE, saveCompleteHandler );
	file.addEventListener( IOErrorEvent.IO_ERROR, ioErrorHandler );
	file.download( req, fileName );
}
&lt;/code&gt;

The problem seems to be the scope of the File object that is used to perform the download. Because it is locally scoped to that method, when the download completes and the completion event is announced, the file object is essentially gone. I&apos;m not sure if AIR is garbage collecting it, or if the variable is just not accessible because it is function-scoped. Either way, I got this error over and over and was pulling my hair out.

The solution is to not var scope the new File object. Unfortunately that seems to open up potential concurrency issues. Because the Delegate object is essentially a Singlton, if I add the file as a public property of the Delegate, and more than one upload goes at the same time on the client, it will get overwritten. That&apos;s not good.

I got around it by creating an Object to wrap around my file called SharedFile. This object has a public property which is a File object. In that case, I can do something like this:

&lt;code&gt;
public function downloadFile( sharedFile:SharedFile ):void {
	var req:URLRequest = new URLRequest( this.sharedFileDownloadURL + sharedFile.name );
	sharedFile.file = new File();
	sharedFile.file.addEventListener( Event.COMPLETE, saveCompleteHandler );
	sharedFile.file.addEventListener( IOErrorEvent.IO_ERROR, ioErrorHandler );
	sharedFile.file.download( req, sharedFile.name );
}
&lt;/code&gt;

So I&apos;m setting the sharedFile.file property to a new File, then using that file object to perform the upload. The I/O error vanishes because the file object is not locally-scoped, and so a reference to it still exists when the completion event fires. Again, I&apos;m not sure of the exact underlying cause of the problem, whether a function-scoped file object is simply not visible when the completion event fires, or whether the AIR runtime is garbage collecting the variable before the completion event fires. Either way, this seems to fix it!
				
				</description>
						
				
				<category>Tools and Technology</category>				
				
				<category>AIR</category>				
				
				<category>Broadchoice Shares Knowledge</category>				
				
				<pubDate>Fri, 29 Aug 2008 13:42:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/8/29/AIR-File-Download-Gotcha</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Better Living Through Transfer and ColdSpring</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/8/15/Better-Living-Through-Transfer-and-ColdSpring</link>
				<description>
				
				We have a live system with customer data and a new requirement comes along that a particular piece of customer data must be encrypted in the database from now on. We already encrypt some columns (using Triple DES - which you might have guessed given the recent posts on my blog and here about mimicking ColdFusion&apos;s encryption in Java/Groovy). What is the smallest possible code change to ensure that as any user updates their data in future, this item will automatically be encrypted - whilst still handling the case of legacy data being unencrypted?

We use Transfer for all our persistent business objects and almost all of our business objects have a decorator defined (for validation or some additional business logic). We also use Brian&apos;s &lt;a href=&quot;http://coldspringutils.riaforge.org/&quot;&gt;TDOBeanInjectorObserver&lt;/a&gt; to automatically inject services into our business objects - just add a setter for a service and the bean injector takes care of the rest.

Here&apos;s the bean injector definition in our ColdSpring file:
&lt;code&gt;
&lt;bean id=&quot;transferObjectInjector&quot; class=&quot;coldspring.transfer.TDOBeanInjectorObserver&quot;&gt;
	&lt;constructor-arg name=&quot;transfer&quot;&gt;&lt;ref bean=&quot;transfer&quot; /&gt;&lt;/constructor-arg&gt;
	&lt;constructor-arg name=&quot;suffixList&quot;&gt;&lt;value&gt;service,datasource&lt;/value&gt;&lt;/constructor-arg&gt;
	&lt;constructor-arg name=&quot;debugMode&quot;&gt;&lt;value&gt;true&lt;/value&gt;&lt;/constructor-arg&gt;
&lt;/bean&gt;
&lt;/code&gt;
Normally you would declare it non-lazy but we already do other non-lazy initialization so in our ColdSpring factory initialization code, we do this:
&lt;code&gt;
&lt;cfset bf.getBean(&quot;transferObjectInjector&quot;) /&gt;
&lt;/code&gt;
to force the bean injector to be initialized which, in turn, registers itself as a Transfer event listener (so that it can intercept object creation). The &lt;tt&gt;suffixList&lt;/tt&gt; specifies that any &lt;tt&gt;set*Service()&lt;/tt&gt; method or &lt;tt&gt;set*Datasource()&lt;/tt&gt; method on the business objects managed by Transfer should be matched to beans defined in ColdSpring and injected.

So how do we add the on-demand encryption to our business object&apos;s data?
				 [More]
				</description>
						
				
				<category>Tools and Technology</category>				
				
				<category>Transfer</category>				
				
				<category>ColdSpring</category>				
				
				<category>Broadchoice Shares Knowledge</category>				
				
				<pubDate>Fri, 15 Aug 2008 22:45:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/8/15/Better-Living-Through-Transfer-and-ColdSpring</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>AIR and Groovy via Spring</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/8/10/AIR-and-Groovy-via-Spring</link>
				<description>
				
				As a fun way to while away a Saturday evening, I decided to look at Joe&apos;s Behavioral Analytics backend code to see if I could create a Flex-based AIR application that talked to services written in Groovy. There&apos;s not really much documentation out there to help so it was a very hit and miss experience but eventually I had a simple AIR application making a RemoteObject call to a Groovy class and getting data back. I&apos;m going to have to talk to Joe about cleaning up the installation I&apos;ve ended up with but here are the highlights (and I&apos;ll blog more about this once I have all the pieces cleaned up):
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.jboss.org/jbossas/downloads/&quot;&gt;JBoss 4.2.3 GA&lt;/a&gt; installed as a Server in Eclipse (using the Web Tool Platform JEE stuff)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.springframework.org/download&quot;&gt;Spring&lt;/a&gt; framework 2.5.5&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;http://coenraets.org/flex-spring/&quot;&gt;Spring-based Flex factory&lt;/a&gt; that allows Flex Remoting to talk to objects via Spring (author Jeff Vroom)&lt;/li&gt;
&lt;li&gt;Groovy - set up per Joe&apos;s recent instructions&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://opensource.adobe.com/wiki/display/blazeds/BlazeDS&quot;&gt;BlazeDS&lt;/a&gt; providing the Flex Remoting service&lt;/li&gt;
&lt;/ul&gt;
Create a Dynamic Web Project in Eclipse and then unzip BlazeDS into it (per the BlazeDS installation docs). Add Spring and the flex.samples.factories.SpringFactory Java class. Configure Flex Remoting according to &lt;a href=&quot;http://weblogs.macromedia.com/lin/README.txt&quot;&gt;Lin&apos;s instructions&lt;/a&gt; to add the Spring factory:
&lt;code&gt;
	&lt;factories&gt;
		&lt;factory id=&quot;spring&quot; class=&quot;flex.samples.factories.SpringFactory&quot;/&gt;
	&lt;/factories&gt;
&lt;/code&gt;
and the context loader:
&lt;code&gt;
	&lt;!-- Spring --&gt;
	&lt;context-param&gt;
		&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
		&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;
	&lt;/context-param&gt;
	
	&lt;!-- load Spring&apos;s WebApplicationContext --&gt;
	&lt;listener&gt;
		&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
	&lt;/listener&gt;
&lt;/code&gt;
and the destination for the RemoteObject:
&lt;code&gt;
    &lt;destination id=&quot;place&quot;&gt;
		&lt;properties&gt;
			&lt;factory&gt;spring&lt;/factory&gt;
			&lt;source&gt;placeholder&lt;/source&gt;
		&lt;/properties&gt;
    &lt;/destination&gt;
&lt;/code&gt;

Create a Flex AIR project and define a RemoteObject that refers to the destination you just defined:
&lt;code&gt;
	&lt;mx:RemoteObject id=&quot;bcp&quot;
			destination=&quot;place&quot;
			endpoint=&quot;http://127.0.0.1:8080/bcpbackend/messagebroker/amf&quot;
			&gt;
		&lt;mx:method name=&quot;test&quot; result=&quot;testResult(event)&quot; fault=&quot;testFault(event)&quot;/&gt;
	&lt;/mx:RemoteObject&gt;
&lt;/code&gt;

Add the &lt;tt&gt;placeholder&lt;/tt&gt; bean definition to your &lt;tt&gt;applicationContext.xml&lt;/tt&gt; file:
&lt;code&gt;
	&lt;bean id=&quot;placeholder&quot; class=&quot;com.broadchoice.bcp.Placeholder&quot;/&gt;
&lt;/code&gt;
&lt;tt&gt;com.broadchoice.bcp.Placeholder&lt;/tt&gt; is a Groovy class that contains a &lt;tt&gt;test&lt;/tt&gt; method (for testing it just takes a string and returns that string plus some additional text).
				
				</description>
						
				
				<category>Groovy</category>				
				
				<category>Flex</category>				
				
				<category>Spring</category>				
				
				<category>AIR</category>				
				
				<category>Tools and Technology</category>				
				
				<category>BlazeDS</category>				
				
				<pubDate>Sun, 10 Aug 2008 05:16:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/8/10/AIR-and-Groovy-via-Spring</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Living in a Cluster</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/8/8/Living-in-a-Cluster</link>
				<description>
				
				The &lt;a href=&quot;http://www.broadchoice.com/products/collaboration_platform/&quot;&gt;Broadchoice Collaboration Platform&lt;/a&gt; (BCP) is deployed on a cluster of servers and this has a number of interesting implications for the design of the application as well as the actual deployment process and file system structure used.

I&apos;ll be posting several entries on clustering considerations but I wanted to start with something that surfaced with the recent launch of this blog. BlogCFC is part of our standard SVN repository (I&apos;ll also be blogging about our source code control processes) and so it is also deployed to the same cluster as the BCP. Each server runs the same code from its own local file system. BlogCFC allows authors to upload images and files that are used as part of the blog entries. If you simply deploy BlogCFC onto each server in the cluster and then create a blog entry and upload an image, that image will be stored directly on the file system of the server on which your request is processed (in fact, the server on which your entire session is processed, since we use &quot;sticky session&quot;). The other servers in the cluster won&apos;t know about the image. For user requests that come in to that first server, the image will be served correctly. For user requests that come in to the other servers, the image will be missing.

The BCP has the same issue - it allows authors to upload CSS, images and documents - but we have to ensure that all these uploaded assets &lt;strong&gt;are&lt;/strong&gt; available to all servers automatically and immediately. Our approach was to design the application in such a way that shared assets are stored in specific directory trees that contain nothing but shared assets. We have a NAS - Network Attached Storage - which is mounted to every server as &lt;tt&gt;/var/www/html&lt;/tt&gt;. That contains a documents directory and a custom assets directory - into which all uploaded content is placed. Symbolic links are used to &quot;map&quot; those shared directories to the appropriate place in the deployment directory tree:
&lt;pre&gt;
/var/www/production/lib -&gt; /var/www/html/lib
/var/www/production/wwwportal/custom -&gt; /var/www/html/custom
&lt;/pre&gt;
We deploy our source tree to &lt;tt&gt;/var/www/production&lt;/tt&gt; (direct from SVN) with &lt;tt&gt;lib&lt;/tt&gt; and &lt;tt&gt;custom&lt;/tt&gt; ignored by SVN. Each server then shares the same uploaded content without needing to use different file paths to how we would deploy to a non-clustered server.

Tonight, I applied the same fix to BlogCFC, adding &lt;tt&gt;blog_images&lt;/tt&gt; and &lt;tt&gt;blog_enclosures&lt;/tt&gt; directories on the NAS and adding symbolic links back into the BlogCFC deployment tree (as &lt;tt&gt;wwwblog/images&lt;/tt&gt; and &lt;tt&gt;wwwblog/enclosures&lt;/tt&gt; respectively). We have not yet dealt with making &lt;tt&gt;blog.init.cfm&lt;/tt&gt; cluster-safe or the XML file generated by the pod manager. For both of those, we actually keep the files under SVN and handle changes as part of a managed process (i.e., by tickets in Trac).

This is just one of many things that need to be considered when designing applications for clustered environments. I&apos;ll be blogging about other clustering issues over the next few weeks.
				
				</description>
						
				
				<category>Tools and Technology</category>				
				
				<pubDate>Fri, 08 Aug 2008 04:19:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/8/8/Living-in-a-Cluster</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>Creating an Eclipse-based Groovy Development Environment for TDD</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/8/6/Creating-an-Eclipsebased-Groovy-Development-Environment-for-TDD</link>
				<description>
				
				Within the system I&apos;m building at &lt;a href=&quot;http://www.broadchoice.com&quot;&gt;Broadchoice&lt;/a&gt;, we&apos;re exploring the use of Groovy, Spring, and Hibernate in combination.  The first step in building a system using this stack is creating an Eclipse-based environment in which we can write and test our code.  To help people do this, I&apos;ve published a Google document entitled &lt;a href=&quot;http://docs.google.com/View?docid=dcnf3wxn_4pwzgssfq&quot;&gt;Creating an Eclipse-based Groovy Development Environment for TDD&lt;/a&gt;.

As it doesn&apos;t contain any &quot;technical secrets&quot; (we don&apos;t really have the concept of a technical secret at Broadchoice!), I thought it&apos;d be handy to share it with the world.

I&apos;ve still got more to document, including how to integrate TestNG tests with Spring and how build (and effectively test!) a Hibernate-enabled Groovy+Spring project.  A lot of this is the result of reading multiple books and a good deal of Googling / piecing together information, so I hope you enjoy it in distilled, ready-to-consume formats!
				
				</description>
						
				
				<category>Groovy</category>				
				
				<category>Tools and Technology</category>				
				
				<category>Broadchoice Shares Knowledge</category>				
				
				<pubDate>Wed, 06 Aug 2008 12:02:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/8/6/Creating-an-Eclipsebased-Groovy-Development-Environment-for-TDD</guid>
				
			</item>
			
		 	
			
			
			<item>
				<title>A bit of practical Groovy</title>
				<link>http://blog.broadchoice.com/index.cfm/2008/8/4/A-bit-of-practical-Groovy</link>
				<description>
				
				While working on server-side components for the &lt;a href=&quot;http://www.broadchoice.com&quot;&gt;Broadchoice&lt;/a&gt; Behavior Analytics product, I&apos;ve been using Groovy to write Java classes.  I&apos;m finding that it has many parallels with &lt;a href=&quot;http://www.adobe.com/products/ColdFusion&quot;&gt;ColdFusion&lt;/a&gt; when it comes to being a productivity layer on top of Java.

A great example little command-line tool I wrote for personal purposes.  I needed to query a Subversion server for all files modified or added in a given array of changeset numbers, building a .zip file containing the entire bundle.  120 lines of Groovy (including nice formatting and comments!) was all it took.

Here&apos;s a few excerpts:

&lt;em&gt;Executing SVN at the command line for each revision number and parsing out the list of changed or added files from the resultant XML:&lt;/em&gt;
&lt;code&gt;
revisions.each{revisionNumber -&gt;
	System.out.print(&quot;Getting log for revision: &quot; + revisionNumber + &quot;\n&quot;)
	
	cmd = &quot;svn log -r &quot; + revisionNumber + &quot; -v --xml --username &quot; + username + &quot; --password &quot; + password + &quot; &quot; + url;
	svnProcess = cmd.execute()
	svnProcess.waitFor()

	new XmlParser().parseText(svnProcess.in.text).logentry.each { entry -&gt;
		revisionFiles[revisionNumber] = entry.paths.path.findAll { 
			return (
				it.&apos;@action&apos;.contains(&apos;M&apos;)
				|| it.&apos;@action&apos;.contains(&apos;A&apos;)
			)
		}.collect { path -&gt;
			path.text()
		}
	}
}
&lt;/code&gt;

Yep, that&apos;s all it takes to execute a command line process, parse its result into an XML document, and then parse that document into a local Map of file!

At the end, I needed to create a zip file of a given directory.  Using the AntBuilder (which dynamically interprets method calls as Ant tasks), it was a no-brainer:

&lt;em&gt;Using AntBuilder to build a ZIP file of all files within a given directory.&lt;/em&gt;
&lt;code&gt;
new AntBuilder().zip(
		destfile : (&quot;build.&quot; + version + &quot;.zip&quot;),
		basedir : &quot;./working/&quot; + version
)
&lt;/code&gt;

Groovy is...groovy.  I&apos;ve always loved ColdFusion for its practicality, and Groovy is providing many of the same features when I need to write raw Java or create command-line tools such as this utility!
				
				</description>
						
				
				<category>Groovy</category>				
				
				<category>Tools and Technology</category>				
				
				<pubDate>Mon, 04 Aug 2008 13:59:00 -0400</pubDate>
				<guid>http://blog.broadchoice.com/index.cfm/2008/8/4/A-bit-of-practical-Groovy</guid>
				
			</item>
			
		 	
			</channel></rss>