<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1510447155903423878</id><updated>2012-01-28T17:04:43.077-05:00</updated><category term='mobile'/><category term='logging'/><category term='philly ete'/><category term='swing'/><category term='junit'/><category term='actor'/><category term='maven'/><category term='mobile phones'/><category term='events'/><category term='spring integration'/><category term='open source'/><category term='mobile application development'/><category term='manik surtani'/><category term='application development'/><category term='software development'/><category term='grails'/><category term='beanconfig'/><category term='iphone'/><category term='emerging technology'/><category term='spring roo'/><category term='dan allen'/><category term='profiles'/><category term='philly startup leaders'/><category term='rails'/><category term='video'/><category term='Flex'/><category term='javaconfig'/><category term='nosql'/><category term='tapworthy'/><category term='JMS'/><category term='windows mobile'/><category term='podcast transcript'/><category term='SpringSource'/><category term='jquery mobile'/><category term='windows phone'/><category term='Adobe'/><category term='facebook'/><category term='jon'/><category term='spring social'/><category term='jeff brown'/><category term='meego'/><category term='scala'/><category term='dbunit'/><category term='java'/><category term='seam'/><category term='software conference'/><category term='security'/><category term='nfc'/><category term='ed burns'/><category term='esb'/><category term='jboss cache'/><category term='springsource roo'/><category term='cloud'/><category term='backbone'/><category term='rest'/><category term='m2eclpise'/><category term='spring 3.1'/><category term='RESTful'/><category term='Nexus'/><category term='android'/><category term='groovy'/><category term='palm'/><category term='ssl'/><category term='unit testing'/><category term='akka'/><category term='architecture'/><category term='screencast'/><category term='ruby'/><category term='jboss world'/><category term='couchdb'/><category term='education'/><category term='kyw newsradio'/><category term='scott davis'/><category term='redmonk'/><category term='javascript'/><category term='Messaging'/><category term='mule'/><category term='redis'/><category term='apple'/><category term='jenkins'/><category term='emmanuel bernard'/><category term='yammer'/><category term='spring mvc'/><category term='mulesoft'/><category term='sonatype'/><category term='david black'/><category term='chariot techcast'/><category term='rhodes'/><category term='tebow'/><category term='pretty faces'/><category term='infinispan'/><category term='griffon'/><category term='agile'/><category term='voldemort'/><category term='ci'/><category term='fulltext'/><category term='html 5'/><category term='podcasts'/><category term='andriod'/><category term='graeme rocher'/><category term='database'/><category term='mentoring'/><category term='cassandra'/><category term='cloud computing'/><category term='spring framework'/><category term='sencha touch'/><category term='groovy algorithm shunting yard'/><category term='JTA'/><category term='hudson'/><category term='couch db'/><category term='James Ward'/><category term='web services'/><category term='Spring Batch'/><category term='mongodb'/><category term='Sonar'/><category term='phillyete'/><category term='keitai'/><category term='rhomobile'/><category term='springone'/><category term='SOAP'/><category term='jquery'/><category term='chris richardson'/><category term='blackberry'/><category term='winning'/><category term='roo in action'/><category term='chariotsolutions'/><category term='mobile development'/><category term='annotation config'/><category term='twitter'/><category term='enterprise integration patterns'/><category term='search'/><category term='jboss'/><category term='mobile web'/><category term='phonegap'/><category term='social media'/><category term='password'/><title type='text'>Chariot Solutions</title><subtitle type='html'>Official Blog</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default?start-index=101&amp;max-results=100'/><author><name>Tracey Welson-Rossman</name><uri>http://www.blogger.com/profile/00460003016667099940</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>120</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2816139648809504467</id><published>2012-01-23T18:24:00.000-05:00</published><updated>2012-01-23T18:24:08.952-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile web'/><category scheme='http://www.blogger.com/atom/ns#' term='sencha touch'/><title type='text'>Introduction to Sencha Touch</title><content type='html'>&lt;p&gt;Steve Smith recently looked at &lt;a href="http://blog.chariotsolutions.com/2011/12/introduction-to-backbonejs-with-jquery.html"&gt;jQuery Mobile and Backbone&lt;/a&gt; using a simple application that allowed a user to track their daily exercise. I'm going to duplicate his example using Sencha Touch. &lt;/p&gt;&lt;p&gt;&lt;a href="http://www.sencha.com/products/touch/"&gt;Sencha Touch&lt;/a&gt; is a framework for building mobile applications using HTML5, CSS3, and Javascript. &amp;nbsp;This example uses the &lt;a href="http://www.sencha.com/blog/sencha-touch-2-developer-preview/"&gt;Developer Preview of Sencha Touch 2.0&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here's what our project looks like.&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-lSZp6K56d3s/TxofVj71h7I/AAAAAAAAABE/oWJcEVo68bM/s1600/files.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-lSZp6K56d3s/TxofVj71h7I/AAAAAAAAABE/oWJcEVo68bM/s1600/files.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;A Sencha Touch application is loaded from an HTML page. The HTML loads CSS and Javascript. Sencha Touch applications typically build the UI using Javascript so the index.html is very simple.&lt;/p&gt;&lt;p&gt;&lt;script src="https://gist.github.com/1650393.js?file=index.html"&gt;&lt;/script&gt;&lt;/p&gt;&lt;p&gt;The &lt;b&gt;touch/&lt;/b&gt; directory contains the Sencha Javascript and CSS from the SDK. &amp;nbsp;Since this is an example, all if the application code is in one file, app.js.  Larger applications will break the code up into more files and directories.&lt;/p&gt;&lt;h2&gt;Sencha Application&lt;/h2&gt; &lt;p&gt;Sencha Touch has a global namespace, Ext, that holds the framework and application code.  The &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.app.Application"&gt;Ext.application&lt;/a&gt; helper function takes a configuration object where we define our application.&lt;/p&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;Ext.application({&lt;br /&gt;    launch: function() {&lt;br /&gt;        // define our app here&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Model&lt;/h2&gt;&lt;p&gt;We extend &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.data.Model"&gt;Ext.data.Model&lt;/a&gt; to define a Model object describing our data.  The data is supplied by the server in a JSON file, &lt;a href="https://raw.github.com/don/sencha-exercise/master/exercise.json"&gt;exercise.json&lt;/a&gt;.  The fields in the model, match the properties in the JSON file.&lt;/p&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;Ext.define("Activity", {&lt;br /&gt;    extend: "Ext.data.Model",&lt;br /&gt;    fields: [&lt;br /&gt;        {name: 'id', type: 'int'},&lt;br /&gt;        {name: 'date', type: 'date'},    &lt;br /&gt;        {name: 'type', type: 'string'},    &lt;br /&gt;        {name: 'distance', type: 'string'},    &lt;br /&gt;        {name: 'minutes', type: 'int'},  &lt;br /&gt;        {name: 'comments', type: 'string'}&lt;br /&gt;    ]&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;/* exercise.json */&lt;br /&gt;[&lt;br /&gt;    {&lt;br /&gt;        "id":3,&lt;br /&gt;        "date": "12/10/2011",&lt;br /&gt;        "type": "Walk",&lt;br /&gt;        "distance": "2.5 miles",&lt;br /&gt;        "comments": "Shouldn't have taken the dog",&lt;br /&gt;        "minutes": 45&lt;br /&gt;    },&lt;br /&gt;    ...&lt;br /&gt;]  &lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Store&lt;/h2&gt;&lt;p&gt;A &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.data.Store"&gt;Store&lt;/a&gt; is used to load and manage data. The Activity model we created is associated with the store. We define a &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.data.proxy.Proxy"&gt;proxy&lt;/a&gt; to load the JSON data from a URL. Finally, we tell the store to automatically load the data when the store is created.&lt;/p&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;var store = Ext.create('Ext.data.Store', {&lt;br /&gt;    storeId: "activityStore",&lt;br /&gt;    model: "Activity",&lt;br /&gt;    proxy: {&lt;br /&gt;        type: 'ajax',&lt;br /&gt;        url: 'exercise.json'&lt;br /&gt;    },&lt;br /&gt;    autoLoad: true&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Once the store is created, we can use the Javascript console to interact with the data.&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-N5bo2f5Di7g/TxoR4A-5EBI/AAAAAAAAAAM/_K3QTDijgRM/s1600/web_inspector.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="325" src="http://2.bp.blogspot.com/-N5bo2f5Di7g/TxoR4A-5EBI/AAAAAAAAAAM/_K3QTDijgRM/s400/web_inspector.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h2&gt;User Interface&lt;/h2&gt;&lt;p&gt;Now we need to display the data. A &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.navigation.View"&gt;NavigationView&lt;/a&gt; shows a navigation bar and holds the &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.dataview.List"&gt;List&lt;/a&gt; component. The list is defined in the code using the object literal syntax. The data store we created is assigned to the list so it can display the records. The itemTmp property defines how to display each item of data. This can be a &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.Template"&gt;template&lt;/a&gt; or a string.&lt;/p&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;var view = Ext.create("Ext.NavigationView", {&lt;br /&gt;    fullscreen: true,&lt;br /&gt;    items: [&lt;br /&gt;        {&lt;br /&gt;            xtype: 'list',&lt;br /&gt;            title: 'Activities',&lt;br /&gt;            itemTpl: '{date} - {type}',&lt;br /&gt;            store: store&lt;br /&gt;        }&lt;br /&gt;    ]&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/--doA1Ftb0Q4/TxoTHyG5ZpI/AAAAAAAAAAs/cfJKB08SjDA/s1600/unformatted.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/--doA1Ftb0Q4/TxoTHyG5ZpI/AAAAAAAAAAs/cfJKB08SjDA/s320/unformatted.png" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Unformatted Date&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;This works but the date doesn't display very well. A &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.util.Format"&gt;format&lt;/a&gt;&amp;nbsp;can be added to the template definition.  &lt;code&gt;{date}&lt;/code&gt; in the itemTpl becomes &lt;code&gt;{date:date("m/d/Y")}&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush:js;highlight:[7]"&gt;&lt;br /&gt;var view = Ext.create("Ext.NavigationView", {&lt;br /&gt;    fullscreen: true,&lt;br /&gt;    items: [&lt;br /&gt;        {&lt;br /&gt;            xtype: 'list',&lt;br /&gt;            title: 'Activities',&lt;br /&gt;            itemTpl: '{date:date("m/d/Y")} - {type}',&lt;br /&gt;            store: store&lt;br /&gt;        }&lt;br /&gt;    ]&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-eiaSzlU3P2I/TxoTHtX3K7I/AAAAAAAAAAk/9vTEYK-iUqc/s1600/formatted.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-eiaSzlU3P2I/TxoTHtX3K7I/AAAAAAAAAAk/9vTEYK-iUqc/s320/formatted.png" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Formatted Date&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2&gt;Adding New Data&lt;/h2&gt;&lt;p&gt;Let's add a &lt;a href="http://docs.sencha.com/touch/2-0/#!/api/Ext.Button"&gt;button&lt;/a&gt; to the header to add a new row of data.&lt;/p&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;view.getNavigationBar().add({&lt;br /&gt;    xtype: 'button',&lt;br /&gt;    text: 'Add',&lt;br /&gt;    align: 'right',&lt;br /&gt;    handler: addNewRow&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The handler property of the button defines the function that is called whenever the button is pressed. Eventually we need a form so the user can add new data. For now, let's define a function addNewRow that will create a new row and add it to the store.&lt;/p&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;var addNewRow = function() {&lt;br /&gt;    // future versions should display a form for adding a record&lt;br /&gt;    var fakeRecord = Ext.create('Activity', {&lt;br /&gt;        date: new Date(), &lt;br /&gt;        type: 'Walk', &lt;br /&gt;        distance: '2 miles', &lt;br /&gt;        minutes: 28, &lt;br /&gt;        comments: 'Auto generated record.'&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;    store.add(fakeRecord);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now when the button is pressed a new row appears in the UI. &amp;nbsp;The store notifies the list, so rows appear as records are added to the store.&lt;/p&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-0JDn1w0aXLo/TxoaUAR7cmI/AAAAAAAAAA0/reBtPguq91U/s1600/add_button.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-0JDn1w0aXLo/TxoaUAR7cmI/AAAAAAAAAA0/reBtPguq91U/s320/add_button.jpg" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Add Button&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-QRMhB4EZN14/TxoaUpDtB5I/AAAAAAAAAA8/9M7PGJVWSgs/s1600/new_row.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-QRMhB4EZN14/TxoaUpDtB5I/AAAAAAAAAA8/9M7PGJVWSgs/s320/new_row.jpg" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;New Row&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;That should be enough to get you started. In future posts we'll look at features like sorting, detail views, navigation, and forms.  The &lt;a href="https://github.com/don/sencha-exercise/tree/intro"&gt;source code is available on github&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2816139648809504467?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2816139648809504467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2012/01/introduction-to-sencha-touch.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2816139648809504467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2816139648809504467'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2012/01/introduction-to-sencha-touch.html' title='Introduction to Sencha Touch'/><author><name>Don Coleman</name><uri>http://www.blogger.com/profile/12254215544227921604</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-lSZp6K56d3s/TxofVj71h7I/AAAAAAAAABE/oWJcEVo68bM/s72-c/files.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6043012151262099858</id><published>2012-01-17T12:37:00.000-05:00</published><updated>2012-01-19T11:47:02.070-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring mvc'/><category scheme='http://www.blogger.com/atom/ns#' term='spring 3.1'/><category scheme='http://www.blogger.com/atom/ns#' term='annotation config'/><category scheme='http://www.blogger.com/atom/ns#' term='profiles'/><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><category scheme='http://www.blogger.com/atom/ns#' term='cloud computing'/><category scheme='http://www.blogger.com/atom/ns#' term='beanconfig'/><category scheme='http://www.blogger.com/atom/ns#' term='javaconfig'/><title type='text'>Spring 3.1 - Environment Profiles</title><content type='html'>&lt;h2&gt;Spring 3.1 Environment Profiles&lt;/h2&gt;&lt;h3&gt;Profiles&lt;/h3&gt;Spring 3.1 now includes support for the long awaited environment aware feature called profiles.  Now we can activate profiles in our application, which allows us to define beans by deployment regions, such as "dev", "qa", "production", "cloud", etc.&lt;br /&gt;&lt;br /&gt;We also can use this feature for other purposes: defining profiles for performance testing scenarios such as "cached" or "lazyload".&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Essential Tokens&lt;/h3&gt;Spring profiles are enabled using the case insensitive tokens &lt;code&gt;spring.profiles.active&lt;/code&gt; or &lt;code&gt;spring_profiles_active&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;This token can be set as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;an Environment Variable&lt;/li&gt;&lt;li&gt;a JVM Property&lt;/li&gt;&lt;li&gt;Web Parameter&lt;/li&gt;&lt;li&gt;Programmatic&lt;/li&gt;&lt;/ul&gt;Spring also looks for the token, &lt;code&gt;spring.profiles.default&lt;/code&gt;, which can be used to set the default profile(s) if none are specified with &lt;code&gt;spring.profiles.active&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Grouping Beans by Profile&lt;/h3&gt;Spring 3.1 provides nested bean definitions, providing the ability to define beans for various environments: &lt;br /&gt;&lt;pre class="brush:xml"&gt;&amp;lt;beans profiles="dev,qa"&amp;gt;&lt;br /&gt;  &amp;lt;bean id="dataSource" class="..."/&amp;gt;&lt;br /&gt;  &amp;lt;bean id="messagingProvider" class="..."/&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Nested &lt;code&gt;&amp;lt;beans&amp;gt;&lt;/code&gt; must appear last in the file.&lt;/b&gt; &lt;br /&gt;Beans that are used in all profiles are declared in the outer &lt;code&gt;&amp;lt;beans&amp;gt;&lt;/code&gt; as we always have, such as Service classes. &lt;br /&gt;&lt;pre class="brush:xml;highlight:[11,22]"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;       xmlns:c="http://www.springframework.org/schema/c"&lt;br /&gt;       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;       xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;       http://www.springframework.org/schema/beans/spring-beans.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;bean id="businessService"&lt;br /&gt;       class="com.c...s.springthreeone.business.SimpleBusinessServiceImpl"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;beans profile="dev,qa"&amp;gt;&lt;br /&gt;        &amp;lt;bean id="constructorBean"&lt;br /&gt;          class="com.chariotsolutions.springthreeone.SimpleBean"&lt;br /&gt;              c:myString="Constructor Set"/&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;bean id="setterBean"&lt;br /&gt;          class="com.chariotsolutions.springthreeone.SimpleBean"&amp;gt;&lt;br /&gt;            &amp;lt;property name="myString" value="Setter Set"/&amp;gt;&lt;br /&gt;        &amp;lt;/bean&amp;gt;&lt;br /&gt;    &amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;beans profile="prod"&amp;gt;&lt;br /&gt;        &amp;lt;bean id="setterBean"&lt;br /&gt;          class="com.chariotsolutions.springthreeone.SimpleBean"&amp;gt;&lt;br /&gt;            &amp;lt;property name="myString" value="Setter Set - in Production YO!"/&amp;gt;&lt;br /&gt;        &amp;lt;/bean&amp;gt;&lt;br /&gt;    &amp;lt;/beans&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If we put a single &lt;code&gt;&amp;lt;bean&amp;gt;&lt;/code&gt; declaration at below any nested &lt;code&gt;&amp;lt;beans&amp;gt;&lt;/code&gt; tags we will get the exception &lt;code&gt;org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'bean'&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Multiple beans can now share the same XML "id"&lt;/b&gt; &lt;br /&gt;In a typical scenario, we would want the DataSource bean to be called &lt;code&gt;dataSource&lt;/code&gt; in both all profiles.  Spring now allow us to create multiple beans within an XML file with the same ID providing they are defined in different &lt;code&gt;&amp;lt;beans&amp;gt;&lt;/code&gt; sets.  In other words, ID uniqueness is only enforced within each &lt;code&gt;&amp;lt;beans&amp;gt;&lt;/code&gt; set.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Automatic Profile Discovery (Programmatic)&lt;/h3&gt;We can configure a class to set our profile(s) during application startup by implementing the&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;/span&gt; appropriate interface.  For example, we may configure an application to set different profiles based on where the application is deployed - in CloudFoundry or running as a local web application. In the &lt;code&gt;web.xml&lt;/code&gt; file we can include an Servlet context parameter, &lt;code&gt;contextInitializerClasses,&lt;/code&gt; to bootstrap this class:&lt;br /&gt;&lt;pre class="brush:xml"&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt;  &amp;lt;param-name&amp;gt;contextInitializerClasses&amp;lt;/param-name&amp;gt;&lt;br /&gt;  &amp;lt;param-value&amp;gt;com.chariotsolutions.springthreeone.services.CloudApplicationContextInitializer&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;The Initializer class&lt;/b&gt; &lt;br /&gt;&lt;pre class="brush:java;highlight:[21,25]"&gt;package com.chariotsolutions.springthreeone.services;&lt;br /&gt;&lt;br /&gt;import org.cloudfoundry.runtime.env.CloudEnvironment;&lt;br /&gt;import org.slf4j.Logger;&lt;br /&gt;import org.slf4j.LoggerFactory;&lt;br /&gt;import org.springframework.context.ApplicationContextInitializer;&lt;br /&gt;import org.springframework.context.ConfigurableApplicationContext;&lt;br /&gt;&lt;br /&gt;public class CloudApplicationContextInitializer implements&lt;br /&gt;  ApplicationContextInitializer&amp;lt;ConfigurableApplicationContext&amp;gt; {&lt;br /&gt;    &lt;br /&gt;  private static final Logger logger = LoggerFactory&lt;br /&gt;    .getLogger(CloudApplicationContextInitializer.class);&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public void initialize(ConfigurableApplicationContext applicationContext) {&lt;br /&gt;    CloudEnvironment env = new CloudEnvironment();&lt;br /&gt;    if (env.getInstanceInfo() != null) {&lt;br /&gt;      logger.info("Application running in cloud. API '{}'",&lt;br /&gt;        env.getCloudApiUri());&lt;br /&gt;      applicationContext.getEnvironment().setActiveProfiles("cloud");&lt;br /&gt;      applicationContext.refresh();&lt;br /&gt;    } else {&lt;br /&gt;      logger.info("Application running local");&lt;br /&gt;      applicationContext.getEnvironment().setActiveProfiles("dev");&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Annotation Support for JavaConfig&lt;/h3&gt;If we are are using JavaConfig to define our beans, Spring 3.1 includes the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;@Profile&lt;/span&gt; annotation for enabling bean config files by profile(s).&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java;highlight:[9]"&gt;package com.chariotsolutions.springthreeone.configuration;&lt;br /&gt;&lt;br /&gt;import com.chariotsolutions.springthreeone.SimpleBean;&lt;br /&gt;import org.springframework.context.annotation.Bean;&lt;br /&gt;import org.springframework.context.annotation.Configuration;&lt;br /&gt;import org.springframework.context.annotation.Profile;&lt;br /&gt;&lt;br /&gt;@Configuration&lt;br /&gt;@Profile("dev")&lt;br /&gt;public class AppConfig {&lt;br /&gt;  @Bean&lt;br /&gt;  public SimpleBean simpleBean() {&lt;br /&gt;    SimpleBean simpleBean = new SimpleBean();&lt;br /&gt;    simpleBean.setMyString("Ripped Pants");&lt;br /&gt;    return simpleBean;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Testing with XML Configuration&lt;/h3&gt;With XML configuration we can simply add the annotation &lt;code&gt;@ActiveProfiles&lt;/code&gt; to the JUnit test class.  To include multiple profiles, use the format &lt;code&gt;@ActiveProfiles(profiles = {"dev", "prod"})&lt;/code&gt;&lt;br /&gt;&lt;pre class="brush:java;highlight:[16]"&gt;package com.chariotsolutions.springthreeone;&lt;br /&gt;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;import org.junit.runner.RunWith;&lt;br /&gt;import org.springframework.beans.factory.NoSuchBeanDefinitionException;&lt;br /&gt;import org.springframework.beans.factory.annotation.Autowired;&lt;br /&gt;import org.springframework.context.ApplicationContext;&lt;br /&gt;import org.springframework.test.context.ActiveProfiles;&lt;br /&gt;import org.springframework.test.context.ContextConfiguration;&lt;br /&gt;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;&lt;br /&gt;import static junit.framework.Assert.assertNotNull;&lt;br /&gt;import static junit.framework.Assert.assertNull;&lt;br /&gt;&lt;br /&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;br /&gt;@ContextConfiguration&lt;br /&gt;@ActiveProfiles(profiles = "dev")&lt;br /&gt;public class DevBeansTest {&lt;br /&gt;&lt;br /&gt;  @Autowired&lt;br /&gt;  ApplicationContext applicationContext;&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void testDevBeans() {&lt;br /&gt;    SimpleBean simpleBean = &lt;br /&gt;      applicationContext.getBean("constructorBean", SimpleBean.class);&lt;br /&gt;    assertNotNull(simpleBean);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test(expected = NoSuchBeanDefinitionException.class)&lt;br /&gt;  public void testProdBean() {&lt;br /&gt;    SimpleBean prodBean = applicationContext.getBean("prodBean", SimpleBean.class);&lt;br /&gt;    assertNull(prodBean);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Testing with JavaConfig&lt;/h3&gt;JavaConfig allows us to configure Spring with or without XML configuration.  If we want to test beans that are defined in a Configuration class we configure our test with the &lt;code&gt;loader&lt;/code&gt; and &lt;code&gt;classes&lt;/code&gt; arguments of the &lt;code&gt;@ContextConfiguration&lt;/code&gt; annotation.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java;highlight:[15,16]"&gt;package com.chariotsolutions.springthreeone.configuration;&lt;br /&gt;&lt;br /&gt;import com.chariotsolutions.springthreeone.SimpleBean;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;import org.junit.runner.RunWith;&lt;br /&gt;import org.springframework.beans.factory.annotation.Autowired;&lt;br /&gt;import org.springframework.test.context.ActiveProfiles;&lt;br /&gt;import org.springframework.test.context.ContextConfiguration;&lt;br /&gt;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;&lt;br /&gt;import org.springframework.test.context.support.AnnotationConfigContextLoader;&lt;br /&gt;&lt;br /&gt;import static org.junit.Assert.assertNotNull;&lt;br /&gt;&lt;br /&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;br /&gt;@ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)&lt;br /&gt;@ActiveProfiles(profiles = "dev")&lt;br /&gt;public class BeanConfigTest {&lt;br /&gt;&lt;br /&gt;  @Autowired&lt;br /&gt;  SimpleBean simpleBean;&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void testBeanAvailablity() {&lt;br /&gt;    assertNotNull(simpleBean);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Declarative Configuration in WEB.XML&lt;/h3&gt;If we desire to set the configuration in &lt;code&gt;WEB.XML&lt;/code&gt;, this can be done with parameters on &lt;code&gt;ContextLoaderListener&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Application Context&lt;/b&gt; &lt;br /&gt;&lt;pre class="brush:xml;highlight:[6,7]"&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt;  &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;  &amp;lt;param-value&amp;gt;/WEB-INF/app-config.xml&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;br /&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt;  &amp;lt;param-name&amp;gt;spring.profiles.active&amp;lt;/param-name&amp;gt;&lt;br /&gt;  &amp;lt;param-value&amp;gt;DOUBLEUPMINT&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;/pre&gt;&lt;b&gt;Log Results&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;DEBUG PropertySourcesPropertyResolver - Found key 'spring.profiles.active' in [servletContextInitParams] with type [String] and value 'DOUBLEUPMINT'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Environment Variable/JVM Parameter&lt;/b&gt;&lt;br /&gt;Setting an environment variable can be done with either &lt;code&gt;spring_profiles_default&lt;/code&gt; or &lt;code&gt;spring_profiles_active&lt;/code&gt;. In Unix/Mac it would be &lt;code&gt;export SPRING_PROFILES_DEFAULT=DEVELOPMENT&lt;/code&gt; for my local system. &lt;br /&gt;&lt;br /&gt;We can also use the JVM "-D" parameter which also works with Maven when using Tomcat or Jetty plugins. &lt;br /&gt;&lt;br /&gt;Note: Remember the tokens are NOT case sensitive and can use periods or underscores as separators. For Unix systems, you need to use the underscore, as above. &lt;br /&gt;&lt;br /&gt;Logging of system level properties &lt;code&gt;DEBUG PropertySourcesPropertyResolver - Found key 'spring.profiles.default' in [systemProperties] with type [String] and value 'dev,default'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;Now we are equipped to activate various Spring bean sets, based on profiles we define.  We can use&amp;nbsp; traditional, XML based configuration, or the features added to support JavaConfig originally introduced in Spring 3.0.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6043012151262099858?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6043012151262099858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2012/01/spring-31-cool-new-features.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6043012151262099858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6043012151262099858'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2012/01/spring-31-cool-new-features.html' title='Spring 3.1 - Environment Profiles'/><author><name>Gordon Dickens</name><uri>https://profiles.google.com/114681050780814546369</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-dMj3fLlkNPA/AAAAAAAAAAI/AAAAAAAAAJY/fR7TY-stMvo/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4501967602398384736</id><published>2012-01-12T09:26:00.000-05:00</published><updated>2012-01-13T11:16:18.007-05:00</updated><title type='text'>Philly ETE - Speaker Interview, Ken Rimple co-author of Spring Roo in Action</title><content type='html'>For our first look at what’s in store for ETE 2012, we talk with our own Ken Rimple, co-author of &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;a href="http://manning.com/rimple" target="_blank"&gt;Spring Roo in Action&lt;/a&gt;&lt;/i&gt;. Ken is Director of Education Services and is a regular co-host of Chariot’s &lt;a href="http://techcast.chariotsolutions.com/" target="_blank"&gt;TechCast&lt;/a&gt; – our monthly podcast series focusing on development and training in Spring, Rails, Scala, Hibernate, Maven and other emerging technologies in the field&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Q:&lt;/b&gt; After last year’s tremendous following and turnout for ETE, people are really expecting this year to raise the bar. Tell us a bit about what you’ll be discussing at this year’s ETE and what people can expect from your presentation in particular.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ken:&lt;/b&gt; I’ll be talking about the subject I actually wrote a book around – &lt;a href="http://springsource.org/spring-roo" target="_blank"&gt;Spring Roo&lt;/a&gt;. It’s a software tool that helps people develop applications in Spring, which is a very popular Java application development platform. I’m going to talk about building Roo add-ons, which is kind of extending the features of the platform with ones that don’t exist today. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Q:&lt;/b&gt; So it’s all about building new features from scratch?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ken:&lt;/b&gt; Exactly&lt;a href="http://www.blogger.com/blogger.g?blogID=1510447155903423878" name="_GoBack"&gt;&lt;/a&gt;! For example, there are add-ons that configure different web frameworks, like Vaadin and JSF. At one point, there was an add-on for programming Flex applications [ed. note: this is currently non-functional], which are Flash-based frontends, and add-ons for other integrations to other systems.&lt;br /&gt;I wrote two for the book: One to install JQuery, which is a Javascript framework, and another one that installs CoffeeScript, which is a language simplifying JavaScript. So, in my talk I’m going to go through how to write add-ons, because it’s such a new community. And I really want to boost the community’s presence so that people can start contributing to the framework. &lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Q: &lt;/b&gt;That sounds pretty impressive – it seems like Roo’s major role is to lend a real boost to the productivity developers get with Spring. With that said, how difficult is it to learn? How much of a learning curve is there for someone who traditionally programs in Java to move to Spring and then add Roo on top of that?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Ken: &lt;/b&gt;That’s a really good question. The thing about Spring – and let’s take a step back here to talk about some background – the thing about Java applications for about five or six years after Java became popular back in the late 90s early 00s was that there were some standard APIs for doing development and they were written by Sun. &lt;br /&gt;&lt;br /&gt;Sun said here’s how you would do web application development, here’s how you would do business programming, etc. Those APIs were kind of limited and they had complexity issues. You ended up writing a lot of XML and extra code.&lt;br /&gt;&lt;br /&gt;So Spring came along as a reaction to the difficulty of writing applications in Java and all the extra work we were having to do. Spring itself is a breath of fresh air for Java programmers. It levels the playing field and made it a lot easier to build applications that were easier to test and things like that. But Spring also adds its own complexity, so you shift from writing a lot of code to configuring components of a framework and ultimately writing less code.&lt;br /&gt;&lt;br /&gt;Spring is a platform that itself is complex, but it makes your programming ultimately easier to write and understand. But to get to the point where you’re actually programming, it takes a lot more work. What Roo does is provide you a simple shell that accepts commands, and Roo does the configuration for you.&lt;br /&gt;&lt;br /&gt;You can tell the shell to "build a web application and add a database to it" giving it simple commands to do so. It makes developing Java applications with Spring easier to get started with. &lt;br /&gt;&lt;br /&gt;[The Roo team] are trying to give you good starting points, relatively good ways of doing things so that you can be productive right away on the Spring platform.&lt;br /&gt;&lt;br /&gt;And the nice thing about Roo is, unlike a lot of other frameworks, it doesn’t force you to program in something different than what you’re used to. You’re still going to program in Spring, you’re still going to program in Java, so it’s just as if you were working on a Spring application or a Java application, but you’ve gotten there quicker. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Q:&lt;/b&gt; So basically there’s a lot less downtime with learning new classes, new syntax, etc.?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Ken:&lt;/b&gt; There can be. I think part of it is [that] if you’re a Spring developer, [Roo] frees you from the busywork you that have to do. I call it "doing my light work" in the book. It really takes care of repetitive tasks. But it’s not hidden from you, the code’s still there, it’s just not in your way as you’re writing your business code.&lt;br /&gt;I think you still need to be aware of the platform you’re working on. So you should learn something about Spring – you can’t ignore it, because you are programming in it. But what Roo does is configure the environment and allow you to quickly create a controller, a Spring Bean, relational mappings with JPA, entities, everything you need to use for transactional programming to databases, for example. All that stuff that takes a project a week, two weeks, three weeks is done for you.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Q:&lt;/b&gt; That sounds like it could be really helpful for companies looking to speed up production, but with so many different layers – Roo on top of Spring on top of Java – does it make it difficult to keep everything compatible and up-to-date?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Ken: &lt;/b&gt;That’s a good question. Normally, Spring issues about one big release per year – but Roo is developed by a team of VMware's Spring Framework developers, and they keep Roo compatible with the latest versions of the software. Roo 1.2 uses Spring 3.1, and I understand it supports Java 7, for example.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Q: &lt;/b&gt;Are there any big changes that you’re excited about with these new updates?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Ken: &lt;/b&gt;I know that one of the major things is that Spring is starting to take into account the environment that you’re running in. You can then turn features on or off based on that environment.&lt;br /&gt;For instance, in development and testing, you may want the logging and reporting turned way up so you can trace through a problem. But in production, you’re going to have that program on a server somewhere, where it’s pretty much lights out and you don’t want to fill up the disk space with lots of logging, so you will dial it back.&lt;br /&gt;&lt;br /&gt;You could tell Spring to enable the logging only if [you are running the code] in a development environment name. That’s something that other platforms such as Ruby on Rails have had for a while and that will make it easier for Spring to play the same sort of role. I’m sure that Roo will be rolling this feature within the next few updates. &lt;br /&gt;&lt;br /&gt;This release of Spring is also the one that officially supports the latest version of Java, so it’s making it grow up a bit more in the infrastructure it needs to remain a leader in enterprise programming solutions.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Q:&lt;/b&gt; So what about mobile? How do Spring and Roo fit in with the explosion of mobile applications that we’re seeing with people using apps on their phones and tablets versus in a desktop environment?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Ken:&lt;/b&gt; Spring and Roo can play a role in a mobile web application very easily. Of course, Spring MVC can host Javascript APIs like JQuery mobile or Sencha Touch, as can any other web application.&lt;br /&gt;From the Spring infrastructure perspective, developers can serve up data back and forth to a phone in any number of formats, because it is a robust server-side infrastructure.&lt;br /&gt;&lt;br /&gt;The challenge for Spring right now is they’ve got to find a path for what they provide to build the client side beyond just enabling Javascript frameworks and mobile web- for example iPhone apps and Android apps and how they support them.&lt;br /&gt;&lt;br /&gt;They have an API called &lt;a href="http://static.springsource.org/spring-android/docs/1.0.x/reference/htmlsingle/" target="_blank"&gt;Spring Android&lt;/a&gt; that provides access to security and data from native Android applications; they also have &lt;a href="http://www.springsource.org/spring-mobile" target="_blank"&gt;Spring Mobile&lt;/a&gt;, which provides device detection, and allows users to enable a mobile or normal web application experience, but they don’t yet have in my opinion, a strong orchestrated handset or tablet strategy. They come from more of a web and server-side infrastructure play, and so the thing I want to see at ETE this year is where they are going with their mobile strategy.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Q: &lt;/b&gt;Sounds like you do a lot of different types of development across all platforms. What do you like most? What gets you excited?&lt;b style="mso-bidi-font-weight: normal;"&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Ken: &lt;/b&gt;I used to like the back-end infrastructure stuff more – like getting databases connected and such – but I’m really starting to get interested in web and mobile, mostly because it’s a new challenge for me. I’ve never been the person to write a beautiful web application. I write it so it works well [and work with web designers]. But I do think from a mobile perspective, there are a lot of toolkits you can use to put together nice, sophisticated applications and it’s more immediate.&lt;br /&gt;So where do I see my focus in the next 6 months to a year? Well, I really want to spend more time on the web, web-mobile tier and even the native mobile tier with iOS and Android. That really interests me.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Q: &lt;/b&gt;Any advice that you’d give to people who are maybe just starting out programming in Java and who don’t know much about Spring and Roo? What would you tell someone who just wants to "jump in" and get going on the platform?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Ken: &lt;/b&gt;I think the best thing to do with Java [or really any] applications is to try to find sample applications that already work and plow through them. I know that it doesn’t sound exciting, but trying things more than anything else helps you learn. I think that tools like Roo can help you get started quickly. You can tell Roo to "go build me an application" and then tinker with it.&lt;br /&gt;&lt;br /&gt;What are you going to do, burn the house down? You’re not going to break anything. I’m a firm believer in writing a lot of "throwaway" code. Get something out there, play with it, tweak a little bit of it. Try things in isolation. I think that experimentation and play is key for a developer, and if you don’t have that interest, you’re going to struggle.&lt;br /&gt;&lt;br /&gt;You really have to put the screwdriver in the light socket and see what happens.&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Ken Rimple is the Director of &lt;a href="http://chariotsolutions.com/education"&gt;Education Services&lt;/a&gt; for Chariot Solutions. He writes about Roo and other technologies for Chariot, and also blogs about technology, photography, and music on his blog, &lt;a href="http://rimple.com/" target="_blank"&gt;rimple.com&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Have a question for Ken that we didn’t cover? Get in touch with us and we’ll post our answers to your questions in a follow up interview as we get closer to ETE 2012! &lt;a href="http://www.blogger.com/goog_634375720"&gt;info@chariotsolutions.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Sign up for &lt;a href="http://www.phillyemergingtech.com/"&gt;Philadelphia Emerging Technologies for the Enterprise&lt;/a&gt; by February 15 and get a special early bird rate – don’t miss out on the chance to be a part of the biggest emerging technology event on the East Coast this year.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4501967602398384736?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4501967602398384736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2012/01/philly-ete-speaker-interview-ken-rimple.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4501967602398384736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4501967602398384736'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2012/01/philly-ete-speaker-interview-ken-rimple.html' title='Philly ETE - Speaker Interview, Ken Rimple co-author of Spring Roo in Action'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6266258354316951852</id><published>2012-01-09T09:11:00.000-05:00</published><updated>2012-01-09T13:04:52.609-05:00</updated><title type='text'>Sorting collections with Backbone.js and jQuery Mobile</title><content type='html'>&lt;style type="text/css"&gt;.gist-highlight {    border-left: 3ex solid #eee;    position: relative;}.gist-highlight pre {    counter-reset: linenumbers;}.gist-highlight pre div:before {    color: #aaa;    content: counter(linenumbers);    counter-increment: linenumbers;    left: -3ex;    position: absolute;    text-align: right;    width: 2.5ex;}&lt;/style&gt;&lt;p&gt;In a previous &lt;a href="http://blog.chariotsolutions.com/2011/12/introduction-to-backbonejs-with-jquery.html"&gt;post&lt;/a&gt;, I provided a simple example of rendering an HTML list view using Backbone.js and jQuery Mobile.  The code from that example ended up rendering a list like this:&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-nPFV44nTzr0/TvNn41kfLDI/AAAAAAAAAzE/f9bbdxZNhT8/s1600/Screen%2BShot%2B2011-12-22%2Bat%2B12.22.21%2BPM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="400" width="257" src="http://4.bp.blogspot.com/-nPFV44nTzr0/TvNn41kfLDI/AAAAAAAAAzE/f9bbdxZNhT8/s400/Screen%2BShot%2B2011-12-22%2Bat%2B12.22.21%2BPM.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Notice that the list is presented in the order that came from the JSON.&lt;/p&gt;&lt;script src="https://gist.github.com/1469100.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;Also, when items are added to the list, they show up at the bottom.  While easy, this isn't the best.  In this post, I'll add sorting to the backbone collection and make a small change to the view so that as new items are added, the list is automatically sorted.&lt;/p&gt;&lt;p&gt;Backbone.js makes these changes very easy.  In order for a Backbone collection to be sorted, you implement a comparator method on the collection.  As models are added to the collection, Backbone will make sure the sorting is maintained based on the comparator implementation.  From the Backbone documentation "Comparator functions take a model and return a numeric or string value by which the model should be ordered relative to others".&lt;/p&gt;&lt;p&gt;We will sort our list based on the date the exercise activity occurred.  Since comparators must return a number or string for sorting, we will return the time in milliseconds since 1/1/70.  Our new collection definition looks like this:&lt;script src="https://gist.github.com/1511105.js?file=snippet.js"&gt;&lt;/script&gt;If we refresh our browser with the updated collection implementation, notice that the list is now sorted by date.&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-qOpz8LkIWmU/TvNpxOmEqfI/AAAAAAAAAzQ/jJZqH1cQNBc/s1600/Screen%2BShot%2B2011-12-22%2Bat%2B12.32.28%2BPM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="400" width="257" src="http://2.bp.blogspot.com/-qOpz8LkIWmU/TvNpxOmEqfI/AAAAAAAAAzQ/jJZqH1cQNBc/s400/Screen%2BShot%2B2011-12-22%2Bat%2B12.32.28%2BPM.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;If we wanted it sorted descending, we would simply return the negative value of the getTime() method.&lt;/p&gt;&lt;p&gt;If you tried to add a new activity, you'll notice that it shows up at the end of the list.  This is due to the fact that we bind a listener to the add method of the collection (line 7 below), and all this does is append the HTML to the end of the list view (line 30 below).&lt;/p&gt;&lt;script src="https://gist.github.com/1511141.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;If you were to open a JS console in the browser and investigate the collection by entering &lt;blockquote&gt;JSON.stringify(exercise.activities)&lt;/blockquote&gt; you would see that the collection is ordered.  To fix the HTML representation of the collection all we need to do is replace the add event binding to call render.  This will re-render the HTML based on the collection.  We can also remove the add method in the View, as it is no longer needed.  Our updated View configuration looks like this:&lt;p&gt;&lt;script src="https://gist.github.com/1511157.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;After refreshing the view, the list will continue to be sorted even when adding new activities.  Since the code just adds an item with todays date, try typing the following in the JS console&lt;/p&gt;&lt;blockquote&gt;exercise.activities.add({id:12, date:"12/01/2011", type:"Interval Run"});&lt;/blockquote&gt;&lt;p&gt;This should add an item at the top of the list.  Now your exercise activity will always be sorted.&lt;/p&gt;&lt;P&gt;The source code can be found in my git repository &lt;a href="https://github.com/stevenpsmith/Exercise/tree/sort"&gt;here&lt;/a&gt;.  This URL will take you to the "sort" branch.  The master branch represents the code from the introduction blog post found &lt;a href="http://blog.chariotsolutions.com/2011/12/introduction-to-backbonejs-with-jquery.html"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6266258354316951852?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6266258354316951852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2012/01/sorting-collections-with-backbonejs-and.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6266258354316951852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6266258354316951852'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2012/01/sorting-collections-with-backbonejs-and.html' title='Sorting collections with Backbone.js and jQuery Mobile'/><author><name>Steve Smith</name><uri>http://www.blogger.com/profile/08979713820164614687</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/-NsBa615hX98/TwRsQ7XcBXI/AAAAAAAAAzc/TrNC7X6ULs4/s220/IMG_0119.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-nPFV44nTzr0/TvNn41kfLDI/AAAAAAAAAzE/f9bbdxZNhT8/s72-c/Screen%2BShot%2B2011-12-22%2Bat%2B12.22.21%2BPM.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-9086551756311204453</id><published>2012-01-03T16:27:00.000-05:00</published><updated>2012-01-03T11:44:29.468-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='backbone'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile web'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery mobile'/><title type='text'>Introduction to Backbone.js with jQuery Mobile</title><content type='html'>&lt;style type="text/css"&gt;.gist-highlight {    border-left: 3ex solid #eee;    position: relative;}.gist-highlight pre {    counter-reset: linenumbers;}.gist-highlight pre div:before {    color: #aaa;    content: counter(linenumbers);    counter-increment: linenumbers;    left: -3ex;    position: absolute;    text-align: right;    width: 2.5ex;}&lt;/style&gt;&lt;p&gt;If you are working on a JavaScript heavy application (think jQuery Mobile, etc.), you probably will want to look at some JavaScript libraries to help add structure, consistency and convenience to your applications.  One of the JavaScript libraries I've used lately is Backbone.js.  To quote Backbone themselves, it provides "models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.".  This is really a great summary of what Backbone can provide to your application.&lt;/p&gt;&lt;p&gt;As an example of how to apply Backbone, I'll create a small jQuery Mobile app and use a Backbone model, collection and view to render the user interface.  Through the use of Backbone's event model, the user interface will update as the model changes or new models are created.&lt;/p&gt;&lt;p&gt;I decided to use jQuery Mobile as the UI framework mainly because I am a mobile guy and it will provide the HTML with some reasonable style with no additional effort on my part.  I know, lazy...but it works for this blog post :)  Continuing on the lazy path, I will refer to jQuery Mobile as JQM from this point forward.&lt;/p&gt;&lt;p&gt;The following assumes you are at least a little familiar with jQuery and JQM.  If not, take a look at the JQM website (&lt;a href="http://jquerymobile.com/"&gt;http://jquerymobile.com/&lt;/a&gt;).  They have some great documentation and even a template for creating a basic app.  All of the code in this post will be available in my github repository (&lt;a href="https://github.com/stevenpsmith/Exercise/tree/BackboneIntro"&gt;https://github.com/stevenpsmith/Exercise/tree/BackboneIntro&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;The application we are going to make will allow a user to log exercise they have done on any given day.  Please remember this is a very basic app for the sole purpose of demonstrating Backbone.js.  The piece that will be developed for this post will involve pulling exercise data from a server and presenting it in a list view, a very common paradigm for mobile apps.  In the end, our app will look like this: &lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-LLAY-2_Q_bc/TuoUzjocCQI/AAAAAAAAAyo/HoJyl7PXprA/s1600/ListView.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="320" width="242" src="http://3.bp.blogspot.com/-LLAY-2_Q_bc/TuoUzjocCQI/AAAAAAAAAyo/HoJyl7PXprA/s320/ListView.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;The JSON we will be dealing with will look like this:&lt;/p&gt;&lt;script src="https://gist.github.com/1469100.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;I like to organize my application structure a little differently than the JQM introduction shows, mainly for organizational reasons.  My application structure looks like this:&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-92C6xt0utsA/TujxoxrXtHI/AAAAAAAAAyc/7aC8uqtWxo8/s1600/dir_structure.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="263" width="253" src="http://1.bp.blogspot.com/-92C6xt0utsA/TujxoxrXtHI/AAAAAAAAAyc/7aC8uqtWxo8/s320/dir_structure.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;All of our work will be done in index.html and app.js.  In real applications I usually break down my JS files even further, but it really isn't necessary here.  The list page of the application is defined within index.html.  It should look like a typical JQM page definition with the only the content portion defined.  We will use the Backbone View to create the list view:&lt;/p&gt;&lt;script src="https://gist.github.com/1477966.js?file=snippet.html"&gt;&lt;/script&gt;&lt;p&gt;If we view this in the browser, we get an empty page with an add button in the header.  Since we want to populate our list view with data, we should define a Backbone model and collection in order to manipulate and store the data via JavaScript.  A basic model and its collection are easily defined:&lt;/p&gt;&lt;script src="https://gist.github.com/1478005.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;The great thing about the collection is it provides a RESTful access back to your server for data retrieval and persistence.  To keep this simple, our data will be served from a static JSON file with the structure referenced earlier.  Since we have no real server side in this example, we can't really save our changes anywhere but in the client's memory.  But the collection will fetch the data from the server and can be used to help render our user interface.  The following code will create an instance of the collection in memory, retrieve the data from the server, and parse it into a collection of models.&lt;/p&gt;&lt;script src="https://gist.github.com/1478036.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;The exercise.initData() function can be called during initialization of the application (or wherever else might be appropriate) to load the data.  Now it is time to render the view.  Backbone views depend upon Underscore.js.  Underscore is a utility library that includes a lot of great features, one of which is view templates.  Backbone can be used with many view template frameworks (e.g. Mustache, Handlbars, etc.), but here we will stick with Underscore templates as they meet our needs.  For our exercise activity items, we need a very basic template like this:&lt;/p&gt;&lt;script src="https://gist.github.com/1478073.js?file=snippet.html"&gt;&lt;/script&gt;&lt;p&gt;Giving the template a unique id will let us access it using typical jQuery selectors.  The data driven parts of the template are surrounded by &lt;blockquote&gt;&lt;%= %&gt;&lt;/blockquote&gt;  As you can see in line 2, we are using the id, date, and type attributes of whatever model is supplied to the template to fill in the HTML accordingly.  While the "identifier" attribute is not a real HTML attribute and not required by any of the frameworks, it would be used to determine what activity the user selected in the list so the appropriate data could be retrieved and displayed on a subsequent page.&lt;/p&gt;&lt;p&gt;The next step is to define the Backbone View that will render the list view.  Backbone views can be defined and set up numerous ways, and the documentation does a great job explaining the options, etc.  I like to define my views so that they are as self contained as possible.  So, rather than allowing Backbone to create the HTML within a DIV (the default behavior), I define the appropriate properties to create a JQM list view as shown in lines 2-4 below: &lt;/p&gt;&lt;script src="https://gist.github.com/1478368.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;From the Backbone site: "The default implementation of render is a no-op. Override this function with your code that renders the view template from model data, and updates &lt;tt&gt;this.el&lt;/tt&gt; with the new HTML. A good convention is to return &lt;tt&gt;this&lt;/tt&gt; at the end of render to enable chained calls".  The &lt;tt&gt;$(this.el)&lt;/tt&gt; refers to the containing element, in this case the &lt;tt&gt;ul&lt;/tt&gt; element.  There are standard attributes that are accessible from within the Backbone View including &lt;tt&gt;collection&lt;/tt&gt; and &lt;tt&gt;model&lt;/tt&gt;.  Lines 17-20 iterate over the collection of activities, fills in the template placeholders with the data from the model, and appends the resulting HTML to the containing element. &lt;/p&gt;&lt;p&gt;If you need to pass arbitrary data to your view, it can be accessed via the &lt;tt&gt;options&lt;/tt&gt; object as shown on line 11 of the code snippet.  As mentioned earlier, I like my Backbone Views to be as self contained as possible, so I provide the containing HTML element for this view (as a jQuery object) when constructing the View instance.  Line 20 sets the HTML of the containing element to the Backbone View and line 21 tells JQM to style things appropriately.&lt;/p&gt;&lt;p&gt;The next step is to instantiate and render the view with the appropriate collection and HTML container.  Since this is the "home" page in our application, this is done after JQM initializes the page.&lt;/p&gt;&lt;script src="https://gist.github.com/1478582.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;Now we have a list view that renders a JQM list based on data in a Backbone collection.  To take advantage of the real power of Backbone models/collections, we can add listeners for changes to the collection that will update the view based on those changes.  The beauty of this is the additional code to accomplish this is minimal. By adding &lt;blockquote&gt;this.collection.bind('add', this.add, this);&lt;/blockquote&gt; to the initialize method of our Backbone View and providing an &lt;tt&gt;add()&lt;/tt&gt; method.&lt;/p&gt;&lt;script src="https://gist.github.com/1478621.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;Here we are just grabbing the list view and appending the new model to the view (and refreshing it so JQM does its magic).  By adding a click handler to the "Add" button, we can test that adding a model to the collection updates the view.&lt;/p&gt;&lt;script src="https://gist.github.com/1478658.js?file=snippet.js"&gt;&lt;/script&gt;&lt;p&gt;There are other methods on which to bind, but this provides a quick example on how Backbone can be used to assist with view rendering and data handling in JavaScript based client applications.&lt;/p&gt;&lt;p&gt;The entire code base is available &lt;a href="https://github.com/stevenpsmith/Exercise/tree/BackboneIntro"&gt;here&lt;/a&gt;.  It can be deployed on any web server.  For OS X, I use the built in web server, but feel free to use the server of your choice.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-9086551756311204453?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/9086551756311204453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/12/introduction-to-backbonejs-with-jquery.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/9086551756311204453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/9086551756311204453'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/12/introduction-to-backbonejs-with-jquery.html' title='Introduction to Backbone.js with jQuery Mobile'/><author><name>Steve Smith</name><uri>http://www.blogger.com/profile/08979713820164614687</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://2.bp.blogspot.com/-NsBa615hX98/TwRsQ7XcBXI/AAAAAAAAAzc/TrNC7X6ULs4/s220/IMG_0119.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-LLAY-2_Q_bc/TuoUzjocCQI/AAAAAAAAAyo/HoJyl7PXprA/s72-c/ListView.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-1670130340470530234</id><published>2011-12-19T11:25:00.001-05:00</published><updated>2011-12-21T08:45:27.205-05:00</updated><title type='text'>Spring Roo 1.2.0 released - it's growing up...</title><content type='html'>&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;On Saturday, 12/17/11, SpringSource/VMware&amp;nbsp;&lt;a href="http://blog.springsource.org/2011/12/17/spring-roo-1-2-0-release-available/" target="_blank"&gt;released version 1.2.0 of Spring Roo&lt;/a&gt;, the Spring rapid application development platform, to the public.&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;There are a lot of good changes in this release to make Roo quite palatable to Enterprise developers, such as:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Multi-POM projects - now you can create web, service, database, and functional tiers and tie them all together with a parent POM. &amp;nbsp;You can even scaffold web interfaces based on models from other projects.&lt;/li&gt;&lt;li&gt;Scaffolded service support and repository support - now, instead of using the Active Record pattern (entities contain their own persistence methods) you can write your own services and repositories. &amp;nbsp;Or, let Spring scaffold them for you. &amp;nbsp;As usual, all scaffolded service and repositories will automatically contain the proper base methods, but you can then extend them and add your own, or push the code in and work with it yourself.&lt;/li&gt;&lt;li&gt;A cleaner add-on API - the Roo team has been working toward cleaning up the add-on internals and making it more consistent. Expect more add-on developers to appear after this release, it's really a straight-forward process to develop them.&lt;/li&gt;&lt;li&gt;JSF support - while this is the initial version of the add-on, it is rather feature-rich. &amp;nbsp;Roo supports either Oracle Mojarra or Apache MyFaces, and theming, and uses composed UIs. &amp;nbsp;In some ways, developing user interfaces with JSF may be easier for newer developers. &amp;nbsp;Unlike earlier efforts, though, Roo is not mounting JSF via the WebFlow integration. &amp;nbsp;Scaffolding is supported, as are rich widgets via PrimeFaces (www.primefaces.org).&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;There is more, including enhancements to GWT and some shell usability enhancements (you can now do a OS escape with the exclamation point&amp;nbsp;&lt;b&gt;and a space&lt;/b&gt;&amp;nbsp;such as&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;roo&amp;gt; ! ls&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;).&amp;nbsp; W&lt;/span&gt;e're waiting on an updated blog entry from&amp;nbsp;&lt;a href="http://blog.springsource.org/author/stewarta/" target="_blank"&gt;Alan Stewart&lt;/a&gt;&amp;nbsp;to detail everything. &amp;nbsp;For now, though, you can download Roo 1.2.0 from&amp;nbsp;&lt;a href="http://springsource.org/spring-roo"&gt;springsource.org/spring-roo&lt;/a&gt;. &amp;nbsp;&lt;a href="http://www.infoq.com/author/Srini-Penchikala" target="_blank"&gt;Srini Penchikala&lt;/a&gt;&amp;nbsp;and I have wrapped up writing chapters for Roo in Action, and are readying it for print in early April. &amp;nbsp;The book covers Roo 1.2.0, and will be helpful for those just starting out. &amp;nbsp;You can purchase the MEAP online at&amp;nbsp;&lt;a href="http://www.manning.com/rimple"&gt;http://www.manning.com/rimple&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Ken is a writer, podcaster and trainer/mentor at Chariot Solutions. He teaches Spring, Maven, and other subjects, and you can see training courses offered by Chariot at &lt;a href="http://chariotsolutions.com/education"&gt;chariotsolutions.com/education&lt;/a&gt;.&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-1670130340470530234?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/1670130340470530234/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/12/spring-roo-120-released-its-growing-up.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1670130340470530234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1670130340470530234'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/12/spring-roo-120-released-its-growing-up.html' title='Spring Roo 1.2.0 released - it&apos;s growing up...'/><author><name>Ken Rimple</name><uri>http://www.blogger.com/profile/10070354859699635524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-JS0Esv4Qwwc/Tu9lo2l1NcI/AAAAAAAAAB4/6pctQKDHiUM/s220/KenRimple-Public-Photo-200x200.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4333895652838169699</id><published>2011-12-16T01:29:00.000-05:00</published><updated>2011-12-15T22:28:26.930-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='yammer'/><category scheme='http://www.blogger.com/atom/ns#' term='winning'/><category scheme='http://www.blogger.com/atom/ns#' term='tebow'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>OpEd: Yammering about Scala, Java, and Winning</title><content type='html'>&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;This is an opinion piece that represents the views of the author, and does not represent the official stance of Chariot Solutions. But sometimes it is fun to weigh in on the news of the day.&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;There has been quite a dust up in the blogosphere about Yammer's decision to switch from using Scala to Java. Google "yammer switching to scala" and you'll get a sampling. You can &lt;a href="http://codahale.com/the-rest-of-the-story/"&gt;read it&lt;/a&gt; for yourself, but the gist of story seems to be that Yammer, the self described "enterprise social network" e.g. private label Twitter, decided to move their development from Scala to Java. The Scala guys at Typesafe heard about this (disclosure: Chariot Solutions is a Typesafe partner), and privately asked Coda Hale, infrastructure architect at Yammer, the reasoning behind the move. Coda responded in another private-but-soon-made-public email. It is a &lt;a href="http://codahale.com/downloads/email-to-donald.txt"&gt;very long and detailed email&lt;/a&gt;, but in summary:&lt;br /&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;"The essence of it is that the friction and complexity that&lt;br /&gt;comes with using Scala instead of Java isn't offset by enough productivity&lt;br /&gt;benefit or reduction of maintenance burden for it to make sense as our default&lt;br /&gt;language."&lt;/pre&gt;Then Hale clarified the &lt;a href="http://codahale.com/the-rest-of-the-story/"&gt;purpose of his email&lt;/a&gt; and Yammer clarified their &lt;a href="http://eng.yammer.com/blog/2011/11/30/scala-at-yammer.html"&gt;official position on Scala&lt;/a&gt;. &amp;nbsp;Yammer's decision has (re)ignited the debate over whether Scala is better or worse than Java. &amp;nbsp;If you read the comments section of this &lt;a href="http://blog.joda.org/2011/11/real-life-scala-feedback-from-yammer.html"&gt;blog post from Stephen Colebourne&lt;/a&gt;, you get the general gist but here is a sampling that I can reprint and still keep this blog "family friendly":&lt;br /&gt;&lt;br /&gt;In favor of Scala:&lt;br /&gt;&lt;span class="Apple-style-span" style="background-color: #e6d8cc; font-family: verdana, georgia, arial; font-size: 11px; line-height: 15px;"&gt;Some pretty serious masochists out there at Yammer. I wonder if their investors now about it.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="line-height: 15px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="line-height: 15px;"&gt;Not in favor of Scala:&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="background-color: #e6d8cc; font-family: verdana, georgia, arial; font-size: 11px; line-height: 13px;"&gt;The code and build process was a rat's nest of pain and people should avoid using scala at all costs on any commercial project where these things can become a big issue.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="background-color: #e6d8cc; font-family: verdana, georgia, arial; font-size: 11px; line-height: 13px;"&gt;I've used and learned lots of different languages but can't recall anything more painful than scala. Cross compiling and maintaining c codebases with native ui on different Linux/winblows envs was easier and less traumatizing than this. It's fine for academic pursuits and personal projects but you're smoking some serious crack to try and justify it commercially.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Opinion #1: Java is winning (like Tebow not Sheen)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The biggest thing that I take away from this whole incident is that Java is winning. &amp;nbsp;I don't mean Java is winning vs Scala or that Java is better than Scala. &amp;nbsp;I mean that Java is,&amp;nbsp;in my opinion, an aging language with many quirks, with a fairly&amp;nbsp;dysfunctional&amp;nbsp;governing body in the JCP, and a yet-to-be-fully-trusted new caretaker in Oracle, full of the baggage of vendor compromises which nearly ruined JEE, and faces many very strong competitors on the JVM itself like Scala, Groovy, and Clojure, and yet -- against all odds and in very &lt;a href="http://espn.go.com/blog/afcwest/post/_/id/36865/another-stunning-tebowmania-chapter"&gt;Tim Tebowesque&lt;/a&gt; form -- is winning over highly skilled engineering shops like Yammer.&lt;br /&gt;&lt;br /&gt;I've been a Java programmer for 10+ years and there are many things about Java that&amp;nbsp;irritate&amp;nbsp;me like the slew of boilerplate code that you need in every single class. &amp;nbsp;But while innovation in the language itself can only go so far while still maintaining backward&amp;nbsp;compatibility, innovation in the wider Java community is still thriving. &amp;nbsp;Java may not be the best language out there, but the battle tested JVM runtime combined with the&amp;nbsp;countless mature open source tools and frameworks make the Java ecosystem as a whole arguably the richest one on the planet.&lt;br /&gt;&lt;br /&gt;For a while I was convinced Java was the new Cobol: a language past its prime which due to its huge popularity will never die out completely, but not on the short list of candidate languages for a green field project. &amp;nbsp;Now I've changed my mind. &amp;nbsp;Java has its warts but there is value in maturity, and it still can compete head to head with any language ecosystem out there.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Opinion #2: Scala is winning too&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Yes, Yammer moved from Java to Scala, but they make explicitly clear that they like Scala too. &amp;nbsp;It is just that Java make more sense for them and their specific business needs. &amp;nbsp;Yammer was able to build an impressive high volume system with a small engineering team using Scala. &amp;nbsp;One shop moving away from Scala does not constitute a trend. &amp;nbsp;Scala has a relatively young ecosystem but already some very impressive open source projects like Akka. &amp;nbsp;I expect the combination of Jonas Boner and Martin Odersky together in a single company to provide a real boost to Scala.&lt;br /&gt;&lt;br /&gt;I've never used Scala on a real project but I'm in love with the syntax and what you can do with the language. &amp;nbsp;I know people who use it all the time and love it as well. &amp;nbsp;Scala is undeniably more complex than Java but with the complexity comes more power. &amp;nbsp;Scala isn't better or worse than Java. &amp;nbsp;It is just different.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Opinion #3: Polygot is hard&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I really like the idea of polygot programming: pick the programming language that fits your problem space. &amp;nbsp;I worked with many large clients that solve every problem with the same Java stack even when it is obviously a bad fit. &amp;nbsp;But one of the things that Hale mentioned in his email was that the choice for Yammer wasn't between Scala and Java, it was between Scala/Java and Java. &amp;nbsp;The context switching caused by thinking in multiple languages was a drag on the team. &amp;nbsp;When you think about it, a programmer is required to know many languages just to build a basic web app using a Java stack: Java, SQL, HTML, Javascript, and CSS. &amp;nbsp;Adding more languages to the mix makes things that much more complex. &amp;nbsp;Then you also include build tools, language idioms, and the ecosystem of libraries and frameworks.&lt;br /&gt;&lt;br /&gt;I work in both Java and Groovy, and I find those languages similar enough to minimize the difficulty of context switching, but I can imagine switching between diverse languages like Java and Clojure might make my head explode.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Opinion #4: Coda Hale is a humorous writer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Not everyone can write about techie stuff and make it humorous and informative. &amp;nbsp;Here is a quote from &lt;a href="http://codahale.com/the-rest-of-the-story/"&gt;his blog post&lt;/a&gt; that made me chuckle:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="background-color: #fefefe;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;"The Scala community needs another giant blog post about ways in which someone doesn’t like Scala like I need a hole in my head, and I’d rather suck a dog’s nose dry than lend a hand to the nerd slapfights on Hacker News."&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I was pleasantly surprised to find that Hale is speaking at my company's annual technology conference &lt;a href="http://phillyemergingtech.com/2012"&gt;Philly ETE&lt;/a&gt;. &amp;nbsp;That's one session I'll be attending.&lt;br /&gt;&lt;br /&gt;And I might just ask him if Scala is better than Java :-)&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4333895652838169699?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4333895652838169699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/12/oped-yammering-about-scala-java-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4333895652838169699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4333895652838169699'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/12/oped-yammering-about-scala-java-and.html' title='OpEd: Yammering about Scala, Java, and Winning'/><author><name>Joel Confino</name><uri>http://www.blogger.com/profile/03306877747132991554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-1117736562447578982</id><published>2011-11-07T03:00:00.000-05:00</published><updated>2011-11-07T03:00:03.051-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy algorithm shunting yard'/><title type='text'>Groovy Algorithms: Shunting Yard</title><content type='html'>Groovy's sugary syntax makes coding algorithms -- dare I say it -- fun.&amp;nbsp; The &lt;a href="http://en.wikipedia.org/wiki/Shunting-yard_algorithm"&gt;shunting yard algorithm&lt;/a&gt;, invented by Dutch computer scientist &lt;a href="http://en.wikipedia.org/wiki/Edsger_Dijkstra"&gt;Edsger Dijkstra&lt;/a&gt;, is used to parse mathematical expressions.&amp;nbsp; You might have picked up on this already, but computers and people think differently.&amp;nbsp; We commonly use &lt;a href="http://en.wikipedia.org/wiki/Infix_notation"&gt;infix&lt;/a&gt; notation to write mathematical expressions.&amp;nbsp; It is what you learned in school.&amp;nbsp; For example: "3 * (2 + 3)".&amp;nbsp; Makes sense to you, but it is inefficient for a computer to process.&amp;nbsp; Things like operator precedent and nested parenthesis make infix rather messy.&amp;nbsp; A more efficient format is postfix or &lt;a href="http://en.wikipedia.org/wiki/Reverse_Polish_notation"&gt;Reverse Polish notation&lt;/a&gt;.&amp;nbsp; In postfix, the operands are listed first, and then the operator.&amp;nbsp; For example: "2 3 + 3 *".&amp;nbsp; This eliminates the need for parenthesis, and allows you to calculate the expression using just a single stack to hold operands and intermediate results.&amp;nbsp; Why didn't we learn this in school?&amp;nbsp; I don't know.&amp;nbsp; Why aren't we using the metric system yet?&amp;nbsp; Why doesn't Siri on my iPhone understand anything I say even though it works great in the commericals?&amp;nbsp; Life's little mysteries.&amp;nbsp; Back to shunting yard.&amp;nbsp; Here is my Groovy implementation of it.&lt;br /&gt;&lt;br /&gt;The main class is ExpressionSolver.&amp;nbsp; The computePostfix method (line 7) shows how easy it is to calculate a postfix expression with a single stack and single pass through the tokens in the expression.&amp;nbsp; It delegates the work of converting from infix to postfix to the appropriately named ShuntingYardAlgorithm class (line 21).&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt;1:  package org.jadcon.expression  &lt;br /&gt;2:  def infixExpression = '5.5 + ((6 + 2) * 4) - -3 * 1.5'  &lt;br /&gt;3:  def postfixExpression = '5.5 6 2 + 4 * -3 1.5 * - +'  &lt;br /&gt;4:  def expectedResult = 42  &lt;br /&gt;5:  assert computePostfix(postfixExpression) == expectedResult   &lt;br /&gt;6:  assert computeInfix(infixExpression) == expectedResult  &lt;br /&gt;7:  def computePostfix(postfixExpression) {  &lt;br /&gt;8:       def stack = []  &lt;br /&gt;9:       postfixExpression.split().each { token -&amp;gt;  &lt;br /&gt;10:            if (token.isNumber()) {  &lt;br /&gt;11:                 stack.add(token)  &lt;br /&gt;12:            } else {  &lt;br /&gt;13:                 def b = stack.pop().toBigDecimal()  &lt;br /&gt;14:                 def a = stack.pop().toBigDecimal()  &lt;br /&gt;15:                 stack.add(Operator.valueFrom(token).calculate(a, b))  &lt;br /&gt;16:            }  &lt;br /&gt;17:       }  &lt;br /&gt;18:       stack.pop()  &lt;br /&gt;19:  }  &lt;br /&gt;20:  def computeInfix(infixExpression) {  &lt;br /&gt;21:       computePostfix(ShuntingYardAlgorithm.convertToPostfix(infixExpression))  &lt;br /&gt;22:  }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The ShuntingYardAlgorithm class coverts an expression from infix to postfix.&amp;nbsp; It requires two stacks: an output stack and a working stack.&amp;nbsp; The main logic is in the processToken method (line 14) which loops through each token.&amp;nbsp; Operands go directly on the output stack.&amp;nbsp; Operators and parenthesis are placed on the working stack to get correctly ordered when placed on the output stack. &lt;br /&gt;&lt;br /&gt;&lt;pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt;1:  package org.jadcon.expression  &lt;br /&gt;2:  class ShuntingYardAlgorithm {  &lt;br /&gt;3:       def static convertToPostfix(infixExpression) {  &lt;br /&gt;4:            def output = []  &lt;br /&gt;5:            def stack = []  &lt;br /&gt;6:            evenSpaceAroundParens(infixExpression).split().each { token -&amp;gt;  &lt;br /&gt;7:                 processToken(token, output, stack)  &lt;br /&gt;8:            }  &lt;br /&gt;9:            while (!stack.isEmpty()) {  &lt;br /&gt;10:                 output.add stack.pop()  &lt;br /&gt;11:            }  &lt;br /&gt;12:            output.join(' ')  &lt;br /&gt;13:       }  &lt;br /&gt;14:       def static processToken(token, output, stack) {  &lt;br /&gt;15:            if (token.isNumber()) {  &lt;br /&gt;16:                 output.add token  &lt;br /&gt;17:            } else {  &lt;br /&gt;18:                 switch (token) {                           &lt;br /&gt;19:                      case "(":  &lt;br /&gt;20:                           stack.add token  &lt;br /&gt;21:                           break  &lt;br /&gt;22:                      case ")":  &lt;br /&gt;23:                           while (stack.last() != "(") {  &lt;br /&gt;24:                                output.add stack.pop()  &lt;br /&gt;25:                           }  &lt;br /&gt;26:                           stack.pop() // pop the left paren and ignore it  &lt;br /&gt;27:                           break  &lt;br /&gt;28:                      default:  &lt;br /&gt;29:                           def operator = Operator.valueFrom(token)  &lt;br /&gt;30:                           while (!stack.isEmpty() &amp;amp;&amp;amp;  &lt;br /&gt;31:                                     stack.last().is(Operator) &amp;amp;&amp;amp;  &lt;br /&gt;32:                                     operator &amp;lt;= stack.last()) {  &lt;br /&gt;33:                                output.add stack.pop()  &lt;br /&gt;34:                           }  &lt;br /&gt;35:                           stack.add operator  &lt;br /&gt;36:                 }  &lt;br /&gt;37:            }  &lt;br /&gt;38:       }  &lt;br /&gt;39:       def static evenSpaceAroundParens(string) {  &lt;br /&gt;40:            def output = []  &lt;br /&gt;41:            string.each { letter -&amp;gt;  &lt;br /&gt;42:                 if (!output.isEmpty() &amp;amp;&amp;amp; letter != ' ') {  &lt;br /&gt;43:                      def last = output.last()  &lt;br /&gt;44:                      if (isParen(letter) &amp;amp;&amp;amp; last != ' ') {  &lt;br /&gt;45:                           output.add ' '  &lt;br /&gt;46:                      } else if (isParen(last)) {   &lt;br /&gt;47:                           output.add ' '  &lt;br /&gt;48:                      }  &lt;br /&gt;49:                 }  &lt;br /&gt;50:                 output.add letter  &lt;br /&gt;51:            }  &lt;br /&gt;52:            output.join()  &lt;br /&gt;53:       }  &lt;br /&gt;54:       def static isParen(letter) {  &lt;br /&gt;55:            letter == '(' || letter == ')'  &lt;br /&gt;56:       }  &lt;br /&gt;57:  }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The final class is Operator which is an enumeration of operators.&amp;nbsp; Groovy makes this code pretty tight using closures.&amp;nbsp; Even threw in a spaceship comparison operator for good measure (line 24).&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt;1:  package org.jadcon.expression  &lt;br /&gt;2:  enum Operator {  &lt;br /&gt;3:       PLUS('+', 0, { a, b -&amp;gt; a + b }),   &lt;br /&gt;4:       MINUS('-', 0, { a, b -&amp;gt; a - b }),   &lt;br /&gt;5:       MULTIPLY('*', 1, { a, b -&amp;gt; a * b }),   &lt;br /&gt;6:       DIVIDE('/', 1, { a, b -&amp;gt; a / b })  &lt;br /&gt;7:       String value  &lt;br /&gt;8:       int precedence  &lt;br /&gt;9:       Closure calculate  &lt;br /&gt;10:       private Operator(String value, int precedence, Closure calculate) {  &lt;br /&gt;11:            this.value = value  &lt;br /&gt;12:            this.precedence = precedence  &lt;br /&gt;13:            this.calculate = calculate  &lt;br /&gt;14:       }  &lt;br /&gt;15:       def static valueFrom(string) {  &lt;br /&gt;16:            for (operator in Operator.values()) {  &lt;br /&gt;17:                 if (operator.value == string) {  &lt;br /&gt;18:                      return operator  &lt;br /&gt;19:                 }  &lt;br /&gt;20:            }  &lt;br /&gt;21:            throw new IllegalArgumentException("invalid operator ${string}")  &lt;br /&gt;22:       }  &lt;br /&gt;23:       def int compareTo(other) {  &lt;br /&gt;24:            precedence &amp;lt;=&amp;gt; other.precedence       &lt;br /&gt;25:       }  &lt;br /&gt;26:       def String toString() {  &lt;br /&gt;27:            value  &lt;br /&gt;28:       }  &lt;br /&gt;29:  }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Coding the shunting yard algorithm was fun exercise in Groovyness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-1117736562447578982?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/1117736562447578982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/11/groovy-algorithms-shunting-yard.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1117736562447578982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1117736562447578982'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/11/groovy-algorithms-shunting-yard.html' title='Groovy Algorithms: Shunting Yard'/><author><name>Joel Confino</name><uri>http://www.blogger.com/profile/03306877747132991554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-9148453286441278238</id><published>2011-10-26T15:38:00.000-04:00</published><updated>2011-10-26T15:38:42.019-04:00</updated><title type='text'>Spring Roo 1.2 will be tipping point for RAD Java</title><content type='html'>I'm going to make a bold statement:  Spring Roo is about to do for Spring developers what Ruby on Rails did for Ruby developers - make developer agility, and not mechanical, rigid architectural structures, the focus of daily developer productivity.&lt;br /&gt;&lt;br /&gt;There.  I've said it.  But I have to step back for a minute and disclaim a few things.  First, as some of you may know I've been working with Spring and Spring-related projects for a while.  I'm also the education director here at Chariot, and Spring has been a mainstay of many of our Java-based consulting projects and course materials - we're also VMware Training Partner.  Finally, I'm an author on Spring Roo in Action by Manning, which is undergoing the transformation from draft to publication by early 2012.&lt;br /&gt;&lt;br /&gt;With the disclaimers aside, let's dig into my treatise. &amp;nbsp;First, a bit about what, exactly, Roo is...&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Roo in a nutshell&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Roo is a developer productivity tool that uses a simple command-line shell to configure projects, install features, and create various objects such as JPA entities, controllers, services, repositories, and tests. &amp;nbsp;Conceptually, it is similar to Rails, Grails, or even JBoss Seam, in that you use it to bootstrap a project. &lt;br /&gt;&lt;br /&gt;Unlike these other frameworks, which lean heavily on dynamically generated code, Roo is a compile-time framework - no "Roo Runtime" exists to interpret your code. &amp;nbsp;The shell adjusts your code and configuration, based on changes made to annotations in source code (either by the Roo shell, or by the developer). &amp;nbsp;Roo even generates setters, getters, JPA code, transaction logic, scaffolded controller views, and a lot more.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Here is a typical Roo JPA entity:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java;"&gt;@RooJavaBean&lt;br /&gt;@RooToString&lt;br /&gt;@RooActiveRecord&lt;br /&gt;public class Employee {&lt;br /&gt;&lt;br /&gt;  @Max(length = 20)&lt;br /&gt;  private String firstName;&lt;br /&gt;&lt;br /&gt;  @NotNull&lt;br /&gt;  @Max(length = 30)&lt;br /&gt;  private String lastName;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You may be saying "where are the getters, setters, IDs, constructors? &amp;nbsp;Isn't this just another strange "hide my code in some unaccessible place" framework?&lt;br /&gt;&lt;br /&gt;Well, yes, and no. &amp;nbsp;It turns out that when you create this entity (via a set of Roo shell commands or just by saving it in the source directory structure), Roo generates some special files, known technically as &lt;i&gt;Aspect-J Inter-Type Declarations&lt;/i&gt;, or informally as &lt;i&gt;mix-ins&lt;/i&gt;. &amp;nbsp;These files contain the boilerplate methods, such as setters and getters, JPA code, the default primary keys and versioning, even a default toString() method.&lt;br /&gt;&lt;br /&gt;You can use this entity directly from a controller or Spring bean:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java;"&gt;Employee e = new Employee();&lt;br /&gt;e.setFirstName("Joe");&lt;br /&gt;e.setLastName("Smith");&lt;br /&gt;e.persist();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As an aside, the &lt;code&gt;@ActiveRecord&lt;/code&gt; annotation generated our &lt;code&gt;persist()&lt;/code&gt; method.  It also generated others, such as &lt;code&gt;getEmployee(Long id)&lt;/code&gt;, &lt;code&gt;update()&lt;/code&gt;, and &lt;code&gt;delete()&lt;/code&gt; to name a few...  That's the Active Record pattern at work.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Is that all it can do?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No, Roo isn't just a persistence layer development tool. &amp;nbsp;Roo is also a development productivity platform. &amp;nbsp;Every feature in Roo is implemented as an &lt;i&gt;add-on&lt;/i&gt;&amp;nbsp;- there are pre-installed add-ons to set up Spring MVC, GWT, MongoDB, various JPA containers such as Hibernate, OpenJPA and EclipseLink, text searching with Solr, JMS with ActiveMQ, Email, Selenium integration tests, and a lot more.&lt;br /&gt;&lt;br /&gt;The real power of Roo will come when developers begin embracing and writing their own &lt;i&gt;add-ons&lt;/i&gt;. &amp;nbsp;Since they install in the shell itself, you can essentially provide pre-configured versions of the Roo environment for your developer team, and give them all the same, consistent productivity tools.&lt;br /&gt;&lt;br /&gt;So, that's Roo in a nutshell. &amp;nbsp;But here's what I think is going to make the upcoming version a break-out tool for 2012.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Spring 3.x is dominant&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For all the JavaOne bombast, let's face it : a large number of developers are using Spring to get things done. &amp;nbsp;Why? &amp;nbsp;Because it simplifies every day development tasks. &amp;nbsp;Spring makes things [replace next word with your favorite explitive] stink less. &amp;nbsp;If you've ever needed to write JDBC code, you know the Roo Jdbc Template is a godsend. &amp;nbsp;Spring MVC has gotten so flexible and powerful that it's trivial to expose RESTful web services and MVC forms. &amp;nbsp;And with projects like Spring Integration and Batch, both also open source efforts, you can wire in service-based architectures, messaging and batch operations without paying tens of thousands of dollars just for a single CPU license.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Spring projects are Open Source&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Just like Ruby on Rails, Spring is an open source platform. &amp;nbsp;Even Spring Integration source code can be downloaded and reviewed. &amp;nbsp;Except a few sub-projects, such as the monitoring core of Spring tc Server, you can debug right into source on just about anything. &amp;nbsp;Spring Roo is yet another project by this team. &amp;nbsp;They put Roo on GitHub (&lt;a href="http://github.com/springsource/spring-roo)"&gt;github.com/springsource/spring-roo)&lt;/a&gt;&amp;nbsp;and have a public &lt;a href="https://jira.springsource.org/browse/ROO"&gt;JIRA&lt;/a&gt; and &lt;a href="http://forum.springsource.org/forumdisplay.php?67-Roo"&gt;forum&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;But Spring moves complexity to configuration, right?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ah, good thinking. &amp;nbsp;If you've done anything with a significantly complex Spring application, you'll see those configuration files, the setup of frameworks such as Spring MVC, Web Flow, JMS, and others, as tasks you'd rather not do. &amp;nbsp;Sure, Spring has evolved over the past decade - from just XML to annotation-driven bean definitions and auto-wiring, to the new JavaConfig feature, which allows you to specify configuration in Java classes.&lt;br /&gt;&lt;br /&gt;This is the Spring adoption price of entry. &amp;nbsp;We've got to configure Spring to do what we want. &amp;nbsp;Inexperienced Spring developers have quite a time learning the ropes. &amp;nbsp;And the Java EE community, with tools like TomEE that do Java EE out of the box require zero configuration. &lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;So, Java EE to the rescue?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, yes and no... &amp;nbsp;Java EE has evolved. &amp;nbsp;Now you can install a Java EE application into a web profile container and be off and running - without installing or downloading additional frameworks. &lt;br /&gt;&lt;br /&gt;However, I look at Java EE and Spring as two different philosophies - as alike and yet different as Nutella and Peanut Butter. &amp;nbsp;Bear with me here... &lt;br /&gt;&lt;br /&gt;While Java EE is a standards-based platform, with input from a wide variety of organizations, it has consistently evolved, but at a slow pace. &amp;nbsp;Java EE is geared toward running on web and application servers, has specific component types, and vetted frameworks such as JPA, JSF, and the dependency injection of JSR-299. &amp;nbsp;Nutella.&lt;br /&gt;&lt;br /&gt;However, Spring, since it evolves due to developer needs, actually can adapt every 12-18 months or earlier, adding features including the JSR-250 Spring annotations, not specifying a single ORM tool or vendor, and generally abstracting and simplifying a pluggable configuration strategy. &amp;nbsp;If you want to use JPA with Hibernate to start your project, then find the database is much too difficult to map, you can always switch to MyBATIS, NoSQL stores or even Spring JDBC without worry. &lt;br /&gt;&lt;br /&gt;Likewise with web frameworks - you can start with Spring MVC, and if your team needs web workflow, give them Spring Web Flow, or if they want container-driven programming, install JSF on Web Flow or the ajaxy GWT. &amp;nbsp;Even Flex clients are easy to bolt on.&lt;br /&gt;&lt;br /&gt;Peanut Butter.&lt;br /&gt;&lt;br /&gt;Ok, I'm completely biased, that is true. &amp;nbsp;And there are others diametrically opposed to my viewpoint. &amp;nbsp;They say Spring is just too complex to configure, and is a "third party framework."&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Enter Roo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Roo's goal is to get configuration tasks out of your way, and remove the boilerplate code so that you can focus on getting things done. &amp;nbsp;Just like any other RAD framework such as Grails, Rails, or Django, it automates the mundane.&lt;br /&gt;&lt;br /&gt;Roo takes commands that can be bundled in a script file. &amp;nbsp;Here is a sample file that creates a voting application:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: text;"&gt; project --topLevelPackage com.springsource.vote&lt;br /&gt; &lt;br /&gt; jpa setup --provider HIBERNATE --database HYPERSONIC_PERSISTENT&lt;br /&gt; &lt;br /&gt; entity jpa --class ~.domain.Choice --testAutomatically&lt;br /&gt; field string namingChoice --notNull --sizeMin 1 --sizeMax 30&lt;br /&gt; field string description --sizeMax 80&lt;br /&gt; web mvc setup&lt;br /&gt; web mvc scaffold ~.web.ChoiceController&lt;br /&gt; &lt;br /&gt; entity jpa --class Vote --testAutomatically&lt;br /&gt; field reference choice --type Choice&lt;br /&gt; field string ip --notNull --sizeMin 7 --sizeMax 15&lt;br /&gt; field date registered --type java.util.Date --notNull --past&lt;br /&gt; web mvc scaffold ~.web.VoteController&lt;br /&gt; &lt;br /&gt; web mvc controller ~.web.PublicVoteController --preferredMapping /public&lt;br /&gt; &lt;br /&gt; web mvc language --code de&lt;br /&gt; web mvc language --code es&lt;br /&gt; &lt;br /&gt; logging setup --level WARN --package WEB&lt;br /&gt; &lt;br /&gt; security setup&lt;br /&gt; &lt;br /&gt; finder list --class ~.domain.Vote --depth 2 --filter reg,betw,IpEq&lt;br /&gt; &lt;br /&gt; logging setup --level INFO&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;What do we get by running this script?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A Spring MVC Web application&lt;/li&gt;&lt;li&gt;JPA based persistence, backed by the latest Hibernate API&lt;/li&gt;&lt;li&gt;Validation provided both server and client-side via the Java EE Bean Validation Framework and Dojo, respectively&lt;/li&gt;&lt;li&gt;Two entities, Choice and Vote, and backing form web pages for create, read, update, delete and list for each&lt;/li&gt;&lt;li&gt;Language support for both English and German&lt;/li&gt;&lt;li&gt;Spring Security&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;So, in short, quite a lot. &amp;nbsp;And Roo has over 30 commands built in, including embedding of content such as twitter and facebook feeds, exporting JSON data from controllers, and much more. &amp;nbsp;Things you'd need to spend a few hours to research now take literally minutes to install and test.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;How does Roo separate the business code from the mundane?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Roo configures the project for you, as we discussed above, but it also builds business-level objects for each thing you create.  Just to show you the correlation between the commands above and the objects they create, let's look at the Vote entity and the VoteController MVC controller:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Vote.java&lt;/b&gt;&lt;/div&gt;&lt;pre class="brush: java;"&gt;@RooJavaBean&lt;br /&gt;@RooToString&lt;br /&gt;@RooDisplayString&lt;br /&gt;@RooJpaActiveRecord&lt;br /&gt;public class Vote {&lt;br /&gt;&lt;br /&gt;    @ManyToOne&lt;br /&gt;    private Choice choice;&lt;br /&gt;&lt;br /&gt;    @NotNull&lt;br /&gt;    @Size(min = 7, max = 15)&lt;br /&gt;    private String ip;&lt;br /&gt;&lt;br /&gt;    @NotNull&lt;br /&gt;    @Past&lt;br /&gt;    @Temporal(TemporalType.TIMESTAMP)&lt;br /&gt;    @DateTimeFormat(style = "M-")&lt;br /&gt;    private Date registered;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;See how the Vote object doesn't have setters, getters, constructors, equals methods, or anything else that can be mechanically generated?  Unlike dynamic language frameworks, Roo generates actual Java-based AspectJ files to hold these artifacts, such as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Vote_Roo_ToString.aj&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Vote_Roo_JpaEntity.aj&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Vote_Roo_DisplayString.aj&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Here is &lt;b&gt;VoteController.java&lt;/b&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java;"&gt;@RequestMapping("/votes")&lt;br /&gt;@Controller&lt;br /&gt;@RooWebScaffold(path = "votes", formBackingObject = Vote.class)&lt;br /&gt;public class VoteController {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Remember, Roo then generates the real code to manage all of the CRUD operations in an Aspect-J ITD file, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;VoteController_Roo_Controller.aj&lt;/span&gt;.  It also scaffolds a set of views.&lt;br /&gt;When you save this file, the Roo shell will rip the method out of the Aspect, so they won't conflict.  Easy, isn't it?&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;You are in control&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ok, you decide, you want to change the behavior of the Roo controller or forms. &amp;nbsp;Maybe you want to go right back to the grid when you're done. &amp;nbsp;Just pluck the method out of the ITD and put it into the class (it's not literally that simple, you'll have to convert the syntax, but close).&lt;br /&gt;&lt;br /&gt;For example, you take the code from the controller aspect method:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;@RequestMapping(value = "/{id}", method = RequestMethod.GET)&lt;br /&gt;public java.lang.String VoteController.show(&lt;/pre&gt;&lt;pre class="brush: java"&gt;                              @PathVariable("id")&amp;nbsp;java.lang.Long id,&amp;nbsp;&lt;/pre&gt;&lt;pre class="brush: java"&gt;                              Model uiModel) {&lt;/pre&gt;&lt;pre class="brush: java"&gt;    addDateTimeFormatPatterns(uiModel);&lt;br /&gt;    uiModel.addAttribute("vote", Vote.findVote(id));&lt;br /&gt;    uiModel.addAttribute("itemId", id);&lt;br /&gt;    return "votes/show";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The syntax is slightly different; you have the class name prefixed to the method name, and spelled-out classes such as java.lang.String.  However, with a little cleanup, you can paste this into your controller class, and modify the return value (changes bolded):&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java;"&gt;@RequestMapping(value = "/{id}", method = RequestMethod.GET)&lt;br /&gt;&lt;b&gt;public String show(@PathVariable("id") Long id, Model uiModel) &lt;/b&gt;{&lt;br /&gt;    addDateTimeFormatPatterns(uiModel);&lt;br /&gt;    uiModel.addAttribute("vote", Vote.findVote(id));&lt;br /&gt;    uiModel.addAttribute("itemId", id);&lt;br /&gt;&lt;b&gt;    return "votes/list";&lt;br /&gt;&lt;/b&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And that's it! &amp;nbsp;In general, you are in control of your Java classes, Roo is in control of the Aspects. &amp;nbsp;If you don't like the code in the aspects, remove the annotation (which will remove the aspect file) or push in the methods you want to customize.&lt;br /&gt;&lt;br /&gt;On the web side, each web framework has different things you can and can't change. &amp;nbsp;In Spring MVC, Roo devised a set of high level tags such as containers for various actions (create, update, list) and component tags for dates, rich text and the like. &amp;nbsp;In Roo in Action I go into detail on how to customize these web pages, and even skip the scaffolding altogether and roll your own web or Ajax interface.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The Roo team listens&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Roo team is in contact with developers and is open to discussions about features. &amp;nbsp;I know I've contributed a number of JIRA issues that have become new features. In that way, the team is listening to the developers and acting in their interests - they recently added service-and-repository support, so that Roo developers don't have to explain to their wincing staff architects that Roo works more magically, like a Rails application. &amp;nbsp;Now those teams will get the productivity Roo brings to the table. &amp;nbsp;Another big (upcoming) addition is multi-project (POM) support, so enterprise developers who have to deploy EARS or separate projects into multiple POMs can benefit as well.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The add-on API is powerful&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the issues with writing Roo add-ons was the stability of the add-on code. &amp;nbsp;Each release broke the code of the prior release. &amp;nbsp;The changes I'm seeing with Roo 1.2 seem to be focused on making the add-on API more useful and perhaps more stable. &amp;nbsp;I hope the team will provide easy upgrade paths, including deprecating rather than removing and renaming classes, with follow-on releases. What can you do with an add-on? &amp;nbsp;Well, pretty much anything. &amp;nbsp;For example:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can manipulate files such as Spring configurations, POM files, servlet.xml, etc, thereby making it easier for them to work with a given API by setting it up for them. &amp;nbsp;&lt;/li&gt;&lt;li&gt;You can use a built-in type parser system to generate and update the annotations and code attached to Java types (classes), thereby activating your add-on's class watcher (which can generate boilerplate code in your own Aspect-J ITDs). &amp;nbsp;&lt;/li&gt;&lt;li&gt;You can add commands to the Roo shell, and specify a method for each command to determine whether it should be exposed (why expose web-based commands when you haven't set up your web engine yet, for example).&lt;/li&gt;&lt;li&gt;You can gain access to the OSGi console and stop/start other bundles, or detect if bundles are installed.&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Roo is NOT a Runtime Platform&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Remember, for all of the smartness involved in assembling features for the Roo shell, it's a compile-time platform that uses Aspect-J to weave code into classes at &lt;i&gt;compile-time&lt;/i&gt;, not &lt;i&gt;run-time&lt;/i&gt;. &amp;nbsp;With SpringSource Tool Suite or IntelliJ IDEA, you can set breakpoints in Aspect-J ITDs, and debug your application in every line of code, even if generated by Roo. &amp;nbsp;Since everything is compile-time, the platform is capable of being faster than typical dynamic language platforms (someone ought to run a benchmark!).&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Important features coming in Roo 1.2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Up until this point in time, the goal of the Roo team has been to stabilize the Roo platform and add-on system. &amp;nbsp;They've added things like a public add-on registry, support for publishing your own company-level add-ons via the OSGi OBR (OSGi Bundle Repository) protocol, and improving overall shell features and performance.So, what is on deck for Roo 1.2? &amp;nbsp;Here are some highlights:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JSF support - including automatic scaffolding of JSF pages for models you specify. &amp;nbsp;The JSF module seems to be using PrimeFaces at this time.&lt;/li&gt;&lt;li&gt;Multi-POM support - a big improvement - will contain the ability to specify POM projects, and WAR, JAR projects. &amp;nbsp;An example already exists in the GitHub project page - look for multimodule.roo and see the commands to set up your own web and repository project.&lt;/li&gt;&lt;li&gt;Support for Spring Data APIs, which simplify CRUD-based application writing by providing (wait for it) proxy-based, generated methods using an interface you provide. &amp;nbsp;This is an extremely powerful API.&lt;/li&gt;&lt;li&gt;Support for NoSQL databases. &amp;nbsp;The MongoDB database is included in the first milestone snapshot.&lt;/li&gt;&lt;li&gt;Support for Spring services - these are automatically marked transactional and delegate either to Roo entity methods, or if repositories exist, delegate to the repository backing an entity.&lt;/li&gt;&lt;li&gt;Ability to switch between service-and-repository or Active-Record implementations of your persistence model just by switching annotations on the JPA entity.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;As with other versions, pre-release upgrades may be a bit tricky - we will have to see whether Roo can upgrade a project in place. &amp;nbsp;The Roo documentation provides help once a version is released.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Resources&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Spring Roo &lt;a href="http://www.springsource.org/roo"&gt;project website&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Manning's &lt;a href="http://manning.com/rimple"&gt;Spring Roo in Action&lt;/a&gt;, Rimple, Penchikala, Dickens, pub date est Jan 2012. &amp;nbsp;MEAP available now, all chapters available in November 2011.&lt;/li&gt;&lt;li&gt;&lt;a href="https://jira.springsource.org/browse/ROO"&gt;Spring Roo JIRA forum&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://forum.springsource.org/forumdisplay.php?67-Roo"&gt;Spring Roo Message Boards&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Spring Roo in Action &lt;a href="http://www.manning-sandbox.com/forum.jspa?forumID=682"&gt;Author Forum&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Twitter: &amp;nbsp;&lt;a href="http://twitter.com/springroo"&gt;@SpringRoo&lt;/a&gt;, &lt;a href="http://twitter.com/rooinaction"&gt;@RooInAction&lt;/a&gt;, &lt;a href="http://twitter.com/techcast"&gt;@TechCast&lt;/a&gt; (the Chariot TechCast covers Roo), and &lt;a href="http://twitter.com/krimple"&gt;@krimple&lt;/a&gt; (that's me)&lt;/li&gt;&lt;li&gt;My Blog: &amp;nbsp;I speak about a wide variety of topics, technical, musical and photography based, at &lt;a href="http://rimple.com/"&gt;rimple.com&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-9148453286441278238?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/9148453286441278238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/10/spring-roo-12-will-be-tipping-point-for.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/9148453286441278238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/9148453286441278238'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/10/spring-roo-12-will-be-tipping-point-for.html' title='Spring Roo 1.2 will be tipping point for RAD Java'/><author><name>Ken Rimple</name><uri>http://www.blogger.com/profile/10070354859699635524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-JS0Esv4Qwwc/Tu9lo2l1NcI/AAAAAAAAAB4/6pctQKDHiUM/s220/KenRimple-Public-Photo-200x200.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-3508296423890764438</id><published>2011-10-17T16:20:00.000-04:00</published><updated>2011-10-19T20:36:17.056-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='actor'/><category scheme='http://www.blogger.com/atom/ns#' term='akka'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Akka Scheduler: Actors with Heartbeats</title><content type='html'>&lt;a href="http://akka.io/"&gt;Akka&lt;/a&gt; is an excellent platform for writing concurrent applications using the Actor model.  Chariot architect Anatoly Polinsky describes the &lt;a href="http://akka.io/"&gt;Akka&lt;/a&gt; scheduler and how you can use it to create a heartbeat for an actor.  From Anatoly's blog:&lt;br /&gt;&lt;br /&gt;&lt;h3 style="color: #555555; margin-bottom: 10px;"&gt;AKKA Scheduler: Sending Message to Actor’s Self on Start&lt;/h3&gt;Akka has a little scheduler written using actors. This can be  convenient if you want to schedule some periodic task for maintenance or  similar. It allows you to register a message that you want to be sent  to a specific actor at a periodic interval.&lt;br /&gt;&lt;div style="margin-bottom: 15px; margin-top: 30px;"&gt;&lt;h3 style="color: #555555; margin-bottom: 10px;"&gt;How Does AKKA Schedule Things?&lt;/h3&gt;&lt;/div&gt;Behind the scenes, AKKA scheduler relies on  “ScheduledExecutorService” from the “java.util.concurrent” package.  Hence when AKKA Scheduler needs to schedule “a message sent to an actor,  given a certain initial delay and interval”, it just wraps the task of  sending a message in a “java.lang.Runnable”, and uses a  “ScheduledExecutorService” to schedule it:&lt;br /&gt;&lt;div class="wp_syntax"&gt;&lt;div class="code"&gt;&lt;pre class="scala" style="font-family: monospace;"&gt;service.&lt;span style="color: black;"&gt;scheduleAtFixedRate&lt;/span&gt;&lt;span style="color: #f78811;"&gt;(&lt;/span&gt; createSendRunnable&lt;span style="color: #f78811;"&gt;(&lt;/span&gt; receiver, message, &lt;span style="color: blue; font-weight: bold;"&gt;true&lt;/span&gt; &lt;span style="color: #f78811;"&gt;)&lt;/span&gt;,&lt;br /&gt;                           initialDelay,                         &lt;br /&gt;                           delay,                             &lt;br /&gt;                           timeUnit&lt;span style="color: #f78811;"&gt;)&lt;/span&gt;.&lt;span style="color: black;"&gt;asInstanceOf&lt;/span&gt;&lt;span style="color: #f78811;"&gt;[&lt;/span&gt;ScheduledFuture&lt;span style="color: #f78811;"&gt;[&lt;/span&gt;AnyRef&lt;span style="color: #f78811;"&gt;]&lt;/span&gt;&lt;span style="color: #f78811;"&gt;]&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin-bottom: 15px; margin-top: 30px;"&gt;&lt;h3 style="color: #555555; margin-bottom: 10px;"&gt;“Heartbeat” Actor&lt;/h3&gt;&lt;/div&gt;Let’s look at the example of scheduling a message that should be sent  to an Actor’s “self” as the Actor on start. Why? Because it is a cool  use case : )&lt;br /&gt;“Heartbeat” would be an ideal example of such use case =&amp;gt; “When a  ‘Hearbeat Actor’ starts, it should start sending heartbeats with a given  interval (e.g. every 2 seconds)”&lt;br /&gt;&lt;div style="margin-bottom: 15px; margin-top: 30px;"&gt;&lt;h3 style="color: #555555; margin-bottom: 10px;"&gt;Creating a Message&lt;/h3&gt;&lt;/div&gt;First we need to create a message that will be scheduled to be sent every so often. We’ll call it a “SendHeartbeat” message:&lt;br /&gt;&lt;div class="wp_syntax"&gt;&lt;div class="code"&gt;&lt;pre class="scala" style="font-family: monospace;"&gt;&lt;span style="color: blue; font-weight: bold;"&gt;sealed&lt;/span&gt; &lt;span style="color: blue; font-weight: bold;"&gt;trait&lt;/span&gt; HeartbeatMessage &lt;span style="color: blue; font-weight: bold;"&gt;&lt;br /&gt;case&lt;/span&gt; &lt;span style="color: blue; font-weight: bold;"&gt;object&lt;/span&gt; SendHeartbeat &lt;span style="color: blue; font-weight: bold;"&gt;extends&lt;/span&gt; HeartbeatMessage&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;Read the full post at: &lt;a href="http://www.dotkam.com/2011/10/11/akka-scheduler-sending-message-to-actors-self-on-start/"&gt;AKKA Scheduler: Sending Message to Actor's Self on Start&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-3508296423890764438?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/3508296423890764438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/10/akka-scheduler-actors-with-heartbeats.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3508296423890764438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3508296423890764438'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/10/akka-scheduler-actors-with-heartbeats.html' title='Akka Scheduler: Actors with Heartbeats'/><author><name>Joel Confino</name><uri>http://www.blogger.com/profile/03306877747132991554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-5450796858340393909</id><published>2011-09-27T10:36:00.000-04:00</published><updated>2011-09-27T10:36:33.251-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><title type='text'>PhoneGap 1.0 Android Plugin updates</title><content type='html'>Kevin Griffin has been working with PhoneGap for some time now. &amp;nbsp;In this new blog post, Kevin discusses new features in PhoneGap 1.0.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;With the upcoming release of PhoneGap 1.0 I thought I would point out a couple of nice additions coming for PhoneGap (Android) Plugin developers (and eventually PhoneGap as a whole).&lt;br /&gt;The first addition is the propagation of lifecycle events (onPause, onResume and onNewIntent) to plugins. Plugin developers are now responsible for reacting appropriately if the app has multitasking turned on, but also have access to the lifecycle of the application. Developing the NFC plugin (&lt;a href="https://github.com/chariotsolutions/phonegap-nfc"&gt;https://github.com/chariotsolutions/phonegap-nfc&lt;/a&gt;) we found this an absolute necessity, so it’s great to see it added in.&lt;br /&gt;Ah the power of Open Source software :)&lt;br /&gt;The second is a new method of loading plugins. To register a plugin now you just need to add your plugin name and class to the plugins.xml (located in res/xml/)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kgriff.posterous.com/phonegap-10-android-plugin-updates"&gt;Read more...&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="gist" id="gist-1070849"&gt;                                                          &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;div class="line" id="LC1"&gt;&lt;br /&gt;&lt;span class="nt"&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-5450796858340393909?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/5450796858340393909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/09/phonegap-10-android-plugin-updates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5450796858340393909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5450796858340393909'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/09/phonegap-10-android-plugin-updates.html' title='PhoneGap 1.0 Android Plugin updates'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-8863809714812775070</id><published>2011-09-22T13:05:00.000-04:00</published><updated>2011-09-22T13:05:25.238-04:00</updated><title type='text'>Isobar Create 48 - A Solution to Parking Hassles Using NFC</title><content type='html'>&amp;nbsp;Recently, Chariot's Director of Consulting, Don Coleman, participated in the Isobar Create 48 NFC Hackathon in Boston. Below is an excerpt from his blog about his experience and his team's second place finish.&amp;nbsp;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;My friend &lt;a href="https://twitter.com/#%21/fiftyforty"&gt;Chris Bernardi&lt;/a&gt; invited me to join his team for the &lt;a href="http://na.isobar.com/2011/isobarcreate48/"&gt;Isobar Create 48 NFC Hackathon&lt;/a&gt; along with  &lt;a href="https://twitter.com/#%21/AprilDiMartino"&gt;April DiMartino&lt;/a&gt; and &lt;a href="https://twitter.com/#%21/marcneuwirth"&gt;Marc Neuwirth&lt;/a&gt;.  The event kicked off on Tuesday around 3 PM at &lt;a href="http://www.spacewithasoul.org/"&gt;Space with a Soul&lt;/a&gt;.  Before the hackathon there were some general Near Field Communication (NFC) presentations by Isobar, Nokia and ICS.  After the NFC intro, they kicked out the people who came for the presentations so we could get started.&lt;br /&gt;None of us came to the hackathon with the killer application idea.  We brainstormed for a while, discarding lots of half-baked ideas and ended up deciding to build an NFC solution to make parking better.  We came up with a bunch of scenarios, but decided to limit our initial implementation to garages with entrance and exit gates, so it was easier to track inventory.&lt;br /&gt;April does an excellent job describing our application:&lt;br /&gt;The working title of the app is “I Got Your Ticket Right Here” and is best understood when said with a Brooklyn NY accent ;-)  We haven’t worked out a shorter and more appropriate title for it yet.  So for purposes of this I will simply refer to it as the Parking app.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://doncoleman.posterous.com/isobar-create-48"&gt;Read more... &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-8863809714812775070?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/8863809714812775070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/09/isobar-create-48-solution-to-parking.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8863809714812775070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8863809714812775070'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/09/isobar-create-48-solution-to-parking.html' title='Isobar Create 48 - A Solution to Parking Hassles Using NFC'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-496729097669311595</id><published>2011-09-01T11:01:00.000-04:00</published><updated>2011-09-01T11:16:56.301-04:00</updated><title type='text'>Checklists and Document Inspections</title><content type='html'>John Shepard, one of our architects, blogged some interesting thoughts on what makes a document inspection.  Most developers will tell you that code reviews are good, and also tell you they aren't done regularly in their organization.  But John goes beyond the scope of code to reviewing other documents such as requirements and technical specifications as well.&lt;br /&gt;&lt;br /&gt;"While there is an ongoing debate on whether or not document inspections are useful, my experience is that on larger projects, they are very useful. They help maintain a minimum level of quality and help disseminate information among team members. Rather than continuing that debate here, I'm going to provide a starting point for checklists for those who have decided to use document inspections. While the checklists do end up being different for each project, I find it helpful to have an obvious place to start."&lt;br /&gt;&lt;br /&gt;Read the full post &lt;a href="http://j-shepard.blogspot.com/2011/07/checklists-and-document-inspections.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-496729097669311595?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/496729097669311595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/09/checklists-and-document-inspections.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/496729097669311595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/496729097669311595'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/09/checklists-and-document-inspections.html' title='Checklists and Document Inspections'/><author><name>Joel Confino</name><uri>http://www.blogger.com/profile/03306877747132991554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-5463470575498216494</id><published>2011-08-09T09:57:00.000-04:00</published><updated>2011-08-09T14:54:12.798-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fulltext'/><category scheme='http://www.blogger.com/atom/ns#' term='search'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Full-Text Search For Relational Data</title><content type='html'>Thanks to internet search engines like Google, Yahoo, and Bing, everyone has become accustomed to searching their data effortlessly. Consequently, as developers of web-based applications, we increasingly find that our customers' requirements include being able to search their application's data in a "Google-like" way.&lt;br /&gt;&lt;br /&gt;For a very small subset of applications that only need to do full-text search on a few database columns, there a some very simplistic solutions, ranging from using a SQL 'like' clause on every column to database-vendor supplied full-text search functionality for designated columns.&lt;br /&gt;&lt;br /&gt;Frequently, however, these simplistic approaches are not enough, either because the data to be searched is large and complex, because the approach's search functionality is limited, or because database neutrality is desired. For these situations, a more advanced solution is needed. Fortunately, there are now a number of solutions available for all of the most popular platforms, languages, and frameworks, and several hosted solutions that are development stack-neutral.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lucene and Compass&lt;/b&gt;&lt;br /&gt;One of the most popular full-text search projects is &lt;a href="http://lucene.apache.org/"&gt;Apache Lucene&lt;/a&gt;, a Java-based, open-source indexing and searching solution. Lucene itself targets indexing and searching of 'documents', but several other projects, most notably &lt;a href="http://www.compass-project.org/"&gt;Compass&lt;/a&gt;, have adapted Lucene for indexing and searching relational data via integration with Object-Relational Mapping libraries such as Java's &lt;a href="http://jcp.org/aboutJava/communityprocess/final/jsr317/index.html"&gt;JPA&lt;/a&gt;, &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;, and others.&lt;br /&gt;&lt;br /&gt;The combination of Lucene and Compass provides Java developers with an easy way to implement Google-like searching of their relational data, including fuzzy searching (spell-check / 'Did you mean...'), &lt;a href="http://en.wikipedia.org/wiki/Stemming"&gt;stemming&lt;/a&gt; ('fishing', 'fished', 'fish', and 'fisher' all match 'fish'), wildcards, and boolean logic.&lt;br /&gt;&lt;br /&gt;For users of the Java JPA ORM, &lt;a href="http://www.compass-project.org/docs/latest/reference/html/gps-jpa.html"&gt;usage of Compass is fairly straightforward&lt;/a&gt;. For users of the &lt;a href="http://grails.org/"&gt;Grails framework&lt;/a&gt;, the &lt;a href="http://www.grails.org/plugin/searchable"&gt;Grails Searchable Plugin&lt;/a&gt; makes implementation of full-text searching almost effortless. I recently added this plugin to a Grails application with a moderately complex data model, and had my full-text search functionality up and running in a few hours, with fine-tuning taking only a few more hours. As the application's data model has grown, very little time has had to be spent on keeping the search functionality up to date.&lt;br /&gt;&lt;br /&gt;There are many other programming languages and platforms in use besides Java, so not surprisingly, &lt;a href="http://wiki.apache.org/lucene-java/LuceneImplementations"&gt;Lucene has been ported to many of them&lt;/a&gt;, including C, C++, .NET, Objective-C, Python, Perl, and Ruby. The most popular of these, due to the popularity of the programming languages, are &lt;a href="http://incubator.apache.org/lucene.net/"&gt;Lucene.net&lt;/a&gt;, which is a C# port targeted at the .NET runtime, and &lt;a href="http://ferret.davebalmain.com/trac/"&gt;Ferret&lt;/a&gt;, which is a Ruby port targeted at the Ruby on Rails framework.&lt;br /&gt;&lt;br /&gt;While Lucene and its variants currently dominate the open-source full-text search landscape, there are other well-known projects, including &lt;a href="http://sphinxsearch.com/&gt;Sphinx&lt;/a&gt; and &lt;a href="http://xapian.org/"&gt;Xapian&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Hosted Solutions&lt;/b&gt;&lt;br /&gt;There may be situations where it makes more sense move your full-text search functionality 'to the cloud'. Several hosted solutions are available, some based on Lucene or other open-source technologies, as well as other, proprietary offerings.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.websolr.com/"&gt;Websolr&lt;/a&gt; is a hosted version of Apache's &lt;a href="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt; which is itself built on Lucene. Other offerings include &lt;a href="http://flying-sphinx.com/"&gt;Flying Sphinx&lt;/a&gt; for Rails (which uses the &lt;a href="http://sphinxsearch.com/"&gt;Sphinx&lt;/a&gt; search engine), and &lt;a href="http://www.indextank.com/"&gt;IndexTank&lt;/a&gt;, which is a proprietary offering.&lt;br /&gt;&lt;br /&gt;Both Flying Sphinx and IndexTank are available as add-ons for the popular &lt;a href="http://www.engineyard.com/"&gt;EngineYard&lt;/a&gt; and &lt;a href="http://www.heroku.com/"&gt;Heroku&lt;/a&gt; Ruby-based hosting platforms. &lt;br /&gt;&lt;br /&gt;I recently tried out IndexTank on Heroku. IndexTank itself targets indexing and searching documents, but the &lt;a href="https://github.com/kidpollo/tanker"&gt;Tanker&lt;/a&gt; gem does a great job of integrating IndexTank with Rails' ActiveRecord ORM. IndexTank's documentation doesn't mention it, and while not available "out of the box", IndexTank does support both &lt;a href="http://blog.indextank.com/523/fuzzy-search-find-what-i-meant-not-what-i-said/"&gt;fuzzy searching and stemming&lt;/a&gt;. All you need to do is send an email to their customer support address, and ask to have it turned on.&lt;br /&gt;&lt;br /&gt;If your application can benefit from full-text search, there are plenty of interesting choices, regardless of your platform or programming language. &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-5463470575498216494?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/5463470575498216494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/08/full-text-search-for-relational-data.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5463470575498216494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5463470575498216494'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/08/full-text-search-for-relational-data.html' title='Full-Text Search For Relational Data'/><author><name>Rich Freedman</name><uri>http://www.blogger.com/profile/06334089409580527109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-WC8GmbpPns0/TxMCTVzu0rI/AAAAAAAAEmA/cOHtbCEutxo/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-5883003061417967218</id><published>2011-08-03T14:09:00.001-04:00</published><updated>2011-08-03T14:48:23.799-04:00</updated><title type='text'>Groovy Script to Tame Gmail Attachments</title><content type='html'>I like Gmail but it has a big short coming: you can't sort mail by attachment size.  This means that if you are running out of space in your Gmail account, you can't easily find large attachments like that 25MB video that your friend sent you of his kid's graduation or other large attachment that you really would like to get rid of.  There are sites like findbigmail.com that will help you find large attachments, but the downside is that you have to trust them and allow them to read all of your email.  I'm a little paranoid so that wasn't something I was willing to do.&lt;br /&gt;&lt;br /&gt;I also like Groovy and so I wrote a little Groovy script that finds large attachments in Gmail and gives them a custom label so you can easily find them.  The script uses &lt;a href="http://www.oracle.com/technetwork/java/javamail/index.html"&gt;JavaMail&lt;/a&gt; which depends on the &lt;a href="http://www.oracle.com/technetwork/java/javase/downloads/index-135046.html"&gt;JavaBeans Activation Framework&lt;/a&gt; (activation.jar).  Both jars need to be in the classpath along with the &lt;a href="http://groovy.codehaus.org/Download"&gt;Groovy&lt;/a&gt; jar.&lt;br /&gt;&lt;br /&gt;The first part of the code makes a connection to Gmail.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;import javax.mail.*&lt;br /&gt;import java.util.Properties&lt;br /&gt;def emailAddress = "you@gmail.com"&lt;br /&gt;def password = "password"&lt;br /&gt;def server = "imap.gmail.com"&lt;br /&gt;def port = 993&lt;br /&gt;def OneMB = 1024000&lt;br /&gt;def FiveMB = 5120000&lt;br /&gt;def props = new Properties()&lt;br /&gt;props.setProperty("mail.store.protocol", "imaps")&lt;br /&gt;props.setProperty("mail.imaps.host", server)&lt;br /&gt;props.setProperty("mail.imaps.port", port.toString())&lt;br /&gt;def session = Session.getDefaultInstance(props,null)&lt;br /&gt;def store = session.getStore("imaps")&lt;br /&gt;store.connect(emailAddress, password)&lt;br /&gt;println "connected to Gmail"&lt;/code&gt;&lt;/pre&gt;Then we define the labels that we want to add.  Labels in Gmail are called folders in JavaMail.&lt;br /&gt;&lt;pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;def bigAttachmentFolder = store.getFolder("1MB+ attachment")&lt;br /&gt;if (!bigAttachmentFolder.exists()) {&lt;br /&gt;   bigAttachmentFolder.create(Folder.HOLDS_MESSAGES)&lt;br /&gt;}&lt;br /&gt;def hugeAttachmentFolder = store.getFolder("5MB+ attachment")&lt;br /&gt;if (!hugeAttachmentFolder.exists()) {&lt;br /&gt;   hugeAttachmentFolder.create(Folder.HOLDS_MESSAGES)&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Next the script iterates through all of the emails looking for attachments.  If a large attachment is found, it is copied into a folder which in Gmail adds the appropriate label to it.&lt;br /&gt;&lt;pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;def folder = store.getFolder("[Gmail]/All Mail")&lt;br /&gt;folder.open(Folder.READ_ONLY)&lt;br /&gt;folder.messages.each { msg -&amp;gt;&lt;br /&gt;try {&lt;br /&gt;    def content = msg.content&lt;br /&gt;    if (content instanceof Multipart) {&lt;br /&gt;        for (i in 0..(content.count - 1)) {&lt;br /&gt;            BodyPart bodyPart = content.getBodyPart(i)&lt;br /&gt;            if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.disposition)&lt;br /&gt;                    &amp;amp;&amp;amp; bodyPart.size &amp;gt; OneMB) {&lt;br /&gt;                println "big attachment: ${bodyPart.fileName} = ${bodyPart.size}"&lt;br /&gt;                folder.copyMessages([msg] as Message[], bigAttachmentFolder);&lt;br /&gt;                if (bodyPart.size &amp;gt; FiveMB) {&lt;br /&gt;                  folder.copyMessages([msg] as Message[], hugeAttachmentFolder);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;} catch (Exception ignore) {&lt;br /&gt;    println "error processing message, no big deal, moving on"&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;println "-----------done------------"&lt;/code&gt;&lt;/pre&gt;That's it! If you modify the script with your email address and password, and then run it, your Gmail account will get 2 new labels: "1MB+ attachments" and "5MB+ attachments" that will allow you find and delete big attachments quickly.  The code is pretty concise, and the JavaMail API looks better in Groovy in my opinion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-5883003061417967218?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/5883003061417967218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/08/groovy-script-to-tame-gmail-attachments.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5883003061417967218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5883003061417967218'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/08/groovy-script-to-tame-gmail-attachments.html' title='Groovy Script to Tame Gmail Attachments'/><author><name>Joel Confino</name><uri>http://www.blogger.com/profile/03306877747132991554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6757096833017685957</id><published>2011-07-25T11:21:00.000-04:00</published><updated>2011-07-25T11:26:09.282-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='roo in action'/><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><title type='text'>Roo In Action Corner - Testing Entity Validations With A Mock Entity</title><content type='html'>&lt;i&gt;This article references the Manning book &lt;a href="http://manning.com/rimple"&gt;Spring Roo in Action&lt;/a&gt;, which Ken Rimple is currently authoring. &amp;nbsp;It is available as a Manning MEAP.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;I've been working hard on the more advanced chapters of Roo in Action, and as part of this I've amassed some background material that didn't make it into the book. &amp;nbsp;This topic, using Spring's Mock Entity support, was one of those topics that didn't get a lot of attention.&lt;br /&gt;In Spring Roo in Action, Chapter 3, I discuss how Roo automatically executes the Bean Validators when persisting a live entity. However, when running unit tests, we don't have a live entity at all, nor do we have a Spring container - so how can we exercise the validation without actually hitting our Roo application and the database? &lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;The answer is that we have to bootstrap the validation framework within the test ourselves. We can use the CourseDataOnDemand class's getNewTransientEntityName method to generate a valid, transient JPA entity. Then, we can:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Mock static entity methods, such as findById, to bring back pre-fabricated class instances of your entity&lt;/li&gt;&lt;li&gt;Initialize the validation engine, bootstrapping a JSR-303 bean validation framework engine, and perform validation on your entity&lt;/li&gt;&lt;li&gt;Set any appropriate properties to apply to a particular test condition&lt;/li&gt;&lt;li&gt;Initialize a test instance of the entity validator and assert the appropriate validation results are returned&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;The concept in action...&lt;/h3&gt;Given a Student entity with the following definition:&lt;br /&gt;&lt;pre class="brush: java;"&gt;@RooEntity&lt;br /&gt;@RooJavaBean&lt;br /&gt;@RooToString&lt;br /&gt;public class Student {&lt;br /&gt;  &lt;br /&gt;  @NotNull&lt;br /&gt;  private String emergencyContactInfo;&lt;br /&gt;&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The listing below shows a unit test method that ensures the NotNull validation fires against missing emergency contact information on the Student entity:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java;"&gt;@Test&lt;br /&gt;public void testStudentMissingEmergencyContactValidation() {&lt;br /&gt;  // setup our test data&lt;br /&gt;  StudentDataOnDemand dod = new StudentDataOnDemand();&lt;br /&gt;&lt;br /&gt;  // tell the mock to expect this call &lt;br /&gt;  Student.findStudent(1L); &lt;br /&gt;  // tell the mocking API to expect a return from the prior call in the form of&lt;br /&gt;  // a new student from the test data generator, dod&lt;br /&gt;  AnnotationDrivenStaticEntityMockingControl.expectReturn(&lt;br /&gt;     dod.getNewTransientStudent(0)); &lt;br /&gt;&lt;br /&gt;  // put our mock in playback mode&lt;br /&gt;  AnnotationDrivenStaticEntityMockingControl.playback(); &lt;br /&gt;&lt;br /&gt;  // Setup the validator API in our unit test&lt;br /&gt;  LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();&lt;br /&gt;  validator.afterPropertiesSet(); &lt;br /&gt;&lt;br /&gt;  // execute the call from the mock, set the emergency contact field&lt;br /&gt;  // to an invalid value &lt;br /&gt;  Student student = Student.findStudent(1L);&lt;br /&gt;  student.setEmergencyContactInfo(null);&lt;br /&gt;  &lt;br /&gt;  // execute validation, check for violations&lt;br /&gt;  Set&amp;lt;ConstraintViolation&amp;lt;Student&amp;gt;&amp;gt; violations = &lt;br /&gt;    validator.validate(student, Default.class);&lt;br /&gt;&lt;br /&gt;  // do we have one?&lt;br /&gt;  Assert.assertEquals(1, violations.size());&lt;br /&gt;&lt;br /&gt;  // now, check the constraint violations to check for our specific error&lt;br /&gt;  ConstraintViolation&amp;lt;Student&amp;gt; violation = violations.iterator().next();&lt;br /&gt;  &lt;br /&gt;  // contains the right message?&lt;br /&gt;  Assert.assertEquals("{javax.validation.constraints.NotNull.message}", &lt;br /&gt;    violation.getMessageTemplate());&lt;br /&gt;   &lt;br /&gt;  // from the right field?&lt;br /&gt;  Assert.assertEquals("emergencyContactInfo", &lt;br /&gt;    violation.getPropertyPath().toString());&lt;br /&gt;}&lt;/pre&gt;&lt;h3&gt;Analysis&lt;/h3&gt;The test starts with a declaration of a StudentOnDemand object, which we'll use to generate our test data. We'll get into the more advanced uses of the DataOnDemand Framework later in the chapter. For now, keep in mind that we can use this class to create an instance of an Entity, with randomly assigned, valid data. We then require that the test calls the Student.findStudent method, passing it a key of 1L. Next, we'll tell the entity mocking framework that the call should return a new transient Student instance. At this point, we've defined our static mocking behavior, so we'll put the mocking framework into playback mode.&lt;br /&gt;Next, we issue the actual Student.findById(1L) call, this time storing the result as the member variable student. This call will trip the mock, which will return a new transient instance. We then set the emergencyContactInfo field to null, so that it becomes invalid, as it is annotated with a @NotNull annotation. Now we are ready to set up our bean validation framework.&lt;br /&gt;&lt;br /&gt;We create a LocalValidatorFactoryBean instance, which will boot the Bean Validation Framework in the afterPropertiesSet() method, which is defined for any Spring Bean implementing InitializingBean. We must call this method ourselves, because Spring is not involved in our unit test. Now we're ready to run our validation and assert the proper behavior has occurred.&lt;br /&gt;We call our validator's validate method, passing it the student instance and the standard Default validation group, which will trigger validation. We'll then check that we only have one validation failure, and that the message template for the error is the same as the one for the @NotNull validation. We also check to ensure that the field that caused the validation was our emergencyContactInfo field.&lt;br /&gt;In our answer callback, we can launch the Bean Validation Framework, and execute the validate method against our entity. In this way, we can exercise our bean instance any way we want, and instead of persisting the entity, can perform the validation phase and exit gracefully.&lt;br /&gt;&lt;h3&gt;Caveats...&lt;/h3&gt;There are a few things slightly wrong here.  First of all, the Data on Demand classes actually use Spring to inject relationships to each other, which I've logged a bug against as &lt;a href="https://jira.springsource.org/browse/ROO-2497"&gt;ROO-2497&lt;/a&gt;.  You can override the setup of the data on demand class and manually create the DoD of the referring one, which is fine.  They have slated to work on this bug for Roo 1.2, so it should be fixed sometime in the next few months.&lt;br /&gt;Also, realize that this is NOT easy to do, compared to writing an integration test.  However, this test runs markedly faster.  If you have some sophisticated logic that you've attached to a &lt;br /&gt;&lt;pre&gt;@AssertTrue&lt;/pre&gt;annotation, this is the way to test it in isolation.&lt;br /&gt;&lt;h3&gt;About this post&lt;/h3&gt;&lt;em&gt;Did you find this post useful?  Ken and Gordon both teach courses in Spring, Hibernate, Integration, Maven, Rails and more for &lt;a href="http://chariotsolutions.com/"&gt;Chariot Solutions&lt;/a&gt;.  Visit our &lt;a class="offsite-link-inline" href="http://chariotsolutions.com/education"&gt;Education Services&lt;/a&gt; page for details on upcoming courses, including August's &lt;a class="offsite-link-inline" href="http://chariotsolutions.com/training_events/hibernate-with-spring-2011-08-10"&gt;Hibernate with Spring&lt;/a&gt;.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6757096833017685957?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6757096833017685957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/07/roo-in-action-corner-testing-entity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6757096833017685957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6757096833017685957'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/07/roo-in-action-corner-testing-entity.html' title='Roo In Action Corner - Testing Entity Validations With A Mock Entity'/><author><name>Ken Rimple</name><uri>http://www.blogger.com/profile/10070354859699635524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-JS0Esv4Qwwc/Tu9lo2l1NcI/AAAAAAAAAB4/6pctQKDHiUM/s220/KenRimple-Public-Photo-200x200.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-1197244904056822726</id><published>2011-07-18T07:10:00.000-04:00</published><updated>2011-07-18T11:27:11.804-04:00</updated><title type='text'>The Ultimate Power of Spring Batch</title><content type='html'>&lt;a href="http://prezi.com/6mnfrgjuh3dp/the-ultimate-power-of-spring-batch/" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5630651698388401282" src="http://1.bp.blogspot.com/-x8U-FJiFZjM/TiQX4yBj_II/AAAAAAAAADU/lXdpmt5caKA/s400/Screen%2Bshot%2B2011-07-18%2Bat%2B7.21.47%2BAM.png" style="cursor: hand; cursor: pointer; float: center; height: 200px; margin: 0 10px 10px 0; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://prezi.com/6mnfrgjuh3dp/the-ultimate-power-of-spring-batch/" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;/a&gt;Chariot architect Anatoly Polinsky has created an interactive Prezi presentation about the power of Spring Batch.  It is an animated blog post because Anatoly is not just a software developer, he's an artist.  It is a cool way to get familiar with what Spring Batch does for you and a lot of fun to watch.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;a href="http://prezi.com/6mnfrgjuh3dp/the-ultimate-power-of-spring-batch/"&gt;http://prezi.com/6mnfrgjuh3dp/the-ultimate-power-of-spring-batch/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-1197244904056822726?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/1197244904056822726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/07/chariot-architect-anatoly-polinsky-has.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1197244904056822726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1197244904056822726'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/07/chariot-architect-anatoly-polinsky-has.html' title='The Ultimate Power of Spring Batch'/><author><name>Joel Confino</name><uri>http://www.blogger.com/profile/03306877747132991554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-x8U-FJiFZjM/TiQX4yBj_II/AAAAAAAAADU/lXdpmt5caKA/s72-c/Screen%2Bshot%2B2011-07-18%2Bat%2B7.21.47%2BAM.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6019566562855402552</id><published>2011-07-10T21:45:00.000-04:00</published><updated>2011-07-11T09:41:51.109-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ci'/><category scheme='http://www.blogger.com/atom/ns#' term='Sonar'/><category scheme='http://www.blogger.com/atom/ns#' term='Nexus'/><category scheme='http://www.blogger.com/atom/ns#' term='jenkins'/><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Growing Up with Jenkins/Hudson, Nexus, and Sonar, Part 1</title><content type='html'>In my &lt;a href="http://chariotsolutions.blogspot.com/2010/06/making-most-of-maven-nexus-hudson-sonar.html"&gt;previous post&lt;/a&gt; I explained why I think you should use Jenkins (or his twin Hudson), Nexus, and Sonar to super-charge your Maven builds. To summarize, Jenkins is a continuous integration server that runs your builds, Nexus is an artifact repository that versions and stores your jars/wars/zips/etc, and Sonar is a metrics server that gathers code metrics and produces nice reports to help you improve code quality. All 3 products are free OSS and really useful. But scaling anything is hard. In this post I'll talk about some of the challenges that you might face when you scale up a Jenkins infrastructure from a few builds a day to thousands of builds a day, and some tips to help overcome those challenges. In the following post, I'll cover Nexus and Sonar tips.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Demo Went Well, But Now The Honeymoon Is Over&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;When you first introduce any new piece of infrastructure, your biggest challenge is generally just getting it installed and working at all. That is surprisingly easy with the Jenkins/Nexus/Sonar stack. They install easily. They have good-looking, intuitive UIs and demo really well. They play nicely together. You figure, "Setting up this CI (continuous integration) thing is a slam dunk. I'll be done by lunch." And then you introduce your beautiful new system to the users. Uhhgg. The users. Everything worked fine until they showed up and started breaking it. In this case, the users are the various development teams within your organization that want to #1 build their code with Jenkins, #2 store their artifacts in Nexus, and #3 gather code metrics with Sonar.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Jenkins&lt;/b&gt; runs all of your builds so obviously it requires a lot of CPU for compilation, running tests, and static code analysis. You will quickly need multiple boxes to handle the daily load of CI builds. Fortunately Jenkins has support for building a server farm quite easily by running a "master" instance that distributes builds to many "slave" instances. In practice this works very well. Some tips:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tip 1&lt;/b&gt;: Partition your master/slave clusters by something logical like development organization. Don't put all of the builds on a single cluster unless you work for a very small organization. This is important for 3 reasons:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;It isolates development organization from each other so you can, for instance, restart or upgrade one cluster without effecting others and keeps "problematic" development organizations isolated (you know how you are...the kind of developer who put infinite loops in your unit tests and stuff like that).&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;It allows you to configure security differently for each cluster which you may need to do if the groups within your company don't like each other. Hey, you're a DevOps, not a psychiatrist so just go with it.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;The Jenkins UI will get very messy very quickly with hundreds of jobs to wade through. It does have filtering features, but it is still slow to render in browsers. IE, I'm looking at you.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tip 2&lt;/b&gt;: Early on, come up with a strategy to automate the creation of new master and slave instances. Two good options are using a provisioning tool like Puppet or Chef, or cloning a VM. One bad option is setting things up manually from memory.&lt;br /&gt;&lt;br /&gt;This kind of automation is important because if you are scaling up (adding more and more development teams to your infrastructure) most likely you'll end up: #1 adding more master/slave clusters, and #2 making global changes across your master/slave instances. For example, Jenkins has an awesome plugin community so it is likely you'll be finding new and useful plugins often. Say you have 5 Jenkins clusters partitioned by development organization (a good choice for partitioning). You'll have to install the plugin on all 5 master instances manually. And say you need to change something in the environment. Assume your 5 master instances each have 2 slaves also. Now you've got to make a change in 15 places. Your chances of fat-fingering a change goes way up plus who wants to do all of that typing? So get on board with the &lt;a href="http://en.wikipedia.org/wiki/DevOps"&gt;DevOps&lt;/a&gt; movement, and automate so your &lt;a href="http://www.infoq.com/presentations/infrastructure-as-code"&gt;infrastructure becomes code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem 1&lt;/b&gt;: You configure Jenkins' security permissions to allow the development teams to create / manage their own jobs. This is a problem because if you want any uniformity at all in your builds, then 500 developers all changing their jobs willy-nilly creates a mess in Jenkins. This makes any kind of global changes to Jenkins jobs using a script very difficult, and doesn't allow you to use Jenkins to do any kind of enforcement of standards or provide a software "chain-of-custody" from source repository to production which can be a very big deal in a big company. Just having standards for Jenkins job names is actually very useful, and in a "free-for-all" model no standards can be enforced.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem 2&lt;/b&gt;: The reverse. You configure Jenkins' security permissions to restrict the development teams from creating / managing their own jobs. Instead only a select number of Jenkins admins can do that task. The Jenkins admins now have new full time job which is very un-fun: manually create jobs all day.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solution&lt;/b&gt;: The crux of the issue is that you want developers to be able to change some fields in a job like the source code URL to their project, but not other things like mandatory builds steps such as quality gates or auditing steps. You also probably want to prevent developers from using Jenkins' cool-but-dangerous feature of allowing a job to run arbitrary script code on the server which obviously could do all kinds of mischief. Jenkins security permissions allow you to either create / manage a job in its entirety or not at all. What you really need is to set permissions on a field by field basis.&lt;br /&gt;&lt;br /&gt;I don't have the perfect solution for this problem. For some of you out there, the whole "Jenkins job management" problem isn't a problem at all: just let the developers own their jobs and be done with it. I was on that side of the argument for a while, but experience has beaten me to down to the realization that some controls are actually a good thing.&lt;br /&gt;&lt;br /&gt;There are 2 solutions I can think of. One is to create a Jenkins plugin that creates a new job type that is customized to your needs. I don't really like that one.&lt;br /&gt;&lt;br /&gt;My suggested solution is to create a simple "Jenkins job management" web application in your favorite rapid application framework (Rails, Grails, etc) that is used by developers to create jobs. This application only allows them to set the fields that are "safe" and behind the scenes does the job creation / maintenance via Jenkins easy-to-use REST API. This is the best of both worlds: self-service creation of jobs but with a measure of control.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem 3&lt;/b&gt;: The builds run really slow&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solution&lt;/b&gt;: There are many, many reasons why this would be true, but there are 3 things I've found helpful aside from just buying bigger hardware.&lt;br /&gt;&lt;br /&gt;The 1st thing is to profile your build. I wrote a simple &lt;a href="http://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj.html"&gt;AspectJ&lt;/a&gt; aspect (using load time weaving) to profile Maven builds and give timings for each Maven plugin that ran. That helped break down a 45 minute build into the different steps and help explain why it was taking so long.&lt;br /&gt;&lt;br /&gt;The 2nd thing is to take all of the build steps that can be deferred until later and process them asynchronously. A CI job needs to run compilation and it needs to run tests to provide immediate feedback. You can't defer those steps. But there are many others that you potentially can defer. For example, Maven site generation is slow. Running Sonar metrics can also be slow. So instead of running the Maven site and Sonar stuff during your build, run them asynchronously. This takes a little engineering but you are a software engineer, right? You could write a simple Jenkins plugin that puts a message in a queue after each successful build. Then have a process outside of Jenkins -- potentially on a different server -- read the queue, and run things like Maven site and Sonar. You can potentially make your builds much faster using this technique, and I've used it successfully.&lt;br /&gt;&lt;br /&gt;The 3rd thing is to pay attention to the build time trend information that Jenkins provides, and automatically email developers if their build takes X% more than it used to. I've often see the root cause of a suddenly slower build is that a slow unit test was introduced. Fixing the test improves the build times, and it is much easier to find the offending test if you notice the slow down right away. You can get the build times via Jenkins REST API, so you can write a little script (Groovy anyone?) that is scheduled to run every night and checks the build times to provide rapid feedback if a job suddenly gets much slowers.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem 4: &lt;/b&gt;No one pays attention to failing Jenkins builds&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solution: &lt;/b&gt;This is a real problem. Developers face a barrage of emails daily, and sometimes the job failure email is just one more to ignore. Obviously peer pressure is the main way to make people care about failing CI jobs. There are many Jenkins plugins that provide &lt;a href="https://wiki.jenkins-ci.org/display/JENKINS/Plugins#Plugins-Buildnotifiers"&gt;build notification&lt;/a&gt;, but my personal favorite way to get people to care is to bridge the virtual world into the physical world by building a CI orb. A CI orb has both a visual representation (some kind of light -- traffic light, lava lamps, glowing orb) and an audio output ("Joel has broken the build"). Instructions for a cool one that I've personally seen can be found &lt;a href="http://www.instructables.com/id/Arduino-Orb-controlled-via-serial-port/"&gt;here&lt;/a&gt;. The CI orb is not just a gimmick -- it really does work. It is easy to ignore 1 or 2 failing Jenkins jobs out of 50. But it is much harder to ignore a large pulsating red orb next to your boss's cube, or your name being read on a loudspeaker. A CI orb helps your team realize the purpose of CI which is to respond to failures quickly.&lt;br /&gt;&lt;br /&gt;&lt;object style="WIDTH: 640px; HEIGHT: 390px" height="390" width="640"&gt;&lt;param name="movie" value="http://www.youtube.com/v/hAziqUeMxkg?version=3"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;br /&gt;&lt;br /&gt;&lt;embed src="http://www.youtube.com/v/hAziqUeMxkg?version=3" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="390"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;In the next post, I'll give you some tips for Nexus and Sonar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6019566562855402552?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6019566562855402552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/07/growing-up-with-jenkinshudson-nexus-and.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6019566562855402552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6019566562855402552'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/07/growing-up-with-jenkinshudson-nexus-and.html' title='Growing Up with Jenkins/Hudson, Nexus, and Sonar, Part 1'/><author><name>Joel Confino</name><uri>http://www.blogger.com/profile/03306877747132991554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2207450831068065059</id><published>2011-07-01T13:43:00.000-04:00</published><updated>2011-07-05T15:16:12.388-04:00</updated><title type='text'>Learnings from Actor Development</title><content type='html'>I spent a fair amount of time developing actor-based systems recently, specifically with the Scala Actor library.  Regardless of whether you are implementing actors with the Scala library, Akka, Lift or Scalaz, some basic gotchas can present themselves until you get a feel for what you're doing.  Here are some of them that I've learned the hard way.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Never Refer Directly to Other Actors&lt;/span&gt;&lt;br /&gt;Actors are fragile and can die easily.  While you typically create a supervisor with a strategy for how to recreate that actor, any other class with a direct reference to that actor that died now has an invalid reference.  If you absolutely must have actors with references to others that do not have a supervisory relationship, use a proxy reference instead - if the actor behind the proxy dies,  you only have to replace it in the proxy, not in every actor with that reference.  Akka solves this problem nicely with ActorRef, where the reference behind it can be recreated without updating anyone holding the reference.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;If You Do Have an Actor's Reference, Avoid Synchronous Method Calls Between Actors&lt;/span&gt;&lt;br /&gt;Regardless of whether your actors are event- (shared thread pool) or thread-based (each actor has its own dedicated thread), avoid having actors make direct method calls on another actor.  It introduces concurrency into classes that are designed to avoid that very situation - the receiving actor can be operating on a thread handling a mailbox message at the same time it is dealing with your call.  Use blocking or future-based message sends instead, which allows the receiving actor to handle the request through its mailbox on its own thread.  Not to harp on the virtues of Akka too much, but the ActorRef type also prevents this kind of behavior.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Write Business Logic in External Idempotent Functions&lt;/span&gt;&lt;br /&gt;Testing actors is difficult, particularly those with side effects.  If you are in a supervisor hierarchy, the receipt of a message may lead to the creation of child actors that have their own side effects which may be difficult to account for in a test environment.  The goal of unit tests is not to test whether actor interaction works, but that the business logic that the actor performs is sound.  Externalize your business logic into functions and partial functions that can be tested outside of actors, and use integration tests to prove only that the actors executing that logic behave as expected as part of an end-to-end functional test.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Beware the Thundering Herd&lt;/span&gt;&lt;br /&gt;When you start creating structures of actors such as supervisor hierarchies, it can seem simplest to send generic messages that are passed through the tree.  However, as actors react and send their own messages, this can lead to event "storms".  This can be addressed using two strategies - 1) use granular messages that target specific events for specific actor instances, and 2) ignore messages of the same type with the same parameter data for a given time period.  You can even implement a common trait for all of your actors that gives them the ability to not handle the same message for an externally-configurable period of time.  Be judicious in how you use this, though - tune it for the loads of your system.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Garbage Collection&lt;/span&gt;&lt;br /&gt;In the case of a supervisor hierarchy that is responsible for configuring servers in a cluster, you may want to implement garbage collecting actors that ensure that each server is pruned of configuration that it currently has but is no longer relevant.  The actors in the supervisor hierarchy will take care of that if one was created to represent that particular configuration item, but if no actor already existed to represent that state, only a garbage collector whose role is specifically to clean up a dirty environment can take care of clearing bad data from the target server.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Always Pass Copies in Immutable Messages&lt;/span&gt;&lt;br /&gt;Copy any object instance that will be passed in a message, so as to avoid accidentally sharing any state.  In almost all cases, you should ensure that your messages themselves are immutable.  &lt;a href="http://www.deanwampler.com/"&gt;Dean Wampler&lt;/a&gt; and &lt;a href="http://al3x.net/"&gt;Alex Payne&lt;/a&gt; make this point specifically in their book, &lt;a href="http://programming-scala.labs.oreilly.com/"&gt;Programming Scala&lt;/a&gt;.  This, combined with very granular messages, can seem expensive in terms of resources.  But it is worth the cost in memory and performance to ensure that your actor behavior is what you expect at design time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Semantic Logging&lt;/span&gt;&lt;br /&gt;Debugging actors isn't easy.  Typically, you have multiple instances of the same class with asynchronous behavior, so it is difficult to discern flow.  Create trace level log output for each actor type that displays specific information about it in a clearly-visible manner.  Use line breaks and tabbed indentation to make it readable, but note that doing so can make your log files even larger than they already are.  This has an unfortunate side effect of forcing you to be very granular in your log configuration as to what logging level is used - package-level logging may be too much information.  It may help to put a timestamp into a message, so you can grep the log for specific messages as they flow through actors.  Also, log the timestamp of when the actor received and handled it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Deteriorating Retry&lt;/span&gt;&lt;br /&gt;If your actors have side effects where a required resource (network connection, database access) may not be available or may fail, use deteriorating retry logic to allow the actor to send itself a message to try again in an increasingly longer interval.  For a good example of this, go to Gmail, disconnect from all networks and watch as it tries to reconnect in longer and longer timeframes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Instrument via JMX for Runtime Clarity&lt;/span&gt;&lt;br /&gt;Register every actor instance with the JVM's MBeanServer, and have their supervisors clean up the instrumentation when they die.  Yes, this comes at a performance cost, but you can make the registration asynchronous through a future while you perform other tasks in initialization and startup.  While you'll still need to profile the threads involved to find threading issues, having the ability to view actor existence and state in JConsole or VisualVM is a wonderful help in knowing what is happening in your system in production.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Prepare for Race Conditions&lt;/span&gt;&lt;br /&gt;As with any asynchronous programming, the timing of actor interactions can be unpredictable.  Make your actor interactions recheck state they depend on so that they can reflect an appropriate state of their own.  If Actor A needs Actor B to have a specific value for its own state to be appropriate, it should not send only one message to Actor B and assume that the value returned is correct that one time.  Keep checking the value (again, possibly with deteriorating retry) until you can be certain you have a correct representation of Actor B's state.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2207450831068065059?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2207450831068065059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/07/learnings-from-actor-development.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2207450831068065059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2207450831068065059'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/07/learnings-from-actor-development.html' title='Learnings from Actor Development'/><author><name>Jamie Allen</name><uri>http://www.blogger.com/profile/14866645571542061539</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_8KbyT6n2_dQ/TF_7o54KDFI/AAAAAAAAAAY/Dii2YRp5Pa0/S220/20070701_IMG_3668.JPG'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4081033658818599558</id><published>2011-06-30T11:08:00.000-04:00</published><updated>2011-06-30T11:08:07.049-04:00</updated><title type='text'>Associative Arrays in Bash 4</title><content type='html'>&amp;nbsp;John Shepard, one of Chariot's architects and newest bloggers, just recently posted this on his blog.&lt;br /&gt;&amp;nbsp;A little different from our more focused software dev posts, we hope you will find this information useful.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I recently switched my work machine from OS X to Fedora. One of the first programs I noticed was missing was Time Machine. After being unable to get any of the backup software for Linux to behave as desired, a project emerged.&lt;br /&gt;&lt;br /&gt;Ignoring most of the details of the backup scripts (all the scripts are available at the end of this post), I'm going to focus on the part working with associative arrays.&lt;br /&gt;&lt;br /&gt;The backup program would need some way to keep only one backup per day for previous days. The obvious way to determine which days are affected is to keep a key value pair of dates and backup counts per day. Key value pairs have a few different names such as maps or dictionaries. In bash key value pairs are called associative arrays.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To declare an associative array use -A&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;declare -A MY_VARIABLE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To access the value just reference the variable as an array element&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;KEY="some value"&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MY_VARIABLE["${KEY}"]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To access the value, or use zero if there is no value, use a default value&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;${MY_VARIABLE["${KEY}"]:-0}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And to set a value (here the value for the key is being set to two)&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MY_VARIABLE["${KEY}"]=2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For looping, to access all keys&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;${!MY_VARIABLE[@]}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The entire set of backup scripts is available on &lt;a href="https://github.com/j-shepard/backup"&gt;github&lt;/a&gt;.&amp;nbsp;&lt;a href="https://github.com/j-shepard/backup/blob/master/cleanup_day.sh"&gt;cleanup_day.sh&lt;/a&gt; contains the associative array code.&lt;br /&gt;&lt;span class="post-author vcard"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4081033658818599558?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4081033658818599558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/06/associative-arrays-in-bash-4.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4081033658818599558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4081033658818599558'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/06/associative-arrays-in-bash-4.html' title='Associative Arrays in Bash 4'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-3693896743173317424</id><published>2011-06-21T13:03:00.000-04:00</published><updated>2011-06-21T13:03:36.654-04:00</updated><title type='text'>HTML 5 Offline Applications with JQuery Mobile</title><content type='html'>I can't believe it is a month since our last post.&amp;nbsp; Vacation got in the way, but our consultants have been blogging on various topics.&amp;nbsp; There is some catching up to do over the next week.&lt;br /&gt; &lt;br /&gt;New to the blogsphere is John Shepard.&amp;nbsp; John recently posted around JQuery ad HTML5, and what he has been doing with his spare time.&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;I was recently playing around with JQuery Mobile and was wondering how easy it would be to create an HTML 5 offline application. I'm not very familiar with HTML or JavaScript, so I figured this would be an interesting project.&lt;br /&gt;&lt;br /&gt;A simple application was required, so a calculator was semi-randomly selected. (The source for the calculator is available at the end of this post.)&lt;br /&gt;&lt;br /&gt;The first step in creating the calculator was to add some HTML that had a text area and some buttons. jQuery Mobile handles a resizing display area and can put buttons in a grid. The hooks into jQuery Mobile seem to be through data-roles and classes. Putting the textarea ....&lt;a href="http://j-shepard.blogspot.com/2011/06/html-5-offline-applications-with-jquery.html"&gt;read more&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-3693896743173317424?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/3693896743173317424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/06/html-5-offline-applications-with-jquery.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3693896743173317424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3693896743173317424'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/06/html-5-offline-applications-with-jquery.html' title='HTML 5 Offline Applications with JQuery Mobile'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6101415746898570333</id><published>2011-05-20T12:36:00.000-04:00</published><updated>2011-05-20T12:36:54.109-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile application development'/><title type='text'>Debugging PhoneGap and JavaScript</title><content type='html'>This is a "reprint" of a guest blog post on the PhoneGap blog, by our resident PhoneGap expert, Hiedi Utley.&amp;nbsp; Hiedi tackles debugging JavaScript on PhoneGap.&lt;br /&gt;&lt;br /&gt;If you have ever written any JavaScript and tried to get it working on a mobile phone then spent hours banging your head against the wall because it just doesn’t work, this post is just for you. Today, we will be looking at ways to troubleshoot, diagnose, and debug your mobile web project. While I will be focusing on debugging interactions with PhoneGap, the strategies outlined here are really applicable to any JavaScript or mobile web project. Since I have been focusing mainly on iOS development, this post will discuss the debugging of JavaScript and PhoneGap within an iPhone application but the same ideas should work for Android and other platforms as well.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.phonegap.com/2011/05/18/debugging-phonegap-javascript/"&gt;Read more..&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6101415746898570333?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6101415746898570333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/05/debugging-phonegap-and-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6101415746898570333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6101415746898570333'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/05/debugging-phonegap-and-javascript.html' title='Debugging PhoneGap and JavaScript'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-311795469023525390</id><published>2011-05-16T14:55:00.000-04:00</published><updated>2011-05-16T14:55:22.190-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dbunit'/><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Spock It Like You Mean It!</title><content type='html'>This post was just put up on the blog of one of our architects, Anatoly Polinsky.&amp;nbsp; Anatoly has a playful take on Spock, a Groovy testing framework, and specifically, abotu connecting Spock with Spring and DbUnit.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So here we go.. Yesterday night we hacked our way into The Ancient Database where besides the data about ancients themselves, we found incredible stats about many different living species of all the planets ancients traveled to.&lt;br /&gt;So what do we do now? Well, we need a way to query/read this data. So we asked &lt;a href="http://en.wikipedia.org/wiki/Samantha_Carter" title="Samantha Carter"&gt;Sam&lt;/a&gt; to develop a reader ( ancients called it a ‘DAO’ ) to find a number of living species on each planet since the “beginning of time”.&lt;br /&gt;So she did, and called this “species reader” a ‘SpeciesDao’.&lt;br /&gt;We, of course, trust Sam. But in ancient technology, trust is always based on challenging the assumption by testing all the possible permutations. So we are calling &lt;a href="http://code.google.com/p/spock/" title="the ancient technology ready specification framework"&gt;Mr. Spock&lt;/a&gt; to help us out…&lt;br /&gt;Sam of course used a well known ancient technique ( code name: &lt;a href="http://static.springsource.org/spring/docs/current/reference/" title="Spring Framework Reference Documentation"&gt;Spring Framework&lt;/a&gt; ) to create a “species reader”, so Mr. Spock will use all the goodies of this technique to inject all the dependencies ( e.g. data source, a reader itself, etc.. ) for a test.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotkam.com/2011/04/06/spock-it-like-you-mean-it/"&gt;Read more...&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-311795469023525390?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/311795469023525390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/05/spock-it-like-you-mean-it.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/311795469023525390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/311795469023525390'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/05/spock-it-like-you-mean-it.html' title='Spock It Like You Mean It!'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-3446034570889450015</id><published>2011-05-01T22:10:00.001-04:00</published><updated>2011-05-01T22:11:24.718-04:00</updated><title type='text'>Digital Philadelphia: A vision of Philadelphia as a regional technology center</title><content type='html'>&lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;i&gt;Here's how to make ithappen, says former CTO Allan Frank&lt;/i&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;By Todd R. Weiss&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;PHILADELPHIA – (&lt;i&gt;Editor's note&lt;/i&gt;: &lt;i&gt;Allan R. Frank, the former CTO of the City of Philadelphia, was scheduledto speak here last Thursday at the 6&lt;sup&gt;th&lt;/sup&gt; annual &lt;u&gt;&lt;span style="color: blue;"&gt;&lt;a href="http://phillyemergingtech.com/2011/"&gt;Emerging Technologies for theEnterprise Conference&lt;/a&gt;&lt;/span&gt;&lt;/u&gt; (ETE). A sick child at home, however,canceled his plans for the day. Frank was kind enough, though, to talk with meby telephone to describe his vision for technology in Philadelphia – which was to have been thesubject of his talk. Here are his thoughts.)&lt;/i&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;From July 2008 to this past February, Allan R. Frank workedas the City of Philadelphia'sfirst-ever &lt;a href="http://www.phila.gov/dot/cio.html"&gt;Chief Technology Officer(CTO)&lt;/a&gt;. Yes, the city has maintained a separate Chief Information Officerpost for a long time, but the CIO is in charge of the city's IT systems andstaff and running IT for its government agencies and processes.&lt;/div&gt;&lt;div class="MsoNormal"&gt;Instead, Frank was brought in to help find ways to usetechnology to make the city a better place to live, work and do business. Hisvision, he said, was to find ways of using technology in the city to bringbusiness people, educators, residents and other movers and shakers together inthe common good.&lt;/div&gt;&lt;div class="MsoNormal"&gt;Frank &lt;a href="http://www.govtech.com/pcio/Philadelphia-CIO-Allan-Frank-Has-Plans.html"&gt;tookthe CTO post&lt;/a&gt; after talking with Mayor Michael Nutter and convincing Nutterthat someone was needed to help connect the area's technological capabilitieswith the issues that were central to the mayor and the city. To Frank, thatmeant showing Nutter how a technology-focused CTO could help the city solve itsmost pressing problems, from economic development to solving poverty toimproving education and more. &lt;/div&gt;&lt;div class="MsoNormal"&gt;Frank said he explained to Nutter how technology could havean impact on a wide range of issues, but that someone was needed to lead theeffort.&lt;/div&gt;&lt;div class="MsoNormal"&gt;"I started explaining to the mayor that I saw a tremendousopportunity for the city to take its place as a cornerstone of a regional technologycenter," he said. By bringing Frank in as CTO, he told Nutter that themayor would finally have someone "sitting at the table to focus on all ofhis goals." &lt;/div&gt;&lt;div class="MsoNormal"&gt;"The mayor obviously shared my vision around theopportunity for how technology plays a role in everything in a city,"Frank said. "He saw the importance of that outside role."&lt;/div&gt;&lt;div class="MsoNormal"&gt;Frank's vision was to continue what Philadelphia has always been – a city offirsts. Since the 1600s, the first library was set up here, as well as thefirst hospital, bank, library, medical school and computer – ENIAC.&lt;/div&gt;&lt;div class="MsoNormal"&gt;With that history in mind, Frank said he envisions the cityas the "ground zero" for the next wave of technological innovation inthe U.S.&lt;/div&gt;&lt;div class="MsoNormal"&gt;"My vision of what I call 'Digital Philadelphia' isasking the question, 'what should it be and what should it look like? This citymust be the national model for urban transformation to the 21&lt;sup&gt;st&lt;/sup&gt;century knowledge economy."&lt;/div&gt;&lt;div class="MsoNormal"&gt;The tools are here in the region to make it happen,including such things as an urban core that has been again attracting youngpeople to move downtown and work in the city, he said. &lt;/div&gt;&lt;div class="MsoNormal"&gt;"We're also the home of Comcast," he said."We could be the next Silicon Valley."&lt;/div&gt;&lt;div class="MsoNormal"&gt;Much of Frank's ideas for the city were born, he said, afterPresident Obama took office, nurtured by Obama's ideas of creating broadbandstimulus efforts to help cities expand their technological infrastructures andabilities.&lt;/div&gt;&lt;div class="MsoNormal"&gt;"In the 1960s, Philadelphiawas manufacturing textiles," Frank said. "Today we should be talkingabout putting in fiber networks and technology parks."&lt;/div&gt;&lt;div class="MsoNormal"&gt;There are 154,660 people employed in IT occupations in the Philadelphia region,employing 7.4% of the area's total workforce, he said. That gives the area the6th &lt;/div&gt;&lt;div class="MsoNormal"&gt;largest concentration of IT workers in the U.S.&lt;/div&gt;&lt;div class="MsoNormal"&gt;Adding to the region's allure as a burgeoning tech centerare the world-class universities here that train qualified technical people, hesaid.&lt;/div&gt;&lt;div class="MsoNormal"&gt;"What about developing tech economic development zonesaround the city, buildings that are pre-wired for 1-gigabit networks and many moreinnovations?" he said. "I was trying to frame this vision of Philadelphia as this zoneof network incubators, and setting up better ways to work with local techcommunity."&lt;/div&gt;&lt;div class="MsoNormal"&gt;All of these things have been part of the regionaldiscussion after he joined the city in 2008 and they will continue to bepursued &lt;a href="http://cityofphiladelphia.wordpress.com/2010/11/24/mayor-nutter-announces-departure-of-chief-technology-officer-allan-frank/"&gt;evenafter he departed from his post&lt;/a&gt; to head back into private industry, hesaid.&lt;/div&gt;&lt;div class="MsoNormal"&gt;"Government can't make all of this happen," Franksaid. "It takes the community at large. And it takes the government to besupportive. Digital Philadelphianeeds to have executives, citizens and tech companies involved."&lt;/div&gt;&lt;div class="MsoNormal"&gt;Now all of those ideas will be the responsibilities ofothers. Frank, who has more than 35 years of experience in technology andbusiness leadership, left his CTO role in February to return full-time to &lt;a href="http://www.akaplex.com/"&gt;The AKA Group LLC&lt;/a&gt;, a strategic consultingfirm that he founded. &lt;/div&gt;&lt;div class="MsoNormal"&gt;Frank remains, however, on a steering committee to helpcontinue these efforts and he believes in the city and the area, he said. Hispassions and energy will continue to help push for these changes, he said.&lt;/div&gt;&lt;div class="MsoNormal"&gt;"Over the last couple of years, you can feel the energyhere," he said. "Our kids should be staying here in Philadelphia to create for technologycompanies" so we need to help create a vibrant tech community here toemploy thousands of people. "The future of the world is cities."&lt;/div&gt;&lt;div class="MsoNormal"&gt;The power to make it all happen here is right in theregion's hands, according to Frank. "What we really have to do is create afreaking wave." &lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;i&gt;Todd R. Weiss is a longtime technology journalist whoworked as a staff writer for Computerworld.com from 2000 to 2008. Now afreelance tech journalist, Weiss contributes regularly to Computerworld,PCWorld.com and other publications. He has also written extensively forLinux.com, ForecastingClouds.com and TechTarget on a wide range of enterpriseIT topics from Linux and open source to disaster recovery, cloud computing,virtualization, application development, IT education and mobile and wirelesstechnologies. He began writing about computers in 1996 after a newspaper editorhe worked for told him that "no one cares about technology."Apparently, the editor was wrong. Follow him on Twitter.com @TechManTalking orcontact him at toddrweiss at gmail dot com.&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-3446034570889450015?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/3446034570889450015/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/05/digital-philadelphia-vision-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3446034570889450015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3446034570889450015'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/05/digital-philadelphia-vision-of.html' title='Digital Philadelphia: A vision of Philadelphia as a regional technology center'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-7038402140277048531</id><published>2011-04-28T16:16:00.001-04:00</published><updated>2011-04-28T16:16:51.767-04:00</updated><title type='text'>Meet your future bosses: Meet the girls of TechGirlz.org</title><content type='html'>&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;By Todd R. Weiss&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;PHILADELPHIA – Yes, the halls here atthe 6&lt;sup&gt;th&lt;/sup&gt; annual &lt;span style="color: blue;"&gt;&lt;u&gt;&lt;a href="http://phillyemergingtech.com/2011/"&gt;EmergingTechnologies for the Enterprise Conference&lt;/a&gt;&lt;/u&gt;&lt;/span&gt; (ETE) arefilled with software developers, business people and technologyvisionaries.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;But if you looked a little deeper, youmight have met your next boss – and she could still be inelementary school.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;In a conference room here this morning,nine girls – ages eight to 15 – met with two    visionary womenin technology who delivered the keynotes for the event – StormyPeters of Mozilla and Molly Holzschlag of Opera Software – to getadvice, encouragement and &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;support in pursuing their youthfulinterests in computers. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;The girls were invited to visit by&lt;span style="color: blue;"&gt;&lt;u&gt;&lt;a href="http://techgirlz.org/"&gt;TechGirlz.org&lt;/a&gt;&lt;/u&gt;&lt;/span&gt;,a Philadelphia-area non-profit group begun two years ago to encourageyoung girls to explore their love of technology even when they thinkit's too geeky to pursue.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;So who are the girls of TechGirlz?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;They are young women like Eliana, 12,who one day decided she wanted to create a video game. First shebegan creating a site for the game using HTML, then she realized sheneeded to use a programming language to build it correctly. She chosePython after attending several technology camps and talking withothers to gaining their expertise. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"I started by teaching myself HTMLthen I started learning Python," said the bright-eyed girl withbraces, hot pink pants  and long, curly dark hair. "What got meinvolved was that ever since I was really little, I was alwaysattracted to video games and computers."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Since then, she's been working hard tofurther develop the game and continue to add features. She's evenexploring the idea of releasing it as an open source project, but shesaid she's not sure she wants to give up control of the project.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Yes, I did say she's 12.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;And those code camps that Eliana's beengoing to? They're with students who are in high school and college,yet there she is coding with the best of them. "I'm still kindof more like an amateur," she said.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Yeah, right.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;I know of companies out there who aredesperate today to find and hire good Python coders and here isEliana, a 12-year-old who is building her own video game fromscratch. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Classic.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Then there's Olivia, 12, in a pinkshirt and ponytail, who loves to do art and design work on hercomputer, "making it go from clunky to smooth and shiny." &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;There was Megan, 13, who said she'dlike to find ways of helping to add emotional context to online chatand other electronic communications. The problem, Megan said, is thatit's hard to know what people are feeling when they are communicatingusing chat – are they mad at you or are they happy with you, shewondered? That's a great problem to solve.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Ten-year-old Kayla had another concern– she created a Web site for her business - making healthy homemadedoggie treats (&lt;span style="color: blue;"&gt;&lt;u&gt;&lt;a href="http://www.kaninekookies.webs.com/"&gt;www.kaninekookies.webs.com&lt;/a&gt;&lt;/u&gt;&lt;/span&gt;)– and sometimes the technology overwhelms her, she said.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Haley, 8, is on her school's roboticsteam and likes to use computers.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Meanwhile, Logan, 15, also likesrobotics and learning about how to make the devices operate. "Itcan be frustrating figuring out how to make them do something,"she said. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;So what advice did Peters andHolzschlag have for the girls?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;First, Peters said, if the girls feeloverwhelmed by the technology, she reminded them that it's not due toany shortcomings of their own.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"It's not you," Peters said."It's the way that the people who are telling you about it aretalking about it. I always think it's the fault of the person who'strying to tell you about it [if they can't explain it better]."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Asking lots of questions is a great wayto learn, Peters added, lauding Olivia for asking what CSS Zen Gardenis all about in the field of Web design. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"If you're brave enough to askwhat CSS is at a technology conference, then I guarantee that 80% ofthe other people in the room are also wondering what CSS is,"Peters said with a laugh.  &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Whatever they choose to do as theycontinue their educations, Peters encouraged the girls to follow whatthey are interested in and not give up on their dreams of pursuing atechnology career.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"What frustrates me is that womenare missing opportunities in a fantastic field," she said. "Istarted in technology because I really liked what computers could do.Now we have computers that can help blind people read, that helppeople find a movie, that enable people to get jobs and more. I justfound computers fascinating and being able to make … them do what Iwanted to do was another part of that."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Holzschlag got involved with computers by accident, she said. She was studying Spanish and linguistics atthe University of Arizona when she suddenly had to drop out of schooldue to a long-term illness. For 10 years she was home-bound.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;One day, a cousin send her an oldCommodore 64  computer and a friend sent her a 300&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;baud modem. She hooked it all togetherand went online using an ancient dial-up service back in 1988. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Suddenly she went from home-bound andbeing isolated to joining a global community, years before theInternet ever appeared, she said.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"It was in that moment that Ilogged on and saw people from around the world," Holzschlagsaid. "I didn't know what I was looking at, but I knew that was'it.'"&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;She's been involved in technology eversince.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"My life changed … because ofthat Commodore 64 and a 300 baud modem that somehow came into mylife,"she said.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Those are the kinds of messages thatTechGirlz.org is working to bring to young girls in the area, saidTracey Welson-Rossman, director of marketing and sales at ChariotSolutions, the Fort Washington, Pa.-based software developmentconsulting company that hosts the annual ETE event.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Welson-Rossman, the founder ofTechGirlz.org, said the group's work started last September whengroups of 15-20 girls would come to participate in lectures,discussions and demonstrations of technology so they could gainexposure and increase their curiosity about high-tech topics.&lt;br /&gt;Theidea is to expose tech-minded girls at a young age to women who areworking in technology so they can be inspired and empowered,Welson-Rossman said. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"We've seen research that saysthat the reason that girls drop out of pursuing technology interestsstarting in ninth grade in high school is because they think it'sgeeky," she said. "They think it's  not creative. Theythink you're working in a cubicle and not talking to anybody."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;To battle those stereotypes, TechGirlzstrives to get to them early and show them how exciting, gratifyingand worthwhile technology jobs can be. "One of the other issuesis that they think it's not cool for girls to be in technology. Andbecause of that they feel that they can't actually express that theyactually &lt;i&gt;like&lt;/i&gt; technology."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"So one of our goals is to createa safe place for them to be able to express this part of theirpersonalities, of their interests," through TechGirlz.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;About 100 girls are involved in theprogram so far. TechGirlz is growing its program by makingconnections with teachers and schools in the metropolitanPhiladelphia area and through communications with home-schoolingorganizations, Scouting groups and others.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt; Men in technology are also welcome tovolunteer and help with the TechGirlz program, Welson-Rossman said."We also want men to be involved because we need to show alltypes of role models. These girls are going to be working with men."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;i&gt;Todd R. Weiss is a longtimetechnology journalist who worked as a staff writer forComputerworld.com from 2000 to 2008. Now a freelance tech journalist,Weiss contributes regularly to Computerworld, PCWorld.com and otherpublications. He has also written extensively for Linux.com,ForecastingClouds.com and TechTarget on a wide range of enterprise ITtopics from Linux and open source to disaster recovery, cloudcomputing, virtualization, application development, IT education andmobile and wireless technologies. He began writing about computers in1996 after a newspaper editor he worked for told him that "noone cares about technology." Apparently, the editor was wrong.  &lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-7038402140277048531?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/7038402140277048531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/meet-your-future-bosses-meet-girls-of.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7038402140277048531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7038402140277048531'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/meet-your-future-bosses-meet-girls-of.html' title='Meet your future bosses: Meet the girls of TechGirlz.org'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2908418322666800863</id><published>2011-04-28T10:54:00.001-04:00</published><updated>2011-04-28T10:54:44.524-04:00</updated><title type='text'>If you hold an Emerging technologies for the Enterprise conference in Philadelphia, people will come</title><content type='html'>&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;i&gt;Here's why they do attend – forlearning, for new ideas, for meeting peers&lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;By Todd R. Weiss&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;PHILADELPHIA – Almost 500 attendeesfrom all over the U.S., and some from as far away as India andSweden, are here at the 6&lt;sup&gt;th&lt;/sup&gt; annual &lt;span style="color: blue;"&gt;&lt;u&gt;&lt;a href="http://phillyemergingtech.com/2011/"&gt;EmergingTechnologies for the Enterprise Conference&lt;/a&gt;&lt;/u&gt;&lt;/span&gt; (ETE). &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;What attracted them to attend thisyear's two-day conference?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;And what have they taken away so far?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;For Michael P. Redlich, a seniorresearch technician for a U.S.-based petrochemical researchorganization, this is his fourth year in a row as an attendee.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"It's basically just the wealth ofinformation that's out there, especially in the area of emergingtechnology," he said. "I never heard of the &lt;a href="http://akka.io/"&gt;Akkaplatform&lt;/a&gt; until today so I went to see what it was about. Itturned out to be about cloud computing. There's just so much to keepup with that it's hard to keep current."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;That's where conferences like this oneare a boon, he said. Redlich, who runs a Java user's group and usesthe enterprise open source &lt;a href="http://www.springsource.org/"&gt;Spring&lt;/a&gt;development platform, said he also attended a session on Spring andcame out with useful new ideas.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"There were some new things inthere that I wasn't even aware of," he said. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Amir Tahvildaran, manager of systemsand applications for Drexel University's Math Forum and GoodwinCollege, said attending the show helps him stay connected to thelatest enterprise software developments.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"It's good to keep up on thenewest things and technologies that you don't have time to keep upwith at work," said Tahvildaran, who is here for his fifth ETEconference. "I hadn't heard of several mobile technologies, suchas &lt;a href="http://www.phonegap.com/"&gt;PhoneGap,&lt;/a&gt; or the &lt;a href="http://community.jboss.org/en/arquillian/faq"&gt;Arquillian&lt;/a&gt;integration testing [tools]."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;As Drexel looks at getting involved inmore mobile projects in the future, these kinds of technologies couldbe very useful to explore, he said. "It was nice to come inhere. People talk sense about why you would get into mobile."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Linda Kaiser, a IT manager for aPhiladelphia-based investment company, was at ETE for the first time.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"I'm here because in my role [asthe leader of a small R&amp;amp;D group] I'm generally interested inemerging technologies," Kaiser said. "We are veryinterested in the mobility topics that they have here at theconference."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;One of the best sessions she attended,she said, was about "intentional emergence" and what large,monolithic enterprises can learn from the Web and from open sourcecommunities. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-weight: normal;"&gt;Presentedby &lt;/span&gt;&lt;strong&gt;&lt;span style="font-weight: normal;"&gt;&lt;a href="http://phillyemergingtech.com/2011/speakers/jim-stogdill"&gt;JimStogdill,&lt;/a&gt; a senior director of architecture innovation withconsulting firm, Accenture, the session dove into the visible shiftsin organizational structure as our society continues to move from theIndustrial Age to the Information Age.&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;strong&gt;&lt;span style="font-weight: normal;"&gt;Stogdilltalked about "how it impacts real organizations that are used todoing things from the top down" instead of in the reverse,Kaiser said. "We have been using Agile software developmentmethodologies for several years now with varying degrees of success.&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-weight: normal;"&gt;Some of that has to do with the need for the organization to shift.There are definitely some interesting sessions here."&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Steve Gass, a Web developer forArmstrong World Industries in Lancaster who is attending his thirdETE show, said he's already learned some intriguing things to takeback to work.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"I got a lot of insights into themobile platform" and how businesses can find ways to connectwith customers, Gass said. "It's something I'm just startingwith" in his job.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;One of the best things he comes awaywith, he said, is the wide range of ideas he hears from presentersand fellow attendees from a wide range of companies.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"I come for a lot of bothtechnical insights and philosophical insights," he said.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Bruce Momjian, a database architectwith &lt;a href="http://www.enterprisedb.com/"&gt;EnterpriseDB,&lt;/a&gt; saidhe's been coming to the ETE conference for four years from his homein nearby Newtown Square, Pa., because the topics covered here arethings he doesn't deal with every day in his work.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"What's neat for me is that thisis a conference that is not in my specialty," he said. "WhenI come here, I learn about new things, like [the programminglanguage] &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt; and about howto write mobile apps in a Web browser. The cool thing for me is thatI get more out of this conference than I do just about anywhere else.It's a different stack."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Another key benefit of the ETEconference, Momjian said, is that it truly highlights some of thebest technology innovations being developed right here in hisbackyard in Philadelphia.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"I learn about what everyone elseis doing plus I get to develop working relationships with tech peoplein the area," he said. ""This gives me a chance toreally be visible and to get to know a lot of the movers and shakersin our area. We have a lot of tech people here in Philadelphia, butwe didn't have anyone to bring us together until now. That's why Ithink this is a core conference. I get so much out of this."  &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;What were your reasons for attendingthis year's conference? &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;And what did you get out of it? &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Please share your stories and lessonslearned here in the comments section of the blog below. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;i&gt;Todd R. Weiss is a longtimetechnology journalist who worked as a staff writer forComputerworld.com from 2000 to 2008. Now a freelance tech journalist,Weiss contributes regularly to Computerworld, PCWorld.com and otherpublications. He has also written extensively for Linux.com,ForecastingClouds.com and TechTarget on a wide range of enterprise ITtopics from Linux and open source to disaster recovery, cloudcomputing, virtualization, application development, IT education andmobile and wireless technologies. He began writing about computers in1996 after a newspaper editor he worked for told him that "noone cares about technology." Apparently, the editor was wrong.  &lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2908418322666800863?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2908418322666800863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/if-you-hold-emerging-technologies-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2908418322666800863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2908418322666800863'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/if-you-hold-emerging-technologies-for.html' title='If you hold an Emerging technologies for the Enterprise conference in Philadelphia, people will come'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2182395631594350611</id><published>2011-04-27T14:29:00.000-04:00</published><updated>2011-04-27T14:29:34.956-04:00</updated><title type='text'>In a new world of tablet computers and smartphones, on-screen buttons are passé</title><content type='html'>&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;i&gt;Design expert: Pay attention to thenew rules of designing for touchscreens&lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;By Todd R. Weiss&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;PHILADELPHIA - As software developersdesign how the next generations of apps will look and work, they needto transform their ideas about how to best put useful content on theshrinking device screens being used by consumers.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;That's because tablet computers,smartphones and other handheld mobile devices dramatically change howconsumers can view content on screens that are much smaller thantraditional desktop displays. Those differences call for a move awayfrom traditional desktop on-screen buttons that simply don't workwell on smaller screens.  &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;What's needed instead, says  JoshClark, an iPhone app consultant and founder of app design firm &lt;a href="http://globalmoxie.com/index.shtml"&gt;GlobalMoxie&lt;/a&gt;, is for app designers to carefully focus on the contentitself so they can visualize and truly find the most relevant ways todisplay it.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;In a thought-provoking presentationhere today at the 6&lt;sup&gt;th&lt;/sup&gt; annual &lt;span style="color: navy;"&gt;&lt;span lang="zxx"&gt;&lt;u&gt;&lt;a href="http://phillyemergingtech.com/2011/"&gt;EmergingTechnologies for the Enterprise Conference&lt;/a&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;(ETE), Clark described why "Buttons Are A Hack: The New Rules ofDesigning for Touch."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"When you remove the mouse andkeyboard … all that remains is you and the device," he said.That approach gets to the core of the connections between users andtheir touchscreen devices because they must use the tactile emotionsof touch to find what they are seeking. The problem, though, is thatnot all touchscreen apps today allow users to truly explore touchnatively, he said. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;One example of this, according toClark, is the &lt;a href="http://abcnews.go.com/ipad"&gt;ABC News app forthe iPad,&lt;/a&gt; which features an Earth globe that can be "spun"with a fingertip to move from story to story for viewing. The problemis it's built for show and doesn't make it easy for users to find thecontent they are seeking, he said, partly because it only displaystwo stories at a time in the main screen and there's no usable index.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"It's actively upstaging thecontent," Clark said. "Whiz-bang graphics don't help usfind information. More attention is given to the contraption than tothe content."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;A better, more intuitive and cleanerapproach comes from &lt;a href="http://itunes.apple.com/us/app/nytimes-for-ipad/id357066198?mt=8"&gt;TheNew York Times Editor's Choice app for the iPhone&lt;/a&gt;, which favorsfunction over form. Instead of trying a flashy, tech interface, theapp displays New York Times content in a form that appears like anewspaper page. Critics, of course, panned the interface as boringand traditional, Clark said, but experiments by other designers foundthat too much change can also be a turn-off for consumers. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Because the New York Times' onlinebrand has been around now for more than 15 years, it's instantlyrecognizable as a brand to online readers, Clark said. And ratherthan rework it with an entirely new look and feel, research foundthat that connection is a boon because it keeps the Times familiarand comfortable for readers.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;The lesson learned?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"Don't underestimate the power ofhum-drum as you go out and design interfaces," Clark said. "Oldideas are not necessarily old-fashioned."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Another key for app design is to matchthe touchscreen capabilities to the content you are producing, hesaid. If the app is for displaying the content of a print magazine,then keep the tactile feel of the paper magazine in mind –visualize how the pages turn and feel so you can keep your users"connected" to the physical magazine as they explore itsonline content. Automated "page flips" can be a goodfeature to use, as they allow the user to "see" the pagesturning as they read the content, but make the pages turn quickly soyou don't lose readers, he said.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"Page flips are window dressingfor sure, but they reinforce that you are reading a newspaper ormagazine or book," which provides context, connection andfamiliarity, Clark said. "And familiarity and intimacy invitetouch. If you're going to make it look like a book [or magazine] thenyou have to make it act like one."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;That's not always done in app designs,and it needs to happen more, he said. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Even Apple's own calendar app for theiPhone isn't intuitive enough due to its design, according to Clark.Where a user should be able to "swipe" a finger across thecalendar screen to turn a page, it's not possible. Instead, they haveto click an arrow to move a page ahead or backward. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;That's just not right withtouchscreens, he said, because they invite intuitive actions such astouching, tapping, swiping – at the expense of those outmodedbuttons. "You see this [disconnect] all over the place" inrecent app designs, he said. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"Just enough is more," Clarksaid, accentuating the idea that design just for the sake of designis not enough. The content delivery of today's apps need to focus onthe users and how &lt;i&gt;they&lt;/i&gt; want to access information throughtheir fingertips and touch.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"Watch a toddler use an iPad,"he said. "They just use it. So design for humans. Design fordirect interaction. Design for toddlers. Think about how kids woulduse the app."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;All of this is still evolving, Clarksaid, as touchscreen app development remains in its infancy today."We're only a year into mainstream tablet app design. Don'tassume that anyone else has it nailed yet, especially the big guys."   &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;That means it's great to watch whatother app developers are doing, but don't immediately jump in tofollow them – they could have gotten it all wrong.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"It's very early and it'sdangerous to lock in on half-baked convention" just because yousee others doing certain things so far, he said."Understand thatyou won't get it right the first time and don't give up."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;i&gt;Todd R. Weiss is a longtimetechnology journalist who worked as a staff writer forComputerworld.com from 2000 to 2008. Now a freelance tech journalist,Weiss contributes regularly to Computerworld, PCWorld.com and otherpublications. He has also written extensively for Linux.com,ForecastingClouds.com and TechTarget on a wide range of enterprise ITtopics from Linux and open source to disaster recovery, cloudcomputing, virtualization, application development, IT education andmobile and wireless technologies. He began writing about computers in1996 after a newspaper editor he worked for told him that "noone cares about technology." Apparently, the editor was wrong.  &lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2182395631594350611?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2182395631594350611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/in-new-world-of-tablet-computers-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2182395631594350611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2182395631594350611'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/in-new-world-of-tablet-computers-and.html' title='In a new world of tablet computers and smartphones, on-screen buttons are passé'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2222029549622795011</id><published>2011-04-27T08:31:00.000-04:00</published><updated>2011-04-27T08:31:50.663-04:00</updated><title type='text'>Welcome: A Guide to What's in Store for you here at the 6th annual Emerging Technologies for the Enterprise Conference</title><content type='html'>&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;By Todd R. Weiss&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;In the next two days, prepare to beinspired, educated, challenged, informed and entertained by a cast ofdiverse IT experts who are here to share their insights andexperiences on a wide swath of software development topics.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;I'm technology journalist Todd R.Weiss, and I'm a regular contributor to Computerworld, PC World andTechTarget, writing about enterprise IT and the challenges it bringsdaily to businesses and their busy IT staffs.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;I'm here on behalf of Chariot Solutionsto help cover this conference and bring some of its key highlights totheir customers and attendees at this 6&lt;sup&gt;th&lt;/sup&gt; annual &lt;a href="http://phillyemergingtech.com/2011/"&gt;EmergingTechnologies for the Enterprise Conference&lt;/a&gt; (ETE) in Philadelphia.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Among the software development notableshere for this information-packed event are:&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;*Mobile application consultant JonathanStark, who is the author of O’Reilly Media’s &lt;i&gt;Building iPhoneApps with &lt;/i&gt;&lt;i&gt;HTML&lt;/i&gt;&lt;i&gt;, &lt;/i&gt;&lt;i&gt;CSS&lt;/i&gt;&lt;i&gt;, and JavaScript&lt;/i&gt;.Jonathan will talk about his alternative approaches to building appsfor iPhone and iPad using only HTML, CSS and JavaScript.   &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;strong&gt;*&lt;/strong&gt;David Kaneda, thedeveloper of &lt;span style="color: navy;"&gt;&lt;span lang="zxx"&gt;&lt;u&gt;&lt;a href="http://www.jqtouch.com/"&gt;jQTouch&lt;/a&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;,a Javascript framework for iPhone development and creative directorat &lt;a href="http://www.sencha.com/"&gt;Sencha&lt;/a&gt;. David will talk aboutSencha Touch, a mobile web app framework that allows developers tocreate rich mobile apps which look and feel native. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;*Josh Clark, a designer who specializesin mobile design strategy and user experience. Josh is the author of “&lt;i&gt;Tapworthy: Designing Great iPhone Apps&lt;/i&gt;” and “&lt;i&gt;BestiPhone Apps&lt;/i&gt;” from O'Reilly Media.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;*Eduardo Jezierski, theCTO of &lt;a href="http://instedd.org/"&gt;InSTEDD&lt;/a&gt;,a non-profit that helps communities around the world use, design anddevelop information tools for their health, safety and development.Eduardo will lecture about "Architecture and Agility With Livesat Stake."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;*Jonas Boner, the creator of the &lt;a href="http://akka.io/"&gt;Akka&lt;/a&gt;development framework, who will describe Akka in detail and show howit can be used to solve hard scalability problems.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;*Mark Chadwick, the chief architect atGoogle subsidiary Invite Media, who will describe how Invite Mediaserves up millions of advertisements to targeted consumers every hourin his lecture, &lt;span style="color: navy;"&gt;&lt;span lang="zxx"&gt;&lt;u&gt;&lt;a href="http://phillyemergingtech.com/2011/sessions/doing-the-mundane-a-million-times-a-minute"&gt;Doingthe Mundane a Million Times a Minute.&lt;/a&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;This year the ETE conference is part ofthe first "&lt;a href="http://www.phillytechweek.com/"&gt;Philly TechWeek&lt;/a&gt;" being organized in Philadelphia across a wide range ofsites in the city. Philly Tech Week is a first-time event that'sbeing promoted to showcase the bustling technology community in theregion. &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;This is the biggest year yet for theETE conference, which is hosting almost 500 attendees in 2011, saidTracey Welson-Rossman, director of sales and marketing for softwaredevelopment consulting firm Chariot Solutions of Fort Washington, Pa.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"We really feel that this is atipping point and that we're going to let people outside the areaknow that there's hidden high-tech gems in the Philadelphia area,"Welson-Rossman said. "Were really fortunate to have this levelof talent that comes to us here at the conference."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;"We know that the Philadelphiacommunity has an incredibly strong tech community," she said."That’s why were able to have this show. We wouldn't be ableto attract the speakers if the area didn’t have this reputation."&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;i&gt;Todd R. Weiss is a longtimetechnology journalist who worked as a staff writer forComputerworld.com from 2000 to 2008. Now a freelance tech journalist,Weiss contributes regularly to Computerworld, PCWorld.com and otherpublications. He has also written extensively for Linux.com,ForecastingClouds.com and TechTarget on a wide range of enterprise ITtopics from Linux and open source to disaster recovery, cloudcomputing, virtualization, application development, IT education andmobile and wireless technologies. He began writing about computers in1996 after a newspaper editor he worked for told him that "noone cares about technology." Apparently, the editor was wrong.  &lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2222029549622795011?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2222029549622795011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/welcome-guide-to-whats-in-store-for-you.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2222029549622795011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2222029549622795011'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/welcome-guide-to-whats-in-store-for-you.html' title='Welcome: A Guide to What&apos;s in Store for you here at the 6th annual Emerging Technologies for the Enterprise Conference'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-3384056723308849552</id><published>2011-04-21T18:27:00.000-04:00</published><updated>2011-04-21T18:27:19.695-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile phones'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile application development'/><title type='text'>PhoneGap Tutorial Series – #6 Writing Your Own Plugin</title><content type='html'>&amp;nbsp;This is the last of the series Hiedi Utley has written on PhoneGap.&amp;nbsp; I hope you have found the series helpful.&amp;nbsp; We hope to have more of this type of blog post in the future to help with developing mobile applications.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How to Create Your Own PhoneGap Plugin&lt;br /&gt;&lt;br /&gt;Today’s topic is about creating your own PhoneGap plugin for iOS development. PhoneGap provides a whole array of built in features to access all sorts of things on a device but what if you want to do something that is not already supported and has not already been provided by a third-party plugin? Stop fretting, just like adding a third-party plugin, if you can write a little Objective-C then you can add your own plugin to PhoneGap as well. In order to create your own plugin you will have to be somewhat familiar with JavaScript as well as Objective-C. This tutorial assumes that you are familiar with JavaScript, Objective-C, the iOS SDK, and the XCode development environment. This post also assumes that you are familiar with the &lt;a href="http://wp.me/p1p7Q1-1a"&gt;PhoneGap project structure&lt;/a&gt; and the &lt;a href="http://wp.me/p1p7Q1-2M"&gt;PhoneGap plugin architecture&lt;/a&gt;, so you may want to peruse some of my earlier posts before continuing on if you haven’t already.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hiediutley.com/2011/04/15/phonegap-tutorial-series-6-writing-your-own-plugin/"&gt;Read more&lt;/a&gt;..&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-3384056723308849552?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/3384056723308849552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/phonegap-tutorial-series-6-writing-your.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3384056723308849552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3384056723308849552'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/phonegap-tutorial-series-6-writing-your.html' title='PhoneGap Tutorial Series – #6 Writing Your Own Plugin'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6254256402125552767</id><published>2011-04-19T15:45:00.000-04:00</published><updated>2011-04-19T15:45:45.291-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile application development'/><title type='text'>PhoneGap Tutorial Series – #5</title><content type='html'>&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;&lt;h3&gt;Extending the PhoneGap API – Third-Party Plugins (NativeControls)&lt;/h3&gt;&lt;h3&gt;&lt;/h3&gt;Continuing on down the path of using third party plugins, today we will look at a little more complex example and use the NativeControls plugin to display a UIActionSheet to allow the user to select whether they want to take a photo using the camera or pick one from the photo library by utilizing the PhoneGap Camera API. &lt;br /&gt;If you haven’t read my previous post on &lt;a href="http://wp.me/p1p7Q1-2M"&gt;Third-Party Plugins (ChildBrowser)&lt;/a&gt; you may want to peruse that to understand the structure of a plugin and how to go about installing one before continuing on.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hiediutley.com/2011/03/30/phonegap-tutorial-series-%E2%80%93-5-third-party-plugins-nativecontrols/"&gt;Read more...&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6254256402125552767?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6254256402125552767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/phonegap-tutorial-series-5.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6254256402125552767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6254256402125552767'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/phonegap-tutorial-series-5.html' title='PhoneGap Tutorial Series – #5'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-8833047476830519728</id><published>2011-04-15T14:36:00.000-04:00</published><updated>2011-04-15T14:36:41.047-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile application development'/><title type='text'>Extending the PhoneGap API – Third-Party Plugins (ChildBrowser)</title><content type='html'>As we are preparing for&lt;a href="http://www.phillyemergingtech.com/"&gt; Emerging Technologies for the Enterprise&lt;/a&gt;, I did not want to forget the rest of the series on PhoneGap API that Hiedi Utley has been penning.&amp;nbsp; Here is part 4.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Extending the PhoneGap API – Third-Party Plugins (ChildBrowser)&lt;/h3&gt;&lt;br /&gt;So the last post was all about editing PhoneGap classes to add a little something extra, today it’s about using a third-party plugin that you may have downloaded from somewhere or gotten from someone. &lt;br /&gt;The plugins that we will be using today are from Jesse MacFayden (aka @purplecabbage on twitter). The original source code for the plugins can be downloaded from github here: &lt;a href="https://github.com/purplecabbage/phonegap-plugins"&gt;https://github.com/purplecabbage/phonegap-plugins.git&lt;/a&gt;&lt;br /&gt;You can also get the entire source for my sample project “HelloPhoneGap” from github here: &lt;a href="https://github.com/hutley/HelloPhoneGap"&gt;https://github.com/hutley/HelloPhoneGap.git&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hiediutley.com/2011/03/30/phonegap-tutorial-series-4-using-a-third-party-plugin/"&gt;Read more..&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-8833047476830519728?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/8833047476830519728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/extending-phonegap-api-third-party.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8833047476830519728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8833047476830519728'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/extending-phonegap-api-third-party.html' title='Extending the PhoneGap API – Third-Party Plugins (ChildBrowser)'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-1320374973315689826</id><published>2011-04-08T14:19:00.000-04:00</published><updated>2011-04-08T14:19:28.892-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile phones'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile application development'/><title type='text'>Extending the PhoneGap API</title><content type='html'>&amp;nbsp;Here is the third installment of Hiedi Utley's series on PhoneGap.&amp;nbsp; We hope you are finding this series helpful as you learn more about developing for mobile applications.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Extending the PhoneGap API&lt;/b&gt; &lt;br /&gt;If you’ve had a chance to play with PhoneGap a bit, chances are you have wanted it to do something that it doesn’t already do. Alas, don’t worry! You don’t have to put in a ticket and hope that the PhoneGap developers agree with you and implement it in some future release, if you can write a little Objective-C then you can do it yourself and use it in your own iOS project. &lt;br /&gt;The topic at hand is all about extending the PhoneGap API whether it’s by editing existing PhoneGap classes, downloading a third-party plugin from somewhere, or by writing your own plugin from scratch. For this post I will concentrate on editing the PhoneGap classes, in later posts I’ll give step-by-step instructions on using a third-party plugin and how to create your own plugin.&lt;br /&gt;If you haven’t already had a chance to read my earlier posts on PhoneGap internals and using the PhoneGap API – you may want to peruse them before reading on.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hiediutley.com/2011/03/28/phonegap-tutorial-series-3-extending-the-phonegap-api/"&gt;Read more...&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-1320374973315689826?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/1320374973315689826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/04/extending-phonegap-api.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1320374973315689826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1320374973315689826'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/04/extending-phonegap-api.html' title='Extending the PhoneGap API'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6847806269451228789</id><published>2011-03-31T11:26:00.000-04:00</published><updated>2011-03-31T11:26:15.844-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile application development'/><title type='text'>Using the PhoneGap API</title><content type='html'>&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;We are a little behind in posting Hiedi Utley's PhoneGap Tutorial Series.&amp;nbsp; Or she is a very fast writer.&lt;br /&gt;In this post, Hiedi discusses the features of PhoneGap API.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Using the PhoneGap API&lt;/h3&gt;Welcome to the second installment of my PhoneGap Tutorial Series! This post is a continuation of &lt;a href="http://hiediutley.wordpress.com/2011/03/14/phonegap-tutorial-series-1-project-structure-and-internals/"&gt;PhoneGap Project Structure and Internals&lt;/a&gt; so if you haven’t already, you may want to peruse that post before continuing on.&lt;br /&gt;We already know that PhoneGap is an open source framework for writing applications using typical web technologies like HTML, CSS, and JavaScript and that the PhoneGap architecture supplies JavaScript wrappers to access native phone features. What you may NOT know is how extensive those features really are or how to actually use them.&lt;br /&gt;This article is all about getting familiar with the current features of the PhoneGap API and how to use them with the iPhone iOS.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hiediutley.com/2011/03/17/phonegap-tutorial-series-2-phonegap-api/"&gt;Read more..&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6847806269451228789?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6847806269451228789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/03/using-phonegap-api.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6847806269451228789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6847806269451228789'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/03/using-phonegap-api.html' title='Using the PhoneGap API'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6040473134214575081</id><published>2011-03-21T09:44:00.000-04:00</published><updated>2011-03-21T18:03:31.625-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><category scheme='http://www.blogger.com/atom/ns#' term='junit'/><title type='text'>What is in my Spring Context?</title><content type='html'>When we are learning Spring, there are times we are not sure which beans are in the Spring context. Especially when we use convenient features of Spring 3 such as &amp;lt;context:annotation-driven/&amp;gt; or &amp;lt;context:component-scan/&amp;gt;.  As developers, we want to inspect the classes that are automatically registered providing the opportunity to look at the source code and javadocs to see what each class does.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;h3&gt;JUnit Tests get Application Context&lt;/h3&gt;Our JUnit tests have the ability to inject the Application Context. This is one of the many benefits of &lt;code&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java"&gt;&lt;br /&gt;@ContextConfiguration(value = "/META-INF/spring/test-app-context.xml")&lt;br /&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;br /&gt;public class BeansInContextTest {&lt;br /&gt;&lt;br /&gt;     @Autowired&lt;br /&gt;     ApplicationContext applicationContext;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Simple Code&lt;/h3&gt;Let's loop through all the beans that are defined or discovered with the following code.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java"&gt;&lt;br /&gt;@Before&lt;br /&gt;public void setup() {&lt;br /&gt;  logger.debug("********************");&lt;br /&gt;  String[] beans = applicationContext.getBeanDefinitionNames();&lt;br /&gt;  for (String o : beans) {&lt;br /&gt;    logger.debug("________________________");&lt;br /&gt;    logger.debug("BEAN = " + o);&lt;br /&gt;    logger.debug("\tType = " + applicationContext.getType(o));&lt;br /&gt;    String[] aliases = applicationContext.getAliases(o);&lt;br /&gt;     if (aliases != null &amp;&amp; aliases.length &gt; 0) {&lt;br /&gt;       for (String a : aliases) {&lt;br /&gt;         logger.debug("\tAliased as: " + a);&lt;br /&gt;       }&lt;br /&gt;     }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  logger.debug("********************");&lt;br /&gt;  logger.debug("*** Number of Beans = {} ***",&lt;br /&gt;    applicationContext.getBeanDefinitionCount());&lt;br /&gt;  logger.debug("********************");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;What is the Alias?&lt;/h4&gt;We can define beans with "id" which by XML law requires it to be unique per file.  This restricts us in the ability to use special symbols for the name should we want to.  I recommend using "id" unless absolutely necessary.  However, should we what to refer to the bean with multiple names or use special symbols, we can use the "name" attribute. By comma separating the tokens, we have the opportunity to refer to a bean with any of the tokens provided.&lt;pre class="brush:xml"&gt;&amp;lt;bean name="mailServer/default, mailServer" class="..."/&amp;gt;&lt;/pre&gt;If no, "id" is provided, the first token becomes the primary and the subse     quent tokens become aliases.  Does this matter in the usage of the beans? No.  But to find "all" the names of the beans, we would display the aliases in addition to the bean names.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Full Test Code&lt;/h4&gt;&lt;pre class="brush:java"&gt;package com.chariot.sample;&lt;br /&gt;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;import org.junit.runner.RunWith;&lt;br /&gt;import org.slf4j.Logger;&lt;br /&gt;import org.slf4j.LoggerFactory;&lt;br /&gt;import org.springframework.beans.factory.annotation.Autowired;&lt;br /&gt;import org.springframework.context.ApplicationContext;&lt;br /&gt;import org.springframework.test.context.ContextConfiguration;&lt;br /&gt;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;&lt;br /&gt;&lt;br /&gt;@ContextConfiguration(value = "/META-INF/spring/test-app-context.xml")&lt;br /&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;br /&gt;public class BeansInContextTest {&lt;br /&gt;  private final Logger logger = LoggerFactory&lt;br /&gt;    .getLogger(BeansInContextTest.class);&lt;br /&gt;&lt;br /&gt;  @Autowired&lt;br /&gt;  ApplicationContext applicationContext;&lt;br /&gt;&lt;br /&gt;  @Before&lt;br /&gt;  public void setup() {&lt;br /&gt;    logger.debug("********************");&lt;br /&gt;    String[] beans = applicationContext.getBeanDefinitionNames();&lt;br /&gt;    for (String o : beans) {&lt;br /&gt;      logger.debug("________________________");&lt;br /&gt;      logger.debug("BEAN = " + o);&lt;br /&gt;      logger.debug("\tType = " + applicationContext.getType(o));&lt;br /&gt;      String[] aliases = applicationContext.getAliases(o);&lt;br /&gt;      if (aliases != null &amp;&amp; aliases.length &gt; 0) {&lt;br /&gt;        for (String a : aliases) {&lt;br /&gt;          logger.debug("\tAliased as: " + a);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;   &lt;br /&gt;    logger.debug("********************");&lt;br /&gt;    logger.debug("*** Number of Beans = {} ***",&lt;br /&gt;      applicationContext.getBeanDefinitionCount());&lt;br /&gt;    logger.debug("********************");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Sample Bean Context&lt;/h4&gt;&lt;pre class="brush:xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;  xmlns:context="http://www.springframework.org/schema/context"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&lt;br /&gt;    http://www.springframework.org/schema/context&lt;br /&gt;      http://www.springframework.org/schema/context/spring-context-3.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;context:annotation-config/&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;bean id="myBean" class="MyCoolBean"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Experiment and Have Fun&lt;/h3&gt;Add beans to the config file.  Import other config files and see what happens.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Wanna Learn More?&lt;/h3&gt; Learn more about what goes on Spring Context by attending a &lt;a href="http://chariotsolutions.com/education"&gt;Core Spring Training&lt;/a&gt; class at Chariot.&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;div style="text-align: center;font-size:200%;background-color:#C0C0C0;border-style:solid;border-color:SteelBlue;border-radius: 40px; -moz-border-radius: 40px; -webkit-border-radius: 40px;"&gt;&lt;a href="http://chariotsolutions.com/education"&gt;Chariot Education Calendar&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br/&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6040473134214575081?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6040473134214575081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/03/what-is-in-my-spring-context.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6040473134214575081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6040473134214575081'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/03/what-is-in-my-spring-context.html' title='What is in my Spring Context?'/><author><name>Gordon Dickens</name><uri>https://profiles.google.com/114681050780814546369</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-dMj3fLlkNPA/AAAAAAAAAAI/AAAAAAAAAJY/fR7TY-stMvo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2842620078200223238</id><published>2011-03-17T09:22:00.000-04:00</published><updated>2011-03-17T09:22:53.981-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile application development'/><title type='text'>PhoneGap Tutorial Series – #1 Project Structure and Internals</title><content type='html'>&lt;h3&gt;&lt;span style="font-size: small; font-weight: normal;"&gt;Heidi Utley, one of the members of our mobile practice, has been working with PhoneGap for one of our clients. She decided to create a series of posts focusing on using PhoneGap for iPhone development.&lt;/span&gt;&lt;/h3&gt;&lt;h3 style="font-weight: normal;"&gt;&lt;span style="font-size: small;"&gt;This first one discusses the project structure.&amp;nbsp; Future posts will review the PhoneGap API, installing a third party plugin, and last building your own PhoneGap plugin.&lt;/span&gt;&lt;/h3&gt;&lt;h3&gt;What is PhoneGap?&lt;/h3&gt;&lt;br /&gt;PhoneGap is an open source framework for writing applications using typical web technologies like HTML, CSS, and javascript. The PhoneGap architecture supplies javascript wrappers that allow a developer to access native phone features (like contacts, GPS, and the camera) by writing their app against the PhoneGap javascript API.&lt;br /&gt;The basic gist is that the typical web developer will be able to write a standalone HTML/CSS/javascript application that runs in a WebKit browser with access to native functions just by calling the PhoneGap javascript. PhoneGap aides the developer by abstracting the complexities of native development by allowing the developer to write the app in well-known technology without having to learn the intricacies of each mobile platform and thereby hiding the complexity of writing the same application multiple times in various native languages (like Objective-C for the iPhone or Java for Android).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hiediutley.wordpress.com/2011/03/14/phonegap-tutorial-series-1-project-structure-and-internals/"&gt;Read more...&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;Stay tuned as we have more discussions around mobile development. Our team continues with their research, for Chariot's own projects (our conference app for Philly ETE) and for our clients.&amp;nbsp; &lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2842620078200223238?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2842620078200223238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/03/phonegap-tutorial-series-1-project.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2842620078200223238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2842620078200223238'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/03/phonegap-tutorial-series-1-project.html' title='PhoneGap Tutorial Series – #1 Project Structure and Internals'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4522980270235708711</id><published>2011-03-10T09:24:00.000-05:00</published><updated>2011-03-10T09:24:13.352-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Xcode3 – Debugging iOS Unit Tests</title><content type='html'>A recent blog post by Hiedi Utley (no, she is not related to our knee challenged second baseman), Chariot's newest team addition.&amp;nbsp; Hiedi has been working in our mobile practice.&amp;nbsp; She reviews some of the challenges of being a Java developer and moving to an iOS environment.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is an excerpt from this post:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;So you have some unit tests (yeah!) and they are failing …. now what?&lt;/h3&gt;&lt;br /&gt;Over the course of my career these past few years, I have become a developer that writes more test code than production code in an effort to never have to spend the wee hours of the morning debugging a horrible production issue. As a java developer turned mobile developer, there are several things that I miss about coding in Java but the number one thing is unit tests.&lt;br /&gt;Don’t get me wrong – I know what you are thinking – probably something along the lines of: “Do a little research dummy! Xcode has a nice Unit Test Bundle target that we can use to run unit tests! All you have to do is write them!” Right…..&lt;br /&gt;Or  maybe after a little more googling around you may even point me to this excellent Apple documentation that explains the process of setting up and running my newly created unit tests but there is a huge section missing from this&lt;a href="http://hiediutley.wordpress.com/2011/03/08/xcode3-debugging-ios-unit-tests/"&gt; guide…&lt;/a&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4522980270235708711?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4522980270235708711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/03/xcode3-debugging-ios-unit-tests.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4522980270235708711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4522980270235708711'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/03/xcode3-debugging-ios-unit-tests.html' title='Xcode3 – Debugging iOS Unit Tests'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-7232495077125399288</id><published>2011-03-07T09:48:00.000-05:00</published><updated>2011-03-07T09:48:50.716-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><title type='text'>Mobile Design Part 3</title><content type='html'>&lt;h2&gt;&lt;span style="font-weight: normal;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-weight: normal;"&gt;The next installment of Kevin Griffin's blog on Mobile Design.&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;h2&gt;&lt;span style="font-size: small;"&gt;Cognitive Effort.&lt;/span&gt;&lt;/h2&gt;In this installment of my thoughts on mobile design, I thought we would take a look at the concept of ‘cognitive effort’. I think I first heard that term used in reference to design from William Van Hecke (@fetjuel) when he spoke at Voices that Matter in Philly. When a guy from The OmniGroup talks to be about making great apps, I tend to shut up and listen.&lt;br /&gt;We have all thought about cognitive effort at some point:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;“Does this screen look too busy?”&lt;/li&gt;&lt;li&gt;“We should move this functionality out of this screen” are signs you thinking about it.&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;What increases cognitive effort?&lt;/strong&gt;&lt;br /&gt;Every question, action, dialog, gesture, tap, shake, voice communiqué we ask the user ultimately ends in some kind of effort be it physical, cognitive or verbal. Sometimes we intentionally make these things progressively harder, games for example. Sometimes we unintentionally make these things progressively harder, continually adding functionality to a screen.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kgriff.posterous.com/part-3"&gt;Read more...&lt;/a&gt; &lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-7232495077125399288?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/7232495077125399288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/03/mobile-design-part-3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7232495077125399288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7232495077125399288'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/03/mobile-design-part-3.html' title='Mobile Design Part 3'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4825141868722692875</id><published>2011-02-17T07:50:00.000-05:00</published><updated>2011-02-17T07:50:19.099-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><category scheme='http://www.blogger.com/atom/ns#' term='junit'/><title type='text'>JUnit &amp; Spring – What You Don’t Know</title><content type='html'>&amp;nbsp;Gordon Dickens, Chariot architect and one of our education trainers, recently wrote this blog post on JUnit and Spring.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When using JUnit in Spring there are several features added that many developers are not aware of.&lt;br /&gt;First, if you are including the Spring Context in your tests, it becomes an Integration Test, no longer a Unit Test.&lt;br /&gt;&lt;hr /&gt;&lt;h3&gt;1. Default Searching of Context File(s)&lt;/h3&gt;To instruct Spring to load beans for the tests in the class, we annotate the class with &lt;code&gt;@ContextConfiguration&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;1a. No File Specified&lt;/h4&gt;&lt;code&gt;@ContextConfiguration&lt;/code&gt; – with no parameters, (by Default) looks for the config file as the same name as the class with the suffix “&lt;code&gt;-context.xml&lt;/code&gt;“.  For example, &lt;br /&gt;&lt;div style="font-weight: bold; text-align: center;"&gt;Using&lt;/div&gt;&lt;div&gt;&lt;div class="syntaxhighlighter  java" id="highlighter_686469"&gt;&lt;div class="toolbar"&gt;&lt;a class="toolbar_item command_help help" href="http://gordondickens.com/wordpress/#"&gt;?&lt;/a&gt;&lt;/div&gt;&lt;table border="0" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;div class="line number1 index0 alt2"&gt;1&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;2&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;3&lt;/div&gt;&lt;div class="line number4 index3 alt1"&gt;4&lt;/div&gt;&lt;div class="line number5 index4 alt2"&gt;5&lt;/div&gt;&lt;div class="line number6 index5 alt1"&gt;6&lt;/div&gt;&lt;div class="line number7 index6 alt2"&gt;7&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="java keyword"&gt;package&lt;/code&gt; &lt;code class="java plain"&gt;com.gordondickens.sample;&lt;/code&gt;&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;&lt;code class="java color1"&gt;@ContextConfiguration&lt;/code&gt;&lt;/div&gt;&lt;div class="line number4 index3 alt1"&gt;&lt;code class="java keyword"&gt;public&lt;/code&gt; &lt;code class="java keyword"&gt;class&lt;/code&gt; &lt;code class="java plain"&gt;UtilsTest {&lt;/code&gt;&lt;/div&gt;&lt;div class="line number5 index4 alt2"&gt;&lt;code class="java spaces"&gt;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="java plain"&gt;...&lt;/code&gt;&lt;/div&gt;&lt;div class="line number6 index5 alt1"&gt;&lt;code class="java plain"&gt;}&lt;/code&gt;&lt;/div&gt;&lt;div class="line number7 index6 alt2"&gt;&lt;code class="java plain"&gt;...&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="font-weight: bold; text-align: center;"&gt;Is equivalent to&lt;/div&gt;&lt;div&gt;&lt;div class="syntaxhighlighter  java" id="highlighter_413594"&gt;&lt;div class="toolbar"&gt;&lt;a class="toolbar_item command_help help" href="http://gordondickens.com/wordpress/#"&gt;?&lt;/a&gt;&lt;/div&gt;&lt;table border="0" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;div class="line number1 index0 alt2"&gt;1&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;2&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;3&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="java spaces"&gt;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="java plain"&gt;...&lt;/code&gt;&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;&lt;code class="java color1"&gt;@ContextConfiguration&lt;/code&gt;&lt;code class="java plain"&gt;(&lt;/code&gt;&lt;code class="java string"&gt;"classpath:/com/gordondickens/sample/UtilsTest-context.xml"&lt;/code&gt;&lt;code class="java plain"&gt;)&lt;/code&gt;&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;&lt;code class="java spaces"&gt;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="java plain"&gt;...&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://gordondickens.com/wordpress/"&gt;&amp;nbsp;Read more...&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4825141868722692875?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4825141868722692875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/02/junit-spring-what-you-dont-know.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4825141868722692875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4825141868722692875'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/02/junit-spring-what-you-dont-know.html' title='JUnit &amp; Spring – What You Don’t Know'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6118521649042421503</id><published>2011-02-10T21:14:00.000-05:00</published><updated>2011-02-11T11:23:54.891-05:00</updated><title type='text'>What's Coming in Spring 3.1</title><content type='html'>Spring 3.1.0 M1 is expected to be released on Feb 10, 2011.  There are many exciting new features expected for the final release which is scheduled for June 2011.&lt;br /&gt;&lt;hr/&gt;&lt;h3&gt;Environment Profiles&lt;/h3&gt;Many times we want separate configuration for different environments such as development, qa, production.  Also, we may want to provide different bean configuration for traditional or cloud environments as well.&lt;ul&gt;&lt;li&gt;Beans can be configured in XML with the additional "profile" attribute&lt;/li&gt;&lt;li&gt;Activate 1..n profiles in code or with java arg &lt;code&gt;-Dspring.profiles.active="dev,qa"&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;ParamName&lt;/code&gt; for &lt;code&gt;DispatcherServlet&lt;/code&gt; "spring.profiles.active"&lt;/li&gt;&lt;li&gt;Integration Tests Class &lt;code&gt;GenericXmlApplicationContext &lt;/code&gt;&lt;/li&gt;&lt;li&gt;Nested "beans" in other words, &lt;code&gt;&amp;lt;beans/&amp;gt;&lt;/code&gt; tag can have other &lt;code&gt;&amp;lt;beans/&amp;gt;&lt;/code&gt; tags within allowing multiple bean sets for different profiles in the same config file&lt;/li&gt;&lt;li&gt;The variable “environment” is already registered for SpEL&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:java;title:'Profile Annotation'"&gt;&lt;br /&gt;@Profile(“development”)&lt;br /&gt;public class MyClass() { ... }&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush:xml;title:'Profile XML Config'"&gt;&lt;br /&gt;&amp;lt;beans profile=“development” … /&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush:java;title:'Property in SPeL'"&gt;&lt;br /&gt;#{environment[‘prop.key’]}&lt;br /&gt;public String myProp;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr/&gt;&lt;h3&gt;The "c" Namespace&lt;/h3&gt;Much like the existing "p" namespace, the "c" namespace supports constructor arguments.  This has the additional benefit of allowing us to reference the constructor arguments by name.&lt;br /&gt;&lt;pre class="brush:xml;title:'Constructor Namespace'"&gt;&lt;br /&gt;&amp;lt;bean class=“…” c:age=“35” c:amount=“50000”/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h3&gt;Cache Abstractions&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Cache Abstractions will be available – not just EHCache, also for Gemfire, Coherence&lt;/li&gt;&lt;li&gt;Package: &lt;code&gt;org.springframework.cache&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Annotation Package: &lt;code&gt;org.springframework.cache.annotation&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&amp;lt;cache: &amp;/gt;&lt;/code&gt; namespace&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:xml;title:'Constructor Namespace'"&gt;&lt;br /&gt;&amp;lt;cache:annotation-driven&amp;gt; //referencing "cacheManager"&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush:java;title:'Cacheable Annotations'"&gt;&lt;br /&gt;@Cacheable  //field or method&lt;br /&gt;&lt;br /&gt;@Cacheable(condition=“name.length &lt; 10”) //conditional&lt;br /&gt;&lt;br /&gt;@CacheEvict // remove field from cache&lt;br /&gt;public void clearMyField() { ... }&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h3&gt;Servlet 3.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;ServletContainerInitializer – XML Free config  (no web.xml)&lt;/li&gt;&lt;li&gt;package org.springframework.web.context.support.AnnotationConfigWebApplicationContext&lt;/li&gt;&lt;li&gt;Async request processing&lt;/li&gt;&lt;li&gt;Standard file upload support&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h3&gt;HTTP Session Improvements&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Share information across multiple browser instances&lt;/li&gt;&lt;li&gt;Uses Shared Cookie&lt;/li&gt;&lt;li&gt;package &lt;code&gt;org.springframework.web.bind.support.SessionAttributeStore&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Conversation "scope"&lt;/li&gt;&lt;li&gt;Useful for MVC &amp; JSF, Web Flow&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h3&gt;Groovy Support&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Groovy/Grails BeanBuilder inclusion&lt;/li&gt;&lt;li&gt;&lt;code&gt;&amp;lt;lang:groovy&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Groovy based template files (alternative to Velocity and Freemarker)&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h3&gt;Feature Configuration&lt;/h3&gt;For Bean &lt;code&gt;@Configuration&lt;/code&gt; - To support applications with Java based configuration.&lt;ul&gt;&lt;li&gt;package &lt;code&gt;org.springframework.context.annotation&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Picked up via &lt;code&gt;AnnotationConfigApplicationContext&lt;/code&gt; // Standalone application context, accepting annotated classes as input&lt;/li&gt;&lt;li&gt;Allows scanning for &lt;code&gt;@Configuration&lt;/code&gt; classes&lt;/li&gt;&lt;li&gt;&lt;code&gt;@FeatureConfiguration&lt;/code&gt; // class level - specify the name of the Spring bean definition&lt;/li&gt;&lt;li&gt;&lt;code&gt;@Feature&lt;/code&gt; // Method w/i &lt;code&gt;@FeatureConfiguration&lt;/code&gt; Class&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h3&gt;Customizable @MVC&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Custom &lt;code&gt;@ExceptionHandler&lt;/code&gt; support for @Controller methods&lt;/li&gt;&lt;li&gt;Custom &lt;code&gt;@ExceptionHandler&lt;/code&gt; support for &lt;code&gt;@RequestBody&lt;/code&gt; &amp;amp; &lt;code&gt;@ResponseBody&lt;/code&gt;&lt;/li&gt;&lt;li&gt;You can write a BeanPostProcessor to change AnnotationMethodHandlerAdapter after construction&lt;/li&gt;&lt;li&gt;Auto-detection of custom &lt;code&gt;HttpMessageConverters&lt;/code&gt; - for example custom MyMappingJacksonHttpMessageConverter&lt;/li&gt;&lt;li&gt;Support for custom message codes resolver with &lt;code&gt;&amp;lt;mvc:annotation-driven/&amp;gt;&lt;/li&gt;&lt;/code&gt;&lt;/ul&gt;&lt;pre class="brush:xml;title:'Web Argument Resolver"&gt;&lt;br /&gt;&amp;lt;mvc:annotation-driven&amp;gt;&lt;br /&gt;  &amp;lt;mvc:custom-web-argument-resolvers&amp;gt;&lt;br /&gt;    &amp;lt;bean class="org.example.MyWebArgumentResolver"/&amp;gt;&lt;br /&gt;  &amp;lt;/mvc:custom-web-argument-resolvers&amp;gt;&lt;br /&gt;&amp;lt;/mvc:annotation-driven&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush:xml;title:'Message Converter Registration"&gt;&lt;br /&gt;&amp;lt;mvc:annotation-driven&amp;gt;&lt;br /&gt;  &amp;lt;mvc:message-converters&amp;gt;&lt;br /&gt;    &amp;lt;bean class="org.springframework.http.converter.StringHttpMessageConverter"/&amp;gt;&lt;br /&gt;    &amp;lt;bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/&amp;gt;&lt;br /&gt;    &amp;lt;bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/&amp;gt;&lt;br /&gt;  &amp;lt;/mvc:message-converters&amp;gt;&lt;br /&gt;&amp;lt;/mvc:annotation-driven&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush:xml;title:'Message Converter Registration"&gt;&lt;br /&gt;&amp;lt;mvc:annotation-driven message-codes-resolver="org.example.MyMessageCodesResolver"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h3&gt;REST Enhancements&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Interceptors for &lt;code&gt;RestTemplate&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;ClientHttpRequestInterceptor&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;bufferRequestBody&lt;/code&gt; property to the &lt;code&gt;SimpleClientHttpRequestFactory&lt;/code&gt; to handle large payloads with &lt;code&gt;RestTemplate&lt;/code&gt;&lt;/li&gt;&lt;li&gt;New &lt;code&gt;WebRequest.checkNotModified(String)&lt;/code&gt; // only had long support previously&lt;/li&gt;&lt;li&gt;New &lt;code&gt;@ResponseEntity&lt;/code&gt;&lt;/li&gt;&lt;li&gt;To support OAuth with &lt;code&gt;ClientHttpRequestInterceptors&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Summary&lt;/h3&gt;Many of the items included here are specific features for 3.1.0.M1, there are many more improvements coming for MVC customization and REST improvements in M2.&lt;ul&gt;&lt;li&gt;&lt;a href="https://jira.springsource.org/secure/ReleaseNote.jspa?projectId=10000&amp;version=11378"&gt;3.1.0.M1 Release Notes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://jira.springsource.org/secure/ReleaseNote.jspa?projectId=10000&amp;version=11379"&gt;3.1.0.M2 Release Notes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.springsource.org/node/3026"&gt;Spring Announcement&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/"&gt;Spring 3.1.0.M1 Features Blog&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-6118521649042421503?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/6118521649042421503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/02/whats-coming-in-spring-31.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6118521649042421503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/6118521649042421503'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/02/whats-coming-in-spring-31.html' title='What&apos;s Coming in Spring 3.1'/><author><name>Gordon Dickens</name><uri>https://profiles.google.com/114681050780814546369</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-dMj3fLlkNPA/AAAAAAAAAAI/AAAAAAAAAJY/fR7TY-stMvo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2786513630071137408</id><published>2011-02-07T13:30:00.000-05:00</published><updated>2011-02-09T10:34:21.040-05:00</updated><title type='text'>Sending Beans as XML with JmsTemplate</title><content type='html'>&lt;a href="http://gordondickens.com/wordpress/wp-content/uploads/2011/02/bean-xml-jms.png"&gt;&lt;img src="http://gordondickens.com/wordpress/wp-content/uploads/2011/02/bean-xml-jms-300x70.png" alt="" title="bean-xml-jms" width="360" height="84" class="aligncenter size-medium wp-image-739" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://gordondickens.com/wordpress/wp-content/uploads/2011/02/no-xsd.png"&gt;&lt;img src="http://gordondickens.com/wordpress/wp-content/uploads/2011/02/no-xsd.png" alt="" title="no-xsd" width="64" height="64" class="aligncenter size-full wp-image-740" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;Introduction&lt;/h3&gt;&lt;br /&gt;We often want to send XML via web services.  We may already have the schema or annotated JAXB2 classes configured in our application.  What if we want to send the same format via JMS?  By default Spring JMS is configured to send &amp; receive objects serialized.  How can we switch to using JAXB2 (or any other OXM marshaling strategy)?&lt;br /&gt;The following example assumes we are going from annotations first instead of from XML Schema.&lt;br /&gt;&lt;h3&gt;Quick Overview&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;Annotate Bean with JAXB2&lt;/li&gt;&lt;li&gt;Configure OXM Converter&lt;/li&gt;&lt;li&gt;Integration Test&lt;/li&gt;&lt;li&gt;Visualize Results&lt;/li&gt;&lt;li&gt;Logging Configuration&lt;/li&gt;&lt;li&gt;Maven Configuration&lt;/li&gt;&lt;/ol&gt;&lt;hr/&gt;&lt;br /&gt;&lt;h4 style="color:darkgreen"&gt;1.  Annotate Bean with JAXB2&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Use JAXB2 annotations for our bean&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:java;title:'Account Bean';highlight:[9,10,12,15,18]"&gt;package com.gordondickens.jmswithoxm;&lt;br /&gt;&lt;br /&gt;import java.math.BigDecimal;&lt;br /&gt;import javax.xml.bind.annotation.XmlAccessType;&lt;br /&gt;import javax.xml.bind.annotation.XmlAccessorType;&lt;br /&gt;import javax.xml.bind.annotation.XmlElement;&lt;br /&gt;import javax.xml.bind.annotation.XmlRootElement;&lt;br /&gt;&lt;br /&gt;@XmlRootElement(name = "account")&lt;br /&gt;@XmlAccessorType(XmlAccessType.FIELD)&lt;br /&gt;public class Account {&lt;br /&gt;     @XmlElement(required = true)&lt;br /&gt;     private String name;&lt;br /&gt;&lt;br /&gt;     @XmlElement&lt;br /&gt;     private String description;&lt;br /&gt;&lt;br /&gt;     @XmlElement&lt;br /&gt;     private BigDecimal balance;&lt;br /&gt;&lt;br /&gt;     public String getName() {&lt;br /&gt;          return name;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public void setName(String name) {&lt;br /&gt;          this.name = name;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public String getDescription() {&lt;br /&gt;          return description;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public void setDescription(String description) {&lt;br /&gt;          this.description = description;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public BigDecimal getBalance() {&lt;br /&gt;          return balance;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public void setBalance(BigDecimal balance) {&lt;br /&gt;          this.balance = balance;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     @Override&lt;br /&gt;     public String toString() {&lt;br /&gt;          return "Account [name=" + name + ", description=" + description&lt;br /&gt;                    + ", balance=" + balance + "]";&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;2. Configure OXM Converter&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Define our Marshalers&lt;/strong&gt; - We see &lt;code&gt;&amp;lt;oxm:jaxb2-marshaller ...&amp;gt;&lt;/code&gt; defines JAXB2 as our marshaller for the Account class&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Register our &lt;code&gt;MarshallingMessageConverter&lt;/code&gt;&lt;/strong&gt; - We register the MarshallingMessageConverter to use the JAXB2 marshaller for both inbound and outbound data&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Register our Converter&lt;/strong&gt; - In the JmsTemplate, we register our &lt;code&gt;oxmMessageConverter&lt;/code&gt; as the &lt;code&gt;messageConverter&lt;/code&gt;.  This replaces the default &lt;code&gt;SimpleMessageConverter&lt;/code&gt; which will relies on &lt;code&gt;Serialization&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Notice the ActiveMQ namespace?&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:xml;title:'JmsWithOxmTest-context.xml';highlight:[20,28,34]"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"&lt;br /&gt;     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"&amp;gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;     xmlns:amq="http://activemq.apache.org/schema/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;     xmlns:oxm="http://www.springframework.org/schema/oxm"&lt;br /&gt;     xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd&lt;br /&gt;          http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.4.0.xsd&lt;br /&gt;          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;amq:broker persistent="false" useJmx="true"&amp;gt;&lt;br /&gt;          &amp;lt;amq:transportConnectors&amp;gt;&lt;br /&gt;               &amp;lt;amq:transportConnector uri="tcp://localhost:61616" /&amp;gt;&lt;br /&gt;          &amp;lt;/amq:transportConnectors&amp;gt;&lt;br /&gt;     &amp;lt;/amq:broker&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;amq:connectionFactory brokerURL="vm://localhost" id="jmsFactory" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- Spring JMS Template --&amp;gt;&lt;br /&gt;     &amp;lt;bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"&amp;gt;&lt;br /&gt;          &amp;lt;property name="connectionFactory" ref="jmsFactory" /&amp;gt;&lt;br /&gt;          &amp;lt;property name="defaultDestination" ref="oxmTestQueue" /&amp;gt;&lt;br /&gt;          &amp;lt;property name="messageConverter" ref="oxmMessageConverter" /&amp;gt;&lt;br /&gt;     &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;amq:queue id="oxmTestQueue" physicalName="oxm.test.queue" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;bean id="oxmMessageConverter"&lt;br /&gt;          class="org.springframework.jms.support.converter.MarshallingMessageConverter"&amp;gt;&lt;br /&gt;          &amp;lt;property name="marshaller" ref="marshaller" /&amp;gt;&lt;br /&gt;          &amp;lt;property name="unmarshaller" ref="marshaller" /&amp;gt;&lt;br /&gt;     &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;oxm:jaxb2-marshaller id="marshaller"&amp;gt;&lt;br /&gt;          &amp;lt;oxm:class-to-be-bound name="com.gordondickens.jmswithoxm.Account" /&amp;gt;&lt;br /&gt;     &amp;lt;/oxm:jaxb2-marshaller&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;3. Integration Test&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Populate the &lt;strong&gt;&lt;code&gt;Account&lt;/code&gt;&lt;/strong&gt; bean&lt;/li&gt;&lt;li&gt;Calls &lt;strong&gt;&lt;code&gt;convertAndSend&lt;/code&gt;&lt;/strong&gt; on the &lt;code&gt;JmsTemplate&lt;/code&gt; to marshal &amp; send the &lt;code&gt;Account&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Includes a &lt;strong&gt;&lt;code&gt;postProcessor&lt;/code&gt;&lt;/strong&gt; callback to log the XML data&lt;/li&gt;&lt;li&gt;Calls &lt;strong&gt;&lt;code&gt;receiveAndConvert&lt;/code&gt;&lt;/strong&gt; on the &lt;code&gt;JmsTemplate&lt;/code&gt; to get &amp; unmarshal the &lt;code&gt;Account&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Asserts&lt;/strong&gt; end state&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:java;title:'JmsWithOxmTest.java'highlight:[31,32,35,55]"&gt;package com.gordondickens.jmswithoxm;&lt;br /&gt;&lt;br /&gt;import static org.junit.Assert.assertEquals;&lt;br /&gt;import static org.junit.Assert.assertNotNull;&lt;br /&gt;import java.math.BigDecimal;&lt;br /&gt;import javax.jms.BytesMessage;&lt;br /&gt;import javax.jms.JMSException;&lt;br /&gt;import javax.jms.Message;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;import org.junit.runner.RunWith;&lt;br /&gt;import org.slf4j.Logger;&lt;br /&gt;import org.slf4j.LoggerFactory;&lt;br /&gt;import org.springframework.beans.factory.annotation.Autowired;&lt;br /&gt;import org.springframework.jms.core.JmsTemplate;&lt;br /&gt;import org.springframework.jms.core.MessagePostProcessor;&lt;br /&gt;import org.springframework.test.context.ContextConfiguration;&lt;br /&gt;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;&lt;br /&gt;&lt;br /&gt;@RunWith(SpringJUnit4ClassRunner.class)&lt;br /&gt;@ContextConfiguration&lt;br /&gt;public class JmsWithOxmTest {&lt;br /&gt;  private static final Logger logger = LoggerFactory&lt;br /&gt;      .getLogger(JunitWithOxmTest.class);&lt;br /&gt;  private static final String TEST_DEST = "oxmTestQueue";&lt;br /&gt;&lt;br /&gt;  @Autowired&lt;br /&gt;  JmsTemplate jmsTemplate;&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void testSendingMessage() {&lt;br /&gt;    Account account = generateTestMessage();&lt;br /&gt;    jmsTemplate.convertAndSend(TEST_DEST, account,&lt;br /&gt;        new MessagePostProcessor() {&lt;br /&gt;          @Override&lt;br /&gt;          public Message postProcessMessage(Message message)&lt;br /&gt;              throws JMSException {&lt;br /&gt;            if (message instanceof BytesMessage) {&lt;br /&gt;              BytesMessage messageBody = (BytesMessage) message;&lt;br /&gt;              // message is in write mode, close &amp; reset to start&lt;br /&gt;              // of byte stream&lt;br /&gt;              messageBody.reset();&lt;br /&gt;&lt;br /&gt;              Long length = messageBody.getBodyLength();&lt;br /&gt;              logger.debug("***** MESSAGE LENGTH is {} bytes",&lt;br /&gt;                  length);&lt;br /&gt;              byte[] byteMyMessage = new byte[length.intValue()];&lt;br /&gt;              int red = messageBody.readBytes(byteMyMessage);&lt;br /&gt;              logger.debug(&lt;br /&gt;                  "***** SENDING MESSAGE - \n&lt;!-- MSG START --&gt;\n{}\n&lt;!-- MSG END --&gt;",&lt;br /&gt;                  new String(byteMyMessage));&lt;br /&gt;            }&lt;br /&gt;            return message;&lt;br /&gt;          }&lt;br /&gt;        });&lt;br /&gt;    Account account2 = (Account) jmsTemplate.receiveAndConvert(TEST_DEST);&lt;br /&gt;    assertNotNull("Account MUST return from JMS", account2);&lt;br /&gt;    assertEquals("Name MUST match", account.getName(), account2.getName());&lt;br /&gt;    assertEquals("Description MUST match", account.getDescription(),&lt;br /&gt;        account2.getDescription());&lt;br /&gt;    assertEquals("Balance MUST match", account.getBalance(),&lt;br /&gt;        account2.getBalance());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private Account generateTestMessage() {&lt;br /&gt;    Account account = new Account();&lt;br /&gt;    account.setBalance(new BigDecimal(12345.67));&lt;br /&gt;    account.setDescription("A no account varmint");&lt;br /&gt;    account.setName("Waskally Wabbit");&lt;br /&gt;    logger.debug("Generated Test Message: " + account.toString());&lt;br /&gt;    return account;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;4. Visualizing Results&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Run: &lt;strong&gt;&lt;code&gt;mvn clean test&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;See Account XML between the block &lt;code&gt;&amp;lt;!-- MSG START --&amp;gt;&lt;/code&gt; &amp;amp; &lt;code&gt;&amp;lt;!--MSG END --&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Output has been Formatted for clarity&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:text;title:'Test Results';highlight:[19,20,21,22,23,24,25,26]"&gt;&lt;br /&gt;-------------------------------------------------------&lt;br /&gt; T E S T S&lt;br /&gt;-------------------------------------------------------&lt;br /&gt;Running com.gordondickens.jmswithoxm.JmsWithOxmTest&lt;br /&gt;&lt;br /&gt;INFO  o.s.o.j.Jaxb2Marshaller - Creating JAXBContext &lt;br /&gt;  with classes to be bound [class com.gordondickens.jmswithoxm.Account]&lt;br /&gt;  &lt;br /&gt;DEBUG c.g.j.JmsWithOxmTest - Generated Test Message: &lt;br /&gt;  Account [name=Waskally Wabbit, description=A no account &lt;br /&gt;  varmint, balance=12345.670000000000072759576141834259033203125]&lt;br /&gt;&lt;br /&gt;DEBUG o.s.j.c.JmsTemplate - Executing callback on JMS Session: &lt;br /&gt;  ActiveMQSession {id=ID:Technophiliac-61135-1296856347600-2:1:1,started=false}&lt;br /&gt;&lt;br /&gt;DEBUG c.g.j.JmsWithOxmTest - ***** MESSAGE LENGTH is 213 bytes&lt;br /&gt;&lt;br /&gt;DEBUG c.g.j.JmsWithOxmTest - ***** SENDING MESSAGE -&lt;br /&gt;&amp;lt;!-- MSG START --&amp;gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&amp;gt;&lt;br /&gt;  &amp;lt;account&amp;gt;&lt;br /&gt;    &amp;lt;name&amp;gt;Waskally Wabbit&amp;lt;/name&amp;gt;&lt;br /&gt;    &amp;lt;description&amp;gt;A no account varmint&amp;lt;/description&amp;gt;&lt;br /&gt;    &amp;lt;balance&amp;gt;12345.670000000000072759576141834259033203125&amp;lt;/balance&amp;gt;&lt;br /&gt;  &amp;lt;/account&amp;gt;&lt;br /&gt;&amp;lt;!-- MSG END --&amp;gt;&lt;br /&gt;&lt;br /&gt;DEBUG o.s.j.c.JmsTemplate - Sending created message:&lt;br /&gt;  ActiveMQBytesMessage {commandId = 0, responseRequired = false, messageId = null, originalDestination = null, originalTransactionId = null, producerId = null, destination = null, transactionId = null, expiration = 0, timestamp = 0, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = null, replyTo = null, persistent = false, type = null, priority = 0, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@b364dcb, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = false, readOnlyBody = true, droppable = false} ActiveMQBytesMessage{ bytesOut = null, dataOut = null, dataIn = java.io.DataInputStream@1a2d502d }&lt;br /&gt;&lt;br /&gt;DEBUG o.s.j.c.JmsTemplate - Executing callback on JMS Session:&lt;br /&gt;  ActiveMQSession {id=ID:Technophiliac-61135-1296856347600-2:2:1,started=true}&lt;br /&gt;&lt;br /&gt;Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.276 sec&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;5. Logging Configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Logback is very similar to Log4J&lt;/li&gt;&lt;li&gt;Logback patterns use Log4J characters also&lt;/li&gt;&lt;li&gt;See: &lt;a href="http://logback.qos.ch/manual/layouts.html#ClassicPatternLayout"&gt;Logback Pattern Layout Documentation&lt;/a&gt;&lt;/ul&gt;&lt;pre class="brush:xml;title:'logback.xml'"&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"&amp;gt;&lt;br /&gt;    &amp;lt;encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"&amp;gt;&lt;br /&gt;      &amp;lt;pattern&amp;gt;%-5level %logger{5} - %msg%n&amp;lt;/pattern&amp;gt;&lt;br /&gt;    &amp;lt;/encoder&amp;gt;&lt;br /&gt;&amp;lt;/appender&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;logger name="com.gordondickens" level="DEBUG" /&amp;gt;&lt;br /&gt;  &amp;lt;logger name="org.springframework.jms" level="DEBUG" /&amp;gt;&lt;br /&gt;  &amp;lt;logger name="org.springframework.oxm" level="DEBUG" /&amp;gt;&lt;br /&gt;  &amp;lt;!--&amp;lt;logger name="org.apache.activemq" level="DEBUG"/&amp;gt; --&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;root level="WARN"&amp;gt;&lt;br /&gt;    &amp;lt;appender-ref ref="STDOUT" /&amp;gt;&lt;br /&gt;  &amp;lt;/root&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;6. Maven Configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Using &lt;strong&gt;Logback&lt;/strong&gt; to support Log4J, SLF4J, Apache (JCL) &amp;amp; Java Util Logging&lt;/li&gt;&lt;li&gt;Included IDE builders for &lt;strong&gt;STS/Eclipse&lt;/strong&gt; &amp;amp; &lt;strong&gt;IntelliJ IDEA&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush:xml;title:'pom.xml';highlight:[131,147,152,157,162]"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0"&lt;br /&gt;  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&amp;gt;&lt;br /&gt;  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;com.gordondickens.jmswithoxm&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;spring-jms-oxm&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;1.0.0.CI-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;&lt;br /&gt;  &amp;lt;name&amp;gt;JMS to OXM Spring&amp;lt;/name&amp;gt;&lt;br /&gt;  &amp;lt;url&amp;gt;http://gordondickens.com&amp;lt;/url&amp;gt;&lt;br /&gt;  &amp;lt;description&amp;gt;Sample JMS with OXM Message Conversion&amp;lt;/description&amp;gt;&lt;br /&gt;  &amp;lt;developers&amp;gt;&lt;br /&gt;    &amp;lt;developer&amp;gt;&lt;br /&gt;      &amp;lt;id&amp;gt;gordon.dickens&amp;lt;/id&amp;gt;&lt;br /&gt;      &amp;lt;name&amp;gt;Gordon Dickens&amp;lt;/name&amp;gt;&lt;br /&gt;      &amp;lt;email&amp;gt;gordondickens@gmail.com&amp;lt;/email&amp;gt;&lt;br /&gt;      &amp;lt;roles&amp;gt;&lt;br /&gt;        &amp;lt;role&amp;gt;Author&amp;lt;/role&amp;gt;&lt;br /&gt;      &amp;lt;/roles&amp;gt;&lt;br /&gt;      &amp;lt;organization&amp;gt;http://www.gordondickens.com&amp;lt;/organization&amp;gt;&lt;br /&gt;    &amp;lt;/developer&amp;gt;&lt;br /&gt;  &amp;lt;/developers&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;properties&amp;gt;&lt;br /&gt;    &amp;lt;spring.version&amp;gt;3.0.5.RELEASE&amp;lt;/spring.version&amp;gt;&lt;br /&gt;    &amp;lt;junit.version&amp;gt;4.8.1&amp;lt;/junit.version&amp;gt;&lt;br /&gt;    &amp;lt;jms.version&amp;gt;1.1.1&amp;lt;/jms.version&amp;gt;&lt;br /&gt;    &amp;lt;slf4j.version&amp;gt;1.6.1&amp;lt;/slf4j.version&amp;gt;&lt;br /&gt;    &amp;lt;activemq.version&amp;gt;5.4.2&amp;lt;/activemq.version&amp;gt;&lt;br /&gt;    &amp;lt;logback.version&amp;gt;0.9.27&amp;lt;/logback.version&amp;gt;&lt;br /&gt;    &amp;lt;log4j.version&amp;gt;1.2.16&amp;lt;/log4j.version&amp;gt;&lt;br /&gt;    &amp;lt;project.build.sourceEncoding&amp;gt;UTF-8&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;br /&gt;    &amp;lt;maven.test.failure.ignore&amp;gt;false&amp;lt;/maven.test.failure.ignore&amp;gt;&lt;br /&gt;  &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;profiles&amp;gt;&lt;br /&gt;    &amp;lt;profile&amp;gt;&lt;br /&gt;      &amp;lt;id&amp;gt;quick&amp;lt;/id&amp;gt;&lt;br /&gt;      &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;maven.test.failure.ignore&amp;gt;true&amp;lt;/maven.test.failure.ignore&amp;gt;&lt;br /&gt;      &amp;lt;/properties&amp;gt;&lt;br /&gt;    &amp;lt;/profile&amp;gt;&lt;br /&gt;  &amp;lt;/profiles&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;dependencies&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${junit.version}&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${log4j.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${slf4j.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;jcl-over-slf4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${slf4j.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;jul-to-slf4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${slf4j.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-classic&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${logback.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${logback.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-access&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${logback.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-test&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.activemq&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;activemq-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${activemq.version}&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.xbean&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;xbean-spring&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;3.7&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-jms&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-oxm&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;javax.xml.bind&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;jaxb-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;2.2.2&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.geronimo.specs&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;geronimo-jms_1.1_spec&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${jms.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;/dependencies&amp;gt;&lt;br /&gt;  &amp;lt;build&amp;gt;&lt;br /&gt;    &amp;lt;plugins&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;2.7.1&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-eclipse-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;2.8&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;          &amp;lt;downloadSources&amp;gt;true&amp;lt;/downloadSources&amp;gt;&lt;br /&gt;          &amp;lt;downloadJavadocs&amp;gt;true&amp;lt;/downloadJavadocs&amp;gt;&lt;br /&gt;          &amp;lt;wtpversion&amp;gt;2.0&amp;lt;/wtpversion&amp;gt;&lt;br /&gt;          &amp;lt;additionalBuildcommands&amp;gt;&lt;br /&gt;            &amp;lt;buildCommand&amp;gt;&lt;br /&gt;              &amp;lt;name&amp;gt;org.springframework.ide.eclipse.core.springbuilder&amp;lt;/name&amp;gt;&lt;br /&gt;            &amp;lt;/buildCommand&amp;gt;&lt;br /&gt;          &amp;lt;/additionalBuildcommands&amp;gt;&lt;br /&gt;          &amp;lt;additionalProjectnatures&amp;gt;&lt;br /&gt;            &amp;lt;projectnature&amp;gt;org.springframework.ide.eclipse.core.springnature&amp;lt;/projectnature&amp;gt;&lt;br /&gt;          &amp;lt;/additionalProjectnatures&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;2.3.2&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;          &amp;lt;source&amp;gt;1.6&amp;lt;/source&amp;gt;&lt;br /&gt;          &amp;lt;target&amp;gt;1.6&amp;lt;/target&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-idea-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;2.2&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;          &amp;lt;downloadSources&amp;gt;true&amp;lt;/downloadSources&amp;gt;&lt;br /&gt;          &amp;lt;downloadJavadocs&amp;gt;true&amp;lt;/downloadJavadocs&amp;gt;&lt;br /&gt;          &amp;lt;dependenciesAsLibraries&amp;gt;true&amp;lt;/dependenciesAsLibraries&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;    &amp;lt;/plugins&amp;gt;&lt;br /&gt;  &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;6. Getting the code&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Code is in my Git Repo:&lt;br /&gt;&lt;code&gt;&lt;a href="https://github.com/gordonad/core-spring-demos/tree/master/demos/JmsOxmDemo"&gt;https://github.com/gordonad/core-spring-demos/tree/master/demos/JmsOxmDemo&lt;/a&gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;Conclusion&lt;/h4&gt;Using Spring, it is very easy to configure projects to send/receive data from XML formatted beans.  This simplification allows us to focus on the message payload using Spring JMS.  If our solution was to serialize the data, the default JMS message conversion would suffice.&lt;br /&gt;&lt;br /&gt;This implementation focussed on annotated JAXB2 beans without an XML schema.  Many projects have existing XML schema, and with Spring JMS this is not difficult to configure.  Even though the example above focussed on JAXB2 as our marshaling strategy, we could have chosen others such as JiBX, XMLBeans, XStream, Castor with relative ease.&lt;br /&gt;&lt;hr/&gt;&lt;h4 style="color:darkgreen"&gt;Further Reading&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#jms"&gt;Spring Reference for JMS - Section &lt;code&gt;21.3.1 Using Message Converters&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;a href="http://chariotsolutions.com/education/education_calendar"&gt;Core Spring Training&lt;/a&gt;&lt;/strong&gt; - Where I teach JMS with Spring&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;a href="http://chariotsolutions.com/education/education_calendar"&gt;Enterprise Integration with Spring Training&lt;/a&gt;&lt;/strong&gt; - Where I teach JMS with Spring&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://www.chariotsolutions.com/education"&gt;&lt;img src="http://www.chariotsolutions.com/images/logoChariotMast.gif" alt="Chariot Solutions" class="aligncenter"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2786513630071137408?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2786513630071137408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/02/sending-beans-as-xml-with-jmstemplate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2786513630071137408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2786513630071137408'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/02/sending-beans-as-xml-with-jmstemplate.html' title='Sending Beans as XML with JmsTemplate'/><author><name>Gordon Dickens</name><uri>https://profiles.google.com/114681050780814546369</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-dMj3fLlkNPA/AAAAAAAAAAI/AAAAAAAAAJY/fR7TY-stMvo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4853351539760899996</id><published>2011-02-04T08:24:00.000-05:00</published><updated>2011-02-04T08:24:34.078-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='tapworthy'/><category scheme='http://www.blogger.com/atom/ns#' term='sencha touch'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Philly ETE 2011 mobile line up!</title><content type='html'>&lt;br /&gt;&lt;h1&gt;&amp;nbsp;&lt;span style="font-size: small;"&gt;This &lt;a href="http://kgriff.posterous.com/"&gt;post&lt;/a&gt; is via Kevin Griffin, Chariot Architect and committee chair of the Mobile tract for ETE:&lt;/span&gt;&lt;/h1&gt;&lt;h1&gt;&amp;nbsp;&lt;a href="http://kgriff.posterous.com/philly-ete-2011-mobile-line-up"&gt;Philly ETE 2011 mobile line up!&lt;/a&gt; &lt;/h1&gt;&lt;div class="editbox"&gt;&lt;/div&gt;&lt;div class="body"&gt;&lt;div class="inner"&gt;Just thought I would post an update on the current lineup for &lt;a href="http://phillyemergingtech.com/2011"&gt;Philly ETE&lt;/a&gt;.&lt;br /&gt;I've been involved in helping get the mobile track lineup sorted out and so far we have confirmed the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Josh Clark - my favorite '&lt;a href="http://www.amazon.com/Tapworthy-Designing-Great-iPhone-Apps/dp/1449381650"&gt;Tapworthy&lt;/a&gt;' author.&lt;/li&gt;&lt;li&gt;Johnathon Stark - He literally wrote the &lt;a href="http://www.amazon.com/dp/1449383262/ref=cm_sw_su_dp"&gt;books&lt;/a&gt; on making mobile apps with &lt;a href="http://www.amazon.com/dp/0596805780/ref=cm_sw_su_dp"&gt;HTML, CSS and JavaScript&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Ted Neward - If you are lazy, and want to write Android apps, he has the talk for you!&lt;/li&gt;&lt;li&gt;Jay McGavren - If you want to write Android apps, in Ruby (Oh yeah!) &lt;b&gt;This&lt;/b&gt; is the talk for you (personally, I can't wait for this one!).&lt;/li&gt;&lt;li&gt;Terry Ryan - Philly Evangelist from Adobe who will use Air, to build Playbook apps. Magic!&lt;/li&gt;&lt;li&gt;David Kaneda - Although technically on the Frameworks track. Go build your mobile apps in &lt;a href="http://www.sencha.com/products/touch/"&gt;Sencha Touch&lt;/a&gt;, seriously go now! That way you can thank him at ETE!&lt;/li&gt;&lt;/ul&gt;With one super secret invite still pending :D&lt;/div&gt;&lt;/div&gt;&lt;footer&gt;                                                                                                                                                                                                                                                                   &lt;section class="share"&gt;                                                                                &lt;/section&gt;&lt;/footer&gt;&lt;br /&gt;&lt;div class="posterous_tweet_button posterous_horizontal_count"&gt;&lt;a class="posterous_tweet_count" data-posterous-retweet-count-id="40646908" href="http://www.backtype.com/search?q=http://kgriff.posterous.com/philly-ete-2011-mobile-line-up"&gt;                      &lt;button class="posterous_retweet_count" id="num_tweets_40646908"&gt;&lt;/button&gt;                    &lt;/a&gt;                  &lt;/div&gt;&lt;div class="facebook_like"&gt;                                          &lt;/div&gt;&lt;section class="comments"&gt;                                                                                                                                                                                                                                                                                                &lt;article class="post clearfix" id="post_40645090"&gt;                &lt;header&gt;                                                                &lt;h1&gt;&lt;/h1&gt;&lt;/header&gt;&lt;/article&gt;&lt;/section&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4853351539760899996?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4853351539760899996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/02/philly-ete-2011-mobile-line-up.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4853351539760899996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4853351539760899996'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/02/philly-ete-2011-mobile-line-up.html' title='Philly ETE 2011 mobile line up!'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-3541390766345416313</id><published>2011-02-01T16:19:00.000-05:00</published><updated>2011-02-01T16:19:38.328-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='password'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Web Application Security</title><content type='html'>The recent news that the popular dating site &lt;a href="http://goo.gl/Q9T8c"&gt;Plenty Of Fish was hacked&lt;/a&gt; and that passwords and other user information was stolen truly disheartened me. &lt;br /&gt;&lt;br /&gt;It was just the latest in a seemingly endless list of such hacks over the years, recently including &lt;a href="http://goo.gl/AE1Ja"&gt;Gawker Media&lt;/a&gt; (Lifehacker, Gizmodo), &lt;a href="http://www.csmonitor.com/Innovation/Latest-News-Wires/2010/1214/McDonald-s-and-Walgreens-email-addresses-birth-dates-stolen-by-hackers"&gt;McDonald's, Walgreen's&lt;/a&gt; and &lt;a href="http://news.softpedia.com/news/Personal-Info-of-Tens-of-Thousands-of-Israelis-Stolen-by-Turkish-Hackers-148020.shtml"&gt;Pizza Hut&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Apparently, &lt;a href="http://xkcd.com/327/"&gt;Little Bobby Tables&lt;/a&gt; is alive and well.&lt;br /&gt;&lt;br /&gt;What is disheartening to me is not so much the security breaches themselves. No site is completely secure. The operators of these and other sites may have been able to do more than they did to prevent the breaches, or maybe they had really good (but not good enough) security. But security breaches will happen. I think that every site has to assume that it is possible that their site will be hacked and their database stolen. &lt;br /&gt;&lt;br /&gt;I'm not suggesting that they just accept the inevitable, and give up. I'm suggesting that everyone that builds a website that collects information from their users (that's every site that has user accounts) should care enough to do their best to ensure that when the site is compromised, the damage is as minimal as possible. That's why the Plenty Of Fish hack was so disturbing. Passwords were apparently stored in the database in &lt;a href="http://en.wikipedia.org/wiki/Cleartext"&gt;clear-text&lt;/a&gt;. Once the database was stolen, passwords were readily available, with no further work on the hacker's part. &lt;br /&gt;&lt;br /&gt;I had thought that clear-text passwords were such a well-known evil that no-one was doing it any more, but apparently I was mistaken. Web developers who don't know any better apparently still store plain-text passwords so that they can implement the even less-secure feature of emailing it to you if you forget it (or even sometimes &lt;a href="http://goo.gl/qbKDt"&gt;even if you don't&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;So, what's the right thing to do? Obviously, the most important prerequisites are being aware of the problem, and caring enough about your users to do something about it. If you've read this far, I'll assume that you have those two covered. &lt;br /&gt;&lt;br /&gt;The next thing is to not store passwords. Let me repeat that - &lt;em&gt;do not store your user's passwords&lt;/em&gt;. By that, I do not mean that you should encrypt the passwords before you store them, though that would be a huge improvement over plaintext. The problem with storing encrypted passwords is twofold. The first, as previously mentioned, is that it may tempt you to decrypt it for some reason (like sending it to the user in an email). The second problem is that unless you are really careful with your encryption, the data thief may very well have the resources to decrypt the passwords.&lt;br /&gt;&lt;br /&gt;Instead of storing a user's password, store a &lt;a href="http://en.wikipedia.org/wiki/Cryptographic_hash"&gt;cryptographic hash&lt;/a&gt; of their password. A cryptographic hash is also known as a one-way hash, and cannot be "decrypted". For authentication, take the user-entered password, run it through the same hash function, and then compare the result to the hash stored in the database. Provide users with the means to securely re-set their password (choose a new one) in the event that they forget it, rather than attempting to send them the old one.&lt;br /&gt;&lt;br /&gt;There are still some issues to be aware of when using cryptographic hashes. If there are collisions (two different passwords hash to the same value), and the thief possesses one of the clear-text passwords by some other means, then they can substitute the known password for the one in the other account. Of course, there's always the possibility that two or more users will pick the same password. For example, in the Gawker Media case, the password data was published on the web, and it was revealed that &lt;a href="http://blogs.wsj.com/digits/2010/12/13/the-top-50-gawker-media-passwords/"&gt;thousands of users had chosen the same few passwords&lt;/a&gt;, with '123456' and 'password' leading the list. If you use a simple hash function, then it seems likely that you will have lots of collisions. This makes several attack vectors, like a &lt;a href="http://goo.gl/J2C1D"&gt;dictionary attack&lt;/a&gt;, or other brute-force attack much more likely to be successful.&lt;br /&gt;&lt;br /&gt;The answer to collisions is &lt;a href="http://goo.gl/X3F2"&gt;random salt&lt;/a&gt;. By appending random bits to the password before hashing it, you can make the hashes much more likely to be unique. A common method is to generate a new, random salt value for each user, and to store the salt in an additional column in the password table. Making the salt available to a hacker does not make the hashes more susceptible to a brute-force attack if no two of the salt values are the same. One thing to be careful of is using the username for salt - unless you intend to never let a user change their username.&lt;br /&gt;&lt;br /&gt;All hash functions are not created equal. As time goes on, and more and more computing power becomes available at relatively low cost, once-unbreakable hash functions become breakable. For instance, &lt;a href="http://en.wikipedia.org/wiki/Sha-1"&gt;SHA-1&lt;/a&gt;, apparently still the most widely used cryptographic hash function, &lt;a href="http://www.schneier.com/blog/archives/2005/02/sha1_broken.html"&gt;was broken in 2005&lt;/a&gt;, and the National Institute of Standards and Technology has recommended that federal agencies stop using it. &lt;a href="http://en.wikipedia.org/wiki/Sha-2"&gt;SHA-2&lt;/a&gt;, the recommended replacement for SHA-1, while not yet broken, has already been recognized by NIST as potentially insecure, and there is already an effort under way to develop &lt;a href="http://en.wikipedia.org/wiki/Sha-3"&gt;SHA-3&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;One-way, randomly-salted SHA-2 (or eventually SHA-3) hashes should solve your password security issues, but what about other user data? What about email addresses, credit card numbers, and the like? I'd like to suggest that the first line of defense is collecting as little sensitive information as possible. Storing credit card information (where legal) is generally &lt;a href="https://www.pcisecuritystandards.org/security_standards/index.php"&gt;unnecessary&lt;/a&gt; and provides the potential attacker with substantial incentive. In short, unless you are a credit card company, you probably shouldn't store credit card information. &lt;br /&gt;&lt;br /&gt;Other user information should be treated just as carefully - stored only if absolutely necessary, and stored with encryption as secure as possible if it must be stored. Assume from the start that your database will be compromised, and make it as difficult as possible for the data to be used.&lt;br /&gt;&lt;br /&gt;There are many other security issues to be concerned about, and I encourage you to research them, but if you care about your users and your reputation, then the least you can do is stop storing sensitive user information in the clear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-3541390766345416313?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/3541390766345416313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/02/web-application-security.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3541390766345416313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3541390766345416313'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/02/web-application-security.html' title='Web Application Security'/><author><name>Rich Freedman</name><uri>http://www.blogger.com/profile/06334089409580527109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-WC8GmbpPns0/TxMCTVzu0rI/AAAAAAAAEmA/cOHtbCEutxo/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2797200483959703254</id><published>2011-02-01T08:25:00.000-05:00</published><updated>2011-02-01T08:25:19.647-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>Executing JavaScript from Objective-C in an iOS App</title><content type='html'>New blog post from Steve Smith, one of the Chariot architects working in our mobile practice.&amp;nbsp; Steve is currently working on updating the mobile app for our&lt;a href="http://www.phillyemergingtech.com/"&gt; Emerging Technologies conference&lt;/a&gt; and will be posting articles from time to time as he finds challenges or discoveries.&lt;br /&gt;&lt;br /&gt;Here is an excerpt:&lt;br /&gt;&lt;br /&gt;The other day, I found the need to execute some JavaScript from a native iOS application. &amp;nbsp;After doing a little research, I discovered that the UIWebView has a stringByEvaluatingJavaScriptFromString method. &amp;nbsp;So I decided to create a quick little proof-of-concept to see how to invoke some JavaScript using this.  I am not going to walk through all the details of creating a project, etc. and will cut right to the important aspects of making the JavaScript call from the objective-c code.&lt;br /&gt;We are going to need a JavaScript function to call and a UIWebView to evaluate the JavaScript.  It would be nice if the JavaScript function took a parameter as well, so we could also prove out the passing of values. &amp;nbsp;Here is the JavaScript function that I will use:&lt;br /&gt;&lt;div class="syntaxhighlighter  jscript" id="highlighter_471322"&gt;&lt;div class="bar"&gt;&lt;div class="toolbar"&gt;&lt;a class="item viewSource" href="http://stevenpsmith.wordpress.com/2011/01/20/executing-javascript-from-objective-c-in-an-ios-app/#viewSource" style="height: 16px; width: 16px;" title="view source"&gt;view source&lt;/a&gt;&lt;a class="item printSource" href="http://stevenpsmith.wordpress.com/2011/01/20/executing-javascript-from-objective-c-in-an-ios-app/#printSource" style="height: 16px; width: 16px;" title="print"&gt;print&lt;/a&gt;&lt;a class="item about" href="http://stevenpsmith.wordpress.com/2011/01/20/executing-javascript-from-objective-c-in-an-ios-app/#about" style="height: 16px; width: 16px;" title="?"&gt;?&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="lines"&gt;&lt;div class="line alt1"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="number"&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;code class="jscript keyword"&gt;var&lt;/code&gt; &lt;code class="jscript plain"&gt;area = &lt;/code&gt;&lt;code class="jscript keyword"&gt;function&lt;/code&gt;&lt;code class="jscript plain"&gt;(diameter) {&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="line alt2"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="number"&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;code class="spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="jscript keyword"&gt;var&lt;/code&gt; &lt;code class="jscript plain"&gt;radius = diameter/2,&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="line alt1"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="number"&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;code class="spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="jscript plain"&gt;area = Math.PI * radius * radius;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="line alt2"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="number"&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;code class="spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="jscript keyword"&gt;return&lt;/code&gt; &lt;code class="jscript plain"&gt;Math.round(area*100)/100;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="line alt1"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="number"&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;code class="jscript plain"&gt;};&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://stevenpsmith.wordpress.com/2011/01/20/executing-javascript-from-objective-c-in-an-ios-app/"&gt;Read more&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2797200483959703254?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2797200483959703254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/02/executing-javascript-from-objective-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2797200483959703254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2797200483959703254'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/02/executing-javascript-from-objective-c.html' title='Executing JavaScript from Objective-C in an iOS App'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-8229761018373654711</id><published>2011-01-24T15:29:00.000-05:00</published><updated>2011-01-24T15:29:24.953-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='andriod'/><title type='text'>Android Development: Best Practices</title><content type='html'>Thanks to Anatoly Polinsky for another blog post &lt;br /&gt;&lt;br /&gt;I got introduced to an Android application development during Philly ETE conference by listening to “&lt;a href="http://phillyemergingtech.com/2010/sessions/a-guided-tour-of-the-android-ete-mobile-application" title="A guided tour of the Android ETE mobile application"&gt;A guided tour of the Android ETE mobile application&lt;/a&gt;” talk, where Andrew Oswald ( a Java Architect from &lt;a href="http://www.chariotsolutions.com/"&gt;Chariot Solutions&lt;/a&gt; ) talked about creating an Android app for the conference, which was a cool introduction to “what it takes” to write one of those apps from scratch. I am looking forward to more talks around mobile development this year at &lt;a href="http://phillyemergingtech.com/2011" title="Philly ETE 2011 Conference"&gt;Philly ETE&lt;/a&gt; conference as well.&lt;br /&gt;&lt;br /&gt;Meanwhile I rely mostly on &lt;a href="http://developer.android.com/guide/index.html" title="Android's Developer Guide"&gt;Android’s Developer Guide&lt;/a&gt; whenever I seek answers to my questions or/and best practices. Here are my notes on such practices I picked up listening to “&lt;a href="http://developer.android.com/videos/index.html#v=yqCj83leYRE" title="A Beginner's Guide to Android"&gt;A Beginner’s Guide to Android&lt;/a&gt;” Google I/O 2010 talk:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotkam.com/2011/01/10/android-development-best-practices/"&gt;Read More.... &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-8229761018373654711?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/8229761018373654711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/01/android-development-best-practices.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8229761018373654711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8229761018373654711'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/01/android-development-best-practices.html' title='Android Development: Best Practices'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-3614265268847586309</id><published>2011-01-18T17:13:00.000-05:00</published><updated>2011-01-18T17:52:31.886-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RESTful'/><category scheme='http://www.blogger.com/atom/ns#' term='spring roo'/><category scheme='http://www.blogger.com/atom/ns#' term='JTA'/><category scheme='http://www.blogger.com/atom/ns#' term='SpringSource'/><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><category scheme='http://www.blogger.com/atom/ns#' term='enterprise integration patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Messaging'/><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='JMS'/><category scheme='http://www.blogger.com/atom/ns#' term='SOAP'/><category scheme='http://www.blogger.com/atom/ns#' term='spring integration'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring Batch'/><category scheme='http://www.blogger.com/atom/ns#' term='web services'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>Enterprise Integration with Spring Training</title><content type='html'>&lt;h3&gt;Are you a Spring Developer?&lt;/h3&gt;&lt;h3&gt;Do you have Enterprise solutions to develop or architect?&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Chariot Solutions, a Spring Training Partner and Philadelphia leader in Spring Training, Mentoring and Consulting can help you take your Spring skills to the next level - Enterprise Integration!&lt;br /&gt;&lt;br /&gt;There are many Spring developers who have learned by experimenting, reading documentation and maybe code dives into an existing application or two.  But with the knowledge you gain from Official SpringSource training at Chariot from our certified SpringSource instructors, you can be more equipped to chose the right tools for your complex integration solutions.&lt;br /&gt;&lt;br /&gt;The Enterprise Integration with Spring (EIwS) course is not only &lt;span style="font-weight:bold;"&gt;extremely valuable&lt;/span&gt; to any Spring developer &lt;span style="font-weight:bold;"&gt;it should be REQUIRED&lt;/span&gt; for anyone architecting Spring applications.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What is cool in the EIwS course?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Synchronous &amp; Asynchronous Processing&lt;/li&gt;&lt;li&gt;Messaging with Enterprise Integration Patterns&lt;/li&gt;&lt;li&gt;Messaging with JMS&lt;/li&gt;&lt;li&gt;Exposing Services with &lt;span style="font-weight:bold;"&gt;RMI&lt;/span&gt;, &lt;span style="font-weight:bold;"&gt;HTTP&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Web Services with &lt;span style="font-weight:bold;"&gt;SOAP&lt;/span&gt;, &lt;span style="font-weight:bold;"&gt;REST&lt;/span&gt; and WS Security - and why REST is cool!&lt;/li&gt;&lt;li&gt;Spring Local and Distributed Transaction Management - JTA/XA - Open Source distributed transactions without a JEE Server&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Service Integration&lt;/span&gt; with SMTP (email), File, JMS, FTP, JDBC, TCP/UDP, XMPP, etc.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Polling and Triggering&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Tasks and Scheduling of Processes&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Message Filtering, Routing, Transformation, Splitting, Aggregating, Bridging and Chaining&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Creating Batch processes&lt;/span&gt; for inline or offline execution&lt;/li&gt;&lt;li&gt;Monitoring Batch process exceptions&lt;/li&gt;&lt;li&gt;Unit and Mock testing of application layers&lt;/li&gt;&lt;li&gt;Modifying Integration processes without recompiling... AWESOME Right?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;One of the key take-aways from this course is knowing which tools are available to choose from and why.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What does Gordon teach?&lt;/h3&gt;When I teach the Core or EIwS classes, I go through the common Spring project application layers, and their respective roles and responsibilities.  We discuss the tools you have within Spring and which to use to solve integration concerns.  In EIwS, the course builds from common concurrency, tasks &amp; scheduling, Messaging with JMS to the flexible power of Spring Integration and Spring Batch tool sets.  I teach layering your applications focussing on the power and flexibility of Service POJOs exposing your processes in a Service Oriented Architecture (SOA) manner and keeping your POJOs - Pure business objects, un-compromised by framework or infrastructure java objects.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;I am teaching EIwS February 22-25, 2010 in Philadelphia! &lt;/span&gt; If you come you will receive:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A shiny new course book&lt;/li&gt;&lt;li&gt;An Official Spring USB thumb drive with SpringSource Tool Suite, Course Documentation PDF, all the labs &amp; solutions&lt;/li&gt;&lt;li&gt;The secret meaning of the acronym "SOA"&lt;/li&gt;&lt;li&gt;Bad humor from your instructor (if I teach you can count on it)&lt;/li&gt;&lt;li&gt;Demo's that Gordon creates (if taking my class)&lt;/li&gt;&lt;li&gt;Lunch, Coffee, Tea &amp; soft drinks&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Q&amp;A&lt;/h3&gt;&lt;hr/&gt;Q: What if I have not taken the Core Spring course?&lt;br /&gt;A: It is highly recommended that you attend the Core Spring Course first.  &lt;a href="http://chariotsolutions.com/education/education_calendar"&gt;Click here to see the Course Schedule&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Q: What if I am not using Spring 3 yet?&lt;br /&gt;A: No problem, although the course focuses on 3.0 features, you will still get usable information for your applications.&lt;br /&gt;&lt;br /&gt;Q: What will I learn?&lt;br /&gt;A: Scroll up.&lt;br /&gt;&lt;br /&gt;Q:  What if I already have used some of the topics covered?&lt;br /&gt;A:  Relax during those chapters or, even better, provide your "in the trenches" experience with the class.&lt;br /&gt;&lt;br /&gt;Q: How can I get management to pay for the class?&lt;br /&gt;A: This course is Essential to my skills, to provide you with better tools to choose the right approach to solving our complex integration needs.  &lt;a href="http://chariotsolutions.com/education/courses/spring_enterprise_integration"&gt;Check Here for possible Early Bird Discounts.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Q: Where do I find out about the Enterprise Integration course?&lt;br /&gt;A: &lt;a href="http://mylearn.vmware.com/mgrReg/courses.cfm?ui=S2&amp;a=one&amp;id_subject=17833"&gt;Click here for SpringSource Training Site&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Q: When is Gordon teaching the class?&lt;br /&gt;A: &lt;a href="http://chariotsolutions.com/education/courses/spring_enterprise_integration"&gt;Click here for the next scheduled course on February 22, 2011&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Q: Is there certification for Enterprise Integration Specialist?&lt;br /&gt;A: &lt;a href="http://www.springsource.com/training/certification/enterpriseintegrationspecialist"&gt;Check here for the status on Enterprise Integration Specialist Certification&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Memorable Quotes:&lt;/h3&gt;&lt;hr/&gt;&lt;ul&gt;&lt;li&gt;"Wow, I just learned in 5 minutes what it took me 2 weeks to do in the past"&lt;/li&gt;&lt;li&gt;"A Spring Developer without &lt;br /&gt;&lt;li&gt;"Understanding the layered design of Spring applications really helps me best architect my solutions."&lt;/li&gt;&lt;li&gt;"I really needed to provide file processing into my database, glad I took this class for those implementation discussions"&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;So, what are you waiting for? Register NOW for Enterprise Integration with Spring!&lt;/h3&gt;&lt;br /&gt;&lt;p style="text-align:center; font:large"&gt;&lt;input type="button" onClick="location.href='http://www.springsource.com/training/class?classID=87768'" value='Click to Choose Course and Register'&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-3614265268847586309?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/3614265268847586309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/01/enterprise-integration-with-spring.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3614265268847586309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3614265268847586309'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/01/enterprise-integration-with-spring.html' title='Enterprise Integration with Spring Training'/><author><name>Gordon Dickens</name><uri>https://profiles.google.com/114681050780814546369</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-dMj3fLlkNPA/AAAAAAAAAAI/AAAAAAAAAJY/fR7TY-stMvo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-7693638719252190575</id><published>2011-01-17T15:17:00.001-05:00</published><updated>2011-01-17T15:25:02.195-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring social'/><category scheme='http://www.blogger.com/atom/ns#' term='social media'/><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><title type='text'>Simple Spring Social for Twitter Friends</title><content type='html'>&lt;p&gt;The Spring Social project provides us developers with an easy way to interact with Twitter, Facebook, LinkedIn &amp;amp; TripIt via the familiar Template objects we have used. Spring has provided Templates for convenient interaction with JDBC, REST, Hibernate, JNDI, and more.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;One of the simplest social media calls is to lookup someone's Twitter friends with the TwitterTemplate.&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;1. Add the Spring Social project dependency to the pom.xml file&lt;/h4&gt;&lt;br /&gt;&lt;pre class="brush: xml"&gt;&amp;lt;dependencies&amp;gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;org.springframework.social&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;spring-social-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;${spring.social.version}&amp;lt;/version&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;  ...&lt;br /&gt;&amp;lt;/dependencies&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;2. Add the Spring Milestone Repository repository to the pom.xml file&lt;/h4&gt;&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;br /&gt;&amp;lt;repositories&amp;gt;&lt;br /&gt;  &amp;lt;repository&amp;gt;&lt;br /&gt;    &amp;lt;id&amp;gt;spring-maven-milestone&amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;name&amp;gt;Spring Maven Milestone Repository&amp;lt;/name&amp;gt;&lt;br /&gt;    &amp;lt;url&amp;gt;http://maven.springframework.org/milestone&amp;lt;/url&amp;gt;&lt;br /&gt;  &amp;lt;/repository&amp;gt;&lt;&lt;br /&gt;  ...&lt;br /&gt;&amp;lt;/repositories&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;3. Create the TwitterTemplate, and ask for friends&lt;/h4&gt;&lt;br /&gt;&lt;pre class="brush:java"&gt;TwitterTemplate twitterTemplate = new TwitterTemplate();&lt;br /&gt;List&amp;lt;String&amp;gt; friends = twitterTemplate.getFriends("chariotsolution");&lt;br /&gt;for (String friend : friends) {&lt;br /&gt;  System.out.println("Friend: " + friend);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;4. Use the code above anywhere in your application&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;In the next blog, I will cover how to use Open Authentication (OAuth) to perform more Twitter operations.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-7693638719252190575?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/7693638719252190575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/01/simple-spring-social-for-twitter_7334.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7693638719252190575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7693638719252190575'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/01/simple-spring-social-for-twitter_7334.html' title='Simple Spring Social for Twitter Friends'/><author><name>Gordon Dickens</name><uri>https://profiles.google.com/114681050780814546369</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-dMj3fLlkNPA/AAAAAAAAAAI/AAAAAAAAAJY/fR7TY-stMvo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-409346359701463976</id><published>2011-01-17T12:01:00.000-05:00</published><updated>2011-01-17T12:01:26.947-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring social'/><category scheme='http://www.blogger.com/atom/ns#' term='SpringSource'/><category scheme='http://www.blogger.com/atom/ns#' term='spring framework'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><title type='text'>Simple Spring Social for Twitter Friends</title><content type='html'>Gordon Dickens recently posted on his blog some thoughts on the Spring Social project. &amp;nbsp; &lt;br /&gt;&lt;br /&gt;The Spring Social project provides us developers with an easy way to interact with Twitter, Facebook, LinkedIn &amp;amp; TripIt via the familiar Template objects we have used. Spring has provided Templates for convenient interaction with JDBC, REST, Hibernate, JNDI, and more.&lt;br /&gt;One of the simplest social media calls is to lookup someone’s Twitter friends with the TwitterTemplate.&lt;br /&gt;&lt;a href="http://gordondickens.com/wordpress/2011/01/03/simple-spring-social-for-twitter-friends/"&gt;Read more..&lt;/a&gt; &lt;br /&gt;&lt;h4&gt;&lt;br /&gt;&lt;/h4&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-409346359701463976?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/409346359701463976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/01/simple-spring-social-for-twitter_17.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/409346359701463976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/409346359701463976'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/01/simple-spring-social-for-twitter_17.html' title='Simple Spring Social for Twitter Friends'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-2065099336950336384</id><published>2011-01-10T15:22:00.000-05:00</published><updated>2011-01-10T15:22:39.943-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><title type='text'>An Introduction to Mobile Device Detection</title><content type='html'>One of our architects, Steve Smith, recently posted this on his blog:&lt;br /&gt;&lt;br /&gt;These days, there are many ways to browse the internet. &amp;nbsp;There are desktop browsers, mobile phone browsers, tablets, tablet/phones (e.g. Dell Streak), etc. all with different screen sizes, resolution, and capabilities. &amp;nbsp;How do you render an appropriate view optimized for the device accessing your site? &amp;nbsp;The answer is device detection.&lt;br /&gt;The two main approaches for device detection are server-side detection and client side detection. &amp;nbsp;Server side detection involves determining the device at the time of the request and then presenting the appropriate view. &amp;nbsp;Client side detection involves manipulating the view after the content has been sent to the browser.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://stevenpsmith.wordpress.com/2010/12/29/an-introduction-to-mobile-device-detection/"&gt;Read the full post.. &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-2065099336950336384?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/2065099336950336384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2011/01/introduction-to-mobile-device-detection.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2065099336950336384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/2065099336950336384'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2011/01/introduction-to-mobile-device-detection.html' title='An Introduction to Mobile Device Detection'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-7831721935011989309</id><published>2010-12-31T07:58:00.000-05:00</published><updated>2010-12-31T07:58:43.233-05:00</updated><title type='text'>Build and Release Management With Apache Maven</title><content type='html'>More than ten years ago, Joel Spolsky of &lt;a href="http://www.joelonsoftware.com"&gt;&amp;quot;Joel on Software&amp;quot; fame&lt;/a&gt; wrote &lt;a href="http://www.joelonsoftware.com/articles/fog0000000043.html"&gt;The Joel Test: 12 Steps to Better Code&lt;/a&gt;. It was a great set of 12 yes/no questions, all of which you should be able to honestly answer &amp;quot;yes&amp;quot; if your team is to have any hope of producing good software in a timely and efficient manner. &lt;br /&gt;&lt;br /&gt;The Joel Test stands up pretty well even today. Joel's first two questions, &amp;quot;Do you use source control?&amp;quot; and &amp;quot;Can you make a build in one step?&amp;quot; are a good start at addressing the need for build automation. With the tools available today, however, I suggest that build management (not just automation) and release management should be added to the "must have" list for productive software development teams.&lt;br /&gt;&lt;br /&gt;Since I mostly work in Java, I'll talk about Java build and release management. There are a few comprehensive tools for Java build and release management (actually many more build management tools than release management tools), but the most popular by far is &lt;a href="http://maven.apache.org"&gt;Apache Maven&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Maven &lt;a href="http://maven.apache.org/background/history-of-maven.html"&gt;started in 2001&lt;/a&gt; as a part of the &lt;a href="http://jakarta.apache.org/alexandria/legacy/"&gt;Apache Alexandria&lt;/a&gt; project, moved to be a part of the &lt;a href="http://turbine.apache.org"&gt;Apache Turbine&lt;/a&gt; project in 2002, became a top-level Apache project in 2003, and had its first milestone release, v1.0, in October of 2005. Version 2.2.1 has been in wide use since its release in August of 2009. Version 3.0 was released in October of 2010, and the current version, 3.0.1 was released in November 2010.&lt;br /&gt;&lt;br /&gt;Maven bills itself as a "software project management and comprehension tool". Its most basic use is as a build tool, commonly as a replacement for &lt;a href="http://ant.apache.org"&gt;Apache Ant&lt;/a&gt;, but it does &lt;a href="http://maven.apache.org/what-is-maven.html"&gt;several other things&lt;/a&gt;, which &lt;a href="http://maven.apache.org/maven-features.html"&gt;taken together&lt;/a&gt;, really do form a useful software project management and comprehension tool. Maven is certainly not an absolute requirement for a good software development team, but the issues that it addresses must be addressed somehow. If your Java development team is not currently addressing these issues in a satisfactory way now, Maven is a good way to get started addressing them in a coherent way. &lt;br /&gt;&lt;br /&gt;As a &lt;b&gt;build tool&lt;/b&gt;, Maven takes the now-common "convention over configuration" approach that seems to have started around 2004 with the &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; web framework. As such, Maven &lt;a href="http://howsoftwareisbuilt.com/2010/06/25/jason-van-zyl-apache-maven/"&gt;was designed to be a highly opinionated tool&lt;/a&gt;, giving structure to the free-for-all that Ant usage had become in many projects. Maven is based on the &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-the-pom.html"&gt;Project Object Model&lt;/a&gt;, an XML configuration file that specifies what goes into a project, but unlike Ant, generally not &lt;b&gt;how&lt;/b&gt; to build it. This is where the convention over configuration comes in - you put your source code and other build artifacts in a directory structure that Maven expects, and then Maven can build it with no further configuration. This results in both simplified build management (no build script to write and maintain), and a project that anyone familiar with Maven can build. There is a well-defined build lifecycle, with well-defined targets: "mvn install" builds, tests, and packages any project built with Maven, and installs the resulting artifact in a local repository (more about repositories later). This is a great improvement over Ant, where the names of the build targets, and what they do are up to the whim of the person writing the &lt;a href="http://ant.apache.org/manual/using.html"&gt;Ant build script&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Maven is much more than just a build tool. It has &lt;a href="http://maven.apache.org/maven-features.html"&gt;many more features&lt;/a&gt;, but to me, the most important are &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html"&gt;Dependency Management&lt;/a&gt; and &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/"&gt;Release Management&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Dependency Management is all about dealing with the libraries (jar files) upon which your project depends (direct dependencies), and those jar files' dependencies (transitive dependencies). With Ant or any other build system that does not manage dependencies, this is left as a manual exercise for the developers. Typically, all of the dependencies are resolved manually, and all of the jar files are put into the project's 'lib' directory. This frequently means that multiple projects using the same third-party libraries will each need to keep a copy of them. &lt;br /&gt;&lt;br /&gt;Maven's paradigm is to have the developer declare the project's direct dependencies in the POM. Maven then resolves the transitive dependencies, and pulls the required jar files (direct and transitive dependencies) from a Maven Repository at build time. Jar files are not kept within the project, just the specification of which jar files to use at build time. There is a "standard" external repository (the "central" repository) that is web-based, and hosted by maven.org, and a local repository in the filesystem on the developer's machine. Jar files are pulled from the central repository, or other external repositories that may be configured, and cached in the local repository.&lt;br /&gt;&lt;br /&gt;This arrangement works well for small, one-off development efforts, but many shops have reusable jar files of their own that are used by multiple internal projects. Historically, many development teams have distributed these reusable in-house developed jar files by either putting them on a shared network directory, or by checking them into the source code version control system. This results in a process that is more manual and cumbersome than it should be, and generally violates the &lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY principle&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Using Maven instead of Ant or a home-grown build system, and managing dependencies through it are a good first step, but for reusable code, Release Management becomes important, and again, Maven can help. Maven, through its &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/"&gt;release plugin&lt;/a&gt;, supports a well-defined release lifecycle, and allows teams to store their reusable code in a centralized Maven repository, just like the "standard" jar files that are kept in the central repository. Teams (or whole companies) can set up their own internal, web-based repository that either enhances or replaces the central repository. Using Maven, they can then "release" their jar files to this repository. Projects using Maven can then declare these jar files as dependencies the same way that they do for jar files in the central repository, and they will be resolved by Maven. No need for shared directories, or placing binaries in the source code version control system. The release plugin takes care of incrementing version numbers and updating them in the version control system, in a standard way.&lt;br /&gt;&lt;br /&gt;The features that have been presented here are just the most prominent ones - Maven is capable of much more, especially with its extensive list of plugins. If your team is not using Maven (or something like it), or is only using Maven as a build tool, I encourage you to spend some time learning more about Maven. It will be time well spent. There are the Maven project's own &lt;a href="http://maven.apache.org/guides/index.html"&gt;"Getting Started" guides&lt;/a&gt; and a &lt;a href="http://www.sonatype.com/books.html"&gt;series of books by Sonatype&lt;/a&gt; (the commercial company behind Maven) for starters.&lt;br /&gt;&lt;br /&gt;Sonatype provides &lt;a href="http://www.sonatype.com/training.html"&gt;online, instructor-led training courses&lt;/a&gt;, and here at Chariot Solutions, &lt;a href="http://chariotsolutions.com/education/courses/maven-intro"&gt;we offer public, on-site training in our Ft. Washington, PA facility&lt;/a&gt;, as well as &lt;a href="http://chariotsolutions.com/education/contact"&gt;custom private courses&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-7831721935011989309?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/7831721935011989309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/12/build-and-release-management-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7831721935011989309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/7831721935011989309'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/12/build-and-release-management-with.html' title='Build and Release Management With Apache Maven'/><author><name>Rich Freedman</name><uri>http://www.blogger.com/profile/06334089409580527109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-WC8GmbpPns0/TxMCTVzu0rI/AAAAAAAAEmA/cOHtbCEutxo/s220/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-1787297176023530429</id><published>2010-12-28T12:37:00.000-05:00</published><updated>2010-12-28T12:37:04.453-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='griffon'/><title type='text'>Painless Java Desktop Application Development with Griffon, MigLayout, and IntelliJ</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://media.xircles.codehaus.org/_projects/griffon/_logos/medium.png" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="100" width="310" src="http://media.xircles.codehaus.org/_projects/griffon/_logos/medium.png" /&gt;&lt;/a&gt;&lt;/div&gt;As Java consultants and developers, a very large percentage our projects are web applications. &lt;br /&gt;We have become accustomed to depending on MVC web frameworks, and almost take for granted that at some level, we will be handling HTTPServletRequests, providing HTTPServletResponses, and deploying our applications to either a servlet container or a full J2EE server.&lt;br /&gt;&lt;br /&gt;Every once in a while, however, the need arises to write an old-fashioned, desktop, thick-ui, non-web-centric application. If you have ever written a Java Swing application, you may have painful memories of dealing with things like BorderLayouts, GridBags, Event Listeners and Event Dispatching Threads, JFrames, and the like. &lt;br /&gt;&lt;br /&gt;As a web developer, when you think about building your desktop application, you might start to think about how you will structure your application, and how you will build and package it. Will you have to re-package your code and all of your dependencies in one giant uber-jar?&lt;br /&gt;Will you make it a web-start application? Fortunately, some folks have been thinking about, and working on these issues.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://griffon.codehaus.org/"&gt;Griffon&lt;/a&gt; is a &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;-based &lt;a href="http://en.wikipedia.org/wiki/Model%E2%80%93View%E2%80%93Controller"&gt;MVC framework&lt;/a&gt; for writing desktop applications. It is written by the Groovy Swing team, and is heavily influenced by &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt;.  If you have worked with Grails, then Griffon will be a very familiar environment. Griffon answers all of the above questions, and more.  &lt;br /&gt;&lt;br /&gt;Using the &lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;convention-over-configuration&lt;/a&gt; and command-line-driven scaffolding paradigms made popular by &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;, &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;, and Groovy on Grails, among others, Griffon generates the project structure, the model, view, and controller objects, and all of the configuration for you. You then customize these to produce your application. &lt;br /&gt;&lt;br /&gt;Working in Groovy, of course, makes this a much more pleasurable experience, dispensing with the &lt;a href="http://thinkrelevance.com/blog/2008/04/01/ending-legacy-code-in-our-lifetime.html"&gt;ceremony&lt;/a&gt; of Java development, and letting you write high-level, fairly terse, yet expressive code, and enabling you to accomplish quite a bit very quickly. The prime example of this in the Griffon framework is the &lt;a href="http://groovy.codehaus.org/Swing+Builder"&gt;SwingBuilder&lt;/a&gt; object - a &lt;a href="http://groovy.codehaus.org/Builders"&gt;Groovy Builder&lt;/a&gt; that provides a DSL for building Swing user interfaces. &lt;a href="http://groovy.codehaus.org/Griffon+Quick+Start#GriffonQuickStart-AddContenttotheView"&gt;Views in Griffon are SwingBuilder scripts&lt;/a&gt;, and greatly simplify the task of creating Swing UIs.   &lt;br /&gt;&lt;br /&gt;Griffon uses the &lt;a href="http://gant.codehaus.org/"&gt;Gant&lt;/a&gt; build system (as does Grails), and by default, packages your application with all its dependencies as an uber-jar (with the correct manifest entries to make it 'executable'), as an applet, and as a java-webstart application.&lt;br /&gt;&lt;br /&gt;When working with Swing, even with the SwingBuilder, one potentially still has to deal with the frustration of laying out the user interface by using a LayoutManager. GridBagLayout is flexible (too flexible?), but about as complicated as it can get. BorderLayout is fairly simple, but the simplicity comes at a cost - you typically wind up nesting lots of BorderLayouts in other BorderLayouts to get the desired behavior. Over the years, alternate layout managers have appeared, and some are quite useful, most notably the &lt;a href="http://www.jgoodies.com/freeware/forms/"&gt;JGoodies Form Layout&lt;/a&gt; and &lt;a href="http://www.datadosen.se/riverlayout/"&gt;RiverLayout&lt;/a&gt;. I tried &lt;a href="http://www.miglayout.com/"&gt;MigLayout&lt;/a&gt; with my Griffon project, and found it to be very flexible and easy to use.&lt;br /&gt;&lt;br /&gt;Here is a screenshot of the main UI of my application:&lt;br /&gt;&lt;div class="thumbnail"&gt;&lt;a href="https://skitch.com/rfreedman/rgdeu/servicetester"&gt;&lt;img src="https://img.skitch.com/20101221-fu86i42eg5gt49n7747fra8sgy.preview.jpg" alt="ServiceTester" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;As mentioned previously, the View is a Groovy SwingBuilder script. The first part of the script sets up an 'application' - the application's "MainFrame", which Griffon interprets according to the runtime environment - for a stand-alone application, it will build a JFrame, and for an applet it will build a JApplet:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="brush: groovy"&gt;package servicetester&lt;br /&gt;&lt;br /&gt;import java.awt.FlowLayout&lt;br /&gt;import net.miginfocom.swing.MigLayout&lt;br /&gt;&lt;br /&gt;application(title: 'Service Tester', minimumSize: [297, 200], maximumSize: [297,200], location: [50, 50], pack: true, locationByPlatform: true) {&lt;br /&gt;&lt;/pre&gt;Note that minimumSize, maximumSize, location, etc. are set as properties here. In straight Java Swing code, these would have been at least one line of code each, and several would have involved building Dimension objects.&lt;br /&gt;&lt;br /&gt;Next is setup of the actions and the menu bar that uses the actions, in this case, a simple 'File' menu with a 'Quit' menu item to exit the application.&lt;br /&gt;Note the use of Groovy closures for associating the Action object with implementation of the action.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="brush: groovy"&gt;actions {&lt;br /&gt;&lt;br /&gt;    action(id: 'exitAction',&lt;br /&gt;            name: 'Quit',&lt;br /&gt;            closure: { System.exit(1) },&lt;br /&gt;            mnemonic: 'Q',&lt;br /&gt;            accelerator: shortcut('Q'),&lt;br /&gt;            shortDescription: 'Quit'&lt;br /&gt;    )&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  menuBar(id: 'menuBar') {&lt;br /&gt;&lt;br /&gt;    menu(text: 'File', mnemonic: 'F') {&lt;br /&gt;      menuItem(exitAction)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I chose to use the MigLayout for the main panel of the view. There are &lt;a href="http://www.miglayout.com/QuickStart.pdf"&gt;lots of ways to initialize a MigLayout&lt;/a&gt;, I used the "fill" parameter to the constructor, which tells it to grow to occupy all available space, which makes sense here because it is the top-level component in the frame.&lt;br /&gt;&lt;pre name="code" class="brush: groovy"&gt;panel(border: emptyBorder(12), layout: new MigLayout('fill')) {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see in the screenshot, there are three groupings of controls - the group of fields above the separator (the input fields), the group of fields below the separator (the output fields), and the "button bar" at the bottom (only one button). To achieve these groupings, I added two panels, each with MigLayout initialized with "fill", as with the main frame, and a third panel with a FlowLayout for the button bar. &lt;br /&gt;These MigLayouts are given constraints of "growy" and "wrap":&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="brush: groovy"&gt;panel(layout: new MigLayout('fill'), &lt;br /&gt;          constraints: "growy, wrap") {&lt;br /&gt;&lt;/pre&gt;"growy" means "grow vertically", and "wrap" means that the next component should be placed below, instead of to the right.&lt;br /&gt;With this configuration, the MigLayout in the main frame gives the button bar it's preferred size, and resizes the other two panels as the main window is resized, giving equal weight to them.&lt;br /&gt;&lt;br /&gt;The two MigLayout panels are very similar. Each has sets of label / input field pairs, which look like:&lt;br /&gt;&lt;pre name="code" class="brush: groovy"&gt;label(text: 'AMQ Broker URL:')&lt;br /&gt;      textField(&lt;br /&gt;              id: 'brokerUrl',&lt;br /&gt;              columns: 40,&lt;br /&gt;              text: bind(target: model, targetProperty: 'brokerUrl', value: model.brokerUrl),&lt;br /&gt;              enabled: bind {model.enabled},&lt;br /&gt;              constraints: 'wrap'&lt;br /&gt;      )&lt;br /&gt;&lt;/pre&gt;The "text:bind" property binds the value entered in the textField to a property in the model - the value entered by the user is placed into the model.&lt;br /&gt;&lt;br /&gt;One big "gotcha" here is that bi-directional binding is not supported. It is possible to bind in each direction, but not both directions at the same time. As one might expect, lots of people are asking for this capability, so I wouldn't be surprised to see it show up soon. I ran into this when trying to set the initial value of the field from the value in the model. The answer for this case is to use the "value" property as shown above - it gives the field it's initial value, and does not participate in the binding mechanism, so it doesn't present the same problem as bi-directional binding. If you do truly need bi-directional binding, at the moment, you'll have to roll your own.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/a/chariotsolutions.com/rfreedman/public_files/ServiceTesterView.groovy?attredirects=0&amp;d=1"&gt;Here&lt;/a&gt; is the full source code for this View.&lt;br /&gt;&lt;br /&gt;Due to its highly-developed sense of structure and general lack of need for configuration, working on a Griffon application using the command line and a text editor is very straightforward. However, IDE support is always nice. &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; does not directly support Griffon, but does support Groovy. Both &lt;a href="http://netbeans.org/"&gt;NetBeans&lt;/a&gt; and &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ&lt;/a&gt; have direct support for Griffon projects. IntelliJ 9 and 10 have direct support for creating, importing, testing, running, and debugging Griffon applications, and I found these features to work quite well.  &lt;br /&gt;&lt;br /&gt;I found the combination of Groovy, Griffon, MigLayout, and IntelliJ to be an extremely productive environment for creating Swing applications, providing much of the application infrastructure, allowing me to dispense with ceremony and concentrate on writing the parts of the application that make it unique. Before embarking on a large or mission-critical Griffon project, however, you do need to be aware that Griffon is still in Beta (0.9.2-beta-3 was &lt;a href="http://groovy.dzone.com/announcements/griffon-092-beta-3-released"&gt;just released&lt;/a&gt; on Dec. 21st, 2010), and so is still in a bit of a state of flux.&lt;br /&gt;&lt;br /&gt;If you are interested in reading about Griffon, there's &lt;a href="http://griffon.codehaus.org/Documentation"&gt;documenatation&lt;/a&gt; at at the Griffon home page, and the &lt;a href="http://manning.com/almiray/"&gt;Griffon In Action&lt;/a&gt; book is available from Manning.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-1787297176023530429?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/1787297176023530429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/12/painless-java-desktop-application.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1787297176023530429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1787297176023530429'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/12/painless-java-desktop-application.html' title='Painless Java Desktop Application Development with Griffon, MigLayout, and IntelliJ'/><author><name>Rich Freedman</name><uri>http://www.blogger.com/profile/06334089409580527109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-WC8GmbpPns0/TxMCTVzu0rI/AAAAAAAAEmA/cOHtbCEutxo/s220/headshot.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-5054862711319022292</id><published>2010-12-01T14:03:00.001-05:00</published><updated>2010-12-01T14:03:45.178-05:00</updated><title type='text'>Nielsen: Android makes huge gains in US smartphone marketshare, RIM takes a backseat, Apple leads in desirability -- Engadget</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;div class="posterous_bookmarklet_entry"&gt; &lt;a href='http://posterous.com/getfile/files.posterous.com/kgriff/rFGyGoJEtbosasvglFikihcEFCDvFqoswbDablGJFtdwgsfefuqziwhABczh/media_httpwwwblogcdnc_pwoaf.png.scaled1000.png'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/kgriff/rFGyGoJEtbosasvglFikihcEFCDvFqoswbDablGJFtdwgsfefuqziwhABczh/media_httpwwwblogcdnc_pwoaf.png.scaled500.png" width="500" height="317"/&gt;&lt;/a&gt; &lt;div class="posterous_quote_citation"&gt;via &lt;a href="http://www.engadget.com/2010/12/01/nielsen-android-makes-huge-gains-in-us-smartphone-marketshare/"&gt;engadget.com&lt;/a&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-5054862711319022292?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/5054862711319022292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/12/nielsen-android-makes-huge-gains-in-us.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5054862711319022292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/5054862711319022292'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/12/nielsen-android-makes-huge-gains-in-us.html' title='Nielsen: Android makes huge gains in US smartphone marketshare, RIM takes a backseat, Apple leads in desirability -- Engadget'/><author><name>Kevin Griffin</name><uri>http://www.blogger.com/profile/03251714915666161180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4981840820415244130</id><published>2010-11-24T13:13:00.001-05:00</published><updated>2010-12-06T15:59:51.982-05:00</updated><title type='text'>Spring into Mobile Application Development</title><content type='html'>&lt;div class="posterous_autopost"&gt;&lt;div class="posterous_bookmarklet_entry"&gt; &lt;blockquote&gt;&lt;div&gt;   &lt;h3&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/" title="Permanent Link" rel="bookmark"&gt;Spring into Mobile Application Development&lt;/a&gt;&lt;/h3&gt;     &lt;p&gt;&lt;small&gt;     Posted on November 19th, 2010 by &lt;a href="http://blog.springsource.com/author/keithd/" title="Posts by Keith Donald"&gt;Keith Donald&lt;/a&gt; in &lt;a href="http://blog.springsource.com/category/spring/" title="View all posts in Spring" rel="category tag"&gt;Spring&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;     &lt;div&gt;    &lt;a href="http://blog.springsource.com/author/keithd/" title="Posts by Keith Donald"&gt;&lt;img title="Keith Donald" src="http://blog.springsource.com/wp-content/images/authors/keithd.jpg" height="112" alt="Keith Donald" width="80" /&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;At &lt;a href="http://www.springone2gx.com/"&gt;SpringOne2gx&lt;/a&gt; we announced exciting new initiatives in the areas of social media and mobile application development.  A few weeks ago, Craig Walls released &lt;a href="http://www.springsource.org/spring-social"&gt;Spring Social&lt;/a&gt;.  Today, Roy Clarkson released &lt;a href="http://www.springsource.org/spring-mobile"&gt;Spring Mobile&lt;/a&gt; and &lt;a href="http://www.springsource.org/spring-android"&gt;Spring Android&lt;/a&gt;.  In this post, I'd like to highlight these projects and share how Spring aims to simplify mobile application development.&lt;/p&gt;  &lt;h3&gt;Choices in Mobile Application Development&lt;/h3&gt;  &lt;p&gt;If you attended SpringOne2gx this year, you've seen &lt;a href="http://greenhouse.springsource.org/"&gt;Greenhouse&lt;/a&gt;, an app we built for our community that also serves as a reference and driver for Spring technology.  Craig showed you some of the &lt;a href="http://blog.springsource.com/2010/11/03/socializing-spring-applications"&gt;social elements&lt;/a&gt; of Greenhouse, such as the ability to connect your account with Twitter and Facebook.  There are also a number of mobile elements.  Specifically, Greenhouse doubles as a mobile web app, and sports native &lt;a href="http://itunes.apple.com/us/app/greenhouse/id395862873"&gt;Greenhouse for iPhone&lt;/a&gt; and Android clients.&lt;/p&gt;  &lt;p&gt;Like many organizations today, we had to answer the basic question of "what mobile platforms to target?"  In the end, we chose to invest in a native experience for iPhone and Android users, while also developing a cross-platform mobile web app.  Our decision to go native was driven by the fact the app is consumer-oriented, and a large number of prospective consumers (application developers) own iPhone and Android devices.  At the same time, the mobile web app aims to provide a good baseline experience that works cross-platform, something that's possible today with the rise of WebKit and HTML 5.&lt;/p&gt;  &lt;p&gt;From our development work, grew Spring Framework contributions: first, a &lt;strong&gt;Spring Mobile&lt;/strong&gt; project that provides extensions to Spring MVC for developing mobile web apps; and second, a &lt;strong&gt;Spring Android&lt;/strong&gt; project that supports the development of native Android clients that communicate with Spring-based back-ends.  I'll take you through each of these projects in turn.&lt;/p&gt;  &lt;h3&gt;Spring Mobile&lt;/h3&gt;  &lt;p&gt;The first problem we tackled was designing a web app that was pleasant for mobile visitors to use.  While a smartphone may have a capable web browser, it still has a small screen and that needs to be accounted for.  There are essentially two approaches to dealing with this problem:&lt;/p&gt;  &lt;ol&gt;  &lt;li&gt;Detect the device that originated the web request and serve a separate site to mobile devices.&lt;/li&gt;  &lt;li&gt;Serve a single site, but progressively enhance it for desktop users by using CSS 3 media queries and JavaScript.&lt;/li&gt;  &lt;/ol&gt;  &lt;p&gt;You can find examples of both techniques in the wild today; for example, the conference site &lt;a href="http://www.lanyrd.com/"&gt;Lanyrd&lt;/a&gt; enhances through client-side detection, while &lt;a href="http://www.speakerrate.com/"&gt;SpeakerRate&lt;/a&gt; uses server-side detection that redirects mobile visitors to a separate site (see for yourself by installing the Firefox User Agent Switcher and setting your user agent to iPhone).&lt;/p&gt;  &lt;p&gt;In Greenhouse, we started with server-side detection.  Specifically, we aimed to apply a different page layout if the device was a mobile device.  Out of this grew a general purpose "Device Resolver Abstraction", which is the defining feature of Spring Mobile 1.0.0.M1.  Some highlights of this feature include:&lt;/p&gt;  &lt;ol&gt;  &lt;li&gt;A HandlerInterceptor that uses a DeviceResolver to detect the Device that originated the current HttpServletRequest.&lt;/li&gt;  &lt;li&gt;The ability to inject the detected Device into @Controller methods and view templates to vary logic by device type.&lt;/li&gt;  &lt;/ol&gt;  &lt;p&gt;Below are some usage examples from the Greenhouse codebase.  First, have a look at the interceptor definition from /WEB-INF/spring/appServlet/servlet-context.xml:&lt;/p&gt;  &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#viewSource" title="view source" style="height: 16px;"&gt;view source&lt;/a&gt;&lt;p&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#printSource" title="print" style="height: 16px;"&gt;print&lt;/a&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#about" title="?" style="height: 16px;"&gt;?&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;code&gt;interceptors&lt;/code&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;!-- On pre-handle, detect the device that originated the web request --&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;code&gt;beans:bean&lt;/code&gt; &lt;code&gt;class&lt;/code&gt;&lt;code&gt;=&lt;/code&gt;&lt;code&gt;"org.springframework.mobile.device.mvc.DeviceResolvingHandlerInterceptor"&lt;/code&gt; &lt;code&gt;/&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;/&lt;/code&gt;&lt;code&gt;interceptors&lt;/code&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;Now, a JSP template that conditionally renders some content if the device is not a mobile device:&lt;/p&gt;  &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#viewSource" title="view source" style="height: 16px;"&gt;view source&lt;/a&gt;&lt;p&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#printSource" title="print" style="height: 16px;"&gt;print&lt;/a&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#about" title="?" style="height: 16px;"&gt;?&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Please try again&amp;lt;&lt;/code&gt;&lt;code&gt;c:if&lt;/code&gt; &lt;code&gt;test&lt;/code&gt;&lt;code&gt;=&lt;/code&gt;&lt;code&gt;"${!currentDevice.mobile}"&lt;/code&gt;&lt;code&gt;&amp;gt; or &amp;lt;&lt;/code&gt;&lt;code&gt;a&lt;/code&gt; &lt;code&gt;href&lt;/code&gt;&lt;code&gt;=&lt;/code&gt;&lt;code&gt;"&amp;lt;c:url value="&lt;/code&gt;&lt;code&gt;/signup" /&amp;gt;"&amp;gt;sign up&amp;lt;/&lt;/code&gt;&lt;code&gt;a&lt;/code&gt;&lt;code&gt;&amp;gt;&amp;lt;/&lt;/code&gt;&lt;code&gt;c:if&lt;/code&gt;&lt;code&gt;&amp;gt;.&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;Finally, a Tiles-based page layout that changes if the device is a mobile device:&lt;/p&gt;  &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#viewSource" title="view source" style="height: 16px;"&gt;view source&lt;/a&gt;&lt;p&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#printSource" title="print" style="height: 16px;"&gt;print&lt;/a&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#about" title="?" style="height: 16px;"&gt;?&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;code&gt;definition&lt;/code&gt; &lt;code&gt;name&lt;/code&gt;&lt;code&gt;=&lt;/code&gt;&lt;code&gt;"page"&lt;/code&gt; &lt;code&gt;templateExpression&lt;/code&gt;&lt;code&gt;=&lt;/code&gt;&lt;code&gt;"/WEB-INF/layouts/${currentDevice.mobile ? 'mobile/' : 'standard/'}page.jsp"&lt;/code&gt; &lt;code&gt;/&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;In addition to these features, Spring Mobile 1.0.0.M1 ships:&lt;/p&gt;  &lt;ol&gt;  &lt;li&gt;A HandlerInterceptor that redirects mobile visitors to another URL.  This is useful if your mobile site truly is a separate application.  Consider Flickr, for example, which will redirect you to &lt;a href="http://m.flickr.com/"&gt;m.flickr.com&lt;/a&gt; if you access &lt;a href="http://www.flickr.com/"&gt;www.flickr.com&lt;/a&gt; from your phone.&lt;/li&gt;  &lt;li&gt;A DeviceResolver implementation that delegates to WURFL for device detection.  WURFL provides a large database of devices and their capabilities.  It is useful when you need to know more about the Device that originated the request, such as its specific screen size, manufacturer, model, preferred markup, or other capabilities.&lt;/li&gt;  &lt;/ol&gt;  &lt;p&gt;Recently, we have also begun exploring the use of &lt;a href="http://www.webmonkey.com/2010/09/make-a-big-splash-on-small-screens-with-media-queries/"&gt;CSS 3 media queries&lt;/a&gt; with &lt;a href="http://www.quirksmode.org/blog/archives/2010/08/combining_media.html#more"&gt;JavaScript&lt;/a&gt; to perform client-side detection.  This approach has the advantage of not requiring special server-side handling unless you aim to vary the semantic content you send to the device, and not just optimize the style.  Not all browsers support media queries, so they may not be an option for you, but if you're &lt;a href="http://davidbcalhoun.com/2010/using-mobile-specific-html-css-javascript"&gt;targeting smartphones&lt;/a&gt; with WebKit-based browsers you should be fine.  In general, the approach of first designing your app for mobile, then progressively enhancing it for desktop feels quite elegant to me.&lt;/p&gt;  &lt;h3&gt;Spring Android&lt;/h3&gt;  &lt;p&gt;For the Android client, a different set of challenges emerged.  We needed to exchange data with the server over HTTPS via REST, and since that data is user-specific we require the user to sign in.  Rather than use Basic Auth, where we would need to store username and password credentials on the device itself, we opted for OAuth.&lt;/p&gt;  &lt;p&gt;OAuth is an emerging standard that provides a token-based authorization scheme.  Essentially, a username and password is traded for an access token, and the access token is used to make requests for protected resources.  This means you only need to store the access token with the device for "remember me" functionality.  Furthermore, we chose to implement the sign in process whereby the client takes you to the server's web site for connection authorization.  In this way, the client never sees your username and passsword, which is important if you allow third-party clients to be developed against your API (which we also want to encourage).  Finally, in the event a user's phone is stolen or otherwise compromised, an access token can be invalidated without the risk of username and password compromise.&lt;/p&gt;  &lt;p&gt;Out of this work, came the desire to get specific modules of the Spring Framework working in an Android environment.  Specifically, we aimed to use &lt;a href="http://blog.springsource.com/2009/03/27/rest-in-spring-3-resttemplate"&gt;RestTemplate&lt;/a&gt; for the REST API calls, and &lt;a href="http://static.springsource.org/spring-security/oauth/index.html"&gt;Spring Security&lt;/a&gt; for the OAuth client.&lt;/p&gt;  &lt;p&gt;I'm pleased announce that the first milestone of Spring Android ships an "Android-ready" RestTemplate.  We're using it in Greenhouse, and we encourage you to use it as the REST client in your own Android applications.   Check out the example usage below:&lt;/p&gt;  &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#viewSource" title="view source" style="height: 16px;"&gt;view source&lt;/a&gt;&lt;p&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#printSource" title="print" style="height: 16px;"&gt;print&lt;/a&gt;&lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29#about" title="?" style="height: 16px;"&gt;?&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;RestTemplate restTemplate = &lt;/code&gt;&lt;code&gt;new&lt;/code&gt; &lt;code&gt;RestTemplate(&lt;/code&gt;&lt;code&gt;new&lt;/code&gt; &lt;code&gt;CommonsClientHttpRequestFactory());&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Event event = restTemplate.getForObject(&lt;/code&gt;&lt;code&gt;"&lt;a href="https://myapp.com/event/"&gt;https://myapp.com/event/&lt;/a&gt;{name}"&lt;/code&gt;&lt;code&gt;, Event.&lt;/code&gt;&lt;code&gt;class&lt;/code&gt;&lt;code&gt;, &lt;/code&gt;&lt;code&gt;"springone2gx"&lt;/code&gt;&lt;code&gt;);&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;In future milestones, you can expect more of the Spring Framework to be supported in an Android environment, such as the Spring Security OAuth client.&lt;/p&gt;  &lt;h3&gt;Getting Started&lt;/h3&gt;  &lt;p&gt;The best way to get started is to &lt;i&gt;see it live&lt;/i&gt; by walking through the Greenhouse app in your own local development environment.  As a reference, Greenhouse uses the Spring Mobile and Spring Android projects, as well as Spring MVC, Security, Social, and Integration.  The &lt;a href="http://www.springsource.org/greenhouse"&gt;project page&lt;/a&gt; provides a &lt;a href="http://www.springsource.org/greenhouse/guide"&gt;guide&lt;/a&gt; that shows you how to get the web app, iPhone client, and Android client all running in your local environment in minutes.&lt;/p&gt;  &lt;p&gt;If you have questions about features, roadmap, or just want to have a discussion with the development team, please do visit our &lt;a href="http://forum.springsource.org/forumdisplay.php?f=25"&gt;community forums&lt;/a&gt;.  We value your feedback.&lt;/p&gt;  &lt;h3&gt;Summary&lt;/h3&gt;  &lt;p&gt;I'm very excited about all the new initiatives we've got going, and especially what we're doing in the social and mobile space.  The first milestones of these projects are just the beginning.  I encourage you to get involved in the projects that are useful to you and help us make them the best they can possibly be.&lt;br /&gt; &lt;/p&gt;&lt;h3&gt;&lt;span class="Apple-style-span" style="font-weight: normal; font-size: 16px; "&gt;via &lt;a href="http://blog.springsource.com/2010/11/19/spring-into-mobile-application-development/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+Interface21TeamBlog+%28SpringSource+Team+Blog%29"&gt;blog.springsource.com&lt;/a&gt;&lt;/span&gt;&lt;/h3&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt; &lt;p&gt;Need to check this out for some old Spring stuff I have worked on :)&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4981840820415244130?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4981840820415244130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/11/spring-into-mobile-application.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4981840820415244130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4981840820415244130'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/11/spring-into-mobile-application.html' title='Spring into Mobile Application Development'/><author><name>Kevin Griffin</name><uri>http://www.blogger.com/profile/03251714915666161180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-740675251459188037</id><published>2010-11-16T22:55:00.001-05:00</published><updated>2010-11-17T09:35:40.540-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='nfc'/><category scheme='http://www.blogger.com/atom/ns#' term='keitai'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>NFC. What does it all mean?</title><content type='html'>&lt;div class="posterous_autopost"&gt;&lt;p&gt;&lt;span class="Apple-style-span"   style="  color: rgb(51, 51, 51); line-height: 22px; font-family:Georgia, 'Times New Roman', Times, serif;font-size:14px;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "&gt;&lt;span class="Apple-style-span"   style="  color: rgb(51, 51, 51); line-height: 22px; font-family:Georgia, 'Times New Roman', Times, serif;font-size:14px;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "&gt;NFC: Near Field Communications: a short-range high frequency wireless communication technology which enables the exchange of data between devices over about a 10 centimeter (around 4 inches) distance (via Wikipedia).&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;Well that's great, but what does it mean, especially when mentioned in conjunction with Gingerbread?&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;As you may (or may not) have heard this week at the Web2.0 Summit Eric Schmidt talk about Android 2.3 and its support for NFC. This could indeed lead the way for mobile payments on devices. NFC will allow for the transmission of credit card data over a defined radio frequency (13.56 MHz).&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;This isn't new, Japanese handsets (Keitai) have had this type of technology for a while (I want to say up to 10 years, but I can't back that up right now). Go google &lt;a href="http://bit.ly/cK2fFM" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: rgb(0, 0, 0); text-decoration: underline; "&gt;Osaifu-Keitai&lt;/a&gt;/&lt;a href="http://bit.ly/cFIqMc" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: rgb(0, 0, 0); text-decoration: underline; "&gt;keitai credit&lt;/a&gt;.&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;However this *is* all exciting news. There is potential for integrating it with conferences, museums, travel, healthcare, payment systems, and countless other things. Lets not forget though, some of these things already exist already:&lt;/p&gt;&lt;ul style="padding-top: 0px; padding-right: 0px; padding-bottom: 5px; padding-left: 30px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "&gt;&lt;li style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 5px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-type: disc; "&gt;Exxon SpeedPass&lt;/li&gt;&lt;li style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 5px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-type: disc; "&gt;Debit cards with Visa PayWave.&lt;/li&gt;&lt;/ul&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', Times, serif; font-size: 14px; color: rgb(51, 51, 51); line-height: 22px; "&gt;Now we have another new way to gain information about our surroundings. #mobilefirst anyone?&lt;/span&gt;&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', Times, serif; font-size: 14px; color: rgb(51, 51, 51); line-height: 22px; "&gt;&lt;/span&gt;Some interesting articles to peruse at your leisure.&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;&lt;a href="http://www.rfid-weblog.com/50226711/rfid_in_museums_another_growing_market.php" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: rgb(0, 0, 0); text-decoration: underline; "&gt;RFID in Museums - Another Growing Market&lt;/a&gt;&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;&lt;a href="http://www.readwriteweb.com/archives/who_will_win_the_mobile_payments_battle_gadgets_nfc_or_apps.php" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: rgb(0, 0, 0); text-decoration: underline; "&gt;Who Will Win the Mobile Payments Battle: Gadgets, NFC or Apps?&lt;/a&gt;&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;&lt;a href="http://www.wired.com/epicenter/2010/08/intuit-squares-off-in-mobile-credit-with-a-little-help-from-apple/" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: rgb(0, 0, 0); text-decoration: underline; "&gt;Intuit Squares Off In Mobile Credit, With A Little Help From Apple&lt;/a&gt;&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;&lt;a href="http://www.rfid-weblog.com/58929511/future_credit_cards_electronic_and_rfid.php" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: rgb(0, 0, 0); text-decoration: underline; "&gt;Future Credit Cards: Electronic and RFID?&lt;/a&gt;&lt;/p&gt;&lt;p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 15px; margin-right: 0px; margin-bottom: 18px; margin-left: 0px; "&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', Times, serif; font-size: 14px; color: rgb(51, 51, 51); line-height: 22px; "&gt;&lt;a href="http://www.youtube.com/watch?v=AKOWK2dR4Dg" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; color: rgb(0, 0, 0); text-decoration: underline; "&gt;Web 2.0 Summit 2010: Eric Schmidt, "A Conversation with Eric Schmidt"&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-740675251459188037?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/740675251459188037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/11/nfc-what-does-it-all-mean.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/740675251459188037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/740675251459188037'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/11/nfc-what-does-it-all-mean.html' title='NFC. What does it all mean?'/><author><name>Kevin Griffin</name><uri>http://www.blogger.com/profile/03251714915666161180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-1536597284631042027</id><published>2010-11-11T12:38:00.000-05:00</published><updated>2010-11-11T12:38:30.276-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring roo'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Configuring LogBack in Roo</title><content type='html'>&amp;nbsp;Gordon Dickens, one of our trainers and architects, recently posted this on his Technophile Blog, on Roo.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://logback.qos.ch/"&gt;LogBack&lt;/a&gt; is the more versatile logging strategy created by the same person that created log4j.  Use the following steps to configure your Roo 1.1 project to use &lt;a href="http://logback.qos.ch/"&gt;LogBack&lt;/a&gt;.&lt;br /&gt;See Also: &lt;a href="http://logback.qos.ch/reasonsToSwitch.html"&gt;Reasons to Switch to LogBack&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;1.  Create a &lt;code&gt;logback.xml&lt;/code&gt; file in &lt;code&gt;src/main/resources&lt;/code&gt;&lt;/h3&gt;&lt;h3&gt;&lt;a href="http://www.blogger.com/goog_388692182"&gt;&lt;code&gt;&amp;nbsp;Cont. here for the remainder of the post &lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;&lt;table border="0" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;a href="http://gordondickens.com/wordpress/2010/11/07/configuring-logback-in-roo/"&gt;&lt;br /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-1536597284631042027?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/1536597284631042027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/11/configuring-logback-in-roo.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1536597284631042027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1536597284631042027'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/11/configuring-logback-in-roo.html' title='Configuring LogBack in Roo'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-3680353757308097038</id><published>2010-11-10T15:34:00.000-05:00</published><updated>2010-11-10T15:41:31.685-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile phones'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile development'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Post Presentation Thoughts from our Mobile Seminar</title><content type='html'>Kevin Griffin was one of the presenters at our first Mobile Seminar Breakfast.  Below is a recap of his thoughts after he finished his presentation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Yesterday I presented at the first in a series of events for Chariot Solutions, the topic was 'Mobile Design Concepts'.&lt;br /&gt;&lt;br /&gt;My goal was to try present things that I had learned/seen/been shown/done over the last couple of years, and try to get the audience out of the 'desktop browser' mind set when developing for mobile.&lt;br /&gt;&lt;br /&gt;I drew from a lot of people that I have seen/meet including Luke Wroblewski (@LukeW), Josh Clark/Tapworthy (@globalmoxie), Mike Lee (@bmf) William Van Hecke (@fetjuel) and Brian Fling's book 'Mobile Design and Development' which I still think is the first book anyone planning on a mobile project should read. I was probably influenced by many more folks than that, but they are the obvious ones to me at the time of writing.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kgriff.posterous.com/post-presentation-thoughts"&gt;Cont. reading..&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-3680353757308097038?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/3680353757308097038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/11/post-presentation-thoughts-from-our.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3680353757308097038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/3680353757308097038'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/11/post-presentation-thoughts-from-our.html' title='Post Presentation Thoughts from our Mobile Seminar'/><author><name>Tracey Welson-Rossman</name><uri>http://www.blogger.com/profile/00460003016667099940</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-1998097032981560084</id><published>2010-11-08T09:51:00.000-05:00</published><updated>2010-11-08T09:51:04.365-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails Validation Constraints Quick Ref</title><content type='html'>This is an excerpt from a blog post by Gordon Dickens, Chariot Architect and Trainer (via Technophile Blog)&lt;br /&gt;&lt;br /&gt;After several iterations of Grails, we have to go to 17 (seventeen) pages to see all the validation constraints?  I wanted to see them on one page.&lt;br /&gt;&lt;hr /&gt;&lt;h3&gt;Grails 1.3.5 – Validation Constraints&lt;/h3&gt;&lt;strong&gt;blank&lt;/strong&gt; – To validate that a String value is not blank&lt;br /&gt;&lt;div style="margin-top: -10px; text-indent: 50px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-top: -10px; text-indent: 50px;"&gt;login(blank:false)&lt;/div&gt;&lt;strong&gt;creditCard&lt;/strong&gt; – To validate that a String value is a valid credit card number&lt;br /&gt;&lt;div style="margin-top: -10px; text-indent: 50px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-top: -10px; text-indent: 50px;"&gt;cardNumber(creditCard:true)&lt;/div&gt;&lt;strong&gt;email&lt;/strong&gt; – To validate that a String value is a valid email address.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://gordondickens.com/wordpress/2010/11/05/grails-validation-constraints-quick-ref/"&gt;Click here for the rest of the article&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-1998097032981560084?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/1998097032981560084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/11/grails-validation-constraints-quick-ref.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1998097032981560084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/1998097032981560084'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/11/grails-validation-constraints-quick-ref.html' title='Grails Validation Constraints Quick Ref'/><author><name>Chariot Solutions</name><uri>http://www.blogger.com/profile/15997073670953019471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='9' src='http://2.bp.blogspot.com/_H7Kcd4Iivao/SpnUZLEm6uI/AAAAAAAAAAM/-lhCXLVnGTI/S220/ChariotLogo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-4838849409301251511</id><published>2010-10-04T19:10:00.000-04:00</published><updated>2010-10-04T22:49:27.153-04:00</updated><title type='text'>Monthly Mobile Musings from September</title><content type='html'>&lt;div&gt;Firstly I should apologize for being a few days late, September was a busy month!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had the privilege and pleasure of joining a top notch panel discussion at &lt;a href="http://momo-ma.com/"&gt;'Mobile Monday Mid-Atlantic'&lt;/a&gt; talking about &lt;a href="http://momo-ma.com/?p=277"&gt;mobile strategy&lt;/a&gt;. For anyone in the Philadelphia area interested/participating in mobile development, Mobile Monday is a must attend event, they have some great topics coming soon and we had a great attendance for the panel discussion again. My thanks again to MOMO-MA for the opportunity to speak and to the audience for the great questions which drove our discussions. I posted my morning after thoughts on my &lt;a href="http://kgriff.posterous.com/mobile-monday-the-morning-after"&gt;blog&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So back to the mobile news, September saw an interesting trend in rumors regarding new Android Markets, both &lt;a href="http://blog.wirelessground.com/verizon-android-market/"&gt;Verizon&lt;/a&gt; and &lt;a href="http://techcrunch.com/2010/09/27/amazon-android-app-store/"&gt;Amazon(!?)&lt;/a&gt; were floated as potentially offering alternatives, perhaps fueling the fragmentation. Legit news about &lt;a href="http://android-developers.blogspot.com/2010/09/more-countries-more-sellers-more-buyers.html"&gt;Android Market expansion&lt;/a&gt; has them now featuring submissions from 20 new countries and taking paid markets up to 32 countries.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In a month where I got excited (yet again) over a new handset, the Nokia  &lt;a href="http://www.youtube.com/watch?v=xrXHXin9Iio&amp;amp;feature=channel"&gt;N8&lt;/a&gt; supposedly launching next month (running Symbian 3) coupled with the &lt;a href="http://www.callingallinnovators.com/10m/default.aspx"&gt;Nokia and AT&amp;amp;T developer competition&lt;/a&gt; got us thinking finally Nokia would get the respect they deserve here in the US. Then Samsung spoiled it all by announcing it's plans to &lt;a href="http://innovator.samsungmobile.com/bbs/tech/view.do?boardName=technology&amp;amp;messageId=99534"&gt;drop support&lt;/a&gt; at the years end, presumably to big up some WP7 love.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Speaking of WP7 love, I attended a Windows Phone 7 Fire-starter event here in Philly this month. My thoughts on that can be found on my &lt;a href="http://kgriff.posterous.com/wp7-wednesday-the-morning-ish-after"&gt;blog&lt;/a&gt;. They are also having a launch event this month (October 11th) which &lt;a href="http://www.engadget.com/2010/10/04/steve-ballmer-and-atandts-ralph-de-la-vega-to-headline-windows-ph/"&gt;engadget&lt;/a&gt; will be live at, check the details &lt;a href="http://www.engadget.com/2010/10/04/steve-ballmer-and-atandts-ralph-de-la-vega-to-headline-windows-ph/"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Time for some Chariot house keeping, we have been hard at work getting ready for ETE 2011 (oh yes, already) and we have some *outstanding* mobile speakers already which will be announced soon, along with the rest of the line up. We are starting a mobile seminar series here in Philadelphia, starting on November 9th featuring a variety of talks and discussions, aimed at helping business identify their mobile needs and how to fulfill them.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-4838849409301251511?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/4838849409301251511/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/10/monthly-mobile-musings-from-september.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4838849409301251511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/4838849409301251511'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/10/monthly-mobile-musings-from-september.html' title='Monthly Mobile Musings from September'/><author><name>Kevin Griffin</name><uri>http://www.blogger.com/profile/03251714915666161180</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-8136159973224988032</id><published>2010-09-16T11:40:00.000-04:00</published><updated>2010-09-21T16:04:55.378-04:00</updated><title type='text'>Setting up TeamCity CI w/ Cucumber, Flex, FunFX, and Firefox in a Headless Environment: Part Two</title><content type='html'>&lt;p&gt;Recently I had the “opportunity” (read: challenge) to setup a continuous integration build for a project with a Flex frontend and a Ruby/Rails backend. The project had been converted from Java-Hibernate-Tomcat to Ruby on Rails.  Cucumber was introduced for GUI testing using the FunFX adapter. It was my first experience with Cucumber, so the combination of Cucumber, FunFX, Flex, and Firefox was a little daunting at first. But we got through it and actually, it turned out to be quite an effective tool in our testing suite.&lt;/p&gt;&lt;p&gt;But the fun really started when I was tasked with building the TeamCity CI server for our project. And after it was all over, I felt I needed to document the trip so others might benefit from it, if not just for posterity. This is the second part of the two-part series on that journey.&lt;/p&gt;&lt;h3&gt;Continuing…&lt;/h3&gt;&lt;p&gt;In the first part we installed the open source software we are using: Java, Ruby, Rails, and all the required Ruby Gems, as well as the Flex 4.1.0 SDK, Firefox, FlashPlayer, and the Git client. The FunFX adapter for Cucumber uses JSSH to communicate with Firefox, so we configured and built Firefox with JSSH to run in a headless environment. We installed the latest Flex 4.1.0 SDK and the FlashPlayer 10.1 plugin for Firefox.&lt;/p&gt;&lt;p&gt;So what we have left is the installation and configuration of TeamCity itself as well as the setup of the build process for our Cucumber, Flex, and FunFX sample project.&lt;/p&gt;&lt;p&gt;So let’s get started.&lt;/p&gt;&lt;h3&gt;Install TeamCity&lt;/h3&gt;&lt;p&gt;Download the latest version of the Professional TeamCity software from the TeamCity web site for the appropriate platform. The Professional version is free but is limited in number of projects, build configurations, and users. We will only define one project and are well within the limit for build configurations.&lt;/p&gt;&lt;p&gt;We will be executing the installation instructions detailed on the TeamCity web site to install TeamCity bundled with the Tomcat servlet container on a Linux platform. They are relatively simple and are documented here. If you wish to install TeamCity to an existing Tomcat servlet container or on a different platform, please refer to the instructions for your specific environment.&lt;/p&gt;&lt;p&gt;We will be using the default admin user that we’ll define during installation. We will also be using HSQLDB and the default build agent. Most of the defaults will suffice for our installation.&lt;/p&gt;&lt;p&gt;Copy the TeamCity&lt;span style="font-family:courier new;"&gt; tar.gz&lt;/span&gt; file to the TeamCity server. SSH into the TeamCity server as yourself. Copy the TeamCity &lt;span style="font-family:courier new;"&gt;tar.gz&lt;/span&gt; file from &lt;span style="font-family:courier new;"&gt;/home/teamcity&lt;/span&gt; to &lt;span style="font-family:courier new;"&gt;/usr/local&lt;/span&gt;, unpackage the &lt;span style="font-family:courier new;"&gt;tar.gz&lt;/span&gt; file, and create a symlink to the TeamCity install directory. You will also need to change the owner of the TeamCity install directory to the 'teamcity' user.&lt;/p&gt;&lt;pre class="brush: bash;"&gt;$ cd /usr/local&lt;br /&gt;$ sudo cp /home/teamcity/TeamCity-5.1.3.tar.gz .&lt;br /&gt;$ sudo tar -xzvf TeamCity-5.1.3.tar.gz&lt;br /&gt;$ sudo ln -s TeamCity teamcity&lt;br /&gt;$ sudo chown -hR teamcity TeamCity&lt;/pre&gt;&lt;p&gt;Logout as yourself and SSH into the TeamCity server as the ‘teamcity’ user. We will run the TeamCity CI server under this ‘teamcity’ user.&lt;/p&gt;&lt;p&gt;Since there is no physical display device attached to the TeamCity server, we need to indicate to TeamCity it will be running in headless mode. This is done by setting TeamCity’s java.awt.headless Java options property to true. You can either create a setenv.sh file in the bin directory or add the statement to the catalina.sh file. If you are installing TeamCity to execute in an existing Tomcat servlet container, add the statement to the catalina.sh file in its Tomcat installation’s bin directory.&lt;/p&gt;&lt;pre class="brush: bash;"&gt;$ cd /usr/local/teamcity/bin&lt;br /&gt;$ echo 'JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"' &gt; setenv.sh&lt;br /&gt;$ chmod +x setenv.sh&lt;/pre&gt;&lt;p&gt;You should also set the &lt;span style="font-weight: bold;font-family:courier new;"&gt;TEAMCITY_SERVER_MEM_OPTS&lt;/span&gt; and &lt;span style="font-weight: bold;font-family:courier new;"&gt;TEAMCITY_AGENT_MEM_OPTS&lt;/span&gt; environment variables as described in the instructions for the TeamCity startup options. Although these values may vary according to your build requirements, we set our values as follows:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; TEAMCITY_SERVER_MEM_OPTS&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; -Xms512m -Xmx1024m -XX:MaxPermSize=1024m&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; TEAMCITY_AGENT_MEM_OPTS&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; -Xms512m -Xmx1024m -XX:MaxPermSize=1024m&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Start the server with the following command:&lt;/p&gt;&lt;pre class="brush: bash;"&gt;$ sh /usr/local/teamcity/bin/runAll.sh start&lt;/pre&gt;&lt;p&gt;Then bring up the TeamCity application in a local browser (&lt;span style="font-family:courier new;"&gt;http://localhost&lt;/span&gt;&lt;tc.server.ip.address&gt;&lt;span style="font-family:courier new;"&gt;:8111&lt;/span&gt;). When the application is initialized for the first time, you are presented with the licensing and conditions of use page. After agreeing to the license, you are prompted to create an administrator account. Fill in the fields as appropriate and create the account. If you log out of TeamCity, use the credentials created here to log back in.&lt;/tc.server.ip.address&gt;&lt;/p&gt;&lt;h3&gt;Create a CI Project&lt;/h3&gt;&lt;p&gt;After creating the administrator account, you are presented with the Projects page. Select the &lt;span style="font-style: italic;"&gt;Create Project&lt;/span&gt; link. Enter the appropriate values in the respective fields of the resulting screen:&lt;/p&gt;&lt;p&gt;&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; FC Converter&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Description:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Fahrenheit to Celsius Conversion project&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Create&lt;/span&gt; button.&lt;/p&gt;&lt;p&gt;Next we will associate the project with a version control system. Select the &lt;span style="font-style: italic;"&gt;VCS Roots&lt;/span&gt; tab and then the &lt;span style="font-style: italic;"&gt;+Create VCS root&lt;/span&gt; link.&lt;/p&gt;&lt;p&gt;Enter an appropriate VCS rootname and select the type of VCS from the dropdown.&lt;/p&gt;&lt;p&gt;The remainder of the screen is refreshed with the fields for the respective VCS. We are illustrating Git here. Enter / select as appropriate for the respective fields:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; VCS rootname:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; fc_converter-root&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Type of VCS:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Git (Jetbrains)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Fetch URL:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; git://github.com/landerson/FC-Converter.git&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Push URL:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;  (leave blank to use Fetch URL)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Branch name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; master&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Clone repository to:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; checkout&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; User Name Style:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Userid(jsmith)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Submodules:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Checkout&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Authentication Method:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Anonymous&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; User name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;  (leave blank)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Path to git:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; /usr/bin/git&lt;/span&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;(or as appropriate)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Clean Policy:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;  (as appropriate)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Checking Interval:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;  (as appropriate)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Test Connection&lt;/span&gt; button to test the SSH handshake with github. The test should succeed.  The test must succeed in order for the TeamCity build configuration to work properly. After the test succeeds, press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button.&lt;/p&gt;&lt;p&gt;Select the &lt;span style="font-style: italic;"&gt;General&lt;/span&gt; tab to return to the main project page. It is from this page that we will create the build configuration for this CI project.&lt;/p&gt;&lt;p&gt;We will create the following build configuration steps:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;checkout the project from the source repository and update the Ruby gems,&lt;/li&gt;&lt;li&gt;compile the Flex source modules,&lt;/li&gt;&lt;li&gt;restart the webserver, and&lt;/li&gt;&lt;li&gt;run the Cucumber FunFX tests.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;First we will create a build step to gather the sources and update any required Ruby Gems. Select the &lt;span style="font-style: italic;"&gt;+Create build configuration&lt;/span&gt; link. Enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;General Settings&lt;/span&gt; screen:&lt;/p&gt;&lt;p&gt;&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Step 1- Collect Sources&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Description: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Checkout sources and update gems.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Fail build if:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; check ‘an error message is logged by build runner’&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Leave the remaining fields blank or checked as-is to accept the defaults.&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;VCS Settings&lt;/span&gt; button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Version Control Settings &lt;/span&gt;screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; +Attach existing VCS root:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; fc_converter-root&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; VCS checkout mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Automatically on server&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Checkout directory:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; checkout&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; VCS labeling mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Do not label&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Choose VCS roots to label:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;  (leave blank- do not check)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;The “&lt;span style="font-family:courier new;"&gt;Automatically on server&lt;/span&gt;“ selection will cause the project source to be checked out of the source repository into the TeamCity project working directory.&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Choose Build Runner &lt;/span&gt;button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Build Runner&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Build runner:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Rake&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Rake tasks:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; gems:install&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Uncheck any &lt;span style="font-style: italic;"&gt;Attached reporters&lt;/span&gt; that may be checked and leave the remaining fields blank.&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button to create the build configuration. The screen is refreshed and should show the following message:&lt;/p&gt;&lt;p&gt;&lt;span style=" ;font-family:courier new;font-size:100%;"&gt;Build configuration "Step 1- Collect Sources" has been created successfully.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Select &lt;span style="font-style: italic;"&gt;FC Converter Project&lt;/span&gt; in the &lt;span style="font-style: italic;"&gt;Administration &gt; FC Converter Project &gt; Step 1 ...&lt;/span&gt; banner line just under the tabs at the top of the page to return to the main project page. If you named your project differently, your project ‘s name will appear in the banner line.&lt;/p&gt;&lt;p&gt;Next we will create a build step to compile the Flex source modules. Select the &lt;span style="font-style: italic;"&gt;+Create build configuration&lt;/span&gt; link. Enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;General Settings&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Step 2- Flex Compiles&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Description: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Compile the Flex source modules.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Fail build if: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; check ‘an error message is logged by build runner’&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Leave the remaining fields blank or checked as-is to accept the defaults.&lt;/p&gt;&lt;p&gt;Although we are not checking out the sources in this step (or any subsequent step), we still need to specify the VCS settings to tell TeamCity where the sources are, e.g., in the checkout directory. Press the &lt;span style="font-style: italic;"&gt;VCS Settings&lt;/span&gt; button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Version Control Settings&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; +Attach existing VCS root:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; fc_converter-root&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; VCS checkout mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Do not checkout files automatically&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Checkout directory:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; checkout&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; VCS labeling mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Do not label&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Choose VCS roots to label:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;  (leave blank)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Press the&lt;span style="font-style: italic;"&gt; Choose Build Runner&lt;/span&gt; button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Build Runner&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Build runner:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Rake&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Rake tasks:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; flex:compile&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Uncheck any &lt;span style="font-style: italic;"&gt;Attached reporters&lt;/span&gt; that may be checked and leave the remaining fields blank.&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button to create the build configuration. The screen is refreshed and should show the following message:&lt;/p&gt;&lt;p&gt;&lt;span style=" ;font-family:courier new;font-size:100%;"&gt;Build configuration "Step 2- Flex Compiles" has been created successfully.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Under the right hand column titled &lt;span style="font-style: italic;"&gt;Configuration Steps&lt;/span&gt;, select &lt;span style="font-style: italic;"&gt;6 Properties and Environment Variables&lt;/span&gt;. On the resulting screen, select &lt;span style="font-style: italic;"&gt;+Add new variable&lt;/span&gt; under &lt;span style="font-style: italic;"&gt;Environment Variables&lt;/span&gt;. Enter the following in the respective fields of the resulting screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; FLEX_HOME&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Value: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; /usr/local/flex_4_sdk&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;and press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button.&lt;/p&gt;&lt;p&gt;Again, select &lt;span style="font-style: italic;"&gt;FC Converter Project&lt;/span&gt; in the &lt;span style="font-style: italic;"&gt;Administration &gt; FC Converter Project &gt; Step 1 ...&lt;/span&gt; banner line just under the tabs at the top of the page to return to the main project page. If you named your project differently, your project ‘s name will appear in the banner line.&lt;/p&gt;&lt;p&gt;Next we will create a build step to restart the Rails web server. Select the &lt;span style="font-style: italic;"&gt;+Create build configuration&lt;/span&gt; link. Enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;General Settings&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Step 3- Restart the Web Server&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Description: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Stop and start the Rails web server.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Fail build if: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; check ‘an error message is logged by build runner’&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Leave the remaining fields blank or checked as-is to accept the defaults.&lt;/p&gt;&lt;p&gt;Although we are not checking out the sources in this step we still need to specify the VCS settings to tell TeamCity the sources are in the checkout directory. Press the &lt;span style="font-style: italic;"&gt;VCS Settings &lt;/span&gt;button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Version Control Settings&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; +Attach existing VCS root:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; fc_converter-root&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; VCS checkout mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Do not checkout files automatically&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Checkout directory:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; checkout&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; VCS labeling mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Do not label&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Choose VCS roots to label:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;  (leave blank)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Choose Build Runner&lt;/span&gt; button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Build Runner&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Build runner:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Rake&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Rake tasks:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; webserver:stop webserver:start&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Additional Rake command line parameters:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; RAILS_ENV=cucumber&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Uncheck any &lt;span style="font-style: italic;"&gt;Attached reporters&lt;/span&gt; that may be checked and leave the remaining fields blank.&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button to create the build configuration. The screen is refreshed and should show the following message:&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new;"&gt;Build configuration "Step 3- Restart the Web Server" has been created successfully.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Again, select &lt;span style="font-style: italic;"&gt;FC Converter Project&lt;/span&gt; in the &lt;span style="font-style: italic;"&gt;Administration &gt; FC Converter Project &gt; Step 1 ..&lt;/span&gt;. banner line just under the tabs at the top of the page to return to the main project page. If you named your project differently, your project ‘s name will appear in the banner line.&lt;/p&gt;&lt;p&gt;Finally, we will create a build step to run the Cucumber FunFX tests. Select the &lt;span style="font-style: italic;"&gt;+Create build configuration&lt;/span&gt; link. Enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;General Settings&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;&amp;nbsp;Step 4- Run Cucumber Tests&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Description: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; Run the Cucumber FunFX Tests.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt; Fail build if: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt; check ‘an error message is logged by build runner’&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Leave the remaining fields blank or checked as-is to accept the defaults.&lt;/p&gt;&lt;p&gt;Although we are not checking out the sources in this step we still need to specify the VCS settings to tell TeamCity the sources are in the checkout directory. Press the &lt;span style="font-style: italic;"&gt;VCS Settings&lt;/span&gt; button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Version Control Settings&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;+Attach existing VCS root:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;&amp;nbsp;fc_converter-root&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;VCS checkout mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;&amp;nbsp;Do not checkout files automatically&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;Checkout directory:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;&amp;nbsp;checkout&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;VCS labeling mode:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;&amp;nbsp;Do not label&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;Choose VCS roots to label:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;(leave blank)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Choose Build Runner&lt;/span&gt; button and enter the following in the respective fields of the resulting &lt;span style="font-style: italic;"&gt;Build Runner&lt;/span&gt; screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;Build runner:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;&amp;nbsp;Rake&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;&amp;nbsp;Rake tasks:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;&amp;nbsp;ci:features&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;Uncheck any &lt;span style="font-style: italic;"&gt;Attached reporters&lt;/span&gt; that may be checked and leave the remaining fields blank.&lt;/p&gt;&lt;p&gt;Press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button to create the build configuration. The screen is refreshed and should show the following message:&lt;p&gt;&lt;span style="font-family:courier new; font-size:100%;"&gt;Build configuration "Step 4- Run Cucumber Tests" has been created successfully.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Under the right hand column titled &lt;span style="font-style: italic;"&gt;Configuration Steps&lt;/span&gt;, select &lt;span style="font-style: italic;"&gt;6 Properties and Environment Variables&lt;/span&gt;. On the resulting screen, select &lt;span style="font-style: italic;"&gt;+Add new variable&lt;/span&gt; under &lt;span style="font-style: italic;"&gt;Environment Variables&lt;/span&gt;. Enter the following in the respective fields of the resulting screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;DISPLAY&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;Value: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;localhost:1.0&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;and press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button.&lt;/p&gt;&lt;p&gt;Again select &lt;span style="font-style: italic;"&gt;+Add new variable&lt;/span&gt; under &lt;span style="font-style: italic;"&gt;Environment Variables&lt;/span&gt;. Enter the following in the respective fields of the resulting screen:&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;Name:&lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;CUCUMBER_FORMAT&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="177"&gt;&lt;span style=";font-family:Times Roman;font-size:85%;"&gt;Value: &lt;/span&gt;&lt;/td&gt;&lt;td width="400"&gt;&lt;span style=";font-family:Courier;font-size:85%;"&gt;progress&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;and press the &lt;span style="font-style: italic;"&gt;Save&lt;/span&gt; button.&lt;/p&gt;&lt;p&gt;Select the &lt;span style="font-style: italic;"&gt;Projects&lt;/span&gt; tab in the top left of the screen to display the build configuration steps for the FC Converter project.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Perform First Build&lt;/h3&gt;&lt;p&gt;We’re now ready to execute our first build. We will use the first build configuration step we created to clone the project source for the first time.&lt;/p&gt;&lt;p&gt;To run the first step, press the &lt;span style="font-style: italic;"&gt;Run&lt;/span&gt; button to the left on the &lt;span style="font-style: italic;"&gt;Step 1- Collect Sources&lt;/span&gt; line. This will add the step to the build queue and it should begin executing immediately. You should see the '&lt;span style="font-style: italic;"&gt;Running:...&lt;/span&gt;' message underneath the step title line within seconds. When the step has completed, '&lt;span style="font-style: italic;"&gt;Running:...&lt;/span&gt;' should be replaced with &lt;span style="font-style: italic;"&gt;'Success'&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;To view the output of the build step, hover the mouse pointer over the down arrow adjacent to the 'Success' label and select the &lt;span style="font-style: italic;"&gt;'Full log'&lt;/span&gt; choice in the resulting drop down menu. Take note of the checkout directory in the log - we will reference this later.&lt;/p&gt;&lt;p&gt;&lt;table style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; width: 629px; height: 133px;" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top" width="479"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;[10:19:14]: Checkout directory: /usr/local/TeamCity/buildAgent/work/fc_converter&lt;br&gt;[10:19:14]: Updating sources: server side checkout...&lt;br&gt;[10:19:14]: [Updating sources: server side checkout...] Will perform clean checkout. Reason: Checkout directory is empty or doesn't exist&lt;br&gt;[10:19:14]: [Updating sources: server side checkout...] Building clean patch for VCS root: fc_converter-root&lt;br&gt;[10:19:14]: [Updating sources: server side checkout...] Repository sources transferred: 2.59Mb total&lt;br&gt;[10:19:14]: [Updating sources: server side checkout...] Removing /usr/local/TeamCity/buildAgent/work/fc_converter&lt;br&gt;[10:19:14]: [Updating sources: server side checkout...] Updating /usr/local/TeamCity/buildAgent/work/fc_converter&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;This is the directory that contains the source for the FC Converter project. Press the browser's back button to return to the FC Converter project page.&lt;/p&gt;&lt;p&gt;The remaining steps of the build process can be setup to automatically run after successful completion of the immediately previous step. We’ll describe how to do this using the second step as an example. Then you can repeat the process for the third and fourth steps, selecting the appropriate preceding step in each.&lt;/p&gt;&lt;p&gt;Hover the mouse pointer over the down arrow immediately following the title of the second step, &lt;span style="font-style: italic;"&gt;Step 2- Flex Compiles&lt;/span&gt;, to expose the dropdown menu. Select &lt;span style="font-style: italic;"&gt;Edit Settings&lt;/span&gt; from the dropdown menu and the &lt;span style="font-style: italic;"&gt;General Settings&lt;/span&gt; page for the step is displayed.&lt;/p&gt;&lt;p&gt;Select &lt;span style="font-style: italic;"&gt;Build Triggering&lt;/span&gt; from the list under the &lt;span style="font-style: italic;"&gt;Configuration Steps&lt;/span&gt; heading on the right margin of the page. We are going to add a build dependency trigger. Select the &lt;span style="font-style: italic;"&gt;+Add new trigger&lt;/span&gt; link and then select &lt;span style="font-style: italic;"&gt;Build Dependency Trigger&lt;/span&gt; in the &lt;span style="font-style: italic;"&gt;Trigger Type&lt;/span&gt; dropdown of the pop-up window. Select &lt;span style="font-style: italic;"&gt;Step 1- Collect Sources&lt;/span&gt; from the &lt;span style="font-style: italic;"&gt;Build Configuration&lt;/span&gt; drop down and press Save.&lt;/p&gt;&lt;p&gt;Select the &lt;span style="font-style: italic;"&gt;Projects&lt;/span&gt; tab at the top of the page to return to the FC Converter project page. Repeat the steps above starting with hovering the mouse pointer for the remaining two steps, selecting the previous step as a build dependency.&lt;/p&gt;&lt;p&gt;When you have finished setting the dependencies, press the &lt;span style="font-style: italic;"&gt;Run&lt;/span&gt; button in the right margin of the &lt;span style="font-style: italic;"&gt;Step 2- Flex Compiles&lt;/span&gt; step to launch the remainder of the build process. Each step will execute upon successful completion of the previous step. You can view the results of an individual step by hovering the mouse pointer over the down arrow immediately following the &lt;span style="font-style: italic;"&gt;‘Success’&lt;/span&gt; status label under the step title and selecting either &lt;span style="font-style: italic;"&gt;‘Short log’&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;‘Full log’&lt;/span&gt;.&lt;h3&gt;Points of Interest…&lt;/h3&gt;&lt;p&gt;Referencing the checkout source directory of the FC Converter project (&lt;span style="font-family:courier new;"&gt;/usr/local/TeamCity/buildAgent/work/fc_converter&lt;/span&gt;)…&lt;/p&gt;&lt;p&gt;In the &lt;span style="font-family:courier new;"&gt;features/support&lt;/span&gt; directory you will notice two files: &lt;span style="font-family:courier new;"&gt;env.rb&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;firewatir_firefox_patch.rb&lt;/span&gt;. Files in the &lt;span style="font-family:courier new;"&gt;support&lt;/span&gt; directory are loaded by Cucumber prior to running features. The purpose of &lt;span style="font-family:courier new;"&gt;env.rb&lt;/span&gt; is to set up the environment for running features. The purpose of &lt;span style="font-family:courier new;"&gt;firewatir_firefox_patch.rb&lt;/span&gt; is as its name indicates: a patch for the &lt;span style="font-style: italic;"&gt;FireWatir::Firefox&lt;/span&gt; class. The patch is to support a headless Firefox environment by pre-pending &lt;span style="font-family:courier new;"&gt;DISPLAY&lt;/span&gt; to the command that invokes Firefox.&lt;/p&gt;&lt;p&gt;The &lt;span style="font-style: italic;"&gt;features/step_definitions&lt;/span&gt; directory contains the &lt;span style="font-family:courier new;"&gt;fc_converter_steps.rb&lt;/span&gt; file which defines the templates for the Cucumber steps used in the&lt;span style="font-family:courier new;"&gt; features/fc_converter.feature&lt;/span&gt; file.&lt;/p&gt;&lt;p&gt;Some things you may want to investigate on your own:&lt;ol&gt;&lt;li&gt;Setting a build trigger for the first step dependent on SCM updates.&lt;/li&gt;&lt;li&gt;Adding more features and Cucumber steps to support them.&lt;/li&gt;&lt;li&gt;Generating some reports from the TeamCity server.&lt;/li&gt;&lt;li&gt;Setting up email notifications on successful and / or failed builds.&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Conclusion…&lt;/h3&gt;&lt;p&gt;Although our project is a very simple example of using Cucumber, Flex, FunFX, and Firefox, the purpose of this article is to illustrate the setup of the server environment to support a remote, headless, continuous integration environment.  And although it’s a little complex, it’s a once-and-done thing. Setting up TeamCity is relatively simple.&lt;/p&gt;&lt;p&gt;Hopefully the log of this journey has helped you in your quest to get Cucumber FunFX tests running in a remote CI environment.&lt;/p&gt;&lt;p&gt;Oh, and if you’re inclined, &lt;a href="http://www.chariotsolutions.com/"&gt;Chariot Solutions&lt;/a&gt; is running a &lt;a href="http://www.chariotsolutions.com/events/ci"&gt;CI event&lt;/a&gt; this fall.&lt;/p&gt;&lt;p&gt;In the future, look for a sister post to this one where we’ll use Hudson as our CI server.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1510447155903423878-8136159973224988032?l=blog.chariotsolutions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.chariotsolutions.com/feeds/8136159973224988032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.chariotsolutions.com/2010/09/setting-up-teamcity-ci-w-cucumber-flex_16.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8136159973224988032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1510447155903423878/posts/default/8136159973224988032'/><link rel='alternate' type='text/html' href='http://blog.chariotsolutions.com/2010/09/setting-up-teamcity-ci-w-cucumber-flex_16.html' title='Setting up TeamCity CI w/ Cucumber, Flex, FunFX, and Firefox in a Headless Environment: Part Two'/><author><name>Lyle Anderson</name><uri>http://www.blogger.com/profile/07374787798199533699</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1510447155903423878.post-6781207780926612889</id><published>2010-09-03T16:26:00.000-04:00</published><updated>2010-09-03T16:28:02.344-04:00</updated><title type='text'>Setting up TeamCity CI w/ Cucumber, Flex, FunFX, and Firefox in a Headless Environment: Part One</title><content type='html'>&lt;p&gt;&lt;style&gt; &lt;!--  /* Font Definitions */ @font-face  {font-family:"Courier New";  panose-1:2 7 3 9 2 2 5 2 4 4;  mso-font-charset:0;  mso-generic-font-family:auto;  mso-font-pitch:variable;  mso-font-signature:3 0 0 0 1 0;} @font-face  {font-family:Times;  panose-1:2 0 5 0 0 0 0 0 0 0;  mso-font-charset:0;  mso-generic-font-family:auto;  mso-font-pitch:variable;  mso-font-signature:3 0 0 0 1 0;} @font-face  {font-family:Wingdings;  panose-1:5 2 1 2 1 8 4 8 7 8;  mso-font-charset:2;  mso-generic-font-family:auto;  mso-font-pitch:variable;  mso-font-signature:0 0 65536 0 -2147483648 0;} @font-face  {font-family:Cambria;  panose-1:2 4 5 3 5 4 6 3 2 4;  mso-font-charset:0;  mso-generic-font-family:auto;  mso-font-pitch:variable;  mso-font-signature:3 0 0 0 1 0;}  /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal  {mso-style-parent:"";  margin:0in;  margin-bottom:.0001pt;  mso-pagination:widow-orphan;  font-size:12.0pt;  font-family:"Times New Roman";  mso-ascii-font-family:Cambria;  mso-ascii-theme-font:minor-latin;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Cambria;  mso-hansi-theme-font:minor-latin;  mso-bidi-font-family:"Times New Roman";  mso-bidi-theme-font:minor-bidi;} h3  {mso-style-link:"Heading 3 Char";  margin:0in;  margin-bottom:.0001pt;  mso-pagination:widow-orphan;  mso-outline-level:3;  font-size:13.5pt;  mso-bidi-font-size:10.0pt;  font-family:"Times New Roman";  mso-ascii-font-family:Times;  mso-hansi-font-family:Times;  mso-bidi-font-family:"Times New Roman";  mso-bidi-theme-font:minor-bidi;  font-weight:bold;  mso-bidi-font-weight:normal;} a:link, span.MsoHyperlink  {color:blue;  text-decoration:underline;  text-underline:single;} a:visited, span.MsoHyperlinkFollowed  {color:purple;  text-decoration:underline;  text-underline:single;} p  {margin:0in;  margin-bottom:.0001pt;  mso-pagination:widow-orphan;  font-size:10.0pt;  font-family:"Times New Roman";  mso-ascii-font-family:Times;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Times;  mso-bidi-font-family:"Times New Roman";} code  {font-family:Courier;  mso-ascii-font-family:Courier;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Courier;  mso-bidi-font-family:Courier;} pre  {mso-style-link:"HTML Preformatted Char";  margin:0in;  margin-bottom:.0001pt;  mso-pagination:widow-orphan;  tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt;  font-size:10.0pt;  font-family:Courier;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-bidi-font-family:Courier;} tt  {font-family:Courier;  mso-ascii-font-family:Courier;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Courier;  mso-bidi-font-family:Courier;} p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph  {margin-top:0in;  margin-right:0in;  margin-bottom:0in;  margin-left:.5in;  margin-bottom:.0001pt;  mso-add-space:auto;  mso-pagination:widow-orphan;  font-size:12.0pt;  font-family:"Times New Roman";  mso-ascii-font-family:Cambria;  mso-ascii-theme-font:minor-latin;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Cambria;  mso-hansi-theme-font:minor-latin;  mso-bidi-font-family:"Times New Roman";  mso-bidi-theme-font:minor-bidi;} p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst  {mso-style-type:export-only;  margin-top:0in;  margin-right:0in;  margin-bottom:0in;  margin-left:.5in;  margin-bottom:.0001pt;  mso-add-space:auto;  mso-pagination:widow-orphan;  font-size:12.0pt;  font-family:"Times New Roman";  mso-ascii-font-family:Cambria;  mso-ascii-theme-font:minor-latin;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Cambria;  mso-hansi-theme-font:minor-latin;  mso-bidi-font-family:"Times New Roman";  mso-bidi-theme-font:minor-bidi;} p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle  {mso-style-type:export-only;  margin-top:0in;  margin-right:0in;  margin-bottom:0in;  margin-left:.5in;  margin-bottom:.0001pt;  mso-add-space:auto;  mso-pagination:widow-orphan;  font-size:12.0pt;  font-family:"Times New Roman";  mso-ascii-font-family:Cambria;  mso-ascii-theme-font:minor-latin;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Cambria;  mso-hansi-theme-font:minor-latin;  mso-bidi-font-family:"Times New Roman";  mso-bidi-theme-font:minor-bidi;} p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast  {mso-style-type:export-only;  margin-top:0in;  margin-right:0in;  margin-bottom:0in;  margin-left:.5in;  margin-bottom:.0001pt;  mso-add-space:auto;  mso-pagination:widow-orphan;  font-size:12.0pt;  font-family:"Times New Roman";  mso-ascii-font-family:Cambria;  mso-ascii-theme-font:minor-latin;  mso-fareast-font-family:Cambria;  mso-fareast-theme-font:minor-latin;  mso-hansi-font-family:Cambria;  mso-hansi-theme-font:minor-latin;  mso-bidi-font-family:"Times New Roman";  mso-bidi-theme-font:minor-bidi;} span.Heading3Char  {mso-style-name:"Heading 3 Char";  mso-style-locked:yes;  mso-style-link:"Heading 3";  mso-ansi-font-size:13.5pt;  mso-bidi-font-size:10.0pt;  font-family:Times;  mso-ascii-font-family:Times;  mso-hansi-font-family:Times;  font-weight:bold;  mso-bidi-font-weight:normal;} span.HTMLPreformattedChar  {mso-style-name:"HTML Preformatted Char";  mso-style-locked:yes;  mso-style-link:"HTML Preformatted";  mso-ansi-font-size:10.0pt;  mso-bidi-font-size:10.0pt;  font-family:Courier;  mso-ascii-font-family:Courier;  mso-hansi-font-family:Courier;  mso-bidi-font-family:Courier;} @page Section1  {size:8.5in 11.0in;  margin:1.0in 1.25in 1.0in 1.25in;  mso-header-margin:.5in;  mso-footer-margin:.5in;  mso-paper-source:0;} div.Section1  {page:Section1;}  /* List Definitions */ @list l0  {mso-list-id:129977086;  mso-list-type:hybrid;  mso-list-template-ids:1708848224 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l0:level1  {mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;} @list l1  {mso-list-id:132456188;  mso-list-template-ids:-1032258536;} @list l2  {mso-list-id:435640758;  mso-list-type:hybrid;  mso-list-template-ids:-1146333178 67698691 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;} @list l2:level1  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} @list l3  {mso-list-id:597057430;  mso-list-template-ids:2082250810;} @list l3:level1  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:.5in;  mso-level-number-position:left;  text-indent:-.25in;  mso-ansi-font-size:10.0pt;  font-family:Symbol;} @list l4  {mso-list-id:925186514;  mso-list-template-ids:52209174;} @list l4:level1  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Symbol;} @list l4:level2  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} @list l4:level3  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Wingdings;} @list l4:level4  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Symbol;} @list l4:level5  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} @list l4:level6  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Wingdings;} @list l4:level7  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Symbol;} @list l4:level8  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} @list l4:level9  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Wingdings;} @list l5  {mso-list-id:1057313997;  mso-list-template-ids:-26855184;} @list l5:level1  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:.5in;  mso-level-number-position:left;  text-indent:-.25in;  mso-ansi-font-size:10.0pt;  font-family:Symbol;} @list l6  {mso-list-id:1065883642;  mso-list-type:hybrid;  mso-list-template-ids:52209174 67698689 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;} @list l6:level1  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Symbol;} @list l7  {mso-list-id:1168525026;  mso-list-template-ids:52209174;} @list l7:level1  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Symbol;} @list l7:level2  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} @list l7:level3  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Wingdings;} @list l7:level4  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Symbol;} @list l7:level5  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} @list l7:level6  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Wingdings;} @list l7:level7  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Symbol;} @list l7:level8  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} @list l7:level9  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:Wingdings;} @list l8  {mso-list-id:1354964890;  mso-list-type:hybrid;  mso-list-template-ids:-800055970 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l8:level1  {mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;} @list l9  {mso-list-id:1506746692;  mso-list-template-ids:-1410059606;} @list l9:level1  {mso-level-number-format:bullet;  mso-level-text:;  mso-level-tab-stop:.5in;  mso-level-number-position:left;  text-indent:-.25in;  mso-ansi-font-size:10.0pt;  font-family:Symbol;} @list l10  {mso-list-id:1515147528;  mso-list-type:hybrid;  mso-list-template-ids:-1033338452 67698691 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;} @list l10:level1  {mso-level-number-format:bullet;  mso-level-text:o;  mso-level-tab-stop:none;  mso-level-number-position:left;  text-indent:-.25in;  font-family:"Courier New";} ol  {margin-bottom:0in;} ul  {margin-bottom:0in;} --&gt; &lt;/style&gt;     &lt;/p&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;Recently I had the “opportunity” (read: challenge) to setup a continuous integration build for a project with a Flex frontend and a Ruby/Rails backend. The project had been converted from Java-Hibernate-Tomcat to Ruby on Rails. &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; was introduced for GUI testing using the &lt;a href="http://wiki.github.com/aslakhellesoy/cucumber/funfx-and-flex"&gt;FunFX&lt;/a&gt; adapter. It was my first experience with Cucumber, so the combination of Cucumber, FunFX, &lt;a href="http://www.adobe.com/products/flex/overview/"&gt;Flex&lt;/a&gt;, and Firefox was a little daunting at first. But we got through it and, actually, it turned out to be quite an effective tool in our testing suite.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;But the fun really started when I was tasked with building the &lt;a href="http://www.jetbrains.com/teamcity"&gt;TeamCity&lt;/a&gt; CI server for our project. I scoured the blogs and tech sites for anything about CI builds of a Flex-Ruby/Rails project with Cucumber and FunFX. I found bits and pieces, like how to setup Firefox in a headless environment and how to setup TeamCity in a headless environment. So I filled in the rest around that to get the TeamCity server up and running with a continuous integration build for our project.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;So why is a headless environment required? Our TeamCity CI server was a remote server- there is no input device or display device. So all of the setup was done via SSH through a VPN.  But more importantly, we needed a headless implementation since FunFX requires browser interaction.  FunFX “attaches” itself to a browser (via JSSH) so we needed a windowing emulator. We use the X virtual frame buffer of the X Window System (Xvfb) for this purpose (more about Xvfb at &lt;a href="http://en.wikipedia.org/wiki/Xvfb"&gt;http://en.wikipedia.org/wiki/Xvfb&lt;/a&gt;).&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;After it was all over, I felt I needed to document it, if not just for posterity, but also so others might benefit. Since setting up the environment is as much an effort as setting up TeamCity, I decided to break it into two parts. So we’ll cover the basics of setting up the server in this first part and then in the second part we’ll tackle getting TeamCity set up. I hope you enjoy the trip as much as I did. &lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;We're using a Debian-based system in this prensentation. We’re going to assume you’re familiar with your operating system and know what most of these commands are. Hopefully you can translate to your operating system, if different.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;Basically, this is what we need to do:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpFirst" style="margin-left: 0.25in; text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:Symbol;" &gt;·&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Install Java&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="margin-left: 0.25in; text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:Symbol;" &gt;·&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Install Ruby and Rails&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="margin-left: 0.25in; text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:Symbol;" &gt;·&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Install Flex SDK&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="margin-left: 0.25in; text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:Symbol;" &gt;·&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Install and Configure Firefox&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:&amp;quot;Courier New&amp;quot;;" &gt;o&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Test JSSH&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:&amp;quot;Courier New&amp;quot;;" &gt;o&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Install FlashPlayer&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="margin-left: 0.25in; text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:Symbol;" &gt;·&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Install the SCM Client&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="margin-left: 0.25in; text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:Symbol;" &gt;·&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Install TeamCity&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:&amp;quot;Courier New&amp;quot;;" &gt;o&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Create the CI project&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:&amp;quot;Courier New&amp;quot;;" &gt;o&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Create the build steps&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpMiddle" style="text-indent: -0.25in;"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;font-family:&amp;quot;Courier New&amp;quot;;" &gt;o&lt;span style="font-size-adjust: none; font-size: 7pt; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;font-family:&amp;quot;Times New Roman&amp;quot;;" &gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt;Run the build&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoListParagraphCxSpLast"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size:180%;"&gt;So Let’s Get Started…&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;Because our Flex-Ruby/Rails project was a bit more complicated than what’s needed, plus it involved other requirements that do not need to be documented here, we’re going to use a small sample project, FC_Convert, an interface to convert Fahrenheit to Celsius. I have uploaded the project to my public github account and we reference it in these procedures.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;First create a user account on the TeamCity server for the ‘teamcity’ user. This will create a&lt;/span&gt;&lt;span style="font-size: 10pt;font-family:Courier;" &gt; /home/teamcity&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt; directory which we will be using.  All downloads are to a local workstation and then copied to this home directory of the ‘teamcity’ user on the TeamCity server. It is assumed you will also have your own account on the TeamCity server with sudo capability that you can use to SSH for all of these tasks.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size:180%;"&gt;Install Java&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;Since this is a Ruby/Rails and Flex project, we do not need the JDK. For our project we are installing the JRE since TeamCity requires either the JRE or a JDK. If your build process requires Java, you’ll need to install the JDK. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;Visit the &lt;a href="http://www.sun.com/java/"&gt;Java website&lt;/a&gt; and download either the JRE or the JDK for the operating platform of your TeamCity server. Install the JRE or JDK per the installation instructions. In addition to adding the Java &lt;/span&gt;&lt;span style="font-size: 10pt;font-family:Courier;" &gt;bin&lt;/span&gt;&lt;span style="font-size: 11pt;"&gt; directory to the PATH environment variable, don’t forget to set the JAVA_HOME environment variable to point to the Java installation directory- TeamCity requires it.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size:180%;"&gt;Install Ruby and Rails&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;As of this writing, the latest version of FunFX (0.2.2) had a conflict with Ruby 1.9.1. Ruby 1.9.1 now includes FasterCSV but with renamed variables and methods. If you install Ruby 1.9.1 and then run FunFX, you will get the following message:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;table class="MsoTableGrid" style="border: medium none ; background: rgb(217, 217, 217) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt; &lt;tr&gt;   &lt;td style="border: 1pt none ; padding: 0in 5.4pt; width: 6.65in;" valign="top" width="479"&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 10pt;font-family:Courier;" &gt;Please   switch to Ruby 1.9's standard CSV library. It's FasterCSV plus support for   Ruby 1.9's m17n encoding engine. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;FunFX uses the FasterCSV library and requires modification to run with Ruby 1.9.1. Since there are no features of Ruby 1.9.1 that we need for this project, we are installing Ruby 1.8.7 instead. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;Installing Ruby and Rails is pretty straightforward. Depending on the platform of the server, Ruby can be installed as a set of pre-compiled executables (Windows) or compiled for the specific platform (Linux, Unix). The distribution files for Ruby installation can be found on the Ruby &lt;a href="http://www.ruby-lang.org/en/downloads/"&gt;downloads&lt;/a&gt; web page. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;And if your server’s operating system has a package installer, i.e., apt-get or yum, it’s even easier to install the latest version of Ruby 1.8:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;table class="MsoTableGrid" style="border: medium none ; background: rgb(217, 217, 217) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt; &lt;tr&gt;   &lt;td style="border: 1pt none ; padding: 0in 5.4pt; width: 6.15in;" valign="top" width="443"&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 10pt;font-family:Courier;" &gt;$ sudo apt-get install ruby-full&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 11pt;"&gt;Otherwise, download the source tar, unpackage it, and then configure, build, and install Ruby.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;table class="MsoTableGrid" style="border: medium none ; background: rgb(217, 217, 217) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt; &lt;tr&gt;   &lt;td style="border: 1pt none ; padding: 0in 5.4pt; width: 6.15in;" valign="top" width="443"&gt;&lt;div style="margin: 0.1pt 0in;"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div style="margin: 0.1pt 0in;"&gt;&lt;p&gt;&lt;span style="font-family:Courier;"&gt;$ cd /usr/local/src&lt;br /&gt;$ sudo cp /home/teamcity/ruby-1.8.7-p302.tgz .&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div style="margin: 0.1pt 0in;"&gt;&lt;p&gt;&lt;span style="font-family:Courier;"&gt;$ sudo tar -xzvf ruby-1.8.7-p302.tgz&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 10pt;font-family:Courier;" &gt;$ cd ruby-1.8.7-p302&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;span style="font-size: 10pt;font-family:Courier;" &gt;$ sudo ./configure&lt;br /&gt;$ sudo make&lt;br /&gt;$ sudo make install&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;div class="MsoNo
