<?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-1280619439915049383</id><updated>2012-01-30T17:46:31.500-06:00</updated><category term='logging'/><category term='bpel'/><category term='nio'/><category term='yahoo pipes'/><category term='cli'/><category term='javascript'/><category term='sailfin'/><category term='unit'/><category term='spring-security'/><category term='junit'/><category term='grizzly'/><category term='glassfish'/><category term='jira'/><category term='jersey'/><category term='maven'/><category term='markupbuilder'/><category term='jbi'/><category term='sip'/><category term='wsdl'/><category term='library'/><category term='sencha'/><category term='ejb3.0'/><category term='dzone'/><category term='uddi-bc'/><category term='grails'/><category term='yugma'/><category term='iphone'/><category term='rss-bc'/><category term='evergreen'/><category term='opensource'/><category term='git'/><category term='jetty'/><category term='websphere'/><category term='rss'/><category term='rails'/><category term='ci'/><category term='virtual'/><category term='tdd'/><category term='spring-insight'/><category term='safari'/><category term='xmlunit'/><category term='linux'/><category term='acegi'/><category term='dependency injection'/><category term='idea'/><category term='centos'/><category term='charts'/><category term='soap'/><category term='java'/><category term='webservices'/><category term='security now'/><category term='dvcs'/><category term='esb'/><category term='ubiquity'/><category term='lucene'/><category term='xslt'/><category term='hudson'/><category term='maven2'/><category term='sip-bc'/><category term='oracle'/><category term='jmeter'/><category term='netbeans'/><category term='rest'/><category term='icefaces'/><category term='appengine'/><category term='groovy'/><category term='javaee'/><category term='archetypes'/><category term='history'/><category term='ssl'/><category term='jboss'/><category term='mvnsh'/><category term='release'/><category term='ubuntu'/><category term='j2ee'/><category term='openesb'/><category term='mercurial'/><category term='vcs'/><category term='extjs'/><category term='json'/><category term='svn'/><category term='servicemix'/><title type='text'>James Lorenzen's Blog</title><subtitle type='html'>The beatings will continue until morale improves.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default?start-index=101&amp;max-results=100'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>133</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-510535543388472070</id><published>2011-04-05T23:11:00.006-05:00</published><updated>2011-04-05T23:22:50.824-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><title type='text'>What's missing from our REST Services?</title><content type='html'>While reading the excellent book &lt;a href="http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260"&gt;RESTful Web Services&lt;/a&gt; I discovered something. A technique used on the web since its beginning. &lt;a href="http://apiwiki.twitter.com/w/page/22554679/Twitter-API-Documentation"&gt;Twitter&lt;/a&gt; and &lt;a href="https://developers.facebook.com/docs/reference/api/"&gt;Facebook&lt;/a&gt; seem to use it. Yet it was absent in the REST Services I had been developing and if I had to guess most REST developers aren't including it either. What is so valuable the Internet would be useless without it? The answer is &lt;a href="http://en.wikipedia.org/wiki/Hypermedia"&gt;hypermedia&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Hypermedia is the technical term used to describe how web pages (resources) are linked or connected. The author of RESTful Web Services calls it &lt;i&gt;connectedness&lt;/i&gt;: how the server guides the client from one application state to another by providing links. A good example of a well-connected application is &lt;a href="http://www.wikipedia.org/"&gt;Wikipedia&lt;/a&gt;. It's very powerful when you could pick a random page and click through every entry on Wikipedia without ever editing your browsers URL. Performing a search on Google is another great example, as it wouldn't be very useful if the search result didn't include any links. Without these links, the client must know and create predefined rules to build every URL it wants to visit.&lt;br /&gt;&lt;br /&gt;So what do links on a website have to do with REST Services? REST was built on the foundation of the web and just because your not returning HTML doesn't mean you shouldn't create relationships between your resources. In fact, it's amazing how powerful embedding links in your responses can be. For instance, it prevents tight coupling between your clients and services as the clients don't have to construct or even know the exact URLs because the services are providing them.&lt;br /&gt;&lt;br /&gt;Let's use Twitter as an example. Assume the following is the URL to get the 20 most recent tweets for my account:&lt;br /&gt;&lt;br /&gt;http://api.twitter.com/1/statuses/user_timeline.json?screen_name=jlorenzen&lt;br /&gt;&lt;br /&gt;And here is a shortened &lt;span class="hw"&gt;fictitious response:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: js"&gt;[&lt;br /&gt;    {&lt;br /&gt;        "text": "Finished watching Battlestar Galatica"&lt;br /&gt;        "id": "55947977415667712"&lt;br /&gt;        "url": "http://api.twitter.com/1/statuses/show/55947977415667712.json"&lt;br /&gt;    },&lt;br /&gt;    {&lt;br /&gt;        "text": "Started watching Battlestar Galatica"&lt;br /&gt;        "id": "45947977415667712"&lt;br /&gt;        "url": "http://api.twitter.com/1/statuses/show/45947977415667712.json"&lt;br /&gt;    }&lt;br /&gt;]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="hw"&gt;Notice each tweet includes a direct URL. Now clients can use that URL value verses constructing it, and if it changes in the future, clients don't have to make any changes.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hw"&gt;&lt;b&gt;Example using Jersey&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="hw"&gt;So what is the best way to include links in your REST Services? Since I use &lt;a href="http://jersey.java.net/"&gt;Jersey&lt;/a&gt; on a daily basis, I'll go ahead and show an example of how to embed links in your responses using Jersey. Most likely, any REST framework is going to provide the same kind of features.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="hw"&gt;Using the twitter example above, the User Status Service with links may look something like this (using groovy):&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;import javax.ws.rs.GET&lt;br /&gt;import javax.ws.rs.Path&lt;br /&gt;import javax.ws.rs.Produces&lt;br /&gt;import javax.ws.rs.QueryParam&lt;br /&gt;import javax.ws.rs.core.Context&lt;br /&gt;import javax.ws.rs.core.UriInfo&lt;br /&gt;&lt;br /&gt;import com.test.UserStatuses&lt;br /&gt;&lt;br /&gt;@Path("/statuses")&lt;br /&gt;class StatusesResource {&lt;br /&gt; &lt;br /&gt;    @Context &lt;br /&gt;    UriInfo uriInfo&lt;br /&gt;&lt;br /&gt;    @GET&lt;br /&gt;    @Path("/user_timeline")&lt;br /&gt;    @Produces(["application/json", "application/xml"])&lt;br /&gt;    def UserStatuses getUserTimeline(@QueryParam("screen_name")String screen_name) {&lt;br /&gt;        def statuses = getStatuses(screen_name)&lt;br /&gt;        &lt;br /&gt;        statuses.each {&lt;br /&gt;            it.url = "${uriInfo.baseUri}statuses/show/$it.id"&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        return new UserStatuses(statuses: statuses)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this simple example, Jersey injects the UriInfo object which we use to get the baseUri of the request. It's really that simple.&lt;br /&gt;&lt;br /&gt;&lt;span class="hw"&gt; &lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="hw"&gt;Potential Issues&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span class="hw"&gt;Well for some it may not be that simple. For example, we discovered an issue when using a reverse proxy (apache httpd). In our production environments, we typically setup apache on port 80 to proxy a localhost JBoss on port 8080. Unfortunately, in this setup the UriInfo.getBaseUri() returns localhost:8080 and not the actual original URL the client used; which is obviously not good. Now if you don't use a reverse proxy then no worries. However, if you do or might potentially in the future, a easy solution seems to be to set the Apache Proxy module option &lt;a href="http://httpd.apache.org/docs/2.0/mod/mod_proxy.html#proxypreservehost"&gt;ProxyPreserveHost&lt;/a&gt; to On. Setting this to On and restarting Apache seems to fix the issue.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="hw"&gt;JSONView Firefox Plugin&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span class="hw"&gt;Once you've started embedding URLs in your REST responses, you might find it useful to install the &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/jsonview/"&gt;JSONView&lt;/a&gt; firefox plugin. It's got some really slick features like formatting the JSON and creating clickable links for URLs.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-CDPU1BtyXfs/TZvmJUmzrBI/AAAAAAAAAMw/zaTzFbvORnM/s1600/TwitterService-JSONView2.png" imageanchor="1"&gt;&lt;img border="0" height="186" src="http://3.bp.blogspot.com/-CDPU1BtyXfs/TZvmJUmzrBI/AAAAAAAAAMw/zaTzFbvORnM/s400/TwitterService-JSONView2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-510535543388472070?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/510535543388472070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/510535543388472070'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2011/04/whats-missing-from-our-rest-services.html' title='What&apos;s missing from our REST Services?'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-CDPU1BtyXfs/TZvmJUmzrBI/AAAAAAAAAMw/zaTzFbvORnM/s72-c/TwitterService-JSONView2.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8849759830560131752</id><published>2010-10-01T13:07:00.000-05:00</published><updated>2010-10-01T13:07:09.328-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='charts'/><category scheme='http://www.blogger.com/atom/ns#' term='sencha'/><category scheme='http://www.blogger.com/atom/ns#' term='extjs'/><title type='text'>How to Change Extjs PieChart Colors</title><content type='html'>When using Sencha's, or extjs, charting capability, most likely your going to want to change the default color scheme. I was faced with this issue today and it's not documented as well as you'd expect. I had to piece together a few articles and I'm still not 100% it's the right way as it's using an undocumented config option. But I wanted to document how I did get it to work to same others some time.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sencha.com/"&gt;Sencha&lt;/a&gt; is very well documented and their &lt;a href="http://dev.sencha.com/deploy/dev/examples/"&gt;examples&lt;/a&gt; are great. Here is the &lt;a href="http://dev.sencha.com/deploy/dev/examples/chart/pie-chart.html"&gt;Pie Chart example&lt;/a&gt; we are going to be updating (using version 3.2.1). For those that don't know, extjs charts are based off of Yahoo's &lt;a href="http://developer.yahoo.com/yui/charts/"&gt;YUI charts&lt;/a&gt; which is also requires Flash. Not only is it pretty simple to create charts with extjs, but we already are using extjs so we decided to prototype some charts using it.&lt;br /&gt;&lt;br /&gt;Here is the code that produces a simple basic PieChart:&lt;br /&gt;&lt;pre class="brush: js"&gt;new Ext.Panel({&lt;br /&gt;    width: 400,&lt;br /&gt;    height: 400,&lt;br /&gt;    title: 'Pie Chart with Legend - Favorite Season',&lt;br /&gt;    renderTo: 'container',&lt;br /&gt;    items: {&lt;br /&gt;        store: store,&lt;br /&gt;        xtype: 'piechart',&lt;br /&gt;        dataField: 'total',&lt;br /&gt;        categoryField: 'season',&lt;br /&gt;        extraStyle:&lt;br /&gt;        {&lt;br /&gt;            legend:&lt;br /&gt;            {&lt;br /&gt;                display: 'bottom',&lt;br /&gt;                padding: 5,&lt;br /&gt;                font:&lt;br /&gt;                {&lt;br /&gt;                    family: 'Tahoma',&lt;br /&gt;                    size: 13&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;});&amp;nbsp;&lt;/pre&gt;&lt;br /&gt;This produces the following &lt;a href="http://dev.sencha.com/deploy/dev/examples/chart/pie-chart.html"&gt;PieChart&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To change the default colors provide a series config option:&lt;br /&gt;&lt;pre class="brush: js; highlight: [11, 12, 13, 14, 15]"&gt;new Ext.Panel({&lt;br /&gt;    width: 400,&lt;br /&gt;    height: 400,&lt;br /&gt;    title: 'Pie Chart with Legend - Favorite Season',&lt;br /&gt;    renderTo: 'container',&lt;br /&gt;    items: {&lt;br /&gt;        store: store,&lt;br /&gt;        xtype: 'piechart',&lt;br /&gt;        dataField: 'total',&lt;br /&gt;        categoryField: 'season',&lt;br /&gt;        series: [{&lt;br /&gt;            style: {&lt;br /&gt;                colors: ["#ff2400", "#94660e", "#00b8bf", "#edff9f"]&lt;br /&gt;            }&lt;br /&gt;        }],&lt;br /&gt;        extraStyle:&lt;br /&gt;        {&lt;br /&gt;            legend:&lt;br /&gt;            {&lt;br /&gt;                display: 'bottom',&lt;br /&gt;                padding: 5,&lt;br /&gt;                font:&lt;br /&gt;                {&lt;br /&gt;                    family: 'Tahoma',&lt;br /&gt;                    size: 13&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;The chart it produces may not look the most appealing but at least we figured out how to change the colors.&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;img border="0" height="187" src="http://1.bp.blogspot.com/_u6FjI-f0VoU/TKYhoXlPvBI/AAAAAAAAAMM/dnCSI49eTKE/s200/piechart-newcolors.png" style="margin-left: auto; margin-right: auto;" width="200" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Pie Chart with New Colors&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_u6FjI-f0VoU/TKYhoXlPvBI/AAAAAAAAAMM/dnCSI49eTKE/s1600/piechart-newcolors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Again, I'm not certain this is the best way to accomplish this as the series config option isn't &lt;a href="http://dev.sencha.com/deploy/dev/docs/output/Ext.chart.PieChart.html#Ext.chart.PieChart-configs"&gt;documented in 3.2.1&lt;/a&gt;. But by piecing together this &lt;a href="http://www.sencha.com/forum/showthread.php?91476-Pie-Chart&amp;amp;highlight=chart+change+colors"&gt;PieChart question&lt;/a&gt; and this &lt;a href="http://miamicoder.com/post/2009/10/Custom-Markers-for-Your-Ext-JS-Charts.aspx"&gt;article&lt;/a&gt;, I was able to figure it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8849759830560131752?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8849759830560131752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8849759830560131752'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/10/how-to-change-extjs-piechart-colors.html' title='How to Change Extjs PieChart Colors'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_u6FjI-f0VoU/TKYhoXlPvBI/AAAAAAAAAMM/dnCSI49eTKE/s72-c/piechart-newcolors.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6780099483875806980</id><published>2010-08-19T21:49:00.000-05:00</published><updated>2010-08-19T21:49:20.212-05:00</updated><title type='text'>Missing Office Equipment Prank</title><content type='html'>Here is Part 2 of my &lt;a href="http://jlorenzen.blogspot.com/2010/08/real-man-of-genius.html"&gt;series&lt;/a&gt; where I reminisce about the good times I had at Williams. As I stated previously, I came across these printed off emails in our attic while moving to our new home. I'm so glad I printed them off. #goodtimes&lt;br /&gt;&lt;br /&gt;Anyway, this was a prank Keith Stanek, Josh Guthman (Guthy), and myself pulled on Michael Brotherman (Are you Miking Me?). Before showing you the email though I need to set the stage. The year was 2003, and our company had just gone through 3 rounds of layoffs. Morale was pretty low. We worked on the 32nd floor of the 52 story BOK building in downtown Tulsa, Oklahoma. During fire drills we had to take the stairs down a floor. During one of the fire drills we noticed the entire 31st floor was void of humans, but a lot of very nice unused office furniture and white boards were still present. We joked around about repurposing some of the nicer equipment, but nothing ever come of it. Until one morning, we noticed Mike had a new chair. A very nice new chair. We gave him junk about it all day, but decided a prank would be better. So we had Josh Guthman (Guthy) write us up a believable email that Keith and I would spoof using the Facilities email address. Here it is:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;From&lt;/b&gt;: Facilities Services-Tulsa&lt;br /&gt;&lt;b&gt;Sent&lt;/b&gt;: Thursday, March 13, 2003 7:39AM&lt;br /&gt;&lt;b&gt;Subject&lt;/b&gt;: Missing Office Equipment&lt;br /&gt;&lt;br /&gt;During a recent audit for unused office equipment we discovered black reclining office chairs were missing from several of the floors in the BOK tower. Upon further investigation we discovered those chairs had been procured by current employees looking to upgrade from their existing chairs. While facilities appreciates your desire to utilize existing assets instead of requisitioning new ones, please remember that Williams is undergoing a cost savings campaign at this time and that all unused equipment needs to remain on its respective floor for proper accounting and redistribution either to the lessee or to an employee in need. If we have not already reacquired your chair, please return it to the floor from which it came by the end of business Friday, March 14.&lt;br /&gt;&lt;br /&gt;Mike smelled it out, but noone ever confessed, and I'm pretty sure deep down, even though his gut was telling him it was a prank, he still didn't want to take the chance in the possibility that it might have been true. The best part about it was the morning we sent the email, Mike and I had a group breakfast meeting with one of the Senior Executives. As we were going down the elevator, he mentioned to me that he was going to bring it up during the meeting, and with a complete straight face I called his bluff and told him that I think he should, knowing that he wouldn't anyway; and if he did it would only make the prank that much better.&lt;br /&gt;&lt;br /&gt;Mike returned the chair.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-6780099483875806980?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6780099483875806980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6780099483875806980'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/08/missing-office-equipment-prank.html' title='Missing Office Equipment Prank'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-51872540511970355</id><published>2010-08-18T21:28:00.000-05:00</published><updated>2010-08-18T21:28:45.664-05:00</updated><title type='text'>Real man of Genius</title><content type='html'>I usually keep this blog professional, but I'm in the process of moving and came across some emails that I just have to share and they are too long to post on facebook. All 3 emails where from my time at The Williams Company in Tulsa, OK where I had the privilege to work with some great friends. People like Keith Stanek, Michael Brotherman (Are you Miking me?), Jason Randall, Josh Guthman (Guthy), Erin Nylund, Becca Fairchild, Jennifer Brandt, and a host of others. I was so fortunate to work with these people and I'm not sure it could ever be duplicated. We had a ton of fun together. During off hours we played a lot of cards (Rook mainly), Starcraft I, and lots and lots of Halflife. Over time, I got to be pretty good at Halflife (HL). At some point we started playing 2 (Keith and Mike) on one and I still would usually win.&lt;br /&gt;&lt;br /&gt;Now to the email. Wednesday August 20, 2003 at 9:45 AM, Michael Brotherman emailed Keith and me his Real man of Genius in my honor. It was done just like the &lt;a href="http://budlight.whipnet.com/"&gt;Real Men Of Genius commercials&lt;/a&gt;. Here it is in it's original form:&lt;br /&gt;&lt;br /&gt;Mr real man of genius...&lt;br /&gt;We solute you, Mr. Total Conqueror in HL.&lt;br /&gt;You who drops bombs that are not in the bathroom.&lt;br /&gt;Who shoots your double barrel in our face.&lt;br /&gt;&lt;br /&gt;Your eyes keep us from getting caught,&lt;br /&gt;But your play keeps us from coming back.&lt;br /&gt;&lt;br /&gt;Here's to you...Mr crossbow no miss,&lt;br /&gt;Mr. Ray gun who makes it no fun.&lt;br /&gt;&lt;br /&gt;We solute you.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My Favorite weapon was the crossbow. Oh good times. Stayed tuned. I've got 2 more coming.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-51872540511970355?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/51872540511970355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/51872540511970355'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/08/real-man-of-genius.html' title='Real man of Genius'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8937840818543986</id><published>2010-08-14T23:20:00.000-05:00</published><updated>2010-08-14T23:20:28.667-05:00</updated><title type='text'>Hash tags in Commit Comments</title><content type='html'>I've been using Yammer, Twitter, and Facebook consistently for awhile now. One of the things I really like are hash tags, where yams or tweets include additional meta information in the comment such as #groovy, #hudson, or #maven. One of the main purposes of hash tags, is it allows others to subscribe to an area of interest verses subscribing to hundreds of individual people. Another purpose it serves, is determining interest value; sort of like a subject heading. Since hash tags are typically at the end of a tweet or yam, I usually read the end first before I commit to reading the whole yam or tweet. I don't follow a ton of people yet, but I do consume a lot of information in a day and in order to find the good I have to wade through the bad. Using hash tags aides in this process.&lt;br /&gt;&lt;br /&gt;I also think hash tags could help in another area: commit comments. It's something important I've &lt;a href="http://jlorenzen.blogspot.com/2010/02/commit-comments-conversation-with-your.html"&gt;mentioned&lt;/a&gt; before, and I think hash tags can be useful in commit comments even if there aren't any tools yet to mash it up. A few days ago, our of habit I accidentally started including some high level hash tags in an svn commit comment and it occurred to me that it might be useful to others, if not myself in 6 months. If we find hash tags useful in yams and tweets, why not commit comments?&lt;br /&gt;&lt;br /&gt;Including tokens in commit comments isn't new. In fact, we already include a Jira number in most of our commit comments and this allows us to view all the commits for a Jira issue. There is even a &lt;a href="http://blogs.atlassian.com/developer/2009/10/dragon_slayer_supplement_action_issues_with_commit_commands.html"&gt;Jira plugin&lt;/a&gt; that allows you to perform actions by specifying hashes in commit comments. For example, if I want to resolve a Jira I can include #resolve in my commit comment, and Jira will automatically Resolve that Jira. And don't feel like you can't include the #resolve tag only if your using that jira plugin. I could see value in seeing a #resolve tag in the final commit of a Jira.&lt;br /&gt;&lt;br /&gt;As an example, here is the exact commit comment I used that includes some hash tags for geoserver and installer.&lt;br /&gt;&lt;br /&gt;"&lt;i&gt;Jira: AC-4207. Got the filtered geowebcache.xml file correctly moved to the production and staging data directories. These files point to localhost with the correct geo port and stage geo port. Also commented out some fixpath.cmd lines to get the installer to work. Finally, I also change the ProcessPanel to not have a condition: &lt;panel classname="ProcessPanel" condition="env.install"&gt; changed to &lt;panel classname="ProcessPanel"&gt;. This should allow us to be really selective in what we install and still allow the process panel to run, whereas before it wasn't running. #geoserver #installer&lt;/panel&gt;&lt;/panel&gt;&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;Now the really cool part is if someone else in the near future notices an issue with geoserver in our installer, this comment will stick out more than a comment without those hashes.&lt;br /&gt;&lt;br /&gt;Another cool thing that could be done is a team subscribing to certain hash tags in the svn commit emails. For example, someone responsible for peer reviewing all DAO changes could subscribe to a hash like #dao. Then when developers are modifying DAO's all they need to do is include the #dao tag.&lt;br /&gt;&lt;br /&gt;I guess what I am saying is perhaps we could also benefit from putting extra hash tags in our commit comments. My brain has already been trained to read them so personally I think it's useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8937840818543986?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8937840818543986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8937840818543986'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/08/hash-tags-in-commit-comments.html' title='Hash tags in Commit Comments'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7617462754452410201</id><published>2010-07-25T21:09:00.001-05:00</published><updated>2010-07-25T21:09:42.471-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='virtual'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Restoring a Clonezilla Image using VirtualBox</title><content type='html'>Ubuntu &lt;a href="http://www.ubuntu.com/desktop"&gt;10.04&lt;/a&gt; has been out for a few months, and I'm still on 09.10. I have had some success in the past upgrading, but I still prefer doing fresh installs. I guess it comes from my windows days, when an occasional fresh install was good for the computer soul. However, this time I'm also starting a new project at work doing .net instead of java, and I really wanted the ability to "come back" to my old setup. Basically, I wanted to convert my host machine to a virtual one or what's called P2V (Physical to Virtual). I tried &lt;a href="http://www.vmware.com/products/converter/"&gt;VMware Converter&lt;/a&gt; but didn't get very far. With some advice from several co-workers though, I did come up with a method that did work and it was fairly easy.&lt;br /&gt;&lt;br /&gt;The basic steps are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;a href="http://clonezilla.org/"&gt;Clonezilla&lt;/a&gt; to &lt;a href="http://clonezilla.org/clonezilla-live/doc/showcontent.php?topic=01_Save_disk_image"&gt;Save a Disk Image&lt;/a&gt; to a external USB drive. This essentially clones my host machine, where I can restore it later. My hard drive is around 120GB, so I put the image on my 500GB external USB drive. This took about 1.5 hours.&lt;/li&gt;&lt;li&gt;Create a new virtual machine on another external USB drive. The nice thing about using Clonezilla, is for this step you can use VMware or &lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;. I used VirtualBox. Obviously, you can't create the virtual machine on your laptop because you don't have enough space. And you can't use the same USB drive because when restoring, Clonezilla needs it to be unmounted. So instead I used another external USB drive.&lt;/li&gt;&lt;li&gt;Start the new virtual machine and boot up Clonezilla to begin &lt;a href="http://clonezilla.org/clonezilla-live/doc/showcontent.php?topic=02_Restore_disk_image"&gt;restoring the image&lt;/a&gt;. You need to change the mode because the default view doesn't work very well when restoring. So at the Clonezilla menu, choose "Other modes of Clonezilla live". Then choose "Clonezilla live (Safe graphic settings, vga=normal)".&lt;/li&gt;&lt;li&gt;When you get to the point where Clonezilla needs to point to the external USB drive that contains the Clonezilla image, remember to enable the USB drive in VirtualBox. To do this, go to the Devices menu option in your virtual machine and select USB Devices and check the appropriate USB drive. Restoring my 120GB image took about 24 hours so make sure to do it when you have time.&lt;/li&gt;&lt;li&gt;Once Clonezilla has finished restoring the image your ready to poweroff the virtual machine, remove the clonezilla CD, and restart.&lt;/li&gt;&lt;/ul&gt;I still had a few adjustments to make in order to get it to work. When I first started my virtual machine, it complained about not having PAE (Physical Address Extension) enabled. I enabled PAE in ubuntu about a &lt;a href="http://twitter.com/jlorenzen/status/17982257006"&gt;month ago&lt;/a&gt; so I could use all 4GB of RAM. Fixing it was easy. Under your machines settings go to System and click on the &lt;u&gt;P&lt;/u&gt;rocessor tab. Check the "Enable PAE/NX" checkbox and restart.&lt;br /&gt;&lt;br /&gt;Once it booted up, it complained about my graphics configuration. I tried selecting "Reconfigure Graphics", but that didn't work. Instead I was able to get passed it by selecting "Run in low graphics for one session". This allowed me to finish booting where I installed the virtualbox guest additions which seemed to solve the graphics issue.&lt;br /&gt;&lt;br /&gt;That is all there is to it. It was all rather easy. Now I can install Ubuntu 10.04 and have the ability to go back to my previous development environment. I could also see lots of different use cases for this. Combined with the ability to &lt;a href="http://joshuahoover.com/2010/04/01/cloning-virtualbox-images/"&gt;clone virtual machines&lt;/a&gt;, all your virtual needs are met.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7617462754452410201?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7617462754452410201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7617462754452410201'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/07/restoring-clonezilla-image-using.html' title='Restoring a Clonezilla Image using VirtualBox'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4565997554718419524</id><published>2010-07-25T00:09:00.001-05:00</published><updated>2010-07-25T00:10:23.737-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Upgrading to Maven 3</title><content type='html'>I've been playing around with &lt;a href="http://maven.apache.org/"&gt;maven 3&lt;/a&gt; lately on our legacy maven 2 multi-module project via &lt;a href="http://jlorenzen.blogspot.com/2010/03/how-to-speed-up-maven.html"&gt;mvnsh&lt;/a&gt;. Like advertised, maven 3 is backwards compatible with maven 2. In fact, most everything worked out of the box when switching to maven 3. In this post, I'm going to highlight the required and currently optional items I changed so you can start preparing to migrate your project to maven 3. But first, what's so special about maven 3 and why would you upgrade? &lt;a href="http://polyglot.sonatype.org/"&gt;Polyglot maven&lt;/a&gt;, &lt;a href="http://shell.sonatype.org/"&gt;mvnsh&lt;/a&gt;, and &lt;a href="http://raibledesigns.com/rd/entry/what_s_new_in_maven"&gt;improved performance&lt;/a&gt; (50%-400% faster) are just a few. And since it's so easy to migrate to maven 3, you really don't have any excuses.&lt;br /&gt;&lt;br /&gt;Currently, I build our project using maven 2.2.1. This article was tested with mvnsh 0.10 which includes maven 3.0-alpha-6. The current release of maven 3 is 3.0-beta-1, while &lt;a href="http://raibledesigns.com/rd/entry/what_s_new_in_maven"&gt;maven 3.1&lt;/a&gt; is due out Q1 of 2011. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Profiles.xml no longer supported&lt;/b&gt;&lt;br /&gt;I haven't really figured out the reasoning, but it doesn't really matter; maven 3.0 no longer supports a profiles.xml. Instead you place your profiles in your ~/.m2/settings.xml. Some of our database processes and integration tests require properties from our profiles.xml. It was simple to solve by just moving my profiles to my settings.xml and everything worked.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Upgrade GMaven Plugin&lt;/b&gt;&lt;br /&gt;We depend pretty heavily on the &lt;a href="http://jlorenzen.blogspot.com/2008/01/maven-groovy-plugin-example.html"&gt;gmaven plugin&lt;/a&gt; for testing, simple groovy scripts, and some ant calls. In order to build some modules I had to upgrade gmaven. The current version we were using was 1.0-rc-3. Our projects built perfectly after changing it to org.codehaus.gmaven:gmaven-plugin:1.2.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;${pom.version} changing to ${project.version}&lt;/b&gt;&lt;br /&gt;Here maven 3 kindly warned me that uses of the &lt;a href="http://docs.codehaus.org/display/MAVENUSER/MavenPropertiesGuide"&gt;maven property&lt;/a&gt; pom.version may no longer be supported in future versions and should be changed to project.version. My modules still built, but thought it was nice of maven to inform me of the potential change.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Version and Scope Issues&lt;/b&gt;&lt;br /&gt;We had a few places where we needed to define a dependency version and another place where we shouldn't have defined a scope. Both instances prevented maven 3.0 from building our modules, but fixing them was easy. The first instance was we defined a version for a plugin in the pluginManagement section, but maven 3 required it also where it was used in the reporting plugin section. Not exactly sure about this one, ideally you would only define your plugin versions in the pluginManagement section but oh well.&lt;br /&gt;&lt;br /&gt;We had some WAR projects using jetty. In the jetty plugin definition we had a dependency on geronimo and had defined a scope of provided. Maven 3 complained about it and since it's really not necessary, just removing it fixed the issue.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;modelVersion&lt;/b&gt;&lt;br /&gt;Maven 3.0 kept warning about using ${modelVersion} instead of ${project.modelVersion}. I was still able to build though, so my guess is the value for modelVersion, 4.0.0, most likely will change when maven 3.1 comes out.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Weird Surefire Output&lt;/b&gt;&lt;br /&gt;This wasn't necessarily an issue with the surefire plugin, but I wanted to comment about it's output when tests failed as I thought it might have been a maven 3 issue. Below is a screenshot of the output when you have failed tests. At first I thought it was a maven 3 issue, but I built the same project using the same commands with maven 2.2.1 and got the same test failures. Hopefully, they can clean this type of thing up, because I could image lots of people getting confused.&lt;br /&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://1.bp.blogspot.com/_u6FjI-f0VoU/TEvG3xOU6EI/AAAAAAAAAL8/B3nuN9HVuH4/s1600/maven3-test-failure.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="168" src="http://1.bp.blogspot.com/_u6FjI-f0VoU/TEvG3xOU6EI/AAAAAAAAAL8/B3nuN9HVuH4/s640/maven3-test-failure.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Failed test output&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;That's essentially it. Happily, there really wasn't much required to change, which goes to show the great lengths the maven team has gone through to ensure backwards compatibility. Finally, here is a &lt;a href="https://cwiki.apache.org/MAVEN/maven-3x-compatibility-notes.html"&gt;Compatibility Notes&lt;/a&gt; maven has provided on the subject of migrating maven 2 projects to maven 3.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4565997554718419524?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4565997554718419524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4565997554718419524'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/07/upgrading-to-maven-3.html' title='Upgrading to Maven 3'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_u6FjI-f0VoU/TEvG3xOU6EI/AAAAAAAAAL8/B3nuN9HVuH4/s72-c/maven3-test-failure.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-898142829659765776</id><published>2010-07-19T00:38:00.001-05:00</published><updated>2010-07-19T00:39:44.285-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>My First Groovy DSL</title><content type='html'>It's no secret I'm a groovy &lt;a href="http://jlorenzen.blogspot.com/2007/12/justify-using-groovy.html"&gt;homer&lt;/a&gt;. I love it. One of the things that makes using groovy so fun, is it's syntax. Being able to get the contents of a file by just saying new File("/home/james/test.log").text is refreshing compared to it's java counterpart. Another thing that makes groovy enjoyable is it's ability to support Domain Specific Languages (DSL). &lt;a href="http://groovy.codehaus.org/Creating+XML+using+Groovy%27s+MarkupBuilder"&gt;MarkupBuilder&lt;/a&gt; is a great example. With Groovy, you can create simple or very complex DSLs for your purposes. To my knowledge there are a few ways you can create your own DSL: extending &lt;a href="http://thediscoblog.com/2007/07/06/builders-are-groovys-bag/"&gt;BuilderSupport&lt;/a&gt; or using &lt;a href="http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing"&gt;methodMissing/propertyMissing&lt;/a&gt;. In my opinion, extending BuilderSupport is more involved while methodMissing/propertyMissing is kind of the poor man's way of creating a DSL.&lt;br /&gt;&lt;br /&gt;Up to this point though, I've never actually came across a good use case for creating a DSL until this past week. We have a large set of &lt;a href="http://jlorenzen.blogspot.com/2009/01/testing-rest-services-with-groovy.html"&gt;automated tests&lt;/a&gt; that run against our REST Services. Since our application is now multi-tenant, all of our tests need a valid organization (tenant). In our case, an organization contains multiple roles and locations. Each test has different requirements on the types of organizations it needs. Some might need 2 unique organizations, while another might need an organization with at least 2 roles and 2 locations. It was this use case that I thought a groovy DSL would fit perfectly.&lt;br /&gt;&lt;br /&gt;My end goal was to have something like this:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;def orgs = OrganizationService.getOrganizations().withRoles().withLocations()&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This would return a list of organizations that had at least 1 role and 1 location. The nice thing about this DSL is it's scalable. Meaning, if we add new lists of information to an organization, we won't have to update our class. Also, an important feature, is the method name Roles and Locations correlate to the JSON named arrays of the organization. So my JSON looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;{"organizations": {"name": "James", "roles": ["R1", "R2"], "locations": ["Tulsa", "Omaha"]}}&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;When writing my DSL I decided to go the poor man's way and use the methodMissing approach combined with the &lt;a href="http://www.ibm.com/developerworks/java/library/j-pg08259.html"&gt;@Delegate&lt;/a&gt; annotation. Here it is:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;import net.sf.json.JSONArray&lt;br /&gt;&lt;br /&gt;class OrganizationFilterArray {&lt;br /&gt;    @Delegate private JSONArray array&lt;br /&gt;    &lt;br /&gt;    OrganizationFilterArray(array) {&lt;br /&gt;        this.array = array&lt;br /&gt;    }&lt;br /&gt;      &lt;br /&gt;    def methodMissing(String name, args) {        &lt;br /&gt;        if (name.startsWith("with")) {&lt;br /&gt;            def length = (args.length == 0) ? 1 : args[0]&lt;br /&gt;            def arrayName = name[4..5].toLowerCase() + name[6..-1]&lt;br /&gt;            &lt;br /&gt;            return filterByLength(arrayName, length)&lt;br /&gt;        } else {&lt;br /&gt;            throw new MissingMethodException(name, this.class, args)&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private filterByLength(listName, length) {        &lt;br /&gt;        def filteredArray = array.findAll {&lt;br /&gt;            it."$listName"?.size() &amp;gt;= length&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        return new OrganizationFilterArray(filteredArray)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I could have just as easily extended &lt;a href="http://json-lib.sourceforge.net/apidocs/index.html?net/sf/json//class-useJSONArray.html"&gt;JSONArray&lt;/a&gt; since it's not final, but I was following the @Delegate guide initially and just thought it was an interesting alternative. The big key here is how I used methodMissing to support an infinite amount of possibilities with how to filter an organization. Everything else I think is pretty self explanatory. When it comes across a method that is missing, withRoles(), it calls my methodMissing method. From there I filter out all the organizations that don't fit the criteria. Eventually, this class could be refactored to support more than just the size of an array. Note, I did have to upgrade the &lt;a href="http://docs.codehaus.org/display/GMAVEN/Home"&gt;gmaven plugin&lt;/a&gt; version to 1.0 to get it work in our maven project.&lt;br /&gt;&lt;br /&gt;I knew from the beginning I wasn't going to use BuilderSupport. It did take me some time to figure out how I was going to support filtered (getOrganizations().withRoles()) and non-filtered versions (getOrganizations()). That is when I decided to extend List or JSONArray, as both method calls had to return my custom List/JSONArray. Overall, I'm pretty happy with the outcome and how long it took me. It was pretty trivial and very fun thanks to groovy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-898142829659765776?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/898142829659765776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/898142829659765776'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/07/my-first-groovy-dsl.html' title='My First Groovy DSL'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4868314563991720388</id><published>2010-07-14T23:21:00.000-05:00</published><updated>2010-07-14T23:21:38.743-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Tip Debugging External Java Dependencies</title><content type='html'>Ever spent time debugging 3rd party java libraries? &lt;a href="http://java.decompiler.free.fr/"&gt;Decompiling&lt;/a&gt; is usually the first step. Attempting to walk through the code can be tedious but it's usually the first line of defense. But what if you want to deploy a slightly modified version? In the past, I've checked out the project and built it with my modifications. Since most open source projects don't support "&lt;a href="http://jlorenzen.blogspot.com/2010/04/thoughts-on-fowlers-continuous.html"&gt;virgin builds&lt;/a&gt;", this has a success rate of about 10%. Fortunately, there is a better way. I'm just disappointed I didn't think of it.&lt;br /&gt;&lt;br /&gt;In our project we deploy a wiki that is based on &lt;a href="http://www.jspwiki.org/"&gt;JSPWiki&lt;/a&gt; using &lt;a href="http://jlorenzen.blogspot.com/2008/05/using-maven-war-overlays-to-extend.html"&gt;maven overlays&lt;/a&gt;. In the version we are using, there isn't any support for being able to configure the wiki files directory outside of a properties file in the WAR. In order to point JSPWiki to a different directory, you would basically have to unzip the WAR, update the file, and then zip the WAR back together (#fail). So, someone on our team discovered we could basically override this behaviour by providing our own implementation of the same class.&lt;br /&gt;&lt;br /&gt;To be more specific, the class under question is &lt;i&gt;com.ecyrd.jspwiki.PropertyReader&lt;/i&gt;. It's included in the JSPWiki.jar file under /WEB-INF/lib. It's default behaviour is not suitable for our needs, so we get an original copy of &lt;i&gt;PropertyReader.java&lt;/i&gt;, and place it under our maven projects &lt;i&gt;/src/main/java&lt;/i&gt; directory under the same package of &lt;i&gt;com.ecyrd.jspwiki&lt;/i&gt;. Once the projects builds, we now have our version of &lt;i&gt;PropertyReader.class&lt;/i&gt; under /WEB-INF/classes, which is important because the ClassLoader will first look under /WEB-INF/classes first before looking in /WEB-INF/lib. This means our class is used instead of the one provided by JSPWiki in /WEB-INF/lib/JSPWiki.jar.&lt;br /&gt;&lt;br /&gt;Now I know what your thinking: that's a horrible idea James. And for the most part I agree, but it's not my fault this ability doesn't already exist in JSPWiki. So if you want to keep your conscience clean, go ahead and continue unpacking and repacking that WAR. I'll be happy getting important things done. Obviously, practicing this is the exception and not the rule. And one should provide the patch as an improvement back to the 3rd party for all to enjoy. And before you start asking yourself why you can't just extend the real PropertyReader and override the necessary methods, which I agree would be more ideal, it's not possible because you'd basically be extending yourself since the modified class is the first class in the classpath.&lt;br /&gt;&lt;br /&gt;This technique has actually helped me twice debug environment specific issues. It'd saved me a huge amount of time not having to build an external library. In fact, if you check out the exact version, you could even perform remote debugging with breakpoints.&lt;br /&gt;&lt;br /&gt;So next time you need to debug an external 3rd party library, consider using this technique before attempting to build it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4868314563991720388?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4868314563991720388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4868314563991720388'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/07/tip-debugging-external-java.html' title='Tip Debugging External Java Dependencies'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5867087521110716756</id><published>2010-07-13T16:51:00.001-05:00</published><updated>2010-07-13T16:52:48.291-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Avatar Maven</title><content type='html'>Today I gave a quick &lt;a href="http://www.slideshare.net/jlorenzen/avatar-maven"&gt;presentation&lt;/a&gt; to some coworkers about &lt;a href="http://maven.apache.org/"&gt;maven&lt;/a&gt;. It's a broad topic, so I kept it fairly limited. Most of my audience was very familiar with maven, so I tried not boring them with stuff they already knew. I tried making it a little engaging by comparing the Avatar, master of all 4 elements, to Maven, master of the build (it's a stretch I know). It's a quick presentation (15 slides) providing some helpful maven tips, what's coming in &lt;a href="http://jaxenter.com/maven-3-0-the-future-of-maven-10580.html"&gt;maven 3&lt;/a&gt;, and &lt;a href="http://ericmiles.wordpress.com/2010/03/26/maven-shell-features"&gt;mvnsh&lt;/a&gt;. Hope you like it.&lt;br /&gt;&lt;br /&gt;&lt;div id="__ss_4748255" style="width: 425px;"&gt;&lt;b style="display: block; margin: 12px 0pt 4px;"&gt;&lt;a href="http://www.slideshare.net/jlorenzen/avatar-maven" title="Avatar Maven"&gt;Avatar Maven&lt;/a&gt;&lt;/b&gt;&lt;object height="355" id="__sse4748255" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=avatarmaven-100713163552-phpapp02&amp;stripped_title=avatar-maven" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4748255" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=avatarmaven-100713163552-phpapp02&amp;stripped_title=avatar-maven" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="padding: 5px 0pt 12px;"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jlorenzen"&gt;jlorenzen&lt;/a&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/1280619439915049383-5867087521110716756?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5867087521110716756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5867087521110716756'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/07/avatar-maven.html' title='Avatar Maven'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7000456018737141634</id><published>2010-07-09T13:55:00.002-05:00</published><updated>2010-07-09T13:59:43.363-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven2'/><title type='text'>Sharing Resources in Maven</title><content type='html'>Today I needed to figure out the best way to share resources across multiple maven modules. We have previously done it 2 different ways, neither of which I thought were very good. The first way was using a relative path to reach across to the modules resource directory (usually not a good practice in maven). It went something like this:&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;resources&gt;&lt;br /&gt;    &lt;resource&gt;&lt;br /&gt;        &lt;directory&gt;../module1/src/main/resources&lt;/directory&gt;&lt;br /&gt;    &lt;/resource&gt;&lt;br /&gt;&lt;/resources&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The second way was using the infamous &lt;a href="http://www.sonatype.com/people/2008/04/how-to-share-resources-across-projects-in-maven/"&gt;maven assembly plugin&lt;/a&gt;. I typically avoid the assembly plugin like I avoid writing Assembly. Plus I prefer avoiding 100 extra lines of XML on something so trivial. Luckily, the Sonatype guys apparently knew this and have come up with a more efficient way of sharing resources using the &lt;a href="http://maven.apache.org/plugins/maven-remote-resources-plugin"&gt;maven-remote-resources-plugin&lt;/a&gt;. It has the advantages of requiring a lot less XML lifting and it's nicely integrated into the maven lifecycle. I did run into one small issue trying to get it to work. By default it only copies **/*.txt files from src/main/resources. For several minutes, I couldn't figure how why it wasn't working until I added an includes for **/*.xml. Then it worked perfectly. Here is the end result:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Creating a resource bundle&lt;/b&gt;&lt;br /&gt;Add the following to your POM which is going to create the resource bundle.&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;plugin&gt;      &lt;br /&gt;    &lt;artifactid&gt;maven-remote-resources-plugin&lt;/artifactid&gt;&lt;br /&gt;    &lt;version&gt;1.1&lt;/version&gt;&lt;br /&gt;    &lt;executions&gt;&lt;br /&gt;        &lt;execution&gt;&lt;br /&gt;            &lt;goals&gt;&lt;br /&gt;                &lt;goal&gt;bundle&lt;/goal&gt;&lt;br /&gt;            &lt;/goals&gt;&lt;br /&gt;            &lt;configuration&gt;&lt;br /&gt;                &lt;includes&gt;&lt;br /&gt;                    &lt;include&gt;**/*.xml&lt;/include&gt;&lt;br /&gt;                &lt;/includes&gt;&lt;br /&gt;            &lt;/configuration&gt;&lt;br /&gt;        &lt;/execution&gt;&lt;br /&gt;    &lt;/executions&gt;&lt;br /&gt;&lt;/plugin&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You now should see the following message in your mvn output while running mvn clean install.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;[remote-resources:bundle {execution: default}]&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This produces a /target/classes/META-INF/maven/remote-resources.xml file which contains references to the resource files. For example,&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;remoteresources&gt;&lt;br /&gt;    &lt;remoteresource&gt;test.xml&lt;/remoteresource&gt;&lt;br /&gt;&lt;/remoteresources&gt;&lt;br /&gt;&lt;/pre&gt;Consuming Resource Bundle&lt;br /&gt;Add the following to the POM which needs to consume the new resource bundle.&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;plugin&gt;      &lt;br /&gt;    &lt;artifactid&gt;maven-remote-resources-plugin&lt;/artifactid&gt;&lt;br /&gt;    &lt;version&gt;1.1&lt;/version&gt;&lt;br /&gt;    &lt;executions&gt;&lt;br /&gt;        &lt;execution&gt;&lt;br /&gt;            &lt;goals&gt;&lt;br /&gt;                &lt;goal&gt;process&lt;/goal&gt;&lt;br /&gt;            &lt;/goals&gt;&lt;br /&gt;            &lt;configuration&gt;&lt;br /&gt;                &lt;resourcebundles&gt;&lt;br /&gt;                    &lt;resourcebundle&gt;com.lorenzen:lorenzen-core:${pom.version}&lt;/resourcebundle&gt;&lt;br /&gt;                &lt;/resourcebundles&gt;&lt;br /&gt;            &lt;/configuration&gt;&lt;br /&gt;        &lt;/execution&gt;&lt;br /&gt;    &lt;/executions&gt;&lt;br /&gt;&lt;/plugin&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You now should see the following message in your mvn output while running mvn clean install.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;[remote-resources:process {execution: default}]&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;You should now be able to look into your second modules /target/classes directory and see test.xml.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7000456018737141634?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7000456018737141634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7000456018737141634'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/07/sharing-resources-in-maven.html' title='Sharing Resources in Maven'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6772534560465936344</id><published>2010-07-01T23:22:00.002-05:00</published><updated>2010-07-01T23:25:44.420-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='lucene'/><category scheme='http://www.blogger.com/atom/ns#' term='rss'/><title type='text'>RSS, Lucene, and REST</title><content type='html'>Sorry for the horrible title. I struggled trying to come up with a worthy title, but after a few minutes I decided to not let &lt;a href="http://codebeneath.blogspot.com/2007/08/perfect-is-enemy-of-very-good.html"&gt;perfection get in the way of good&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;My team has recently worked on a new feature I am pretty excited about: adding support for RSS/Atom in our application. I know your thinking so what. It's not really the what I am excited about but the how. What I'm really excited about was how the story was defined and implemented.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Approach&lt;/b&gt;&lt;br /&gt;We had the simple requirement from a newer customer to provide an RSS feed for newly created items. This actually wasn't the first time for this requirement. We prototyped a similar capability a long time ago using OpenESB and the RSS BC, but for &lt;a href="http://jlorenzen.blogspot.com/2009/03/grails-create-app-esb.html"&gt;multiple reasons&lt;/a&gt; it just didn't work out.&lt;br /&gt;&lt;br /&gt;So our first decision had to answer: how we were going to implement it......again, but better. Before the sprint began, a few of us got together and hashed out a potential solution: how about we use the Search REST Service, which is backed by &lt;a href="http://lucene.apache.org/java/docs/index.html"&gt;Lucene&lt;/a&gt;, to support &lt;a href="http://lucene.apache.org/java/2_9_2/queryparsersyntax.html"&gt;&lt;span id="goog_1808686975"&gt;&lt;/span&gt;Advanced searches&lt;span id="goog_1808686976"&gt;&lt;/span&gt;&lt;/a&gt; and return RSS?&lt;br /&gt;&lt;br /&gt;Why does this excite me so much? To understand that I need to explain our application at a high level. It's a completely javascript-based application using ExtJS (now &lt;a href="http://www.sencha.com/"&gt;sencha&lt;/a&gt;), backed by REST Services using &lt;a href="https://jersey.dev.java.net/"&gt;Jersey&lt;/a&gt;. Consequently, we have a lot of REST Services. Right now those REST Services support returning XML or JSON using a custom Response Builder we have created internally.&lt;br /&gt;&lt;br /&gt;I'm excited because this single user story could have a huge improvement on the entire system:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If we modified the Search Service to return RSS, then all our REST Services could support RSS.&lt;/li&gt;&lt;li&gt;The REST Service would now support Advanced searches. Previously, it only really supported basic keyword searches.&lt;/li&gt;&lt;li&gt;Any search they perform could now be subscribe to via RSS.&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;Implementation&lt;/b&gt;&lt;br /&gt;I'm not going to go into every detail on how it was done. I wasn't even actually the one who implemented it (see &lt;a href="http://eclectic-tech.blogspot.com/"&gt;Matt White&lt;/a&gt;. He did a fantastic job.). We did have one major hurdle we had to overcome, and that was how to index items to enable &lt;a href="http://lucene.apache.org/java/2_9_2/queryparsersyntax.html"&gt;advanced searches&lt;/a&gt; like Status=New.&lt;br /&gt;&lt;br /&gt;Previously this wasn't possible given how we were indexing our items. We were basically indexing the item by building up a large String containing all the item information like the following:&lt;br /&gt;&lt;pre class="brush: groovy"&gt;import org.apache.lucene.document.Document&lt;br /&gt;import org.apache.lucene.document.Field&lt;br /&gt;&lt;br /&gt;def Document createDocument(item) {&lt;br /&gt;    Document d = new Document()&lt;br /&gt;    &lt;br /&gt;    doc.add(new Field("content",&lt;br /&gt;        getContent(item),&lt;br /&gt;        Field.Store.NO,&lt;br /&gt;        Field.Index.ANALYZED))&lt;br /&gt;        &lt;br /&gt;    return d&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def String getContent(item) {&lt;br /&gt;    def s = new StringBuilder()&lt;br /&gt;    &lt;br /&gt;    s.append(item.getTitle()).append(" ")&lt;br /&gt;    s.append(item.getStatus()).append(" ")&lt;br /&gt;    s.append(item.getPriority()).append(" ")&lt;br /&gt;    s.append(item.getDescription()).append(" ")&lt;br /&gt;    &lt;br /&gt;    return s.toString()&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The problem with this is performing a search for "New" would have returned any item with a status of New as well as any items that contained the word New. The solution was to just add another Field to the Document.&lt;br /&gt;&lt;pre class="brush: groovy"&gt;doc.add(new Field("Status",&lt;br /&gt;    item.getStatus(),&lt;br /&gt;    Field.Store.NO,&lt;br /&gt;    Field.Index.NOT_ANALYZED));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now the Search Service could support advanced searches like: Status:"New". You should put the value in quotes in case the value contains spaces (ie Status:"In Progress"). And since Lucene is so powerful, it also means the follow search would work: Status:"New" AND Priority:"High" AND "Hurricane". Now users have the freedom to subscribe to a near limitless amount of RSS feeds based on Advanced Searches.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Start to Finish&lt;/b&gt;&lt;br /&gt;I think there were several reasons why this story was a success in my eyes. Most importantly where the two really smart co-workers who worked on it: Matt White and Chuck Hinson. All three of us knew of this user story ahead of time and we were able to discuss it technically days before backlog selection. This allowed us to brainstorm some ideas. Once we narrowed it down, we spent some more time separately looking into the code to find out the level of difficulty and if Advanced Searches like Status:New would be possible. Overall, together I'd say we spent 3-4 hours doing the preliminary work. Doing that preliminary work I think really enabled us to give a proper WAG for the story.&lt;br /&gt;&lt;br /&gt;I really can't speak for how the development went (I was at Disney World for 10 days with the family), but I was really impressed with the tests Matt wrote. He wrote a number of unit tests making sure advanced searches worked and basic searches still worked. On top of that, he wrote an overall functional test using &lt;a href="http://jlorenzen.blogspot.com/2009/01/testing-rest-services-with-groovy.html"&gt;HttpBuilder&lt;/a&gt; executing the REST Service just as our javascript client would. &lt;br /&gt;&lt;br /&gt;Finally, once the main work was finished, we uploaded a diff file to our internal instance of &lt;a href="http://www.reviewboard.org/"&gt;Review Board&lt;/a&gt;. From there I was able to perform a peer review where we found a minor bug in the changes.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;I am sure it's not an original idea, but I thought it was a fun User Story that hopefully will provide a lot of value beyond what was originally estimated. Ideally, this might help others who are in similar situations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-6772534560465936344?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6772534560465936344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6772534560465936344'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/07/rss-lucene-and-rest.html' title='RSS, Lucene, and REST'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-2038567867122876467</id><published>2010-05-14T22:40:00.000-05:00</published><updated>2010-05-14T22:40:03.794-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='release'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>How to create a release without the maven2 release plugin</title><content type='html'>One of the most referenced articles I have written is "&lt;a href="http://jlorenzen.blogspot.com/2007/09/how-to-create-release-using-maven2.html"&gt;How to create a release using the maven release plugin&lt;/a&gt;". But what if you can't get the maven release plugin to work with your project? Perhaps like our team, you've got a legacy maven2 multi-module project that's been nigh impossible to use with the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/"&gt;release plugin&lt;/a&gt;. Our project has a mix of WAR modules combined with some Flex modules. I believe our last issue was some googlecode flex mojo wasn't working with the release plugin. Consequently, for the past year or so, we've been manually creating our releases. This actually hasn't been that much of a pain since we really only do it once a sprint at the end. Combined with my favorite &lt;a href="http://www.debianadmin.com/howto-replace-multiple-file-text-string-in-linux.html"&gt;perl script&lt;/a&gt; it doesn't really take that long. However, it does have the disadvantage of requiring some knowledge of what and now to do it. Ideally, it would be a job in &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt;, anyone on the team could run as many times as they like.&lt;br /&gt;&lt;br /&gt;In an effort to try and &lt;a href="http://jlorenzen.blogspot.com/2010/04/thoughts-on-fowlers-continuous.html"&gt;automate as much as possible&lt;/a&gt;, I decided to try and automate releasing our legacy multi-module project using bash. This has several benefits: create a release faster, done consistently each time, turn-key solution anyone on the team can run that doesn't require stale documentation on how to do it.&lt;br /&gt;&lt;br /&gt;It took my several hours to essentially duplicate the maven release plugin process. Thanks to our new intern Scott Rogers and linux master Ron Alleva, I was eventually able to get it finished. It's my first "official" bash script so pardon the mess. If you've never attempted to automate your release project, first consider reading my article on &lt;a href="http://jlorenzen.blogspot.com/2007/09/how-to-effectively-use-snapshot.html"&gt;How to effectively use SNAPSHOT&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is the script available as a gist on github: &lt;a href="http://gist.github.com/401974"&gt;project-release.sh&lt;/a&gt;. Here is what it does:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Copies the current working branch (i.e. trunk) into another branch. It uses the pom.xml &lt;scm&gt;&lt;url&gt; value to get the current working branch.&lt;/url&gt;&lt;/scm&gt;&lt;/li&gt;&lt;li&gt;Updates all the pom.xml version sections of the current working branch&lt;/li&gt;&lt;li&gt;Commits the pom.xml changes&lt;/li&gt;&lt;li&gt;Checks out the release branch&lt;/li&gt;&lt;li&gt;Updates all the pom.xml version sections of the release branch (basically stripping off -SNAPSHOT)&lt;/li&gt;&lt;li&gt;Commits the pom.xml changes&lt;/li&gt;&lt;/ol&gt;To run this script all you have to do is run: &lt;i&gt;project-release.sh 2 false&lt;/i&gt;. The first parameter (2) is the increment position that the current working branch needs to be next. For example, if trunk was on 1.2.0-SNAPSHOT and the position passed in was 2, then trunk gets updated to 1.3.0-SNAPSHOT. If the position was 3 then trunk would be updated to 1.2.1-SNAPSHOT. The second parameter is used when testing. It's like the dryRun option in the maven release plugin. When set to true, nothing gets copied or committed.&lt;br /&gt;&lt;br /&gt;A few notes about the script:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The base branch URL is hardcoded but could easily be passed in as another parameter or placed and read from some external file.&lt;/li&gt;&lt;li&gt;It uses the cmd &lt;i&gt;xpath&lt;/i&gt; to extract out the pom version, project name, and scm url. I'm on ubuntu 9.10 and according to synaptic I have libxml-xpath-perl version 1.13-6 installed.&lt;/li&gt;&lt;li&gt;It doesn't run any maven commands like mvn deploy. Other jobs in CI can accomplish that or you can easily add them into the script.&lt;/li&gt;&lt;li&gt;To run from Hudson:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Create a New Job&lt;/li&gt;&lt;li&gt;In the Build section Add a Execute Shell Step&lt;/li&gt;&lt;li&gt;Update the Command text with: $WORKSPACE/trunk/project-release.sh 2 false&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;Overall, I'm pretty happy with the outcome. And as we start to perform more releases among multiple projects I think it's going to really come in handy. I think ideally you should try and release your project using the maven release plugin, but if that isn't possible then don't give up. Just clone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-2038567867122876467?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2038567867122876467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2038567867122876467'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/05/how-to-create-release-without-maven2.html' title='How to create a release without the maven2 release plugin'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5058753529986294660</id><published>2010-04-14T22:43:00.004-05:00</published><updated>2010-04-15T23:33:10.855-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ci'/><title type='text'>Thoughts on Fowler's Continuous Integration</title><content type='html'>It's always kind of nice to go back to the basics. I've always enjoyed re-reading basic programming practices and patterns. I tend to forget the things I don't use on a daily basis. That's why I enjoyed reading Martin Fowler's article on &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt;. The article says the last significant update occurred May 2006, but it's withstood the test of time; much like &lt;a href="http://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar"&gt;The Cathedral and the Bazaar&lt;/a&gt;. But if you don't have the time to read this rather long article, here are a few of the favorites I pulled out as I read it over the course of a few days. Before that, let me explain a little bit of my experience.&lt;br /&gt;&lt;br /&gt;At my first programming job we didn't really have a VCS (Version Control System) like CVS or SVN nor did we have a CI (Continuous Integration) server; we really didn't know any better. We essentially did all of our work straight off a shared drive (I know). But that was before I came to Gestalt, now Accenture, 5 years ago. Since then I've been exposed to CVS--&amp;gt;SVN--&amp;gt;Git, Ant--&amp;gt;Maven 1--&amp;gt;Maven 2,&amp;nbsp; CruiseControl--&amp;gt;Hudson, and finally TDD (Test Driven Development). Being exposed to all of this has been a huge improvement to my career. More importantly it's been a huge benefit to how I write software and the tools our teams use such as VCS and CI. I can't image developing software without them.&lt;br /&gt;&lt;br /&gt;Here are some points out of &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt; that I would think applies to any project java or not:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Work does not stop on your commit&lt;/b&gt;&lt;br /&gt;&lt;blockquote&gt;"However my commit doesn't finish my work. At this point we build again, but this time on an integration machine based on the mainline code. Only when this build succeeds can we say that my changes are done."&lt;/blockquote&gt;So true. Just because you ran some tests locally or manually tested it, doesn't mean your done just because you checked in your changes. You've got to monitor CI to ensure it passes. This has been a topic of discussion on my team lately as we've come in in the morning with a few broken builds. Solution: check in often during the day, but don't checkin and leave and not verify CI passed. Either stay late, sign in at home, come in early, or checkin first thing the next day.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple checkout build rule&lt;/b&gt;&lt;br /&gt;&lt;blockquote&gt;"The basic rule of thumb is that you should be able to walk up to the project with a virgin machine, do a checkout, and be able to fully build the system."&lt;/blockquote&gt;This is a very important point. Not only will this improve the productivity of new team members but also reduce the amount of time it takes to create new CI jobs. This rule is even more important for open source projects. I've had several issues in the past trying to patch open source projects and wasted several hours just trying to build their code. If you want people do contribute to your project, make it easy for them to build your software. For example, I've been wanting to write a simple &lt;a href="http://do.davebsd.com/wiki/Docky"&gt;Docky plugin&lt;/a&gt; for &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt;, but have ran into several issues (&lt;a href="https://answers.launchpad.net/docky/+question/99325"&gt;New Plugin&lt;/a&gt; and &lt;a href="https://answers.launchpad.net/docky/+question/99967"&gt;Missing Package&lt;/a&gt;) trying to build the Do project. Have those questions really been Answered? NO! What have I done about it? I haven't retried it since. To restate Mr. Fowler, I should be able to easily checkout your code and at a minimum build it. As an added bonus it'd be nice to run unit tests as well.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Automate everything&lt;/b&gt;&lt;br /&gt;&lt;blockquote&gt;"However like most tasks in this part of software development it can be automated - and as a result should be automated. Asking people to type in strange commands or clicking through dialog boxes is a waste of time and a breeding ground for mistakes."&lt;/blockquote&gt;If your just getting started with CI this can often be difficult. But your long term goal should be to automate everything. This includes creating/destroying your database, deploying/undeploying your application, automating your tests, copying configuration files around. I'd even go as far as to say automate the creation of the development environment: installing maven and java for example. Again this not only speeds up new team members productivity but also those virgin CI servers.&lt;br /&gt;&lt;br /&gt;Two great examples of this. Before we had a internal CI team, our team was manually setting up multiple CI servers with maven, java, jboss, and a database. These new servers couldn't be used until all of this stuff was manually configured. Then our internal CI team helped automate some of this stuff and we can very easily use hudson to point jobs at different servers within minutes. Something that wasn't really possible before without manually intervention. And all they really did was call a few simple ant copy commands from maven.&lt;br /&gt;&lt;br /&gt;Another good example of this comes back from our old CruiseControl and Ant days. At one point in our project we were constantly breaking a major piece of functionality and one of the main reasons was it was very difficult to test. It was a distributed test with multiple servers communicating with multiple clients via SIP. The build process called for building the latest code, stopping 2 instances of weblogic (1 local, 1 remote), starting weblogic, deploying the latest code, waiting for weblogic to finish starting (not easy mind you), and then running our automated test. This was rather huge undertaking, but given a few weeks we had the core of it automated. It was amazing. I never thought it would have been possible, but it was and anytime that test failed we knew immediately we broke something. We were able to accomplish the difficult parts by calling remote bash scripts via ssh from ant.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Imperfect Tests&lt;/b&gt;&lt;br /&gt;&lt;blockquote&gt;"Imperfect tests, run frequently, are much better than perfect tests that are never written at all. "&lt;/blockquote&gt;Not exactly sure what he means by imperfect tests, but this is one place I currently disagree. It takes practice to write good tests. Once you refactor and maintain tests over a long period of time you start getting pretty good at writing tests that require less refactoring. One of the things that is killing the productivity of our team right now is what I call "cronically failing tests" or tests that randomly fail for no reason. You check the change log and nothing changed in the build which means it shouldn't have failed. You rebuild the job and it passes. Here lately this can be attributed to date comparison asserts and issues with timing. For example, the test passes when the database is local, but fails when the database is remote. Or you get different results when the time on the database server is not sync'd. The end result is this produces false negatives that really hurt the validity of CI; developers just start ignoring all failures. Once you've identified one of these cronically failing tests, it's important the author of that test, or the person who last modified it, refactor the test to be flexible. If the author doesn't do it, they will continue producing these types of imperfect tests.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Good Build Characteristics&lt;/b&gt;&lt;br /&gt;He had several comments I would wrap into good general build characteristics. Two of which are fast builds and accessible artifacts. As a general rule he suggests keeping build times to around 10 minutes. Which is usually achievable for compile/unit test jobs, but database related and above can usually take longer. My general guideline is try to keep those longer running builds to around 30 minutes, but definitely no longer than an hour. Unfortunately right now, we have several of those 40-55 minute builds I'd like to trim down some. It'd be great to see a hudson plugin that could show me how long each part of my build took.&lt;br /&gt;&lt;br /&gt;With a combination of our company maven repository and hudson, it's pretty easy to make our artifacts accessible. This is really huge as sometimes I don't waste time building certain things that take forever to build; I'll just download them from hudson. I know a lot of times our DBA will just download the zip he wants to test and prevents him from updating his source and building, etc. Another related topic is we have several nightly jobs that deploy the latest code to jboss/websphere that can be used the next day by everyone to see/test/verify the latest code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Rollback Deployment&lt;/b&gt;&lt;br /&gt;&lt;blockquote&gt;"If you deploy into production one extra automated     capability you should consider is automated rollback."&lt;/blockquote&gt;This was a pretty new concept for me and one we don't necessarily follow. I've heard of Continuous Deployment, but never really heard about a rollback feature. I know we've accidentally benefited from a build failing and not deploying the latest nightly code thus allowing us to perform diff-debugging to track down a bug. We had 2 servers that built the night before, 1 passed and the other failed so it contained the previous days build. A bug was detected on the passing server and we were unable to reproduce on the outdated server. This told us it had been introduced in the past 24 hours. This isn't exactly rolling back but maybe the morale of the story is keeping a server around that is behind a day.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;There is a lot of good general information in this article and I would encourage anyone to take the time to read it. I only highlighted the things that really stuck out at me; there were a lot more useful things I passed mentioning.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5058753529986294660?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5058753529986294660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5058753529986294660'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/04/thoughts-on-fowlers-continuous.html' title='Thoughts on Fowler&apos;s Continuous Integration'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4547304435980284774</id><published>2010-04-08T11:01:00.003-05:00</published><updated>2010-04-08T11:05:29.279-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='websphere'/><title type='text'>Possible solution for WebSphere issue NMSV0310E</title><content type='html'>It's been quite a ride porting our EAR from JBoss 4.2.1 to WebSphere 6.1. &lt;a href="http://jlorenzen.blogspot.com/2009/12/installing-websphere-61-on-centos-53.html"&gt;Installation issues on CentOS&lt;/a&gt; and &lt;a href="http://jlorenzen.blogspot.com/2010/01/precompiling-jsps-for-websphere-61.html"&gt;Precompiling JSPs&lt;/a&gt; were just a few of the issues we encountered. We are still producing 2 different EARs, but both are based on identical WARs.&lt;br /&gt;&lt;br /&gt;The latest issue had to do with receiving a WebSphere exception from a Init Servlet that started a separate Thread. This Thread contained code that indirectly performed a JNDI lookup to get a Datasource. Unlike JBoss, WebSphere apparently doesn't like &lt;a href="http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html#spring-4"&gt;Unmanaged Threads&lt;/a&gt; performing JNDI lookups.&lt;br /&gt;&lt;br /&gt;Here is the WebSphere exception:&lt;br /&gt;&lt;br /&gt;"&lt;i&gt;javaURLContex E NMSV0310E: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component. This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;This seems to be a rather common issue in WebSphere with multiple possible solutions. I guess ideally you &lt;i&gt;should&lt;/i&gt; try and &lt;a href="http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html"&gt;configure&lt;/a&gt; a container-managed Thread using CommonJ (see section Scheduling and thread pooling). Unfortunately, the &lt;a href="http://static.springsource.org/spring/docs/2.5.6/api/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.html"&gt;configuration&lt;/a&gt; is different for JBoss.&lt;br /&gt;&lt;br /&gt;Fortunately, I think I stumbled upon another solution. While reviewing the WAR Spring applicationContext.xml file that configured our Datasource I noticed a property called &lt;i&gt;lookupOnStartup&lt;/i&gt;. It was set to false and when setting it to true, the exception went away.&lt;pre&gt;&lt;code&gt;&amp;lt;bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"&amp;gt;&lt;br /&gt;    &amp;lt;property name="jndiName" value="java:comp/env/jdbc/MY-DS"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="lookupOnStartup" value="true"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="cache" value="true"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="proxyInterface" value="javax.sql.DataSource"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;When setting it back to false the exception appeared again; setting it back to true the exception was gone. Unfortunately, I can only speculate as to why this solved the issue. My guess is, when &lt;i&gt;lookupOnStartup&lt;/i&gt; was false, the first attempt to get the Datasource was from a separate Thread which WebSphere didn't like. However, when setting &lt;i&gt;lookupOnStartup&lt;/i&gt; to true, the first time the Datasource was retrieved was by a container-managed Thread and once my separate Thread needed the Datasource it was already looked up and cached. According to the javadocs for &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jndi/JndiObjectFactoryBean.html#setLookupOnStartup%28boolean%29"&gt;JndiObjectFactoryBean.setLookupOnStartup&lt;/a&gt; the default is true, so it can't be that bad, right? I can't think of a reason why someone would want this delayed.&lt;br /&gt;&lt;br /&gt;If you ever run into this issue, you might consider setting &lt;i&gt;lookupOnStartup&lt;/i&gt; to true and see if that fixes your issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4547304435980284774?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4547304435980284774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4547304435980284774'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/04/possible-solution-for-websphere-issue.html' title='Possible solution for WebSphere issue NMSV0310E'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5597196130107759875</id><published>2010-03-17T00:11:00.005-05:00</published><updated>2010-03-17T00:34:45.693-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mvnsh'/><category scheme='http://www.blogger.com/atom/ns#' term='cli'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>How to Speed up Maven</title><content type='html'>How many times do you invoke maven in a day? How much time could you save if you shaved 15 seconds off each execution? That doesn't really sound like a lot but when executed a 100 times a day it adds up quickly; and 15 seconds is probably conservative. Now stop being selfish and think collectively as team how often maven is executed. 15 seconds for 50-100 builds a day across a team of 10-15 programmers adds up even quicker. This was my experience experimenting with the &lt;a href="http://wiki.github.com/mrdon/maven-cli-plugin/"&gt;maven-cli-plugin&lt;/a&gt; with a simple sub-module running &lt;i&gt;mvn clean install&lt;/i&gt; with unit tests.&lt;br /&gt;&lt;br /&gt;I had never actually heard of maven providing this ability. I had seen and used it for other technologies like grails and scala, but I never considered if maven did as well. It wasn't until &lt;a href="http://twitter.com/jstrachan"&gt;James Strachen&lt;/a&gt; recently tweeted about attempting to use a new feature provided by Sonatype called &lt;a href="http://shell.sonatype.org/"&gt;mvnsh&lt;/a&gt;: "a CLI Interface that enables you to speed up your builds because project information and Maven plugins are loaded into a single, always-ready JVM instance". From the &lt;a href="http://shell.sonatype.org/faq.html"&gt;FAQ&lt;/a&gt;, "The Maven engine is only started up (bootstrapped) one time and then held in a "ready" state waiting for user input of Maven or other shell command". Since I spend most of my day basically running maven, I was very intrigued.&lt;br /&gt;&lt;br /&gt;Unfortunately, it appears mvnsh only supports maven 3 projects and our projects are still using maven 2. Even though I've read maven 3 is &lt;a href="http://www.sonatype.com/people/2009/11/maven-3x-paving-the-desire-lines-part-one-2/"&gt;backwards compatible&lt;/a&gt;, I'm still waiting for a more official stable release (maven 3 is currently at 3.0-alpha-7). On the bright side, it appears mvnsh was set to improve on the maven-cli-plugin that supports maven 2 projects.&lt;br /&gt;&lt;br /&gt;So I just wanted to share my experience getting the maven-cli-plugin set up and get the word out to fellow maven users to improve their productivity. Overall it seems to work as expected and does improve my local build times. I'm on Ubuntu 9.10, maven 2.0.10, and JDK 1.5. As I mentioned in the beginning, using &lt;i&gt;cli:execute-phase&lt;/i&gt; decreased my build times approximately 15 seconds. The biggest disadvantage so far is I don't have access to my alias's, which I depend on heavily for just about everything I do with maven.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Getting started with the maven-cli-plugin&lt;/b&gt;&lt;br /&gt;I basically followed the &lt;a href="http://wiki.github.com/mrdon/maven-cli-plugin/user-guide"&gt;Common Setup&lt;/a&gt; instructions on the github wiki User Guide.&lt;br /&gt;&lt;br /&gt;I added the pluginGroup to my settings.xml file:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;pluginGroups&amp;gt;&lt;br /&gt;    &amp;lt;pluginGroup&amp;gt;org.twdata.maven&amp;lt;/pluginGroup&amp;gt;&lt;br /&gt;&amp;lt;/pluginGroups&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;I then added a new profile to my settings.xml file:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;profile&amp;gt;&lt;br /&gt;    &amp;lt;id&amp;gt;cli&amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;pluginRepositories&amp;gt;&lt;br /&gt;        &amp;lt;pluginRepository&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;twdata-m2-repository&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;name&amp;gt;twdata.org Maven 2 Repository&amp;lt;/name&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://twdata-m2-repository.googlecode.com/svn/&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;/pluginRepository&amp;gt;&lt;br /&gt;    &amp;lt;/pluginRepositories&amp;gt;&lt;br /&gt;&amp;lt;/profile&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;And finally I enabled the new profile in settings.xml:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;activeProfiles&amp;gt;&lt;br /&gt;    &amp;lt;activeProfile&amp;gt;cli&amp;lt;/activeProfile&amp;gt;&lt;br /&gt;&amp;lt;/activeProfiles&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;b&gt;Using the maven-cli-plugin&lt;/b&gt;&lt;br /&gt;The maven-cli-plugin basically supports 2 goals: execute and execute-phase. Use execute when you want to run goals and use execute-phase when you want to run phases. It's unfortunate the plugin forces you to pre-commit to one or the other; hopefully mvnsh has improved this. I typically run clean install which are phases so I ran: &lt;i&gt;mvn cli:execute-phase&lt;/i&gt;. This puts you in an interactive shell where you can run clean install. Once finished you continue to stay in the shell allowing you to repeatedly execute mvn phases without having to bootstrap maven each time.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;Since I spend a majority of my time executing maven and this simple experiment decreased my build times, I plan on using the cli plugin for every day use when I don't want to use my alias's. Also, this plugin should work on windows as well so don't think you are left out. Let me know how your mileage varies. Do you have any other tips that improve maven execution times?&lt;br /&gt;&lt;br /&gt;On a side note, I'm sure the django/python crowd cringe at how much time java developers waste compiling and deploying. Execution times are something I believe they don't have to worry about.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5597196130107759875?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5597196130107759875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5597196130107759875'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/03/how-to-speed-up-maven.html' title='How to Speed up Maven'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1244212587354725326</id><published>2010-03-01T15:48:00.002-06:00</published><updated>2010-03-04T07:58:53.883-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Free Maven Repository Hosting for Open Source projects by Sonatype</title><content type='html'>I'm very excited to &lt;a href="http://java.dzone.com/news/sonatype-free-maven-repo"&gt;see&lt;/a&gt; Sonatype support maven repositories for Open Source projects that use maven. In all honesty, they didn't have to do this. Unfortunately, the java.net repo was &lt;a href="http://java.dzone.com/articles/dont-publish-nexus-oss-here"&gt;harming&lt;/a&gt; the maven reputation. I've had direct experience using the java.net maven repo and can say it was an unpleasant experience. When we open sourced our 4 JBI (Java Business Integration) &lt;a href="http://wiki.open-esb.java.net/Wiki.jsp?page=GestaltUserCenter"&gt;Components&lt;/a&gt; their home existed on java.net and we used the their maven repo. It was difficult to upload anything and it seemed to be constantly down.&lt;br /&gt;&lt;br /&gt;Before this announcement, open source java projects using maven didn't really have an option as to where they could publish their artifacts. To my knowledge neither Google Code or Sourceforge offered this capability. Apache and Codehaus did and obviously you still have the Maven Central (http://repo1.maven.org/maven2/), but I never went through the process of what it took to use them. Now it doesn't matter where your project is hosted. Hopefully the next thing to come is free Continuous Integration services in the cloud using &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt;. I think this is the next step for project hosting sites like Google Code and github.&lt;br /&gt;&lt;br /&gt;Providing free maven repos I think has a lot of benefits and not just for maven users. For example, this should benefit all dependency management tools that are built on top of maven repos. I'm not 100% sure tools like &lt;a href="http://ant.apache.org/ivy/"&gt;Ivy&lt;/a&gt;, &lt;a href="http://groovy.codehaus.org/Grape"&gt;Grape&lt;/a&gt;, &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;, and &lt;a href="http://buildr.apache.org/"&gt;Buildr&lt;/a&gt; use maven repo's, but my guess is they do and this will benefit those users. Another benefit is being able to standardize on maven repositories, hopefully preventing users from searching where they can find your artifacts. I've wasted a lot of time in the past trying to find valid repositories where I could find artifacts for a project I was wanting to use.&lt;br /&gt;&lt;br /&gt;I'm also very impressed with the &lt;a href="https://docs.sonatype.com/display/NX/OSS+Repository+Hosting"&gt;features&lt;/a&gt; Sonatype is providing. Not only will they support release artifacts but &lt;a href="http://www.blogger.com/goog_1267710764129"&gt;SNAPSHOT's&lt;/a&gt; as well which could consume a lot of space. You'll also be able to easily sync with Central. Finally, they will support a staging repo in order to test things out before officially releasing.&lt;br /&gt;&lt;br /&gt;So go &lt;a href="https://docs.sonatype.com/display/NX/OSS+Repository+Hosting"&gt;sign up&lt;/a&gt; and thanks &lt;a href="http://www.sonatype.com/"&gt;Sonatype&lt;/a&gt;. Also, read this &lt;a href="http://jlorenzen.blogspot.com/2007/09/how-to-create-release-using-maven2.html"&gt;post&lt;/a&gt; to learn how to release your project using the maven release plugin.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1244212587354725326?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1244212587354725326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1244212587354725326'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/03/free-maven-repository-hosting-for-open.html' title='Free Maven Repository Hosting for Open Source projects by Sonatype'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3300634824329473048</id><published>2010-02-24T22:15:00.011-06:00</published><updated>2010-02-26T14:42:47.430-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jira'/><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='vcs'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Commit Comments: A Conversation with your Future Self</title><content type='html'>&lt;a href="http://www.wpromote.com/blog/wp-content/uploads/2008/11/back-to-the-future.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://www.wpromote.com/blog/wp-content/uploads/2008/11/back-to-the-future.jpg" style="cursor: pointer; float: right; height: 280px; margin: 0pt 0pt 10px 10px; width: 434px;" /&gt;&lt;/a&gt;I frequently find myself searching subversion commit logs trying to find hints as to why certain "features/bugs" where introduced and why. Usually this results in wasting several hours and almost every time I get frustrated with a lack of dialogue in commit comments. I can't stress enough the importance of this often over looked feature when committing changes. A lot of developers look at it like a 30 second burden that's preventing them from taking lunch earlier. What they really should be doing is pretending it's a conversation with their future self. Six months from now you're most likely going to be seeing those comments, or lack of, wondering why you made that change. It's in that moment I'd rather have a very descriptive summary of what changed and why verses diff'in every version known to man.&lt;br /&gt;&lt;br /&gt;I'm not asking for a Kevin Costner script, just be a little more specific. On average, my comments are 1-3 sentences. For the important changes, I've used paragraphs before. Comments with fewer than 5 words drive me nuts, and I have seen a lot of them.&lt;br /&gt;&lt;br /&gt;Ever seen a movie where campers make a trail using something like marshmallows so they can find their way back? Think of your commit comments like marshmallows helping you unravel the mystery of an issue and start developing the habit of providing more descriptive commit comments.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Other Useful Tools&lt;/span&gt;&lt;a href="http://3.bp.blogspot.com/_u6FjI-f0VoU/S4YFhTDRSrI/AAAAAAAAALw/w9lS45K_ct8/s1600-h/jira-svn.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5442043269331634866" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/S4YFhTDRSrI/AAAAAAAAALw/w9lS45K_ct8/s400/jira-svn.png" style="cursor: pointer; float: right; height: 136px; margin: 0pt 0pt 10px 10px; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;One of the tools I have grown fond of is the &lt;a href="https://studio.plugins.atlassian.com/wiki/display/SVN/Subversion+JIRA+plugin"&gt;Jira subversion plugin&lt;/a&gt;. Our team uses Jira as our issue tracking system. Nothing gets committed without a Jira number. This is enforced using a subversion &lt;a href="http://svnbook.red-bean.com/nightly/en/svn.reposadmin.create.html"&gt;pre-commit hook&lt;/a&gt;, so every developer has to start their comment with a Jira number. Then in Jira, there is a Subversion Commits link at the bottom to where anyone can view the files changes and their comments.&lt;br /&gt;&lt;br /&gt;Using the subversion pre-commit hook has another added bonus, which is using the &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/JIRA+Plugin"&gt;Hudson Jira Plugin&lt;/a&gt;. After a successful build, hudson will extract the Jira number(s) from the commit comments and add a comment to the Jira stating it was integrated at a specific build # and includes a link.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3300634824329473048?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3300634824329473048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3300634824329473048'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/02/commit-comments-conversation-with-your.html' title='Commit Comments: A Conversation with your Future Self'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_u6FjI-f0VoU/S4YFhTDRSrI/AAAAAAAAALw/w9lS45K_ct8/s72-c/jira-svn.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-412196823407340366</id><published>2010-02-16T23:45:00.019-06:00</published><updated>2010-02-17T01:03:35.475-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='jetty'/><category scheme='http://www.blogger.com/atom/ns#' term='jersey'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Rapid REST Development with maven jetty plugin</title><content type='html'>Ever wonder how much time is wasted by Java developers rebuilding and redeploying web applications? For me alone I can't imagine it. In fact, I'd be embarrassed if Google Buzz made it public knowledge without my consent. Two years ago I wrote an article "&lt;a href="http://jlorenzen.blogspot.com/2007/10/no-more-j2ee-webapps.html"&gt;No more J2EE Apps&lt;/a&gt;" and I received a lot of great feedback. Let me first say that I think, IMHO, Java Developers are at a disadvantage when it comes to rapidly developing web applications with a static language. Developers using python, php, rails, or grails really don't even have to spend a second trying to solve this problem. On the other hand, Java Developers have to figure out how to best accomplish this, and every situation seems to be different: JBoss, Weblogic, Eclipse, Idea, Netbeans, Jetty, JRebel. Of all the solutions I think &lt;a href="http://www.zeroturnaround.com/jrebel/"&gt;JRebel&lt;/a&gt; provides the best chance for success that solves any environment no matter the web container or developers IDE of choice.&lt;br /&gt;&lt;br /&gt;I haven't really done much hardcore java development in awhile, but in order to improve my team's productivity, I am going to be exploring best practices the next couple of months concerning this area. First up, I am going to explain how I got the &lt;a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin"&gt;maven jetty plugin&lt;/a&gt; to work with our REST Services WAR and the steps necessary to redeploy changes. The nice thing about jetty is it's easy to use from maven and we could use it in our CI environment to possibly reduce our build times and provide quicker feedback. The downside is each change requires jetty to hotdeploy the new WAR. End the end I think the best solution will be a combination of JBoss+JRebel. But I won't get to for awhile.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Maven Jetty Plugin&lt;/span&gt;&lt;br /&gt;My first prototype uses the maven-jetty-plugin version 6. The application we are testing is a WAR containing REST Services built with &lt;a href="https://jersey.dev.java.net/"&gt;Jersey&lt;/a&gt; (JAX-RS). Here is a good posting by my co-worker Jeff Black "&lt;a href="http://codebeneath.blogspot.com/2008/03/jersey-jetty-and-maven-style.html"&gt;Jersey...Jetty and Maven style!&lt;/a&gt;". This example didn't work for me because for some insane reason the init-param, com.sun.ws.rest.config.property.packages, does not work in WebSphere. So I had to do some slight modifications to get it to work without that being declared. My pom.xml and jetty.xml files are below. Most "normal" non-Jersey applications don't need all of this, but it was necessary to get our legacy WAR working with jetty.&lt;br /&gt;&lt;br /&gt;Here are the steps involved to start jetty and redeploy changes:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;mvn install jetty:run&lt;/span&gt; - this will first build the WAR and then start jetty while also deploying the WAR. Running install was necessary because I reference the exploded WAR directory under target in the jetty configuration.&lt;/li&gt;&lt;li&gt;Make changes to source code&lt;/li&gt;&lt;li&gt;Run "&lt;span style="font-weight: bold;"&gt;mvn compile war:exploded&lt;/span&gt;" in a separate terminal to compile your changes and copy the new class files to the location Jersey expects to find them. Which in my case is /target/myapp/WEB-INF/classes&lt;/li&gt;&lt;li&gt;Click back to the terminal running jetty and hit the ENTER key. This causes jetty to reload the WAR. This is because by default I set the scan interval to 0 and jetty.reload to manual, so I can batch up multiple changes before reloading.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Overall I am happy with the results so far. Previously, it took 1-2 minutes and sometimes more to rebuild the war and hotdeploy to JBoss. Using the jetty plugin this now takes around 30 seconds. Again, I think this could be further improved by using JRebel.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tips&lt;/span&gt;&lt;br /&gt;I did have to update my MAVEN_OPTS environment variable to increase Java's PermGenSpace since jetty reloads the WAR each time and you'll quickly run out of memory. This was something I was already doing in JBoss. Here is what it is set to:&lt;br /&gt;&lt;br /&gt;export MAVEN_OPTS="-Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m"&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Sample Files&lt;/span&gt;&lt;br /&gt;Here is my pom.xml&lt;br /&gt;&lt;pre class="brush: xml"&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;maven-jetty-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;6.1.22&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;configuration&amp;gt;&lt;br /&gt;      &amp;lt;jettyConfig&amp;gt;${project.build.testOutputDirectory}/jetty.xml&amp;lt;/jettyConfig&amp;gt;&lt;br /&gt;      &amp;lt;scanIntervalSeconds&amp;gt;${jetty.scan.sec}&amp;lt;/scanIntervalSeconds&amp;gt;&lt;br /&gt;      &amp;lt;useTestClasspath&amp;gt;true&amp;lt;/useTestClasspath&amp;gt;&lt;br /&gt;      &amp;lt;webAppConfig&amp;gt;&lt;br /&gt;          &amp;lt;baseResource implementation="org.mortbay.resource.ResourceCollection"&amp;gt;&lt;br /&gt;              &amp;lt;resourcesAsCSV&amp;gt;${project.build.directory}/myapp&amp;lt;/resourcesAsCSV&amp;gt;&lt;br /&gt;          &amp;lt;/baseResource&amp;gt;&lt;br /&gt;      &amp;lt;/webAppConfig&amp;gt;&lt;br /&gt;      &amp;lt;systemProperties&amp;gt;&lt;br /&gt;          &amp;lt;systemProperty&amp;gt;&lt;br /&gt;              &amp;lt;name&amp;gt;jetty.port&amp;lt;/name&amp;gt;&lt;br /&gt;              &amp;lt;value&amp;gt;${jetty.port}&amp;lt;/value&amp;gt;&lt;br /&gt;          &amp;lt;/systemProperty&amp;gt;&lt;br /&gt;      &amp;lt;/systemProperties&amp;gt;&lt;br /&gt;      &amp;lt;systemProperties&amp;gt;&lt;br /&gt;          &amp;lt;systemProperty&amp;gt;&lt;br /&gt;              &amp;lt;name&amp;gt;jetty.reload&amp;lt;/name&amp;gt;&lt;br /&gt;              &amp;lt;value&amp;gt;${jetty.reload}&amp;lt;/value&amp;gt;&lt;br /&gt;          &amp;lt;/systemProperty&amp;gt;&lt;br /&gt;      &amp;lt;/systemProperties&amp;gt;&lt;br /&gt;  &amp;lt;/configuration&amp;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;commons-dbcp&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-dbcp&amp;lt;/artifactId&amp;gt;&lt;br /&gt;          &amp;lt;version&amp;gt;1.2.1&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;net.sourceforge.jtds&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;jtds&amp;lt;/artifactId&amp;gt;&lt;br /&gt;          &amp;lt;version&amp;gt;1.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;com.oracle.jdbc&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;ojdbc14&amp;lt;/artifactId&amp;gt;&lt;br /&gt;          &amp;lt;version&amp;gt;10.2.0&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;/plugin&amp;gt;&lt;br /&gt;.....&lt;br /&gt;&amp;lt;properties&amp;gt;&lt;br /&gt; &amp;lt;jetty.port&amp;gt;8080&amp;lt;/jetty.port&amp;gt;&lt;br /&gt; &amp;lt;jetty.scan.sec&amp;gt;10&amp;lt;/jetty.scan.sec&amp;gt;&lt;br /&gt; &amp;lt;jetty.reload&amp;gt;manual&amp;lt;/jetty.reload&amp;gt;&lt;br /&gt;&amp;lt;/properties&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here is my jetty.xml located under /src/test/resources used to define the Datasource.&lt;br /&gt;&lt;pre class="brush: xml"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Configure id="Server" class="org.mortbay.jetty.Server"&amp;gt;&lt;br /&gt; &lt;br /&gt;  &amp;lt;New id="MYAPP-DS" class="org.mortbay.jetty.plus.naming.Resource"&amp;gt;&lt;br /&gt;      &amp;lt;Arg&amp;gt;jdbc/MYAPP-DS&amp;lt;/Arg&amp;gt;&lt;br /&gt;      &amp;lt;Arg&amp;gt;&lt;br /&gt;          &amp;lt;New class="org.apache.commons.dbcp.BasicDataSource"&amp;gt;&lt;br /&gt;              &amp;lt;Set name="driverClassName"&amp;gt;oracle.jdbc.driver.OracleDriver&amp;lt;/Set&amp;gt;&lt;br /&gt;              &amp;lt;Set name="url"&amp;gt;jdbc:oracle:thin:@localhost:1521:XE&amp;lt;/Set&amp;gt;&lt;br /&gt;              &amp;lt;Set name="username"&amp;gt;user&amp;lt;/Set&amp;gt;&lt;br /&gt;              &amp;lt;Set name="password"&amp;gt;password&amp;lt;/Set&amp;gt;&lt;br /&gt;          &amp;lt;/New&amp;gt;&lt;br /&gt;      &amp;lt;/Arg&amp;gt;&lt;br /&gt;  &amp;lt;/New&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/Configure&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-412196823407340366?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/412196823407340366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/412196823407340366'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/02/rapid-rest-development-with-maven-jetty.html' title='Rapid REST Development with maven jetty plugin'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6907380188923699422</id><published>2010-02-04T07:53:00.021-06:00</published><updated>2010-02-04T10:14:44.042-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='extjs'/><title type='text'>Getting Started with Extjs</title><content type='html'>I was recently approached by an internal co-worker within Accenture about our teams experience with &lt;a href="http://www.extjs.com/"&gt;Extjs&lt;/a&gt;. Out of 150,000+ employees in Accenture he was able to find us through &lt;a href="http://www.yammer.com/"&gt;Yammer&lt;/a&gt;, a free private twitter-like service for companies. Originally I was just going to respond to him via email after our phone conversation, but that would only benefit him. Instead I thought it might be a good idea to share that experience on this blog.&lt;br /&gt;&lt;br /&gt;My current team has been using Extjs for about 2 years. I don't consider myself an expert nor do I actually like developing in a language that needs to work in multiple browsers. We started out with version 2.x and late last year converted our projects to version 3, which was no easy task.&lt;br /&gt;&lt;br /&gt;I will say Extjs has impressed this Java developer. Their documentation and examples are excellent and feedback on the forums is great. Most of my team didn't have any prior heavy javascript backgrounds and all have been able to come up to speed quickly. Right now I think the biggest drawback is the GPL licensing of version 3. I understand why they did it, but doesn't mean I have to like it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Extjs Resources&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a style="font-weight: bold;" href="http://www.extjs.com/deploy/dev/examples/samples.html"&gt;Examples&lt;/a&gt; - Extjs comes with a nice library of great examples on all kinds of things you can do with Extjs. All the examples also come with the download. One of the neatest examples is the &lt;a href="http://www.extjs.com/deploy/dev/examples/grid-filtering/grid-filter-local.html"&gt;Advanced Grid Filtering&lt;/a&gt;. One of the main reasons we upgraded to version 3 was for this feature.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a style="font-weight: bold;" href="http://www.extjs.com/deploy/dev/docs/"&gt;API Documentation&lt;/a&gt; - The javadoc for extjs. This is the most important and most referenced documentation for any extjs developer. Keep in mind this only shows the most recent version. If you want the API documentation for previous versions, you'll need to download that version of Extjs. The download includes the same API documentation. For local installation or offline reference, there is also a very nice Adobe Air app (see &lt;a href="http://www.extjs.com/products/extjs/download.php"&gt;download page&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;&lt;a style="font-weight: bold;" href="http://www.extjs.com/forum/"&gt;Forums&lt;/a&gt; - The forums are very active and we have received a lot of help. We also have purchased the premium support and overall I'd say it was worth it. Especially since we no longer have that goto javascript guru anymore (yeah you know who you are).&lt;/li&gt;&lt;li&gt;&lt;a style="font-weight: bold;" href="http://www.extjs.com/learn/Ext_Extensions"&gt;Community Plugins&lt;/a&gt; - It's not huge but between the examples noted above and the community plugins we have been able to reuse a lot and create some neat stuff pretty fast.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Blogs&lt;/span&gt; - I'd recommend subscribing to the official &lt;a href="http://www.extjs.com/blog/"&gt;Extjs blog&lt;/a&gt; as well as this search related &lt;a href="http://www.dzone.com/links/feed/search/extjs/rss.xml"&gt;feed&lt;/a&gt; from DZone. And, just because I think it is cool, &lt;a href="http://www.google.com/reader/bundle/user%2F06921991648092671376%2Fbundle%2Fextjs"&gt;here&lt;/a&gt; is Google Reader bundle I created that captures everything I tag with extjs. Finally, here is a &lt;a href="http://jlorenzen.blogspot.com/search?q=extjs"&gt;search&lt;/a&gt; on my blog about articles I have written about Extjs.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Books&lt;/span&gt; - According to Amazon there are &lt;a href="http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&amp;amp;field-keywords=extjs&amp;amp;x=0&amp;amp;y=0"&gt;multiple books&lt;/a&gt; out right now about developing with Extjs. I have "&lt;a href="http://www.amazon.com/Learning-Ext-JS-Shea-Frederick/dp/1847195148/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1265296289&amp;amp;sr=8-1"&gt;Learning Ex JS&lt;/a&gt;" by Shea Frederick.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Miscellaneous&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Javascript/CSS Consolidator&lt;/span&gt; - One of the best moves we made was investing in a javascript/css consolidator. Props go out to &lt;a href="http://joe.kueser.com/"&gt;Joe Kueser&lt;/a&gt; for doing this for us. After a few months of development, our application started to grind to a slow crawl as several (80+) javascript and css files where being downloaded. Using the &lt;a href="https://jawr.dev.java.net/"&gt;jawr framework&lt;/a&gt; we reduced that to around 20 GET requests which improved performance dramatically. Not only does it combine multiple files into one but it also minifies them (removes comments and spaces, etc) and supports gzipping them. I have been very impressed with jawr. It has exceeded our expectations and I would recommend it to anyone.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Development Environment&lt;/span&gt; - No web developer would be complete without Firefox and &lt;a href="http://getfirebug.com/"&gt;Firebug&lt;/a&gt;. But for those occansional nasty IE issues I haven't found the perfect solution. In the past I have had some luck with &lt;a href="http://code.google.com/p/jsdt/"&gt;jsdt&lt;/a&gt;. Currently I am using IE8 in virutalbox in IE7 mode with it's built in &lt;a href="http://techie-buzz.com/ie8/ie8-includes-developer-tools.html"&gt;Developer Tools&lt;/a&gt;. Although not firebug, it's the closest I have come to find. For those really bad IE6 issues I have used the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=e59c3964-672d-4511-bb3e-2d5e1db91038&amp;amp;displaylang=en"&gt;Internet Explorer Developer Toolbar&lt;/a&gt; which beats scattered alerts in your code and is better than nothing.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Extjs version 2.x or 3.x&lt;/span&gt; - There has been a lot of &lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;ct=res&amp;amp;cd=1&amp;amp;ved=0CAkQFjAA&amp;amp;url=http%3A%2F%2Fwww.gwt-ext.com%2Fblog%2F04272008%2Fjacks-response.pdf&amp;amp;ei=ue5qS_mLCIju-QaBoNyGBA&amp;amp;usg=AFQjCNGut2SptzwCkkXGpya2XH8MbTj1Gg&amp;amp;sig2=5iM6JBbsEMhFLqUaciR5cg"&gt;history&lt;/a&gt; surrounding the licensing strategy so I won't go into all of that. Just know that version 2.x is LGPL and can be used or embedded into your applications for free. Version 3.x is GPL which means if your project isn't some internal IT app or also GPL you need to purchase &lt;a href="http://www.extjs.com/products/license.php"&gt;developer licenses&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Public Uses&lt;/span&gt; - Here are just a few well known sites I have noticed using Extjs: &lt;a href="http://quicken.intuit.com/"&gt;Quicken Online&lt;/a&gt; and &lt;a href="http://www.djindexes.com/"&gt;Dow Jones Industrial Index&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;jQuery Integration&lt;/span&gt; - In case you want to combine jQuery and Extjs you can by using the extjs-jquery-adapter available in the download. I haven't really used jQuery a lot but from what I have read and heard, it's a great javascript library that supports animation and DOM querying. You can do these things in Extjs, but jQuery looks like it might do it better and cleaner. I think Extjs excels in providing out of the box prebuilt and customizable Widgets/Components like the Grid (Table).&lt;br /&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/1280619439915049383-6907380188923699422?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6907380188923699422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6907380188923699422'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/02/getting-started-with-extjs.html' title='Getting Started with Extjs'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7413131131594087621</id><published>2010-01-28T22:51:00.017-06:00</published><updated>2010-01-28T23:25:33.806-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='websphere'/><category scheme='http://www.blogger.com/atom/ns#' term='j2ee'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Precompiling JSPs for WebSphere 6.1</title><content type='html'>Don't envy me..........Your about to witness my efforts from the past 2-3 weeks.&lt;br /&gt;&lt;br /&gt;For the past week I have been trying to get precompiled JSPs working for &lt;a href="http://www-01.ibm.com/support/docview.wss?uid=swg27007472"&gt;WebSphere 6.1&lt;/a&gt;, because our target environment does not include the Java Development Kit (JDK) for security reasons. The following is a brief explanation on how to precompile JSPs for WebSphere 6.1 using maven2. And as an added bonus, I'll also explain how to use the &lt;a href="http://mojo.codehaus.org/was6-maven-plugin/"&gt;maven-was6-plugin&lt;/a&gt; to automate deployment of a WAR using Jython.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Precompiling JSPs for WebSphere&lt;/span&gt;&lt;br /&gt;First off, let me say, this was not fun. I spent a ton of time trying to figure out why the precompiled JSPs worked on JBoss 4.2.1, but not WebSphere 6.1. Both maven jspc plugins (&lt;a href="http://mojo.codehaus.org/jspc-maven-plugin/usage.html"&gt;jspc-maven-plugin&lt;/a&gt; and &lt;a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Jspc+Plugin"&gt;maven-jetty-jspc-plugin&lt;/a&gt;) produced precompiled JSPs that worked on JBoss, but not WebSphere. From what I could tell it all boiled down to the fact that JBoss 4.2.1 includes the 2.1 version of jsp-api while WebSphere 6.1.0.27 includes the 2.0 version. Just so you believe me, the 2 conflicting jars in WebSphere were: $WAS_HOME/lib/j2ee.jar and $WAS_HOME/plugins/com.ibm.ws.webcontainer_2.0.0.jar. On the plus side, I did find a great Java decompiler for linux called &lt;a href="http://java.decompiler.free.fr/"&gt;jd-gui&lt;/a&gt;. I'd highly recommend it for any operation system. It uses jad, but provides a nice GUI interface that even lets you open a jar and explore any .class file.&lt;br /&gt;&lt;br /&gt;In summary, based on my experience, the 2 existing maven jspc plugins do not create compatible precompiled JSPs with WebSphere 6.1.0.27. Surprisingly, the solution that ended up working was using the JspBatchCompiler.sh script that comes with WebSphere.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/rweb_jspbchtl.html"&gt;JspBatchCompiler.sh&lt;/a&gt; was exactly what we needed. Thankfully, you can give this script a WAR or EAR file and it will explode it, precompile all the JSPs, and repackage it back up again. This script is located under $WAS_HOME/bin. Once I verified it by manually running the script, the next step was to automate it using maven. Since I wasted so much time figuring everything else out, I didn't spend a ton of time improving the maven portion. Instead I decided to go with what I knew and that was using the &lt;a href="http://mojo.codehaus.org/exec-maven-plugin/"&gt;exec-maven-plugin&lt;/a&gt; to run the script. The following is the profile I used to precompile the JSPs in the WARs located in the EAR.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;!--Maven Profile to precompile JSPs--&gt;&lt;br /&gt;&lt;!--mvn -Pprecompile -DwasHome=/opt/websphere--&gt;&lt;br /&gt;&amp;lt;profile&amp;gt;&lt;br /&gt;&amp;lt;id&amp;gt;precompile&amp;lt;/id&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.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;exec-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;   &amp;lt;execution&amp;gt;&lt;br /&gt;       &amp;lt;id&amp;gt;precompile-was-ear-jsps&amp;lt;/id&amp;gt;&lt;br /&gt;       &amp;lt;phase&amp;gt;validate&amp;lt;/phase&amp;gt;&lt;br /&gt;       &amp;lt;goals&amp;gt;&lt;br /&gt;           &amp;lt;goal&amp;gt;exec&amp;lt;/goal&amp;gt;&lt;br /&gt;       &amp;lt;/goals&amp;gt;&lt;br /&gt;       &amp;lt;configuration&amp;gt;&lt;br /&gt;           &amp;lt;executable&amp;gt;${wasHome}/bin/JspBatchCompiler.sh&amp;lt;/executable&amp;gt;&lt;br /&gt;           &amp;lt;arguments&amp;gt;&lt;br /&gt;               &amp;lt;argument&amp;gt;-ear.path&amp;lt;/argument&amp;gt;&lt;br /&gt;               &amp;lt;argument&amp;gt;${pom.basedir}/target/${project.artifactId}-${project.version}.${project.packaging}&amp;lt;/argument&amp;gt;&lt;br /&gt;               &amp;lt;argument&amp;gt;-jdkSourceLevel&amp;lt;/argument&amp;gt;&lt;br /&gt;               &amp;lt;argument&amp;gt;15&amp;lt;/argument&amp;gt;&lt;br /&gt;           &amp;lt;/arguments&amp;gt;&lt;br /&gt;       &amp;lt;/configuration&amp;gt;&lt;br /&gt;   &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&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-antrun-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt;   &amp;lt;execution&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;rename-replace-was-ear&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;phase&amp;gt;validate&amp;lt;/phase&amp;gt;&lt;br /&gt;   &amp;lt;goals&amp;gt;&lt;br /&gt;       &amp;lt;goal&amp;gt;run&amp;lt;/goal&amp;gt;&lt;br /&gt;   &amp;lt;/goals&amp;gt;&lt;br /&gt;   &amp;lt;configuration&amp;gt;&lt;br /&gt;       &amp;lt;tasks&amp;gt;&lt;br /&gt;           &amp;lt;move file="${java.io.tmpdir}/${project.artifactId}-${project.version}.${project.packaging}"&lt;br /&gt;         tofile="${pom.basedir}/target/${project.artifactId}_jspc-${project.version}.${project.packaging}"/&amp;gt;&lt;br /&gt;           &amp;lt;delete file="${pom.basedir}/target/${project.artifactId}-${project.version}.${project.packaging}"/&amp;gt;&lt;br /&gt;       &amp;lt;/tasks&amp;gt;&lt;br /&gt;   &amp;lt;/configuration&amp;gt;&lt;br /&gt;   &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&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;/profile&amp;gt;&lt;br /&gt;&lt;/pre&gt;The first plugin section uses the exec-maven-plugin to run the JspBatchCompiler.sh and takes the EAR as input. The second plugin section uses the &lt;a href="http://maven.apache.org/plugins/maven-antrun-plugin/"&gt;maven-antrun-plugin&lt;/a&gt; to basically rename the EAR to include a keyword (_jspc) in the EAR filename so everyone knows when they have an EAR with precompiled JSPs. It then moves the new EAR from it's tmp location back to the modules target directory where everything expects it to be. Once that is done, it removes the old EAR to avoid confusion.&lt;br /&gt;&lt;br /&gt;About the only improvement that could be made is making it portable to other Operating Systems like Windows. This "could" be accomplished by using the &lt;a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/rweb_jspant.html"&gt;JspC ant task&lt;/a&gt; WebSphere provides, but I couldn't find any good examples of how to do that via maven, so I took a rain check.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Deploy WAR to WebSphere 6.1&lt;/span&gt;&lt;br /&gt;This Jython &lt;a href="http://code.google.com/p/codesnippetssite/wiki/InstallEar"&gt;code snippet&lt;/a&gt; literally saved our sprint. I am not sure how I would have automated deploying and undeploying a WAR via maven without it as the maven-was6-plugin really only works with EARs. This is because when deploying a WAR you need to provide the WARs contextroot, which the plugin currently doesn't support (&lt;a href="http://jira.codehaus.org/browse/MWAS-59"&gt;MWAS-59&lt;/a&gt;). I was however able to call the Jython script from the maven-was6-plugin to undeploy and deploy a WAR.&lt;br /&gt;&lt;br /&gt;The following profiles and Jython scripts show how to use maven and Jython to undeploy and deploy a WAR. The Jython scripts exist in files under the same directory as the pom.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;!--Maven Profile to Undeploy WebSphere WAR--&gt;&lt;br /&gt;&lt;!--mvn -Pundeploy-war -DwasHome=/opt/websphere--&gt;&lt;br /&gt;&amp;lt;profile&amp;gt;&lt;br /&gt;&amp;lt;id&amp;gt;undeploy-war&amp;lt;/id&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.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;was6-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt; &amp;lt;execution&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;undeploy&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;phase&amp;gt;validate&amp;lt;/phase&amp;gt;&lt;br /&gt;   &amp;lt;goals&amp;gt;&lt;br /&gt;     &amp;lt;goal&amp;gt;wsAdmin&amp;lt;/goal&amp;gt;&lt;br /&gt;   &amp;lt;/goals&amp;gt;&lt;br /&gt; &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt; &amp;lt;wasHome&amp;gt;${wasHome}&amp;lt;/wasHome&amp;gt;&lt;br /&gt; &amp;lt;profileName&amp;gt;AppSrv01&amp;lt;/profileName&amp;gt;&lt;br /&gt; &amp;lt;conntype&amp;gt;SOAP&amp;lt;/conntype&amp;gt;&lt;br /&gt; &amp;lt;applicationName&amp;gt;petstore_war&amp;lt;/applicationName&amp;gt;&lt;br /&gt; &amp;lt;earFile&amp;gt;${pom.basedir}/target/petstore.war&amp;lt;/earFile&amp;gt;&lt;br /&gt; &amp;lt;updateExisting&amp;gt;false&amp;lt;/updateExisting&amp;gt;&lt;br /&gt; &amp;lt;language&amp;gt;jython&amp;lt;/language&amp;gt;&lt;br /&gt; &amp;lt;script&amp;gt;uninstallApp.py&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;host&amp;gt;localhost&amp;lt;/host&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;/profile&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush: py"&gt;# File: uninstallApp.py&lt;br /&gt;# Jython script to undeploy WAR&lt;br /&gt;# FYI, the was6 plugin does support the ability to pass in params to the jython script&lt;br /&gt;cellName = 'testbed01Node01Cell'&lt;br /&gt;nodeName = 'testbed01Node01'&lt;br /&gt;serverName = 'server1'&lt;br /&gt;&lt;br /&gt;#Install the app&lt;br /&gt;print "Installing App: "&lt;br /&gt;AdminApp.install("../petstore.war", "-contextroot /petstore -defaultbinding.virtual.host default_host -usedefaultbindings");&lt;br /&gt;AdminConfig.save();&lt;br /&gt;&lt;br /&gt;#Start the app&lt;br /&gt;apps = AdminApp.list().split("\n");&lt;br /&gt;theApp = ""&lt;br /&gt;for iApp in apps:&lt;br /&gt;if str(iApp).find("petstore") &gt;= 0:&lt;br /&gt;theApp = iApp;&lt;br /&gt;print "Starting App: ", theApp&lt;br /&gt;appManager = AdminControl.queryNames('cell='+cellName+',node='+nodeName+',type=ApplicationManager,process='+serverName+',*')&lt;br /&gt;AdminControl.invoke(appManager, 'startApplication', theApp)&lt;br /&gt;print "Application installed and started successfuly!"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Here is the profile and Jython script I used to Deploy a WAR:&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;!--Maven Profile to Deploy WebSphere WAR--&gt;&lt;br /&gt;&lt;!--mvn -Pdeploy-war -DwasHome=/opt/websphere--&gt;&lt;br /&gt;&amp;lt;profile&amp;gt;&lt;br /&gt;&amp;lt;id&amp;gt;deploy-war&amp;lt;/id&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.codehaus.mojo&amp;lt;/groupId&amp;gt;&lt;br /&gt;&amp;lt;artifactId&amp;gt;was6-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&amp;lt;executions&amp;gt;&lt;br /&gt; &amp;lt;execution&amp;gt;&lt;br /&gt;   &amp;lt;id&amp;gt;deploy&amp;lt;/id&amp;gt;&lt;br /&gt;   &amp;lt;phase&amp;gt;validate&amp;lt;/phase&amp;gt;&lt;br /&gt;   &amp;lt;goals&amp;gt;&lt;br /&gt;     &amp;lt;goal&amp;gt;wsAdmin&amp;lt;/goal&amp;gt;&lt;br /&gt;   &amp;lt;/goals&amp;gt;&lt;br /&gt; &amp;lt;/execution&amp;gt;&lt;br /&gt;&amp;lt;/executions&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt; &amp;lt;wasHome&amp;gt;${wasHome}&amp;lt;/wasHome&amp;gt;&lt;br /&gt; &amp;lt;profileName&amp;gt;AppSrv01&amp;lt;/profileName&amp;gt;&lt;br /&gt; &amp;lt;conntype&amp;gt;SOAP&amp;lt;/conntype&amp;gt;&lt;br /&gt; &amp;lt;applicationName&amp;gt;petstore_war&amp;lt;/applicationName&amp;gt;&lt;br /&gt; &amp;lt;earFile&amp;gt;${pom.basedir}/target/petstore.war&amp;lt;/earFile&amp;gt;&lt;br /&gt; &amp;lt;updateExisting&amp;gt;false&amp;lt;/updateExisting&amp;gt;&lt;br /&gt; &amp;lt;language&amp;gt;jython&amp;lt;/language&amp;gt;&lt;br /&gt; &amp;lt;script&amp;gt;installApp.py&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;host&amp;gt;localhost&amp;lt;/host&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;/profile&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush: py"&gt;# File: installApp.py&lt;br /&gt;# Jython script to deploy WAR&lt;br /&gt;# FYI, the was6 plugin does support the ability to pass in params to the jython script&lt;br /&gt;cellName = 'testbed01Node01Cell'&lt;br /&gt;nodeName = 'testbed01Node01'&lt;br /&gt;serverName = 'server1'&lt;br /&gt;&lt;br /&gt;#Install the app&lt;br /&gt;print "Installing App: "&lt;br /&gt;AdminApp.install("../petstore.war", "-contextroot /petstore -defaultbinding.virtual.host default_host -usedefaultbindings");&lt;br /&gt;AdminConfig.save();&lt;br /&gt;&lt;br /&gt;#Start the app&lt;br /&gt;apps = AdminApp.list().split("\n");&lt;br /&gt;theApp = ""&lt;br /&gt;for iApp in apps:&lt;br /&gt;if str(iApp).find("petstore") &gt;= 0:&lt;br /&gt;theApp = iApp;&lt;br /&gt;print "Starting App: ", theApp&lt;br /&gt;appManager = AdminControl.queryNames('cell='+cellName+',node='+nodeName+',type=ApplicationManager,process='+serverName+',*')&lt;br /&gt;AdminControl.invoke(appManager, 'startApplication', theApp)&lt;br /&gt;print "Application installed and started successfuly!"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;That's it. The Jython scripts could be improved by making the cell, node, and server names configurable instead of hardcoded and it "appears" the maven-was6-plugin supports passing in properties, but I just didn't have the time to figure it out at the moment.&lt;br /&gt;&lt;br /&gt;By the way, I hope maven 3 has solved the XML verbosity when it comes to doing simple things like creating profiles. That's a lot of XML to do very little.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7413131131594087621?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7413131131594087621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7413131131594087621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7413131131594087621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7413131131594087621'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/01/precompiling-jsps-for-websphere-61.html' title='Precompiling JSPs for WebSphere 6.1'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5141901518317319621</id><published>2010-01-14T11:06:00.003-06:00</published><updated>2010-01-14T11:29:07.910-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dzone'/><category scheme='http://www.blogger.com/atom/ns#' term='rss'/><category scheme='http://www.blogger.com/atom/ns#' term='yahoo pipes'/><title type='text'>DZone Top Links Feed</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_u6FjI-f0VoU/S09UR-0uxQI/AAAAAAAAALc/oscqsLOikC4/s1600-h/dzone-top-links.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 309px; height: 309px;" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/S09UR-0uxQI/AAAAAAAAALc/oscqsLOikC4/s320/dzone-top-links.png" alt="" id="BLOGGER_PHOTO_ID_5426648743903413506" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I have a problem: The &lt;a href="http://www.dzone.com/"&gt;DZone Top Links&lt;/a&gt; section is great but doesn't support an RSS feed. It has feeds for just about everything else. This would be like &lt;a href="http://digg.com/"&gt;digg&lt;/a&gt; or &lt;a href="http://tweetmeme.com/"&gt;tweetmeme&lt;/a&gt; not having a feed for their most popular links. What makes it worse is I read a majority of their Top Links, but in order to do so I have to keep a tab open in firefox. Wouldn't it be great if I could just subscribe via &lt;a href="http://www.google.com/reader"&gt;Google Reader&lt;/a&gt;? And now thanks to &lt;a href="http://pipes.yahoo.com/"&gt;Yahoo Pipes's&lt;/a&gt; screen scrapping capability you can.&lt;br /&gt;&lt;br /&gt;Click this link to subscribe to the DZone Top Links Feed: &lt;a href="http://pipes.yahoo.com/jlorenzen/dzonetoplinks"&gt;http://pipes.yahoo.com/jlorenzen/dzonetoplinks&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This was accomplished by cloning my &lt;a href="http://jlorenzen.blogspot.com/2008/10/using-yahoo-pipes-screen-scraping-to.html"&gt;RssHuskerPedia&lt;/a&gt; pipe and changing a few things around. These pipes depend on the Fetch Page module which essentially lets you scrap the page allowing you to create a list. This feed doesn't contain all the metadeta that would normally come from an official DZone feed, but it supports the basics and prevents me from missing great articles that I would have normally missed.&lt;br /&gt;&lt;br /&gt;Please vote this up on DZone to get the word out and hopefully DZone will create an official one. If it gets voted up enough and makes it to the Top Links section, hopefully you won't get stuck in an infinite loop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5141901518317319621?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5141901518317319621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5141901518317319621'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2010/01/dzone-top-links-feed.html' title='DZone Top Links Feed'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_u6FjI-f0VoU/S09UR-0uxQI/AAAAAAAAALc/oscqsLOikC4/s72-c/dzone-top-links.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5155515430504636811</id><published>2009-12-15T10:36:00.002-06:00</published><updated>2009-12-15T10:51:41.967-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='websphere'/><category scheme='http://www.blogger.com/atom/ns#' term='centos'/><title type='text'>Installing WebSphere 6.1 on CentOS 5.3</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_u6FjI-f0VoU/Syavm4KiUcI/AAAAAAAAAKI/C0qa4Xz2ai0/s1600-h/websphere-launchpad.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px; height: 142px;" src="http://2.bp.blogspot.com/_u6FjI-f0VoU/Syavm4KiUcI/AAAAAAAAAKI/C0qa4Xz2ai0/s200/websphere-launchpad.png" alt="" id="BLOGGER_PHOTO_ID_5415208684406067650" border="0" /&gt;&lt;/a&gt;My colleagues and I have had a very difficult time trying to get IBM WebSphere 6.1 installed in CentOS 5.3. Thanks to the help of Matt White, we finally believe we have figured out a work around.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Issue&lt;/span&gt;&lt;br /&gt;The swing installer does not load after clicking on the Install link within the HTML Launch page. This issue is best documented in the &lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=358811"&gt;Redhat&lt;/a&gt; and &lt;a href="http://www-01.ibm.com/support/docview.wss?rs=180&amp;amp;uid=swg21372845"&gt;IBM&lt;/a&gt; communities.&lt;br /&gt;Basically, we would perform a netinstall of CentOS 5.3, unpack was.cd.6100.wasdev.nocharge.linux.ia32.tar.gz into a subdirectory, and run ./launchpad.sh. Firefox would load the install page which contains a link to install WebSphere that brings up a Java Swing Application that performs the actual install. Problem is the Java Swing app never appears. After closing the browser, launchpad complains saying, "No supported Web browser was detected". Also we discovered an error in the following log file /tmp/niflogs/log.txt:&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;Process, com.installshield.wizard.StandardWizardListener, err, could not initialize interface swing&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Solution(s)&lt;/span&gt;&lt;br /&gt;We actually never figured out how to solve this issue. We tried different JDKs, different browsers, 64 bit versions, etc. Nothing fixed the problem. Thanks to Matt White though, we did figure out a possible work around.&lt;br /&gt;&lt;br /&gt;Open a new terminal and go to the websphere directory were you unpacked the installer. cd into the WAS directory and run: &lt;span style="font-style: italic;"&gt;sudo java -jar setup.jar&lt;/span&gt;. The Java Swing install app appears and you are now able to install WebSphere. We have had mixed results with it automatically creating a default profile (AppSvr01), so if it does not create a default profile, you can manually create it by running the /opt/IBM/WebSphere/AppServer/bin/ProfileManagement/pmt.sh script.&lt;br /&gt;&lt;br /&gt;The other possible solution is to install an older version of CentOS such as 5.1, install WebSphere 6.1, and then upgrade CentOS to 5.3. I tried doing this with 5.2 and the launchpad still failed, but we know of others that we think used 5.1 and it worked.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_u6FjI-f0VoU/Syaw9njtHcI/AAAAAAAAAKY/2MeYdOA_Alw/s1600-h/websphere-installer.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 130px;" src="http://4.bp.blogspot.com/_u6FjI-f0VoU/Syaw9njtHcI/AAAAAAAAAKY/2MeYdOA_Alw/s200/websphere-installer.png" alt="" id="BLOGGER_PHOTO_ID_5415210174596849090" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5155515430504636811?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5155515430504636811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5155515430504636811'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/12/installing-websphere-61-on-centos-53.html' title='Installing WebSphere 6.1 on CentOS 5.3'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_u6FjI-f0VoU/Syavm4KiUcI/AAAAAAAAAKI/C0qa4Xz2ai0/s72-c/websphere-launchpad.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6083528042147465861</id><published>2009-11-16T13:09:00.014-06:00</published><updated>2009-11-19T23:34:00.093-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='security now'/><category scheme='http://www.blogger.com/atom/ns#' term='ssl'/><title type='text'>Preventing Insecure Login pages</title><content type='html'>If you are a webpage author or use confidential information on the internet (credit card information, social security number, login credentials for paypal or banking), you might think twice the next time you log into your favorite website. I know I started paying more attention after listening to Steve Gibson's &lt;a href="http://www.grc.com/securitynow.htm"&gt;Security Now&lt;/a&gt; podcast titled "&lt;a href="http://www.twit.tv/sn217"&gt;The Fundamentally Broken Browser Model&lt;/a&gt;". That title is a bit confusing, but the underlying issue is very serious. That is why I would like to further explain the issue by providing a simple example, then a real world example using facebook, and then discuss a simple solution.&lt;br /&gt;&lt;br /&gt;First, what does Mr. Gibson mean by The Fundamentally Broken Browser Model? Well, at this years Black Hat conference, a hacker named Moxie Marlinspike gave a presentation where he talked about how he was able to capture sensitive information at a public WiFi hotspot using open tools he created. Specifically, during a 24-hour period, he intercepted 114 logins to yahoo, 50 logins to gmail, 42 to ticketmaster, 14 to rapidshare, 13 to hotmail, 9 to paypal, 9 to LinkedIn, and 3 to facebook. So how did Moxie do it? He took advantage of a common flaw of most login pages: &lt;span style="font-weight: bold;"&gt;the login pages themselves are not received by the client over SSL allowing man-in-the middle attacks to change the submit URL&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;SSL (Secure Socket Layer) has been the common method for securing HTTP, but has been limited to only sensitive areas of a website for performance reasons. Sites have always protected a user's private information (usernames, passwords, credit card numbers, etc) using SSL, but to date no one has thought about actually securing the login page itself and this is a huge problem as most sites don't encrypt their login pages. Not encrypting login forms leaves it open to modification before it returns to the user.&lt;br /&gt;&lt;br /&gt;This attack has 2 basic steps. First, the malicious user needs to be on the same network (LAN) and utilize ARP (Address Resolution Protocol) spoofing techniques to insert himself in-between connections (this is pretty scary considering how many times I have connected to restaurant, hotel, and airport WiFi hotspots). Second, a LAN user has to visit a login page that was received over a non-SSL connection.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Simple Example&lt;/span&gt;&lt;br /&gt;To explain the issue better, let me use a simple example (let's leave ARP spoofing out for now). A user visits an e-commerce site http://www.eco.com. Like most sites, eco.com includes a Login link at the top. Clicking on this link takes the user to http://www.eco.com/login, which returns a simple login form in HTML.&lt;br /&gt;&lt;pre class="brush: html"&gt;&amp;lt;form method="POST" action="https://www.eco.com/login/authenticate"&amp;gt;&lt;br /&gt;    Username: &amp;lt;input name="username" type="text"&amp;gt;&lt;br /&gt;    Password: &amp;lt;input name="password" type="password"&amp;gt;&lt;br /&gt;    &amp;lt;input value="Submit" type="submit"&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&lt;/pre&gt;The user types in their username and password, clicks the Submit button, and their private information is sent encrypted over SSL. It is sent over SSL because the form's action value is set to an SSL URL (https://www.eco.com/login/authenticate). But there is one big problem. The Login link the user click was non-SSL (http://www.eco.com/login), meaning the response back to client was sent over the network as clear-text and could easily be modified by man-in-the middle attacks using ARP spoofing. A malicious user could change the form's submit URL from https://www.eco.com/login/authenticate to http://www.eco.com/login/authenticate and the user would never know it happened. There are few default clues to indicate this is happening. So a malicious user, changes the submit URL to a non-SSL URL, a user clicks Submit, and their credentials are sent as clear-text over the network.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;facebook example&lt;/span&gt;&lt;br /&gt;Armed with this new information I wondered how some of my favorite sites handle this situation. No matter what I tried, it looked like gmail, ebay, and paypal where safe and used SSL for their login pages. So that gave me some peace of mind. However, facebook provides us with a perfect bad example.&lt;br /&gt;&lt;br /&gt;If your like me, I type facebook in my browser and use the CRTL+ENT keyboard shortcut to fill in the rest. So I end up at http://www.facebook.com. If you are not currently logged into facebook, you are presented with the following home page that includes a form to register or login.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_u6FjI-f0VoU/SwYoRFFHJZI/AAAAAAAAAJ4/azCm5VULiAo/s1600/facebook.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 182px;" src="http://4.bp.blogspot.com/_u6FjI-f0VoU/SwYoRFFHJZI/AAAAAAAAAJ4/azCm5VULiAo/s320/facebook.png" alt="" id="BLOGGER_PHOTO_ID_5406052676591363474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Again, this home page includes a login page that was sent over a non-SSL connection. As we expect, if you look at the source, you can see the HTML form does post securely to the URL https://login.facebook.com/login.php?login_attempt=1. So what do you do if you don't want to fill in a form that was received over a non-SSL connection? Fortunately, facebook also supports SSL for its home page (https://www.facebook.com), it just takes a little awareness and an extra step.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Solution&lt;/span&gt;&lt;br /&gt;More sites need to use SSL for their login forms, and not just for when users post their credentials. At a minimum, like facebook, sites should also support SSL and ideally all login forms would automatically be requested over SSL. If you come across a site that initially does not use SSL for the login page, try and use https. If that fails then think about using a VPN solution or even a travellers router.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-6083528042147465861?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6083528042147465861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6083528042147465861'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/11/preventing-insecure-login-pages.html' title='Preventing Insecure Login pages'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_u6FjI-f0VoU/SwYoRFFHJZI/AAAAAAAAAJ4/azCm5VULiAo/s72-c/facebook.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4986313406752708316</id><published>2009-11-07T00:31:00.005-06:00</published><updated>2009-11-07T00:58:54.152-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='appengine'/><title type='text'>Google App Engine with Grails</title><content type='html'>After I &lt;a href="http://jlorenzen.blogspot.com/2009/11/learning-with-grails-security-extjs.html"&gt;recently&lt;/a&gt; got a grails app to work with spring-security, REST, and cache I wanted to try my luck and create a Google App Engine application using grails. Unfortunately, I think it's still pretty early as I ran into several issues early on. However, I see enormous potential once these issues get resolved.&lt;br /&gt;&lt;br /&gt;I am using grails v1.1.1, &lt;a href="http://grails.org/plugin/app-engine"&gt;app-engine plugin&lt;/a&gt; v0.8.5, with &lt;a href="http://www.grails.org/plugin/gorm-jpa"&gt;gorm-jpa&lt;/a&gt; v0.5. The first issue I ran into was deploying when using &lt;span style="font-style: italic;"&gt;grails app-engine deploy&lt;/span&gt;. It failed to work subsequent times after I got the WAR initially deployed using &lt;span style="font-style: italic;"&gt;/app-sdk/bin/appcfg.sh&lt;/span&gt;. It complained about not supplying an email address. Turns out there is a &lt;a href="http://old.nabble.com/GAE-plug-in---deploy-issue-%28GRails-1.1.1---Google-App--Engine-SDK-1.2.1%29-td23836346.html"&gt;bug&lt;/a&gt; related to ant that should get fixed soon. The work around was simple enough; just hit Enter before typing in your email address.&lt;br /&gt;&lt;br /&gt;Secondly, I was disappointed to find out that the spring-security (acegi) plugin wasn't compatible in GAE. Based on the compile errors I received locally, it appears spring-security depends on hibernate which is not an option in GAE (you either get JDO or JPA). I chose JPA because according to the documentation, JDO doesn't support any of the GORM dynamic finders methods where as JPA supports most of them. I guess now that I think about it, I'm not suprised acegi didn't work in GAE; just disappointed.&lt;br /&gt;&lt;br /&gt;I found a minor &lt;a href="http://jira.codehaus.org/browse/GRAILSPLUGINS-1663"&gt;issue&lt;/a&gt; I submitted concerning the default delete action in generated controllers. Seems the gorm-jpa plugin doesn't wrap the delete method around a [Domain].withTransaction closure which apparently is required (see the save action).&lt;br /&gt;&lt;br /&gt;Finally, I was unable to get content negotiation working using the withFormat concept I described &lt;a href="http://jlorenzen.blogspot.com/2009/11/learning-with-grails-security-extjs.html#rest"&gt;here&lt;/a&gt;. It worked locally running grails app-engine run, but threw an exception in GAE:&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;Caused by: java.security.AccessControlException: access denied java.lang.RuntimePermission getClassLoader&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My guess is it's related to the Security issues they report on the FAQ:&lt;br /&gt;&lt;blockquote&gt;"The current preview release of the Google AppEngine SDK has a bug that doesn't allow it to run Groovy code when the full permissions restrictions are used. This will be fixed in the next release, but in the meantime the development environment runs without emulating the permissions restrictions of the actual AppEngine environment."&lt;br /&gt;&lt;/blockquote&gt;Overall, I enjoyed the easy commands it provides to build, run, and deploy to GAE. The deploy was suprisingly pretty quick. I was able to view the exceptions in GAE easily. I was just prevented from making any real progress. If you want to see what I did get done, which was not much, check it out here &lt;a href="http://james-lorenzen.appspot.com/"&gt;http://james-lorenzen.appspot.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4986313406752708316?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4986313406752708316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4986313406752708316'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/11/google-app-engine-with-grails.html' title='Google App Engine with Grails'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-759472401967426188</id><published>2009-11-03T23:11:00.026-06:00</published><updated>2009-11-04T00:24:32.201-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='extjs'/><category scheme='http://www.blogger.com/atom/ns#' term='spring-insight'/><category scheme='http://www.blogger.com/atom/ns#' term='spring-security'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='acegi'/><title type='text'>Learning with Grails: Security, Extjs, REST, Spring Insight</title><content type='html'>Unfortunately, security and performance are often postponed early in the development process and are surpassed for new functionality. Reasonable justification usually includes cost and time. A few of the real issues I think are difficulty and lack of experience. I have to admit I am no security or performance expert, and implementing both early on would be time consuming and difficult. I've always heard security done after the fact is never as good if it's done in the beginning. So I wanted to share my experience using the &lt;a href="http://www.grails.org/plugin/acegi"&gt;spring-security (acegi) plugin&lt;/a&gt; in grails. Not only did I learn a lot about security, but also how to add support for REST Services and integrate Ajax clients using Extjs, how to enable caching, and inspect the performance of my app using Spring Insight that comes with the Springsource &lt;a href="http://www.springsource.com/products/tcserver/devedition"&gt;tc server developer edition&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Table of Contents&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="#spring-security"&gt;Spring-Security (Acegi)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#rest"&gt;REST Support for Extjs Ajax clients&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#spring-insight"&gt;Spring Insight and Caching&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="spring-security"&gt;&lt;span style="font-weight: bold;"&gt;Spring-Security (Acegi)&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;Building authentication and authorization into your app in the beginning can be difficult, but with the spring-security plugin and grails it's super easy. There are other security plugins for grails, but I decided on spring-security/acegi since our team has contemplated using it on our project several times and it seems to have a pretty good history. This isn't a how to guide on using the security plugin,  the &lt;a href="http://www.grails.org/plugin/acegi"&gt;documentation&lt;/a&gt; is pretty good. However, I do want to share some unexpected things I ran into and how I arrived at some of my conclusions.&lt;br /&gt;&lt;br /&gt;When applying the security capabilities, I applied Test-Driven Development (TDD) to test my assumptions and changes. After I installed the plugin, I got started right away creating Users, Roles, and Requestmaps in Bootstrap. Requestmap is the domain model mapping roles to URIs. I prefered this method initially because I wanted to persist this information to the database. First I wanted to lock down the ability to delete a model I called Event. Here is a sample Bootstrap to accomplish it:&lt;br /&gt;&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: groovy"&gt;&lt;![CDATA[&lt;br /&gt;def admin = new Authority(authority: "ROLE_ADMIN", description: "admin").save()&lt;br /&gt;new Requestmap(url: "/event/delete/**", configAttribute: "ROLE_ADMIN").save()&lt;br /&gt;new Person(username: "admin", userRealName: "admin",&lt;br /&gt;    passwd: authenticateService.encodePassword("admin"),enabled: true, email: "")&lt;br /&gt;    .addToAuthorities(admin).save()&lt;br /&gt;]]&gt;&lt;/script&gt;In this first test I created an admin role, mapped the admin role to /event/delete, and then added a new user to the admin role. This worked as expected but had a pretty big security hole (see &lt;a href="http://old.nabble.com/Unexpected-observations-using-spring-security-%28acegi%29-plugin-to26105478.html#a26105478"&gt;Unexpected observations using spring-security plugin&lt;/a&gt;). The issue was unauthorized users were still able to delete events using the edit form. Underneath, grails submits to the index action and the controller handles directing the request to the delete action in the controller bypassing the security created by my Requestmap. I could hide the Delete button on the edit page, but malicous users could still expliot this hole.&lt;br /&gt;&lt;br /&gt;So instead of using Requestmap, I &lt;a href="http://www.grails.org/AcegiSecurity+Plugin+-+Securing+URLs"&gt;annotated&lt;/a&gt; my controller actions. This method can properly handle the use case above and deny unauthorized access to the delete action.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: groovy"&gt;&lt;![CDATA[&lt;br /&gt;@Secured(['ROLE_ADMIN'])&lt;br /&gt;def delete = {......}&lt;br /&gt;]]&gt;&lt;/script&gt;I also learned that users have to be associated with a Role, otherwise they are unable to log in (see &lt;a href="http://old.nabble.com/Unexpected-observations-using-spring-security-%28acegi%29-plugin-to26105478.html#a26105478"&gt;post&lt;/a&gt;). This seemed rather annoying since I was expecting to use the predefined roles: IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED, and IS_AUTHENTICATED_ANONYMOUSLY without having to associate all my users with roles. Two suggestions by Burt where to extend a Base model class that supported a default Role for all Users, or extend the GrailsDaoImpl class to remove the role requirement for users.&lt;br /&gt;&lt;br /&gt;In summary, it seems best to annotation your controllers instead of using Requestmap and keep in mind that by default all users need to be associated with a role to login into your application.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="rest"&gt;&lt;span style="font-weight: bold;"&gt;REST Support for Extjs Ajax clients&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;Now that I have portions of my app locked down, I wanted to see how this effected Rich Internet Applications (RIAs) such as those that use &lt;a href="http://www.extjs.com/"&gt;Extjs&lt;/a&gt;. I wanted to answer 2 basic questions:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;How can javascript clients remove admin functions like Delete buttons?&lt;/li&gt;&lt;li&gt;How could I modify my controller to support multiple clients that need HTML, JSON, or XML?&lt;/li&gt;&lt;/ol&gt;To test these questions, I downloaded and &lt;a href="http://jlorenzen.blogspot.com/2008/08/getting-started-with-grails-and-extjs.html"&gt;installed extjs&lt;/a&gt; into my grails app and created a simple grid based on the array-grid example in extjs. As part of this test I wanted to add a Delete button to the bottom toolbar, so that I could later enable o&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_u6FjI-f0VoU/SvEAJU7Ib6I/AAAAAAAAAJo/AbQZCPvFJSY/s1600-h/grails-grid.png" target="_blank"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px; height: 82px;" src="http://1.bp.blogspot.com/_u6FjI-f0VoU/SvEAJU7Ib6I/AAAAAAAAAJo/AbQZCPvFJSY/s200/grails-grid.png" alt="" id="BLOGGER_PHOTO_ID_5400097588429483938" border="0" /&gt;&lt;/a&gt;r disable based on the users role.&lt;br /&gt;&lt;br /&gt;I'm not super proud of how I contrived the roles and used them in javascript, but below is how I did it (If you were doing this for real, I'd make this a point of focus to come up with a better solution like creating a service that returned this information as JSON that could be called by an Ajax client).&lt;br /&gt;&lt;br /&gt;Since there is no real easy way to get access to the users roles in a gsp, I set a bean in the controller that is used in the gsp. So in EventController I added the following grid action:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: groovy"&gt;&lt;![CDATA[&lt;br /&gt;@Secured("IS_AUTHENTICATED_FULLY")&lt;br /&gt;def grid = {&lt;br /&gt;    [ authorities: authenticateService.principal().getAuthorities() ]&lt;br /&gt;}&lt;br /&gt;]]&gt;&lt;/script&gt;Then in a new grid.gsp I added the following:&lt;br /&gt;&lt;pre class="brush: js"&gt;&lt;br /&gt;Ext.onReady(function() {&lt;br /&gt;    var roles = new Ext.util.MixedCollection();&lt;br /&gt;    &lt;% authorities?.each { %&gt;&lt;br /&gt;        roles.add("&lt;%=it.authority%&gt;");&lt;br /&gt;    &lt;% } %&gt;&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;Then when I build the grid, I could eanble or disable the Delete button by doing:&lt;br /&gt;&lt;pre class="brush: groovy"&gt;&lt;br /&gt;roles.contains("ROLE_ADMIN")&lt;br /&gt;&lt;/pre&gt;That's pretty much how I disabled certain gui items that are restricted based on role. Again not very pretty, but effective.&lt;br /&gt;&lt;br /&gt;Next, I wanted to populate my grid with real data from my controller. Fortunately for developers, grails excels in this area using convention over configuration using the withFormat &lt;a href="http://grails.org/doc/1.0.x/guide/single.html#6.8%20Content%20Negotiation"&gt;content negiotation&lt;/a&gt; with URI Extensions. All I had to do was modify the controllers list action to support more than HTML responses:&lt;br /&gt;&lt;pre class="brush: groovy"&gt;&lt;br /&gt;def list = {&lt;br /&gt;    params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)&lt;br /&gt;    def events = Event.list(params)&lt;br /&gt;    withFormat {&lt;br /&gt;        html { [eventInstanceList: events, eventInstanceTotal: Event.count()] }&lt;br /&gt;        xml { render events as XML }&lt;br /&gt;        json { render( [list: events] as JSON ) }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Here I easily add support for XML and JSON clients while also continuing to support clients who want HTML. One thing to note, is I like naming arrays in JSON; that is why you see the render([list: events]) syntax. Without that, the JSON response looks like this&lt;br /&gt;&lt;pre&gt;{[{"class":"Event".....&lt;/pre&gt;instead of my preferred way&lt;br /&gt;&lt;pre&gt;{"list":[{"class":"Event".....&lt;/pre&gt;Now all the client needs to do is request the URI /event/list.json or /event/list.xml.&lt;br /&gt;&lt;br /&gt;Here is my &lt;a href="http://pastebin.com/f63dea460"&gt;complete javascript&lt;/a&gt; that includes the example JsonStore and Grid definitions.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="spring-insight"&gt;&lt;span style="font-weight: bold;"&gt;Spring Insight and Caching&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;Next, I really wanted to try out the Spring Insight capability that is now included in the Springsource &lt;a href="http://www.springsource.com/products/tcserver/devedition"&gt;tc server developers edition&lt;/a&gt;. This would let you see into how grails and hibernate are operating on your behalf per request. For many web applications, there are typically 2 bottlenecks that degrade performance: 1) number of trips from the client to server 2) number of trips to the database. Using the Spring Insight tool, developers can see what SQL is being executed and how long it took.&lt;br /&gt;&lt;br /&gt;To get started with Spring Insight I followed their &lt;a href="http://static.springsource.com/projects/tc-server/6.0/devedition/devedition-single.html#N101F4"&gt;Getting Started Guide&lt;/a&gt;. Once I had Insight running (http://localhost:8080/insight), I next ran 'grails war' to create a WAR that I could deploy to tomcat (&lt;span style="font-weight: bold;"&gt;Note&lt;/span&gt;: if you do this multiple times, redeploy, you have to be careful with what you do in your apps Bootstrap class. I was doing a lot of inserts that caused my WAR to fail deployment because by default when running 'grails war', grails defaults to the production environment which uses an update file database. So my Bootstrap was trying to add roles and users that already existed and that caused deployment to fail).&lt;br /&gt;&lt;br /&gt;The WAR deployed fine and I was up and running watching my apps performance metrics in the Insight dashboard as I moved around in my app. What I noticed first was unexpected multiple JDBC calls when I thought &lt;a href="http://grails.org/doc/latest/guide/single.html#5.5.2.2%20Caching%20Strategy"&gt;caching&lt;/a&gt; was enabled by default in grails.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_u6FjI-f0VoU/SvEKQVT8WfI/AAAAAAAAAJw/wOzL9TWTKiU/s1600-h/spring-insight-nocache.png" target="_blank"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 125px;" src="http://1.bp.blogspot.com/_u6FjI-f0VoU/SvEKQVT8WfI/AAAAAAAAAJw/wOzL9TWTKiU/s200/spring-insight-nocache.png" alt="" id="BLOGGER_PHOTO_ID_5400108703908911602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;What I learned was you have to enable caching on a per domain or query basis. So I added the following to my Event domain model&lt;br /&gt;&lt;pre class="brush: groovy"&gt;&lt;br /&gt;static mapping = {&lt;br /&gt;    cache true&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;rebuilt and redeployed the war and was able to see fewer JDBC calls proving that my cached domain was working. I then added a new Event, viewed all events, and saw the extra select call since the cache was purged.  Pretty impressive!&lt;br /&gt;&lt;br /&gt;Next I wondered if spring-security was caching all the user and role information by default like it advertised. If not that could be a huge performance issue. Spring Insight was also able to prove that it was caching its results.&lt;br /&gt;&lt;br /&gt;Overall, I learned a lot about grails, security, REST, extjs, caching, and spring insight and grails was the perfect platform to prototype these concepts in preparation for real production use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-759472401967426188?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/759472401967426188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/759472401967426188'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/11/learning-with-grails-security-extjs.html' title='Learning with Grails: Security, Extjs, REST, Spring Insight'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_u6FjI-f0VoU/SvEAJU7Ib6I/AAAAAAAAAJo/AbQZCPvFJSY/s72-c/grails-grid.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-88942656654920045</id><published>2009-08-04T11:06:00.006-05:00</published><updated>2009-08-04T11:27:36.502-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Blank screen when installing Ubuntu</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.debuntu.org/files/images/bootsplash.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 322px; height: 228px;" src="http://www.debuntu.org/files/images/bootsplash.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Several co-workers and I run encrypted &lt;a href="http://www.ubuntu.com/products/WhatIsUbuntu/desktopedition"&gt;Ubuntu Desktop&lt;/a&gt; on our work laptops. Specifically I have an HP Compaq 6710b and they have all had monitor issues when installing Ubuntu. If you run the default "Install Ubuntu" option, the next screen will just be a blank screen. I need to get this documented because I always forget how to fix it.&lt;br /&gt;&lt;br /&gt;While at the Ubuntu Splash screen do the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Press the F1 key for "Help"&lt;/li&gt;&lt;li&gt;Press the F6 key for "Special boot parameters for special machines"&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;There you will see an option in the middle described as:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Laptops with screen display problems vga=771&lt;/span&gt;. We need to append this to the Boot Options.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Press the ESC key to get back to the Splash page&lt;/li&gt;&lt;li&gt;Press F6 for "Other Options" and then Press ESC&lt;/li&gt;&lt;/ul&gt;Now the Boot Options should be visible. It should look something like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Boot Options file=/cdrom/preseed/ubuntu.see initrd=/install/initrd.gz quiest --&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Delete the trailing &lt;span style="font-style: italic;"&gt;--&lt;/span&gt; and add in &lt;span style="font-style: italic;"&gt;vga=771&lt;/span&gt;. You should have the following:&lt;br /&gt;&lt;br /&gt;Boot Options file=/cdrom/preseed/ubuntu.see initrd=/install/initrd.gz quiest vga-771&lt;br /&gt;&lt;br /&gt;Press the enter key and you should now be able to successfully install Ubuntu.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-88942656654920045?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/88942656654920045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/88942656654920045'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/08/blank-screen-when-installing-ubuntu.html' title='Blank screen when installing Ubuntu'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-606596809293560502</id><published>2009-07-23T00:16:00.006-05:00</published><updated>2009-07-23T01:13:48.222-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Linux config files available on github</title><content type='html'>I pushed several of my common linux config files that I often find myself sharing with others via email to github. I'd say it's currently specific to Java developers that are using maven2. I lean heavily on alias's defined in my .bashrc file which lives under my home directory. Hopefully others will fork this project and I can merge forked changes back into my project.&lt;br /&gt;&lt;br /&gt;Not only did I want to provide an easy way to share among co-workers, but I also wanted to be able to port to other machines or even when I need to rebuild my work laptop. Also, I just want to get more comfortable with a DVCS workflow. Thanks to Ron Alleva's post (&lt;a href="http://www.ronniealleva.org/index.php/2008/08/28/using-git-and-subversion-in-5-easy-steps/"&gt;Using Git and Subversion in 5 Easy Steps&lt;/a&gt;) about getting setup with using git as the client to svn, I am all set at work to start using git.&lt;br /&gt;&lt;br /&gt;Please check it out at &lt;a href="https://github.com/jlorenzen/linux-config-files/tree"&gt;https://github.com/jlorenzen/linux-config-files/tree&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;git clone git://github.com/jlorenzen/linux-config-files.git&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Currently it includes:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;.bashrc&lt;/span&gt; - Contains my alias's&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;.synergy.config&lt;/span&gt; - Config file I stole from Joe Kueser which lets me control a windows machine with the keyboard and mouse connected to my linux laptop (see &lt;a href="http://synergy2.sourceforge.net/"&gt;synergy&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;.vimrc&lt;/span&gt; - Simple vim settings. Nothing special yet&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;idea.sh&lt;/span&gt; - Simple IntelliJ Idea startup script for linux&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;idea.vmoptions&lt;/span&gt; - Modified vmoptions for IntelliJ Idea&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;start-hudson.sh&lt;/span&gt; - Example of a generic linux startup script&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;stop-hudson.sh&lt;/span&gt; - Example of a generic linux stop script&lt;/li&gt;&lt;/ol&gt;For those looking to create a github account (and for my future reference) I struggled on how to sync up my local master with the master on github. Thankfully history was around to remind me.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;git push origin master&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This was after I did the one step (I think) to add the origin:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;git remote add origin git@github.com:jlorenzen/linux-config-files.git&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-606596809293560502?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/606596809293560502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/606596809293560502'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/07/linux-config-files-available-on-github.html' title='Linux config files available on github'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-144616675073903626</id><published>2009-07-22T21:47:00.006-05:00</published><updated>2009-07-22T22:54:09.446-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Minor issue with Ubuntu Desktop</title><content type='html'>Linux and Ubuntu are awesome. I switched from developing on Windows XP to Ubuntu Desktop in late 2007 (7.04 or Feisty Fawn). I will never again develop on an windows machine. Hopefully I won't ever work for a company that requires a windows platform, but at that point I would rather buy my own work computer or setup Ubuntu in a virtual instance. I really appreciate Rob Madole and Brian O'Neill for showing my the right path. I remember Brian's frustration anytime he was forced to pair with me on my windows machine. Now I am like that with my co-workers.&lt;br /&gt;&lt;br /&gt;Even though Ubuntu is great, I still have one minor compliant. Well it's really 3 things combined: Extended Monitor support, Compiz, and &lt;a href="http://do.davebsd.com/"&gt;Gnome-Do&lt;/a&gt;. I am addicted to all 3, but trying to get all 3 to work together seems impossible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Extended Monitor Support&lt;/span&gt;&lt;br /&gt;The big problem here is going back and forth between work and home. At work I want to use my monitor, but at home I use just the laptop monitor. In the past I ran nvidia-settings when I wanted go back and forth. This has been improved with some help from Ron Alleva by using the xrandr command. He gave me some alias's to run when I wanted to switch. When I first installed 8.10, I used those alias's, but it seems lately its being auto-detected because when I plug my monitor in at work, ubuntu recognizes it and I don't have to run anything. Nor do I have to run anything now when I get home. So it would seem I have a good handle on this now, but when using an extended monitor other things don't work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Compiz&lt;/span&gt;&lt;br /&gt;I love compiz mainly for one thing: transparency in my terminal. I'm sure I have set a million other settings before, but enabling the Normal Visual Effects under the System &gt; Preferences &gt; Appearance setting is usually one of the first things I do. I believe this setting uses Compiz. With this setting enabled, my terminal window is transparent enough that I can see other applications in the background, like firefox or pidgin which I typically have behind terminal without having to switch back and forth. Unfortunately, it seems I can't have this setting enabled when I have an extended monitor.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Gnome-Do&lt;/span&gt;&lt;br /&gt;Man I love it. I am hoping to eventually get to a point to where I have an entirely clean desktop like &lt;a href="http://www.eastwoodzhao.com/gnome-do-clean-ubuntu-desktop/"&gt;this&lt;/a&gt;. My favourite is the docky option seen &lt;a href="http://farm4.static.flickr.com/3421/3259062271_51f4d0d257.jpg"&gt;here&lt;/a&gt; which is similar to Mac's Spotlight. Gnome-Do works just fine with an extended monitor, but docky requires compiz to be running in Normal mode and if you recall compiz doesn't work for me when using an extra monitor.&lt;br /&gt;&lt;br /&gt;This is probably a pretty minor compliant verses all the ones I had against Windows, so I don't expect any new patches coming out of Canonical. In an ideal world, my extra monitor would just be automatically detected, compiz would work, and therefore gnome-do docky would work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-144616675073903626?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/144616675073903626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/144616675073903626'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/07/minor-issue-with-ubuntu-desktop.html' title='Minor issue with Ubuntu Desktop'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5297239515110163280</id><published>2009-06-19T11:30:00.013-05:00</published><updated>2009-06-19T12:55:51.182-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven2'/><title type='text'>Maven Global Excludes</title><content type='html'>To my knowledge, maven2 currently does not have the ability to globally exclude dependencies. Instead there is the tedius way of excluding a transitive dependency inline with the direct dependency (see &lt;a href="http://www.sonatype.com/books/maven-book/reference/pom-relationships-sect-conflict.html"&gt;Conflict Resolution&lt;/a&gt;) For complex multi-module projects, this can be difficult to manage and having the ability to exclude a dependency globally could be very useful. Seems like others share the same feelings (&lt;a href="http://jira.codehaus.org/browse/MNG-3196"&gt;MNG-3196&lt;/a&gt;). Unfortunately, for maven2 users this is targeted for maven3. So until then, here is a tip on how to globally exclude dependencies in your project (provided by my co-worker &lt;a href="http://www.ronniealleva.org/"&gt;Ron Alleva&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;To globally exclude a dependency all you need to do is set the dependencies scope value to &lt;span style="font-style: italic;"&gt;provided&lt;/span&gt;. This supports excluding transitive dependencies, which is really what you want.&lt;br /&gt;&lt;br /&gt;So for example, let's assume I have a WAR project that depends on commons-logging-1.1, which according to "&lt;span style="font-style: italic;"&gt;mvn dependency:tree&lt;/span&gt;" has a transitive dependency on avalon-framework-4.1.3.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;[INFO] +- commons-logging:commons-logging:jar:1.1:compile&lt;br /&gt;[INFO] |  +- logkit:logkit:jar:1.0.1:compile&lt;br /&gt;[INFO] |  \- avalon-framework:avalon-framework:jar:4.1.3:compile&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;Assuming I want to exclude avalon-framework from my WAR, I would add the following to my projects POM with a scope of provided. This works across all transitive dependencies and allows you to specify it once.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;dependencies&amp;gt;&lt;br /&gt;  &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;artifactid&amp;gt;avalon-framework&amp;lt;/artifactid&amp;gt;&lt;br /&gt;      &amp;lt;groupid&amp;gt;avalon-framework&amp;lt;/groupid&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;4.1.3&amp;lt;/version&amp;gt;&lt;br /&gt;      &lt;span style="font-weight: bold;"&gt;&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;&lt;/span&gt;&lt;br /&gt;  &amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;This even works  when specifying it in the parent POM, which would prevent projects from having to declare this in all child POMs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5297239515110163280?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5297239515110163280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5297239515110163280'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/06/maven-global-excludes.html' title='Maven Global Excludes'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7000820915915651857</id><published>2009-05-18T02:28:00.003-05:00</published><updated>2009-05-18T02:45:53.282-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Ubuntu, Oracle XE, and SQLPLUS</title><content type='html'>In the past for local development, I have used MS SQL Server running in a VMware windows instance, but that got to be too burdensome and consumed to much of my 2GB of RAM (who would have thought that 10 years ago when I was playing Star Craft on a desktop with 32MB of RAM). Anyways, on a recent business trip with a co-worker (Matt White) who also runs ubuntu, he brought to my attention &lt;a href="http://www.oracle.com/technology/tech/linux/install/xe-on-kubuntu.html"&gt;Oracle XE&lt;/a&gt; and how easy it was to install via apt-get and how small a footprint it was considering it's a database and it's Oracle.&lt;br /&gt;&lt;br /&gt;I have been very impressed so far and would highly recommend it for linux users wanting a local database. Again, not only is it easy to install via apt-get once you add the repos, but I really don't notice it consuming too many resources.&lt;br /&gt;&lt;br /&gt;Two hints I would like to self document more than anything is after installation the name of the SID is XE. You don't specify it during installation, but that is what it is. So my connection string in jboss looks like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;jdbc:oracle:thin:@localhost:1521:XE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The second hint I wanted to self document is how to get sqlplus working. Personally, I'm often times too lazy to write straight SQL to manipulate data manually. Not only that but it's not a real good use of my time. But after this weekend I got familar with it again due to a lack of a good GUI tool like Oracle SQL Developer at one of our production sites. I was basically forced to use sqlplus to change a few values. The one huge benefit it has, is you don't have to wait on some slow GUI tool to load. So locally I now have, Oracle SQL Developer for extended use, got the SQL Query Plugin in Idea to use when writing code, and now sqlplus. So when I am impatient and I don't have Idea up, I plan on using sqlplus.&lt;br /&gt;&lt;br /&gt;It doesn't work right out of the box. You have to set ORACLE_HOME and add it's bin directory in PATH and also set the ORACLE_SID.&lt;br /&gt;&lt;br /&gt;I added the following to my home's .bashrc file:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;export ORACLE_HOME=/usr/lib/oracle/xe/app/oracle/product/10.2.0/server&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;export ORACLE_SID=XE&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;export PATH=$ORACLE_HOME/bin:$PATH&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After that reload the .bashrc file by running . .bashrc and then run sqlplus.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7000820915915651857?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7000820915915651857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7000820915915651857'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/05/ubuntu-oracle-xe-and-sqlplus.html' title='Ubuntu, Oracle XE, and SQLPLUS'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4477003689375452697</id><published>2009-04-18T11:49:00.016-05:00</published><updated>2009-06-11T16:33:05.268-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Mock Testing with Groovy</title><content type='html'>Mock classes enable developers to quickly write unit tests that would otherwise require integration tests because of the need for a database, web container, or servlet container. Using mock classes helps to test a class in isolation and enables rapid feedback. It's not ideal to have a project with only integration tests and no unit tests. Mock classes enable unit testing that otherwise would be impossible.&lt;br /&gt;&lt;br /&gt;So how does one create a mock class? Well, there definitely is not a shortage of mock frameworks: &lt;a href="http://easymock.org/"&gt;EasyMock&lt;/a&gt;, &lt;a href="http://www.jmock.org/"&gt;jMock&lt;/a&gt;, &lt;a href="http://code.google.com/p/gmock/"&gt;Gmock&lt;/a&gt;, &lt;a href="http://groovy.codehaus.org/Using+MockFor+and+StubFor"&gt;MockFor and StubFor&lt;/a&gt;. You can always just create your own mock class in your test suite (which I have done in the past when in a pinch). But in my opinion these solutions lack one thing: the ability to quickly create a simple mock that when called returns what I want. To many of the mock frameworks force you to jump through hoops and call methods like &lt;span style="font-style: italic;"&gt;expect()&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;replay()&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;verify()&lt;/span&gt;. What I want is the ability to define a mock class in a single line and inject it myself.&lt;br /&gt;&lt;br /&gt;I thought MockFor and StubFor would be the solution, but the documentation is lacking and I haven't figured out how to make it work for me. Ideally I would like to say something like:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def mock = new MockFor(ICarDao.class) {&lt;br /&gt;   getCar: {return new Car(color: "blue")}&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Then MockFor would mock out the remaining methods of ICarDao and now I have a mock class that implements the getCars method that when called by the Class Under Test (CUT) will return a single Car model. But MockFor doesn't work like this and neither do any of the mock frameworks to my knowledge.&lt;br /&gt;&lt;br /&gt;There is hope however. Below you can read about 2 alternatives: groovy's metaClass and &lt;span style="font-style: italic;"&gt;as&lt;/span&gt; keyword. Both require the use of groovy in your tests. If you haven't switched to using groovy to write tests yet, even for Java, then it's time to start now. There is no other framework or library that can make you more productive when writing tests. It's an instant boost.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy's metaClass&lt;/span&gt;&lt;br /&gt;As seen in this &lt;a href="http://jlorenzen.blogspot.com/2008/07/groovy-threads-and-metaclass-example.html"&gt;example&lt;/a&gt;, groovy's meta programming is very powerful. In that post I show how one can essentially mock out &lt;span style="font-style: italic;"&gt;Thread.startDaemon()&lt;/span&gt; by using &lt;span style="font-style: italic;"&gt;Thread.metaClass.static.startDaemon&lt;/span&gt;. Groovy's meta programming is very powerful as seen by it's heavy use in grails to make things simple. But it doesn't work in all cases.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy's &lt;/span&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;as&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; keyword&lt;/span&gt;&lt;br /&gt;Using metaClass is by far the easiest and my favorite way to create a mock class. However, this didn't work for me in my recent attempt to write some unit tests for a Java Manager class that used spring to inject a DAO that the manager used. It didn't work I believe because my Manager class never created the concrete DAO. It defines some getters and setters and expects spring to inject the concrete class. Because of this metaClass didn't work (bummer). So I did a lot of research to come up with a competitive alternative: groovy's &lt;span style="font-style: italic;"&gt;as&lt;/span&gt; keyword.&lt;br /&gt;&lt;br /&gt;Let's start by defining the Manager class:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;public class CarManager {&lt;br /&gt;   private ICarDao dao;&lt;br /&gt;&lt;br /&gt;   public void startCar() {&lt;br /&gt;       Car car = dao.getCar();&lt;br /&gt;       .......&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public CarManager setCarDao(ICarDao dao) {&lt;br /&gt;       this.dao = dao;&lt;br /&gt;       return this;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Now to test this using mock classes and the as keyword all you need to do is this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class CarManagerTest extends GroovyTestCase {&lt;br /&gt;   def void test_start_car() {&lt;br /&gt;       ICarDao mock = [&lt;br /&gt;           getCar: {return new Car(color: "blue")}&lt;br /&gt;       ] as ICarDao;&lt;br /&gt;&lt;br /&gt;       def cut = new CarManager().setCarDao(mock);&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;This uses a map and the &lt;span style="font-style: italic;"&gt;as&lt;/span&gt; keyword to implement an interface. Here the key is the name of the method to mock and the value is a closure of what you want returned when called. And there is no need to define all the methods of the interface, just the ones you want to mock out.&lt;br /&gt;&lt;br /&gt;To me, metaClass and the as keyword are much cleaner and simpler compared to the current mock frameworks. At least for this type of testing. Those frameworks might be perfectly useful for other types of testing, I just haven't ran into them yet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4477003689375452697?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4477003689375452697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4477003689375452697'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/04/mock-testing-with-groovy.html' title='Mock Testing with Groovy'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8381916071044341366</id><published>2009-04-13T20:34:00.002-05:00</published><updated>2009-04-13T20:44:21.201-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Better Offline Capabilities with Maven 2.0.10</title><content type='html'>This week while traveling on business, I had hoped to get a lot of work done, but was quickly disappointed when I wasn't able to build because maven couldn't download the latest SNAPSHOTs. Even though I had fresh local SNAPSHOT versions that would suffice.&lt;br /&gt;&lt;br /&gt;Fortunately, maven 2.0.10 was recently released and it promised fixes for this exact situation (see &lt;a href="http://maven.apache.org/release-notes-2.0.x.html"&gt;release notes&lt;/a&gt;). Currently I am happily using version 2.0.9.&lt;br /&gt;&lt;br /&gt;So now that I am at the hotel I decided to see if an upgrade would help me. I first built the submodule again to make sure I got the dreaded unable to download dependency. Downloaded and installed 2.0.10 and rebuilt again. And I am very excited to report that it worked&lt;br /&gt;&lt;br /&gt;To stay tuned into everything Maven, subscribe to &lt;a href="http://www.sonatype.com/people/author/brian/"&gt;Brian's Enterprise Blog&lt;/a&gt; at Sonatype. Brian Fox is one of the head developers for Maven and according to Google Reader I read 100% of his posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8381916071044341366?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8381916071044341366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8381916071044341366'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/04/better-offline-capabilities-with-maven.html' title='Better Offline Capabilities with Maven 2.0.10'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1429528851965577886</id><published>2009-03-13T23:17:00.005-05:00</published><updated>2009-03-14T00:36:41.467-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='esb'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>grails create-app esb</title><content type='html'>I know it seems like a strange app to create with grails, especially when there a several other capable opensource ESBs available (&lt;a href="http://www.mulesource.org/"&gt;mule&lt;/a&gt;, &lt;a href="http://servicemix.apache.org/"&gt;servicemix&lt;/a&gt;, &lt;a href="https://open-esb.dev.java.net/"&gt;openesb&lt;/a&gt;), but instead of asking yourself why, ask yourself why not. While it may not offer all the same features (BPEL) it's certainly a possibility for certain circumstances. This possibility was spawned together with co-worker &lt;a href="http://www.blackholelogic.com/"&gt;Kit Plummer&lt;/a&gt; when discussing different options for an upcoming story that required email integration. At first it seemed kind of ridiculous, especially since we were already using openesb in jboss, but it started to make some sense the more we thought about it.&lt;br /&gt;&lt;br /&gt;So how could a MVC web framework possibly replace a feature complete ESB? Well, first let me explain my background. I don't consider myself an ESB expert, but I do have some experience with ServiceMix and OpenESB (see &lt;a href="http://jlorenzen.blogspot.com/search?q=openesb"&gt;openesb topics&lt;/a&gt;). In fact, my former company, let our team develop and open source 4 JBI Binding Components for &lt;a href="https://rss-bc.dev.java.net/"&gt;RSS&lt;/a&gt;, &lt;a href="https://sip-bc.dev.java.net/"&gt;SIP&lt;/a&gt;, &lt;a href="https://uddi-bc.dev.java.net/"&gt;UDDI&lt;/a&gt;, and &lt;a href="https://xmpp-bc.dev.java.net/"&gt;XMPP&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here was a short list of complaints I had with running OpenESB v2 in jboss:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;At first it was pretty simple to setup, install, and run for a single developer, but trying to duplicate that across a large distributed team and things get more complicated. This included the difficulty of setting it up in all of our CI and beta environments. It's not as easy as just running Glassfish which includes OpenESB.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;OpenESB v2 basically required Netbeans, which again isn't too hard for one developer. But asking your team to run a second unfamiliar IDE is no easy task. The OSGi based OpenESB v3 does not require Netbeans, but it does make it easier.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Composite Applications are less than easy to create, test, maintain, version, deploy in CI, etc. At least not compared to a Grails WAR anyways. Being able to consistently do those 5 things over 12-24 months is really bigger than you think.&lt;/li&gt;&lt;li&gt;Security. It's more difficult to lock it down compared to a WAR running in jboss fronted by apache.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Here are some advantages we saw in treating Grails like an ESB:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Easy. Simple. Trivial for everything including: developing, maintaining, testing, deploying, versioning, securing, and installing.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Grails is plugin based and has a growing number of &lt;a href="http://www.grails.org/Plugins"&gt;good plugins&lt;/a&gt;. One of the main benefits of an ESB is leveraging all the other work so you don't have to write anything. Things like HTTP, JMS, SMTP, JDBC, RSS, XMPP, FTP, BPEL, XSLT, and FILE just to name a few. Granted many Grails plugins are web focused, but there are several similar capabilities such as HTTP, JMS, JDBC, SMTP, RSS, and Workflow. Beyond that writing your own Grails plugin is easy compared to writing your own ESB component. See the &lt;a href="http://stateyourbizness.blogspot.com/2008/08/sending-emails-from-grails-apps.html"&gt;Mail plugin&lt;/a&gt; as an example of how easy it is to send an email in Grails.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Doesn't require Netbeans. Developers can continue using their favorite IDE.&lt;/li&gt;&lt;/ol&gt;Despite all of that, I do think the case can be made better for OpenESB if your team is already using Glassfish+OpenESB (or GlassfishESB) and Netbeans. But it does make it much more difficult if your not. And I know that ServiceMix v3 was deployable as a WAR, but that was not it's default behavior. Not sure about the OSGi based v4, but I can't imagine they stopped supporting WAR deployment. Of the two I think ServiceMix reminds me more of a Grails app as far as simplicity is concerned.&lt;br /&gt;&lt;br /&gt;There is one big disadvantage to using Grails like an ESB: fewer incoming protocols. I could be wrong on this one but with grails your probably limited HTTP and maybe JMS (outside of setting up quartz jobs and polling). But with an ESB its really unlimited (HTTP, JMS, JDBC, SMTP, SIP, XMPP).&lt;br /&gt;&lt;br /&gt;I am sure I am missing several other key pieces, so interested in hearing from others. The nice thing is our implementation is hidden behind a REST API that could easily be supported by a bloated ESB.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1429528851965577886?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1429528851965577886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1429528851965577886'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/03/grails-create-app-esb.html' title='grails create-app esb'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7726037359180980786</id><published>2009-02-26T09:21:00.003-06:00</published><updated>2009-02-26T10:39:55.181-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Find when a branch was created in svn</title><content type='html'>If you merge between branches and HEAD in subversion, you most likely need to know at what revision the branch was created at. Assuming you don't have the luxury of the &lt;a href="http://www.javaworld.com/javaworld/jw-01-2008/jw-01-svnmerging.html?page=1"&gt;new merging features&lt;/a&gt; in subversion 1.5, here is a trick I learned from the &lt;a href="http://svnbook.red-bean.com/en/1.0/re15.html"&gt;svn docs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;svn log --stop-on-copy http://server/svn/myapp/branches/myapp-1.0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This will stop once it hits the revision the branch was created at, verses continuing on until r1. Previously I would log the entire branch, and do a grep for the comments I inserted when I created the branch. Not ideal but it worked. Now I use the &lt;span style="font-style: italic;"&gt;--stop-on-copy&lt;/span&gt; option and I know real quick the revision the branch was created at. Giving me the revision I need to use in the merge.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;svn merge -r 546:767 http://server/svn/myapp/trunk&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Can't wait until we upgrade to subversion 1.5 or a &lt;a href="http://jlorenzen.blogspot.com/2008/06/dvcs-im-sold.html"&gt;DVCS&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7726037359180980786?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7726037359180980786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7726037359180980786'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/02/find-when-branch-was-created-in-svn.html' title='Find when a branch was created in svn'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6521427272395184842</id><published>2009-02-03T22:10:00.009-06:00</published><updated>2009-02-03T23:37:17.211-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='security now'/><title type='text'>Security news for work and personal</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thisweekintech.com/files/imagecache/coverart/coverart/podcast_2_3.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px; height: 200px;" src="http://www.thisweekintech.com/files/imagecache/coverart/coverart/podcast_2_3.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.grc.com/securitynow.htm"&gt;Security Now&lt;/a&gt; is a popular podcast that discusses important issues related to personal computer security. It's led by &lt;a href="http://www.thisweekintech.com/"&gt;TWiT&lt;/a&gt; (This Week in Tech) producer Leo Laporte and SpinRite creater and security expert Steve Gibson. However, it's not only for geeks like myself but very understandable by non-geeks. Each week Steve does an excellent job of explaining complicated concepts in layman terms. It's really good in that each topic applies to not only my work but also home computer security. While on my trip to Korea, I was able to get caught up on the past few episodes and consequently want to share with the Lorenzen Nation the things I have learned.&lt;br /&gt;&lt;br /&gt;For example, one of the first things I learned when first listening to SN (Security Now) was how WEP was broken. I know I know, pretty pathetic, but I actually never knew this. My guess, or hope, is someone reading this actually didn't know it either. So if you are running a WEP wireless network at home or your business, and assuming you want that network inaccessible by outsiders, like your neighbors, then consider switching to a WPA network. Apparently joining a WEP enabled network is about as easy as joining an unsecured network.&lt;br /&gt;&lt;br /&gt;Secondly, I learned a lot about chan&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.opendns.com/img/features_content_filtering.gif"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 348px; height: 164px;" src="http://www.opendns.com/img/features_content_filtering.gif" alt="" border="0" /&gt;&lt;/a&gt;ges I could make to my home network to make it more safe and secure. Specifically, this weekend I switched my networks DNS to use &lt;a href="http://www.opendns.com/"&gt;OpenDNS&lt;/a&gt;. The main reason was for its parental controls capability. Before I made the change I was easily able to visit an adult content site. Once I switched to OpenDNS and selected the filtering ability, I was no longer able to visit these sites. Now I feel a lot more comfortable knowing that when my kids are on the computer, these sites aren't going to pop up.&lt;br /&gt;&lt;br /&gt;Next, SN devoted several episodes to &lt;a href="http://www.grc.com/sn/notes-176.htm"&gt;DropMyRights &lt;/a&gt;and &lt;a href="http://www.sandboxie.com/"&gt;Sandboxie&lt;/a&gt;. Both are used to help reduce windows from getting infected by malware. I would recommend any Windows user at least using DropMyRights. It's free, easy to install, and easy to use. I started using it this weekend and it's worked perfectly so far. DropMyRights was created by a Microsoft employee who wanted to login as an admin, as we all do, but still run certain applications with restricted rights. Why is that important? Well among the many things malware does, all of which require admin rights, are:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Creating files in the system32 directory.&lt;/li&gt;&lt;li&gt;Terminating various processes.&lt;/li&gt;&lt;li&gt;Disabling the Windows Firewall.&lt;/li&gt;&lt;li&gt;Downloading and writing files to the system32 directory.&lt;/li&gt;&lt;li&gt;Deletes registry values in HKLM.&lt;/li&gt;&lt;/ol&gt;All of this stuff fails if the user is not an administrator. But developers hate running as a non-admin, so the solution is install DropMyRights or not run winblowz. Then to run Firefox you run something like the following: &lt;span style="font-style: italic;"&gt;"C:\Program Files\DropMyRights\DropMyRights.exe" "C:\Program Files\Mozilla Firefox\firefox.exe"&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sandboxie.com/"&gt;Sandboxie&lt;/a&gt;, is another neat security application that lets you run any application or drive basically in a separate sandbox. So when you run Firefox in sandboxie, if malware gets installed, it's installed in the sandbox and not your OS. It's very flexible; a caller even said they ran a thumbdrive in a sandbox. This one costs money so I have yet to install it.&lt;br /&gt;&lt;br /&gt;Finally, I learned that if you can afford over 200 PS3's and are incredibly smart about cryptography you can crack the md5 hash and create your own valid fraudulent certificate. Over the past few years, researchers have gradually weakened md5, but have finally basically broken it to where no one should be using it now in certificates. This one applies at work and home. Not only should I not be creating certificates at work using md5, but at home I should not visit sites over https that use certificates that use md5. See the &lt;a href="http://www.grc.com/sn/notes-177.htm"&gt;resource notes &lt;/a&gt;for episode #177 for further information (under Breaking SSL by Spoofing a Certificate Authority). I found several trusted certificate authorities defined on my home computer that use md5. Even a few expired certificates using md2, which I guess malware could change your system time if you weren't running DropMyRights. If you want to see this in action, set your system time to August 15th, 2004 and then visit this site &lt;a href="https://i.broke.the.internet.and.all.i.got.was.this.t-shirt.phreedom.org/"&gt;https://i.broke.the.internet.and.all.i.got.was.this.t-shirt.phreedom.org&lt;/a&gt; and check out the certificate. This will setup a secure connection using a fraudulent cerificate.&lt;br /&gt;&lt;br /&gt;In summary, I have learned a great deal about work and home computer security by listening to the Security Now podcast. Even if I didn't understand all of the details, it has definitely made me a more aware user security-wise. Do as I did and get rid of your WEP network, switch to OpenDNS, install DropMyRights on Windows, and subscribe to the Security Now podcast (very easy in iTunes).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-6521427272395184842?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6521427272395184842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6521427272395184842'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/02/security-news-for-work-and-personal.html' title='Security news for work and personal'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3394478070247693736</id><published>2009-01-17T02:32:00.009-06:00</published><updated>2009-01-17T03:38:09.813-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='json'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Testing REST Services with Groovy</title><content type='html'>For awhile now, RIAs (Rich Internet Applications) have rapidly started replacing traditional server-side web applications (JSP, JSF, etc). Typically, these flashier sites are created using Flex or javascript libraries like extjs or yui. At the heart of these sexy applications live simple REST services that return JSON or XML.&lt;br /&gt;&lt;br /&gt;Testing these REST services should be made a high priority for several reasons:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;It's the contract between the client and server. Breaking that contract should be avoided.&lt;/li&gt;&lt;li&gt;Your application may not be the only client. Once external parties start consuming your REST services you'll want tests in place to ensure you don't break their clients.&lt;/li&gt;&lt;li&gt;To validate the response is well-formed XML or properly constructed JSON&lt;/li&gt;&lt;li&gt;Valuable black-box test, testing the entire server-side stack starting from the REST layer going all the way down to the DAO layer to the database.&lt;/li&gt;&lt;/ol&gt;So, what's the easiest way to test REST services? For awhile now I have been combing the internet for the best tools to accomplish this goal, since I wasn't going to do it in pure Java, and I think I finally found the right combination using &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; and &lt;a href="http://groovy.codehaus.org/modules/http-builder/"&gt;HttpBuilder&lt;/a&gt;. Groovy because its super easy to parse XML and JSON, and HttpBuilder because it's a great wrapper for the popular Apache Commons HTTP Client library.&lt;br /&gt;&lt;br /&gt;Now let's say you have a REST service at the URL &lt;span style="font-style: italic;"&gt;http://localhost:8080/myapp/api/books&lt;/span&gt; that returns this JSON:&lt;br /&gt;&lt;pre&gt;{"books":[&lt;br /&gt;  {"name":"Being Mad","author":"Kit Plummer"},&lt;br /&gt;  {"name":"Clown Life","author":"Josh Hoover"},&lt;br /&gt;  {"name":"You Miss Me","author":"Ron Alleva"},&lt;br /&gt;  {"name":"Talk to me Goose","author":"Jeff Black"}&lt;br /&gt;]}&lt;br /&gt;&lt;/pre&gt;This is how simple it is to write a test in Groovy using HttpBuilder:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;import groovyx.net.http.HTTPBuilder&lt;br /&gt;import groovyx.net.http.Method&lt;br /&gt;import static groovyx.net.http.ContentType.JSON&lt;br /&gt;&lt;br /&gt;class BooksTest extends GroovyTestCase {&lt;br /&gt;  def void test_get_all_books() {&lt;br /&gt;      def http = new HTTPBuilder("http://localhost:8080")&lt;br /&gt;&lt;br /&gt;      http.request(Method.valueOf("GET"), JSON) {&lt;br /&gt;          url.path = '/myapp/api/books'&lt;br /&gt;&lt;br /&gt;          response.success = {resp, json -&gt;&lt;br /&gt;              json.books.each { book -&gt;&lt;br /&gt;                  assert book.name != ""&lt;br /&gt;              }&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;To me the major advantage to this approach is being able to traverse the JSON response like I would in javascript. If the response was XML it be just as easy too.&lt;br /&gt;&lt;br /&gt;The only two remaining items you would need would be adding the &lt;a href="http://groovy.codehaus.org/GMaven"&gt;gmaven plugin&lt;/a&gt; to your pom and httpbuilder as a dependency.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3394478070247693736?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3394478070247693736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3394478070247693736'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2009/01/testing-rest-services-with-groovy.html' title='Testing REST Services with Groovy'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3468786857279843000</id><published>2008-12-17T00:08:00.002-06:00</published><updated>2008-12-17T00:24:49.744-06:00</updated><title type='text'>Control versioning in new maven-release-plugin</title><content type='html'>I have been waiting with much anticipation for the new version of the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/index.html"&gt;maven-release-plugin&lt;/a&gt; to be, well released. Our team uses this time saving plugin heavily but since moving to a MAJOR.MINOR.PATCH version strategy we quickly found out that it needed some new features. What we really needed was the ability to specify versions for the tag and for the new trunk. For example, when HEAD is at 2.1.0-SNAPSHOT, while in batch-mode the new default version would be 2.1.1-SNAPSHOT, but I want it to be 2.2.0-SNAPSHOT.&lt;br /&gt;&lt;br /&gt;Fortunately, someone else was thinking the same thing and the new capabilities where already in the works. Our current version we are using is 2.0-beta-7. But I noticed today the maven team finally released 2.0-beta-8 (see &lt;a href="http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-release-plugin/2.0-beta-8/"&gt;repo1&lt;/a&gt;). Here are the &lt;a href="http://jira.codehaus.org/browse/MRELEASE/fixforversion/13812"&gt;release notes&lt;/a&gt; for the new version.&lt;br /&gt;&lt;br /&gt;What I was specifically interested in was the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/examples/non-interactive-release.html"&gt;new batch-mode features&lt;/a&gt;. Now instead of having to manually update the POMs after creating a release I can do the following automatically in CI:&lt;br /&gt;&lt;br /&gt;mvn release:prepare -DdevelopmentVersion=2.2.0-SNAPSHOT&lt;br /&gt;&lt;br /&gt;I haven't tested it yet, but will know in the near future if it works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3468786857279843000?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3468786857279843000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3468786857279843000'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/12/control-versioning-in-new-maven-release.html' title='Control versioning in new maven-release-plugin'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3802198408798061676</id><published>2008-12-05T11:17:00.010-06:00</published><updated>2008-12-08T16:29:34.928-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven2'/><title type='text'>Maven Profiles: Something you need to know</title><content type='html'>An issue came up today in our CI environment and I learned something new about &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-profiles.html"&gt;maven profiles&lt;/a&gt;. Something that everyone who uses maven should know. Perhaps, like your environment, our project uses &lt;a href="http://maven.apache.org/"&gt;maven2&lt;/a&gt; to build and we take advantage of multiple profiles (see our example &lt;a href="http://jlorenzen.blogspot.com/2008/07/maven-not-downloading-latest-snapshots.html"&gt;here&lt;/a&gt;). A common use for profiles is to define new modules and properties. For example:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;profiles&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;profile&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;id&amp;gt;integration-tests&amp;lt;/id&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;modules&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;module&amp;gt;integration&amp;lt;/module&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&amp;lt;/modules&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;properties&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;   &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;app.port&amp;gt;8080&amp;lt;/app.port&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;/properties&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;/profile&amp;gt;&lt;br /&gt;&amp;lt;profiles&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;This profile is activated when you run &lt;span style="font-style: italic;"&gt;mvn -P integration-tests install&lt;/span&gt;. But sometimes you want a profile on all the time. Maven profiles have the ability to be actived by default. To do this just do the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;profiles&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;profile&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;id&amp;gt;integration-tests&amp;lt;/id&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;b&gt;&lt;/b&gt;&lt;/code&gt;&lt;code&gt;&lt;b&gt;&amp;lt;activation&amp;gt;&lt;br /&gt;&lt;/b&gt;&lt;/code&gt;&lt;code&gt;&lt;b&gt;    &lt;/b&gt;&lt;/code&gt;&lt;code&gt;&lt;b&gt;    &lt;/b&gt;&lt;/code&gt;&lt;code&gt;&lt;b&gt;    &amp;lt;activeByDefault&amp;gt;true&amp;lt;/activeByDefault&amp;gt;&lt;br /&gt;&lt;/b&gt;&lt;/code&gt;&lt;code&gt;&lt;b&gt;    &lt;/b&gt;&lt;/code&gt;&lt;code&gt;&lt;b&gt;    &lt;/b&gt;&lt;/code&gt;&lt;code&gt;&lt;b&gt;&amp;lt;/activation&amp;gt;&lt;/b&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;modules&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &amp;lt;module&amp;gt;integration&amp;lt;/module&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;/modules&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;properties&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &amp;lt;app.port&amp;gt;8080&amp;lt;/app.port&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;/properties&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;&amp;lt;/profile&amp;gt;&lt;br /&gt;&amp;lt;profiles&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;Then you can just run &lt;span style="font-style: italic;"&gt;mvn install&lt;/span&gt; and that module and property will already be active.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;activeByDefault.....Sometimes&lt;/span&gt;&lt;br /&gt;Turns out that perhaps maven should have renamed it to &lt;span style="font-style: italic;"&gt;activeByDefaultSometimes&lt;/span&gt;. Reading their &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-profiles.html"&gt;documentation&lt;/a&gt; I learned something important about maven profiles:&lt;br /&gt;&lt;blockquote&gt;"&lt;span style="font-style: italic;"&gt;This profile will automatically be active for all builds unless another profile in the same pom is activated using one of the previously described methods. &lt;u&gt;All profiles that are active by default are automatically deactivated&lt;/u&gt; when a profile in the pom is activated on the command line or through its activation config.&lt;/span&gt;"&lt;/blockquote&gt;So in my example, if I have more than one profile defined in my pom and I run that new profile, then my integration-tests profile is deactivated. For example, when I run &lt;span style="font-style: italic;"&gt;mvn -P SecondProfile&lt;/span&gt;, the module and property defined in the integration-tests profiles are not available to my build. One trick to see which profiles are activated when running maven is to run &lt;span style="font-style: italic;"&gt;mvn help:active-profiles&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;In general I have never been a huge fan of profiles. They feel clumsy, clutter up the cmd line, and are not well known among your team. As their documentation states, "adding profiles to your build has the potential to break portability for your project". Instead of using Profiles, attach to known phases. For example, see my second example from this &lt;a href="http://jlorenzen.blogspot.com/2008/06/how-to-ftp-artifacts-in-maven2.html"&gt;previous post&lt;/a&gt;. In this example, I use the maven-antrun-plugin to attach to the &lt;span style="font-style: italic;"&gt;install&lt;/span&gt; phase. Now this will run anytime I run &lt;span style="font-style: italic;"&gt;mvn install&lt;/span&gt;. No clumsy profile I have to memorize and run. Given that, I am not saying you should avoid Profiles all together. Just use them as a last resort.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3802198408798061676?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/3802198408798061676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=3802198408798061676' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3802198408798061676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3802198408798061676'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/12/maven-profiles-something-you-need-to.html' title='Maven Profiles: Something you need to know'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5917865561375812279</id><published>2008-11-05T00:09:00.003-06:00</published><updated>2008-11-05T00:25:00.432-06:00</updated><title type='text'>Spare cycles to write some posts</title><content type='html'>Starting this week I am going to spend the next couple of weeks in &lt;a href="http://maps.google.com/maps?q=map+panama+city,+fl&amp;amp;ie=UTF-8&amp;amp;oe=utf-8&amp;amp;rls=org.mozilla:en-US:official&amp;amp;client=firefox-a&amp;amp;um=1&amp;amp;sa=X&amp;amp;oi=geocode_result&amp;amp;resnum=1&amp;amp;ct=title"&gt;Panama City, Florida&lt;/a&gt; on business working with the &lt;a href="http://www.1af.acc.af.mil/"&gt;1st AF&lt;/a&gt; here at &lt;a href="http://en.wikipedia.org/wiki/Tyndall_Air_Force_Base"&gt;Tyndall Air Force Base&lt;/a&gt;. In my down time, like right now while I copy over hundreds of MBs over a slow VPN connection, I plan on catching up on some blog ideas I have been wanting to write.&lt;br /&gt;&lt;br /&gt;Here is my goal:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Discuss and promote our iPhone app &lt;a href="http://handtronics.com/apps/BorrowMe"&gt;BorrowMe&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Multi-part series on security. For the past two sprints I have written about 6 lines of code, but I have learned a ton about securing our web based application using LDAP+Active Directory and SmartCard authentication or &lt;a href="http://www.cac.mil/"&gt;CAC&lt;/a&gt; (Common Access Card) authentication as referred by in the DoD. (U.S. Department of Defense), Apache, SSL, and OpenSSO.&lt;/li&gt;&lt;li&gt;Talk some more about &lt;a href="http://www.ubuntu.com/products/whatisubuntu/serveredition/jeos"&gt;Ubuntu JeOS&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/1280619439915049383-5917865561375812279?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/5917865561375812279/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=5917865561375812279' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5917865561375812279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5917865561375812279'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/11/spare-cycles-to-write-some-posts.html' title='Spare cycles to write some posts'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1411026091263291711</id><published>2008-10-22T09:47:00.005-05:00</published><updated>2008-10-22T10:58:21.733-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='release'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>More tips on using the maven2 release plugin</title><content type='html'>This blog's most &lt;a href="http://my4.statcounter.com/project/standard/popular.php?project_id=2821167"&gt;frequently&lt;/a&gt; visited post was the one I did over a year ago titled "&lt;a href="http://jlorenzen.blogspot.com/2007/09/how-to-create-release-using-maven2.html"&gt;How to create a release using the maven2 release plugin&lt;/a&gt;". Automating this portion of our frequent release process without a doubt has saved my team hundreds of hours over the past year. For that reason I would like to provide some new tips I discovered yesterday when I needed to change the subversion comment used by the release plugin when committing any changes.&lt;br /&gt;&lt;br /&gt;For teams not using the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/"&gt;maven-release-plugin&lt;/a&gt; yet, this handy plugin helps automate the complete process when releasing your software. It helps save time by doing the following and more:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First it will build your project running any tests you specify&lt;/li&gt;&lt;li&gt;If successful, it will then commit your project into a tag&lt;/li&gt;&lt;li&gt;Update the tag pom versions from say 1.0.0-SNAPSHOT to 1.0.0&lt;/li&gt;&lt;li&gt;Change the tag pom SCM URL to correctly point to the tag instead of HEAD&lt;/li&gt;&lt;li&gt;Most importantly, it will build the release (1.0.0) and upload the artifacts to your companies maven2 repository (archiva now in our case; was artifactory).&lt;/li&gt;&lt;li&gt;Finally, it will increment the pom versions in HEAD to be the next release (1.0.1-SNAPSHOT).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tip #1 - Change Commmit Comment&lt;/span&gt;&lt;br /&gt;By default the maven-release-plugin uses a comment like, &lt;span style="font-style: italic;"&gt;[maven-release-plugin] prepare release project-1.0.0&lt;/span&gt;, when doing any type of commit such as creating a tag/branch or incrementing the pom versions. Which works wonderful until your team implements a Subversion pre-commit hook requiring all commits to start with certain keywords (Story: ZZZ, Jira: ZZ-N). Luckily the maven-release-plugin has an option to override the comment.&lt;br /&gt;&lt;br /&gt;There are two simple ways to provide the plugin with the comment. The first sets the system property, scmCommentPrefix, to the predefined prefix. The second, provides the prefix comment in the pom.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;mvn release:clean release:prepare -DscmCommentPrefix=Jira: AC-100 [maven-release-plugin]&lt;br /&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-release-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;     &amp;lt;configuration&amp;gt;&lt;br /&gt;         &amp;lt;scmCommentPrefix&amp;gt;Jira: AC-100 [maven-release-plugin]&amp;lt;/scmCommentPrefix&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;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tip #2 - Configuration Options via -D&lt;/span&gt;&lt;br /&gt;Disappointed that I didn't catch this earlier, especially since I have been using &lt;span style="font-style: italic;"&gt;-DpreparationGoals&lt;/span&gt; for awhile now, but all of the &lt;a href="http://maven.apache.org/plugins/maven-release-plugin/prepare-mojo.html"&gt;optional parameters&lt;/a&gt; for the &lt;span style="font-style: italic;"&gt;prepare&lt;/span&gt; goal can be defined with -D rather than in the POM (as above). So if you wanted to change the default tagBase to use /branches instead of the default /tags do the following. However, I would still put this static value in the pom.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;mvn release:clean release:prepare -DtagBase=http://project.svn.org/svn/project/branches&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Tip #3 - Allow SNAPSHOT dependencies&lt;/span&gt;&lt;br /&gt;This new feature is going to be huge for legacy projects who weren't raised with the release plugin. As mentioned in my previous post, previous versions of the release plugin didn't allow you to have SNAPSHOT dependencies; rightfully so too since that wouldn't be a very good practice to have a release depend on a changing dependency. However, I think this feature prevented many projects from using the release plugin because their snapshot depenencies were too many to change and it was just easier to continue doing same old.&lt;br /&gt;&lt;br /&gt;Even though I have not used this feature, it would seem now one could release a project using this plugin and still have SNAPSHOT dependencies. However, after creating the release it would still be a good idea to go back in the release and change any SNAPSHOT dependencies to releases.&lt;br /&gt;&lt;br /&gt;I believe this is a new feature so you might also want to upgrade to the latest version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1411026091263291711?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1411026091263291711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1411026091263291711' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1411026091263291711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1411026091263291711'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/10/more-tips-on-using-maven2-release.html' title='More tips on using the maven2 release plugin'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7073841858435543227</id><published>2008-10-15T23:12:00.008-05:00</published><updated>2008-10-15T23:47:39.191-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rss'/><category scheme='http://www.blogger.com/atom/ns#' term='yahoo pipes'/><title type='text'>Using Yahoo Pipes screen scraping to create an RSS Feed</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://l.yimg.com/us.yimg.com/i/us/pps/logo_1.gif"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 119px;" 45px="" src="http://l.yimg.com/us.yimg.com/i/us/pps/logo_1.gif" alt="" border="0" /&gt;&lt;/a&gt;The internet amazes me. Every time I use it, or write something for it, I continue to be blown away. Take for example, my favorite website for Husker information: &lt;a href="http://www.huskerpedia.com/"&gt;http://www.huskerpedia.com&lt;/a&gt; (for those that don't know, what I mean by husker information is Nebraska Cornhusker Football. I was born in Nebraska so I naturally follow the cornhuskers.). Someone takes the time to consolidate all husker information and updates this site. It is the de facto standard for Husker news. Unfortunately, this site does not come with any type of notifications via an RSS feed.&lt;br /&gt;&lt;br /&gt;Now this site does not necessarily amaze me, but rather how I can take a tool like &lt;a href="http://pipes.yahoo.com/pipes/"&gt;Yahoo Pipes&lt;/a&gt;, scrape the latest news, and in a couple of hours subscribe to that feed in &lt;a href="http://www.google.com/reader/view/"&gt;Google Reader&lt;/a&gt;. Not only that, but I cloned Paul Arterburn's &lt;a href="http://pipes.yahoo.com/pipes/pipe.info?_id=3kjpvHEK3RGgCetYCB2yXQ"&gt;Huskerpedia Pipe&lt;/a&gt; to get started and now everyone can take advantage of my new feed by either subscribing to it, making it better, or cloning it for their own use.&lt;br /&gt;&lt;br /&gt;This would make the second time I have used Yahoo Pipes to accomplish something complex very easily. Several months ago, I created a pipe called the &lt;a href="http://pipes.yahoo.com/pipes/pipe.info?_id=BIEpr9Q63BGcD_03JhOy0Q"&gt;Gestalt Shared Feed&lt;/a&gt;, that combined all of my co-workers shared items from their Google Reader feed. This allowed us to read the best of the best among ourselves and has really helped our communication. I think we have about 10 people who share items and many more who subscribe to it.&lt;br /&gt;&lt;br /&gt;Check out my &lt;a href="http://pipes.yahoo.com/pipes/pipe.info?_id=1fedaf2576cdd82160e81fb72e6d209e"&gt;RssHuskerPedia Pipe&lt;/a&gt; and view the source if you are curious. See below for the before and after.&lt;br/&gt;&lt;br/&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_u6FjI-f0VoU/SPbGCRikg_I/AAAAAAAAAGQ/LNbZrr95g00/s1600-h/huskerpedia.png"&gt;&lt;img style="margin: 0pt 0pt 0px 10px; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_u6FjI-f0VoU/SPbGCRikg_I/AAAAAAAAAGQ/LNbZrr95g00/s320/huskerpedia.png" alt="" id="BLOGGER_PHOTO_ID_5257607357372072946" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br/&gt;&lt;br/&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_u6FjI-f0VoU/SPbGObO0SJI/AAAAAAAAAGY/tjxWuStiYlM/s1600-h/googlereader.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_u6FjI-f0VoU/SPbGObO0SJI/AAAAAAAAAGY/tjxWuStiYlM/s320/googlereader.png" alt="" id="BLOGGER_PHOTO_ID_5257607566132005010" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7073841858435543227?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7073841858435543227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7073841858435543227' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7073841858435543227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7073841858435543227'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/10/using-yahoo-pipes-screen-scraping-to.html' title='Using Yahoo Pipes screen scraping to create an RSS Feed'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_u6FjI-f0VoU/SPbGCRikg_I/AAAAAAAAAGQ/LNbZrr95g00/s72-c/huskerpedia.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8466117509478751572</id><published>2008-08-28T00:20:00.002-05:00</published><updated>2008-08-28T00:40:16.043-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Me lovin Git</title><content type='html'>As I stated &lt;a href="http://jlorenzen.blogspot.com/2008/06/dvcs-im-sold.html"&gt;previously&lt;/a&gt;, I am sold on DVCS, and today it just got better.&lt;br /&gt;&lt;br /&gt;I came across a situation where I needed to share highly experimental code with a teammate. There was no way I could check this code into our normal repo, so what first pops into your head: email (strongbad style). You've been here and don't pretend you haven't used email. Oh yes the wonderful land of emailing around jar or zip files repeatedly.&lt;br /&gt;&lt;br /&gt;Emailing source code around stopped today. Instead I got on the phone with &lt;a href="http://www.ronniealleva.org/"&gt;Ron Alleva&lt;/a&gt; who helped walk me through the simple git commands to create my own local master repo. It was so simple it was ridiculous.&lt;br /&gt;&lt;br /&gt;Here are the steps to create and share hack code in minutes&lt;br /&gt;&lt;ol&gt;&lt;li&gt;install git&lt;br /&gt;&lt;/li&gt;&lt;li&gt;cd to the folder you wish to share&lt;/li&gt;&lt;li&gt;run &lt;span style="font-style: italic;"&gt;git init&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;run &lt;span style="font-style: italic;"&gt;git add .&lt;/span&gt;&lt;/li&gt;&lt;li&gt;run &lt;span style="font-style: italic;"&gt;git commit -a&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Have your teammate clone it by running &lt;span style="font-style: italic;"&gt;git clone ssh://user@host/path/to/repo.git/&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;Ironically after my teammate first cloned it and tested the code it failed because of a recent change I made. So I made the fix, committed it to my local repo, and he was able to &lt;span style="font-style: italic;"&gt;git pull&lt;/span&gt; those changes. Also, if he makes any changes we can share them easily as well by him using &lt;span style="font-style: italic;"&gt;git push&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8466117509478751572?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8466117509478751572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8466117509478751572' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8466117509478751572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8466117509478751572'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/08/me-lovin-git.html' title='Me lovin Git'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8203844773754109274</id><published>2008-08-27T21:50:00.000-05:00</published><updated>2008-08-28T00:20:12.753-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ubiquity'/><title type='text'>Testing the new firefox plugin Ubiquity</title><content type='html'>Today I found out about the new experimental firefox plugin &lt;a href="http://www.techcrunch.com/2008/08/26/if-you-want-to-create-a-mashup-just-ask-your-browser-mozilla-labs-launches-ubiquity/"&gt;Ubiquity&lt;/a&gt; and I wanted to give a try in my blog. So far I am very impressed and it seems to be working fine on linux, even though the documentation says they don't support it yet (I am running Ubuntu 8.04 with firefox 3).&lt;br /&gt;&lt;br /&gt;It was easy to &lt;a href="http://www.azarask.in/blog/post/ubiquity-in-depth/"&gt;install&lt;/a&gt;. After installation firefox takes you to the firefox egg &lt;a href="about:ubiquity"&gt;about:ubiquity&lt;/a&gt; which contains one of the best tutorials I have ever followed.&lt;br /&gt;&lt;br /&gt;To try it out you can get a map of where I work. First install ubiquity and highlight this address:&lt;br /&gt;&lt;br /&gt;407 Pennsylvania Ave Joplin, MO&lt;br /&gt;&lt;br /&gt;then invoke ubiquity (CRTL+SPACEBAR) and type map. Click on the map and then click on &lt;span style="font-style: italic;"&gt;Insert map in page&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Pretty slick. So far today I have used the language translation features, bold, tinyurl, and map. In a way it reminds me a lot of &lt;a href="https://wiki.ubuntu.com/GnomeDo"&gt;Gnome-Do&lt;/a&gt; for linux in that it provides a quick way to get information but obviously ubiquity is much more powerful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8203844773754109274?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8203844773754109274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8203844773754109274' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8203844773754109274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8203844773754109274'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/08/testing-new-firefox-plugin-ubiquity.html' title='Testing the new firefox plugin Ubiquity'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5519636637124427253</id><published>2008-08-18T23:37:00.002-05:00</published><updated>2008-08-18T23:46:42.400-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>Waiting for Free iPhone SDK</title><content type='html'>What is this a Starbucks waiting line? Am I trying to download a microsoft product? Sure seems like it. Tonight I had a goal of getting my first Hello World app working for an iphone, but apple had other plans. While waiting for my turn in line to download the free SDK I watched the following video "&lt;a href="http://www.iphonedevcentral.org/tutorials.php?page=ViewTutorial&amp;amp;id=49&amp;amp;uid=27391603"&gt;Hello World Final SDK&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_u6FjI-f0VoU/SKpP8UFxKeI/AAAAAAAAAGA/HVLTfbqe4eo/s1600-h/Picture+1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/SKpP8UFxKeI/AAAAAAAAAGA/HVLTfbqe4eo/s320/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5236085414375270882" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5519636637124427253?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/5519636637124427253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=5519636637124427253' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5519636637124427253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5519636637124427253'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/08/waiting-for-free-iphone-sdk.html' title='Waiting for Free iPhone SDK'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_u6FjI-f0VoU/SKpP8UFxKeI/AAAAAAAAAGA/HVLTfbqe4eo/s72-c/Picture+1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4899185637403310119</id><published>2008-08-09T23:48:00.006-05:00</published><updated>2008-08-10T00:17:20.952-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='extjs'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Getting started with Grails and Extjs</title><content type='html'>This article describes how to get started using &lt;a href="http://extjs.com/"&gt;extjs&lt;/a&gt; with your grails app. Since the &lt;a href="http://grails.org/Ext+Plugin"&gt;plugin&lt;/a&gt; is deprecated because of the GPL license fiasco, I decided to write my own simple grails script to handle installing extjs for the team for 2 main reasons:&lt;br /&gt;1) Prevents me from having to commit 500+ files into SVN for every new version&lt;br /&gt;2) Makes it easier to upgrade to newer versions of extjs in the future&lt;br /&gt;&lt;br /&gt;We have 2 existing internal applications that use extjs and every upgrade I am kicking myself for not using maven to extract the extjs zip file. So with our new grails app I wanted to not make the same mistake.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Install Extjs&lt;/span&gt;&lt;br /&gt;1) Download your choice of extjs. Note as of version 2.1 extjs is under the GPL license. Meaning if your project isn't open sourced under the GPL or an internal company app then you need to use the 2.0.x versions (2.0.2 is the latest). In our case I downloaded version 2.2.&lt;br /&gt;&lt;br /&gt;2) Copy ext-2.2.zip into your grails plugins directory&lt;br /&gt;&lt;br /&gt;3) cd into your grails application&lt;br /&gt;&lt;br /&gt;4) Add the zip file to svn (or whatever): &lt;span style="font-style: italic;"&gt;svn add plugins/ext-2.2.zip&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;5) run &lt;span style="font-style: italic;"&gt;grails create-script install-extjs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;6) Add the script to svn: &lt;span style="font-style: italic;"&gt;svn add scripts/InstallExtjs.groovy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;7) Modify the InstallExtjs.groovy script and add the &lt;a href="http://pastebin.com/f53a88be2"&gt;following GANT code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;8) run &lt;span style="font-style: italic;"&gt;grails install-extjs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;9) Exclude the unziped ext directory: &lt;span style="font-style: italic;"&gt;svn propedit svn:ignores web-app/js &lt;/span&gt;Exclude the folder &lt;span style="font-style: italic;"&gt;ext&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Test it out&lt;/span&gt;&lt;br /&gt;Now that you have extjs installed you can copy one of their examples into the grails web-app directory and update the links.&lt;br /&gt;&lt;br /&gt;1) Open up the ext-2.2.zip file again and extract the array-grid.html and array-grid.js files from the &lt;span style="font-style: italic;"&gt;examples/grid&lt;/span&gt; folder to the grails web-app directory.&lt;br /&gt;&lt;br /&gt;2) Modify the array-grid.html file. Update the relative links for css and javascript by replacing ../../ with js/ext/. For example, href="../../resources/css/ext-all.css", should now be href="js/ext/resources/css/ext-all.css"&lt;br /&gt;&lt;br /&gt;3) Open up the array-grid.html file in your browser.&lt;br /&gt;&lt;br /&gt;Now you have extjs installed with a simple example on how to use it. Next I would like to create a grails controller that returns JSON to populate a simple grid.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4899185637403310119?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4899185637403310119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4899185637403310119' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4899185637403310119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4899185637403310119'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/08/getting-started-with-grails-and-extjs.html' title='Getting started with Grails and Extjs'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-106554668694543883</id><published>2008-07-20T06:33:00.006-05:00</published><updated>2008-07-20T07:28:29.343-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails: Lessons Learned</title><content type='html'>Here are some lessons learned concerning lazy vs eager fetching and how to delete a child object in a &lt;a href="http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html#5.2.1.2%20One-to-many"&gt;One-to-many&lt;/a&gt; relationship (unfortunately it's not super obvious).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;First Lesson: Don't set eager fetching globally&lt;/span&gt;&lt;br /&gt;I by no means am a grails expert, but based on my experience don't set the eager fetching in your Domain as the &lt;a href="http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html#5.3.4%20Eager%20and%20Lazy%20Fetching"&gt;example&lt;/a&gt; shows (unless you have a very good reason and understand the consequences). Lazy vs Eager fetching is well described in the grails &lt;a href="http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html#5.3.4%20Eager%20and%20Lazy%20Fetching"&gt;documentation&lt;/a&gt;, so I won't repeat it, but anyone using One-to-many relationships needs to know the differences.&lt;br /&gt;&lt;br /&gt;The default behavior in grails is lazy fetching, which results in &lt;a href="http://www.javalobby.org/java/forums/t20533.html"&gt;n+1 queries&lt;/a&gt;. In some cases this might be ideal, in others it may not. When it's not you have a couple of choices. The example in the grails documentation sets a &lt;span style="font-style: italic;"&gt;fetchMode&lt;/span&gt; property on the Domain. This sets it globally and every time the Domain is accessed, grails is going to load all it's many relationships. The path I recommend is to specify the fetch mode when retrieving the data. For example, the &lt;a href="http://grails.org/doc/1.0.x/ref/Domain%20Classes/list.html"&gt;&lt;span style="font-style: italic;"&gt;list()&lt;/span&gt;&lt;/a&gt; method has a parameter called &lt;span style="font-style: italic;"&gt;fetch&lt;/span&gt; and can be used like this: &lt;span style="font-style: italic;"&gt;Book.list(fetch: [authors: "eager"])&lt;/span&gt;. This gives you the most flexibility by not specifying the fetch mode globally, but allowing you to fetch eagerly when necessary.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Second Lesson: Use Hibernate Events to help remove associations&lt;/span&gt;&lt;br /&gt;Like myself, you might actually have a One-to-many relationship where you need to delete a child. Unfortunately this use case isn't documented very well and it actually took me a little bit to figure out.&lt;br /&gt;&lt;br /&gt;So lets say you have the following two domains&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class Parent {&lt;br /&gt;  static hasMany = [kids: Kid]&lt;br /&gt;  String name&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Kid {&lt;br /&gt; static belongsTo = [parent: Parent]&lt;br /&gt; String name&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;And you save the following&lt;br /&gt;&lt;pre&gt;&lt;code&gt;new Parent(name: "James").addToKids(name: "Ayden").save()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;Now Ayden turns 18 and going off to college and you need to remove him. You might think this would work:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;Kid.findByName("Ayden").delete()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;But it doesn't because the parent James still has a reference to the kid Ayden in the kids list (&lt;span style="font-style: italic;"&gt;parent.kids&lt;/span&gt;). So you have to do the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def kid = Kid.findByName("Ayden")&lt;br /&gt;kid.parent.removeFromKids(kid)&lt;br /&gt;kid.delete()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;Why that isn't the default behavior in grails I don't know, but to prevent you from repeating code everywhere you can use &lt;a href="http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html#5.5.1%20Events%20and%20Auto%20Timestamping"&gt;Hibernate events&lt;/a&gt;. In the Kid Domain add the following &lt;span style="font-style: italic;"&gt;beforeDelete&lt;/span&gt; property:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class Kid {&lt;br /&gt;   static belongsTo = [parent: Parent]&lt;br /&gt;   def beforeDelete = {&lt;br /&gt;       parent.removeFromKids(this)&lt;br /&gt;   }&lt;br /&gt;   String name&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;And now when you want to remove a Kid, all you need to do is call &lt;span style="font-style: italic;"&gt;kid.delete()&lt;/span&gt;. The hibernate events are interesting. By default grails supports 4 events: &lt;span style="font-style: italic;"&gt;beforeInsert&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;beforeUpdate&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;beforeDelete&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;onLoad&lt;/span&gt;. However, there is a recent plugin called &lt;a href="http://docs.codehaus.org/display/GRAILS/Hibernate+Events+Plugin"&gt;Hibernate Events Plugin&lt;/a&gt; that adds 7 more events: &lt;span style="font-style: italic;"&gt;beforeLoad&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;afterLoad&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;beforeSave&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;afterSave&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;afterInsert&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;afterUpdate&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;afterDelete&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-106554668694543883?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/106554668694543883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=106554668694543883' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/106554668694543883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/106554668694543883'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/07/grails-lessons-learned.html' title='Grails: Lessons Learned'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-2065544425576046467</id><published>2008-07-18T06:35:00.004-05:00</published><updated>2009-01-18T22:47:39.693-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='json'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Grails JSON Parser</title><content type='html'>Here is a quick example on parsing JSON in grails using groovy (surprisingly, google isn't returning any good hits). Also, if you needed this ability in just straight groovy, I am sure you could include the specific grails jar in your classpath.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;import grails.converters.*&lt;br /&gt;&lt;br /&gt;def jsonArray = JSON.parse("""['foo','bar', { a: 'JSONObject' }]""")&lt;br /&gt;println "Class of jsonArray: ${jsonArray.class.name}"&lt;br /&gt;jsonArray.each { println "Value: ${it}" }&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;FYI, it appears from the &lt;a href="http://www.nabble.com/each%28%29-on-a-JSONArray-%28org.codehaus.groovy.grails.web.json.JSONArray%29-to13566751.html#a13682252"&gt;mailing list&lt;/a&gt; this was added around 1.0 RC1.&lt;br /&gt;&lt;br /&gt;Building JSON is super easy too in grails/groovy using the &lt;a href="http://grails.org/Controller+Dynamic+Methods"&gt;render as&lt;/a&gt;. And don't forget to import grails.converters.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;render Book.list(params) as JSON&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;: Read my recent &lt;a href="http://jlorenzen.blogspot.com/2009/01/testing-rest-services-with-groovy.html"&gt;article&lt;/a&gt; on testing REST Services that return JSON using groovy and httpbuilder.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-2065544425576046467?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/2065544425576046467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=2065544425576046467' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2065544425576046467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2065544425576046467'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/07/grails-json-parser.html' title='Grails JSON Parser'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-273998052129102146</id><published>2008-07-11T09:15:00.006-05:00</published><updated>2008-07-18T04:55:41.353-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy Threads and MetaClass example</title><content type='html'>* &lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt; - the code has been updated. The original test was incorrect and was producing a false positive. What you see now is the correct way.&lt;br /&gt;&lt;br /&gt;It's been awhile since I have been able to play around with grails/groovy. Now, instead of using a pretend app to learn grails/groovy, I have teamed up with &lt;a href="http://codebeneath.blogspot.com/"&gt;Jeff Black&lt;/a&gt;, &lt;a href="http://gallemore.blogspot.com/"&gt;Chad Gallemore&lt;/a&gt;, and &lt;a href="http://imnotpete.com/"&gt;Sam Jones&lt;/a&gt; (fellow office co-workers here in &lt;a href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;q=joplin,+MO&amp;amp;ie=UTF8&amp;amp;z=11"&gt;Joplin, MO&lt;/a&gt;) to rewrite an existing small internal java webapp using grails. It's a perfect application for grails and so far we are loving it.&lt;br /&gt;&lt;br /&gt;Early on, we needed to figure out 2 things:&lt;br /&gt;1) Groovy way of creating Threads&lt;br /&gt;2) Writing an integration test for a Groovy Service&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy Threads&lt;/span&gt;&lt;br /&gt;Below is a summary of our service that shows how to start new threads in groovy.&lt;br /&gt;&lt;pre&gt;class ProjectService {&lt;br /&gt;  def discover() {&lt;br /&gt;      Project.list().each {&lt;br /&gt;          Thread.startDaemon {&lt;br /&gt;              jobService.update(it)&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Service Integration test with MetaClass&lt;/span&gt;&lt;br /&gt;Here is the integration test I wrote that tests the above Service.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;void testEmptyProject() {&lt;br /&gt;   def called = false&lt;br /&gt;&lt;br /&gt;   Project.metaClass.static.list = {[]}&lt;br /&gt;   Thread.metaClass.static.startDaemon = {Closure c -&gt; c.call()}&lt;br /&gt;   JobService.metaClass.update = {called = true}&lt;br /&gt;   new ProjectService(jobService: new JobService()).discover()&lt;br /&gt;&lt;br /&gt;   assertFalse('updateJobs should not have been called', called)&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;The first missing key for me was the &lt;span style="font-weight: bold;"&gt;static&lt;/span&gt; keyword on metaClass since in the service I am calling Project.list() and Thread.startDaemon(). The second mystery was how to mock out Thread.startDaemon() since there could be, and was, a race condition between the update closure setting called = true and my assertFalse.&lt;br /&gt;&lt;br /&gt;Thanks &lt;a href="http://gallemore.blogspot.com/"&gt;Chad&lt;/a&gt; for the suggestion of using metaClass. I also got a lot of help from Glenn Smith's blog about &lt;a href="http://blogs.bytecode.com.au/glen/2008/03/12/mockfor-march---unit-testing-grails-controllers.html"&gt;testing controllers&lt;/a&gt; and Dustin's groovy &lt;a href="http://dustinwhitney.blogspot.com/2008/03/groovy-threads.html"&gt;thread example&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-273998052129102146?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/273998052129102146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=273998052129102146' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/273998052129102146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/273998052129102146'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/07/groovy-threads-and-metaclass-example.html' title='Groovy Threads and MetaClass example'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4247227408941146300</id><published>2008-07-03T12:28:00.005-05:00</published><updated>2008-07-03T13:12:29.012-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven not downloading latest snapshots or releases</title><content type='html'>Ever had issues with maven not downloading the latest snapshots when you know for a fact new snapshots are available? Or your CI environment just deployed a new release (2.0), but when another Hudson job builds, maven does not download the latest 2.0 release artifact. Want an automated solution so you don't have to manually delete the artifacts from your local repository just so maven will download the latest?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Force maven to download latest snapshots&lt;/span&gt;&lt;br /&gt;Our company uses &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt; for our automated CI environments. Our project basically has two jobs. The first job checks out and builds HEAD when modified and deploys SNAPSHOT WARs to our companies maven2 repository (artifactory). The second job, which builds nightly, uses maven to download the SNAPSHOT WARs from artifactory, creates an EAR, deploys it to JBoss, and runs integration tests. By default, maven will check once a day for changes to snapshots, so when our second job was triggered, maven inside hudson was not downloading the latest SNAPSHOT WARs.&lt;br /&gt;&lt;br /&gt;The solution was to append the -U in the maven goals (run &lt;span style="font-style: italic;"&gt;mvn -help&lt;/span&gt;). It stands for update-snapshots and tells maven to update all snapshots no matter what.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_u6FjI-f0VoU/SG0UilmDDTI/AAAAAAAAAFw/1acertfrtr0/s1600-h/dashU.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://bp0.blogger.com/_u6FjI-f0VoU/SG0UilmDDTI/AAAAAAAAAFw/1acertfrtr0/s320/dashU.png" alt="" id="BLOGGER_PHOTO_ID_5218850127632076082" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Force maven to download latest releases&lt;/span&gt;&lt;br /&gt;Our next problem was when we created a branch and started creating release artifacts such as 2.0. Unfortunately the description given by maven for the -U option is incorrect (or at least in v 2.0.9), "Forces a check for updated releases and snapshots on remote repositories". As much as I tried, the -U option wouldn't work in our hudson job to force maven to download the latest non-snapshot releases.&lt;br /&gt;&lt;br /&gt;The only current solution I know of is to use the &lt;a href="http://maven.apache.org/plugins/maven-dependency-plugin/"&gt;maven-dependency-plugin&lt;/a&gt; and its goal &lt;a href="http://maven.apache.org/plugins/maven-dependency-plugin/purge-local-repository-mojo.html"&gt;purge-local-repository&lt;/a&gt;. So in your maven goals at some point execute &lt;span style="font-style: italic;"&gt;mvn dependency:purge-local-repository&lt;/span&gt; and maven will physically delete your projects artifacts from the local repository (/home/user/.m2/repistory) and its transitive dependencies (I think). I tried setting the &lt;span style="font-style: italic;"&gt;actTransitively&lt;/span&gt; to false and it didn't work for us so I just removed it. I also set &lt;span style="font-style: italic;"&gt;verbose&lt;/span&gt; to true so I could see what maven deleted in Hudson's console output.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_u6FjI-f0VoU/SG0V7f4kS5I/AAAAAAAAAF4/fEddQyN1Yrw/s1600-h/purge.png"&gt;&lt;img style="cursor: pointer;" src="http://bp0.blogger.com/_u6FjI-f0VoU/SG0V7f4kS5I/AAAAAAAAAF4/fEddQyN1Yrw/s320/purge.png" alt="" id="BLOGGER_PHOTO_ID_5218851655107496850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The pipes are used to separate out different goals to isolate its classpath or properties. That way we can skip tests in one run, and then run them in the next all in the same goals section.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4247227408941146300?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4247227408941146300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4247227408941146300' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4247227408941146300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4247227408941146300'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/07/maven-not-downloading-latest-snapshots.html' title='Maven not downloading latest snapshots or releases'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_u6FjI-f0VoU/SG0UilmDDTI/AAAAAAAAAFw/1acertfrtr0/s72-c/dashU.png' height='72' width='72'/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4206903205344205092</id><published>2008-06-26T00:01:00.002-05:00</published><updated>2008-06-26T00:16:56.456-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='dvcs'/><title type='text'>DVCS? I'm sold</title><content type='html'>As a casual reader of DVCS advantages like git and mercurial, I think I am ready. Motivated by a great &lt;a href="http://derekslager.com/blog/posts/2008/06/dvcs-myths.ashx"&gt;article&lt;/a&gt; shared by &lt;a href="http://www.blackholelogic.com/"&gt;Kit Plummer&lt;/a&gt;, I am sold and ready to start using it. Unfortunately, it's probably not going to happen any time soon at work until a) IT supports a mercurial server like they do svn or b) I start a new project were new decisions like language (ruby/groovy) and source control can be made and I'm not hindered by "we are already using svn, why switch" or "I just got comfortable with svn" or "every team member would have to learn mercurial". Reminds me of my favoriate Zed Shaw quote from this &lt;a href="http://www.zedshaw.com/blog/2008-04-09.html"&gt;article&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;"This folks is the classic problem with programmers today.  They absolutely refuse to learn anything new unless they can see that learning the new hotness will give them an immediate 200% boost in salary or get them hot honeys at the next conference."&lt;br /&gt;&lt;/blockquote&gt;Now that I see that Hudson has a &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/Mercurial+Plugin"&gt;mercurial plugin&lt;/a&gt; and &lt;a href="http://confluence.atlassian.com/display/JIRAEXT/Mercurial+Plugin"&gt;Jira&lt;/a&gt; does as well, then technically speaking, I can't think of any other reason not to switch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4206903205344205092?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4206903205344205092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4206903205344205092' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4206903205344205092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4206903205344205092'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/06/dvcs-im-sold.html' title='DVCS? I&apos;m sold'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7880863204281116061</id><published>2008-06-15T21:02:00.007-05:00</published><updated>2008-06-15T22:00:03.520-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven2'/><title type='text'>How to FTP artifacts in maven2</title><content type='html'>If there is one word a team should keep in mind when building a CI (Continuous Integration) environment it's &lt;span style="font-weight: bold;"&gt;Automate&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;Automate&lt;/span&gt;, and &lt;span style="font-weight: bold;"&gt;Automate&lt;/span&gt; (see &lt;a href="http://www.testearly.com/2008/02/04/continuous-production-production-ready-softwareany-time/"&gt;Production-ready software, on-demand&lt;/a&gt;). Most teams, including mine currently, performs their releases manually; creating the branch, incrementing the POMs, uploading the artifacts to a repository, etc. This is one reason I &lt;a href="http://jlorenzen.blogspot.com/2007/09/how-to-create-release-using-maven2.html"&gt;wrote&lt;/a&gt; about using the maven release plugin to automate this process. I will say that having a CI server such as &lt;a href="http://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt; only helps in making automation easier.&lt;br /&gt;&lt;br /&gt;My team also creates an official release about once every two months and supports that release anywhere between 1-2 weeks to months. It's also pretty intense during those 1-2 weeks when we have co-workers on-site installing and supporting our software in a completely different timezone and with limited access to the phone and internet.&lt;br /&gt;&lt;br /&gt;Over the weekend I wrote a simple maven2 pom to help automate FTP'ing the release artifacts to an FTP server. Last week we created a branch and a job in hudson that builds that branch. After it successfully builds we use the assembly plugin to package our EAR, documentation, SQL files, and everything else into a single folder. In the past, a guy would then manually copy these files to the FTP server, which was used by the on-site team to download the latest artifacts containing improvements and bug fixes. This release we wanted to automate this step to increase our response time for the on-site team.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;First Try using GMaven Plugin&lt;/span&gt;&lt;br /&gt;I knew that Ant had an &lt;a href="http://ant.apache.org/manual/OptionalTasks/ftp.html"&gt;FTP task&lt;/a&gt; and I love doing Ant in Groovy because its so much easier so I decided to first try the &lt;a href="http://groovy.codehaus.org/GMaven"&gt;GMaven plugin&lt;/a&gt; (maven groovy plugin). It was a short trip since the FTP task is an optional library in Ant and you have to include the jar in your POM, but I could never get the gmaven plugin to recognize the dependency (see &lt;a href="http://jira.codehaus.org/browse/MGROOVY-152"&gt;MGROOVY-152&lt;/a&gt;). Look at the Jira issue attachments if you want to reference my POM as an example. It's too bad I couldn't get this to work because it would have been sweet:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;log.info('Entering in ftp script')&lt;br /&gt;&lt;br /&gt;def config = [server: 'localhost',&lt;br /&gt;   remotedir: '/home/jlorenzen/ftptest',&lt;br /&gt;   user: 'ftp',&lt;br /&gt;   password: 'ftp'&lt;br /&gt;];&lt;br /&gt;&lt;br /&gt;ant.ftp(config) {&lt;br /&gt;   fileset(dir: '&lt;/code&gt;&lt;code&gt;/home/jlorenzen/Documents&lt;/code&gt;&lt;code&gt;')&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Second Try Maven AntRun Plugin&lt;/span&gt;&lt;br /&gt;I was finally able to get this to work using the maven-antrun-plugin. Here is my POM&lt;br /&gt;&lt;pre&gt;&lt;code&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-antrun-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;          &amp;lt;executions&amp;gt;&lt;br /&gt;              &amp;lt;execution&amp;gt;&lt;br /&gt;                  &amp;lt;id&amp;gt;ftp&amp;lt;/id&amp;gt;&lt;br /&gt;                  &amp;lt;phase&amp;gt;install&amp;lt;/phase&amp;gt;&lt;br /&gt;                  &amp;lt;goals&amp;gt;&lt;br /&gt;                      &amp;lt;goal&amp;gt;run&amp;lt;/goal&amp;gt;&lt;br /&gt;                  &amp;lt;/goals&amp;gt;&lt;br /&gt;                  &amp;lt;configuration&amp;gt;&lt;br /&gt;                      &amp;lt;tasks&amp;gt;&lt;br /&gt;                          &amp;lt;ftp server="localhost"&lt;br /&gt;                                  remotedir="/home/jlorenzen/ftptest"&lt;br /&gt;                                  userid="ftp"&lt;br /&gt;                                  password="ftp"&amp;gt;&lt;br /&gt;                              &amp;lt;fileset dir="/home/jlorenzen/Documents"/&amp;gt;&lt;br /&gt;                          &amp;lt;/ftp&amp;gt;&lt;br /&gt;                      &amp;lt;/tasks&amp;gt;&lt;br /&gt;                  &amp;lt;/configuration&amp;gt;&lt;br /&gt;              &amp;lt;/execution&amp;gt;&lt;br /&gt;          &amp;lt;/executions&amp;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;ant&amp;lt;/groupId&amp;gt;&lt;br /&gt;                  &amp;lt;artifactId&amp;gt;ant-commons-net&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                  &amp;lt;version&amp;gt;1.6.5&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;commons-net&amp;lt;/groupId&amp;gt;&lt;br /&gt;                  &amp;lt;artifactId&amp;gt;commons-net&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                  &amp;lt;version&amp;gt;1.4.1&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;/plugin&amp;gt;&lt;br /&gt;  &amp;lt;/plugins&amp;gt;&lt;br /&gt;&amp;lt;/build&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7880863204281116061?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7880863204281116061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7880863204281116061' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7880863204281116061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7880863204281116061'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/06/how-to-ftp-artifacts-in-maven2.html' title='How to FTP artifacts in maven2'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1896957855182668227</id><published>2008-05-18T23:26:00.003-05:00</published><updated>2008-05-18T23:41:09.064-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><title type='text'>Accessing Hudson Variables with a Free-Style Project</title><content type='html'>&lt;a href="http://weblogs.java.net/blog/johnsmart/archive/2008/03/using_hudson_en.html"&gt;Here&lt;/a&gt; is a great article on creating a manifest file containing hudson variables so that you can know exactly what build number and svn number built your artifact. However, in my case I wanted to create a properties file under my maven2 project under &lt;span style="font-style: italic;"&gt;src/main/resources&lt;/span&gt; and let maven filtering take care of the rest. But for some reason it wouldn't work. After some further research, I eventually found out that free-style projects appear to not work the same as a maven2 project in hudson when trying to access hudson variables.&lt;br /&gt;&lt;br /&gt;In summary, hudson variables work as expected when you create a maven2 project in hudson. With a free-style project you have to perform an extra step. Why, I don't know; I am sure there is a good reason. It's just too late to figure it out.&lt;br /&gt;&lt;br /&gt;Here are the extra steps you can follow to create a properties file containing hudson values.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update POM&lt;/span&gt;&lt;br /&gt;In your projects POM or parent POM add the following properties at the bottom&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;project&amp;gt;&lt;br /&gt; ....&lt;br /&gt; &amp;lt;properties&amp;gt;&lt;br /&gt;     &amp;lt;build.number&amp;gt;${BUILD_NUMBER}&amp;lt;/build.number&amp;gt;&lt;br /&gt;     &amp;lt;build.id&amp;gt;${BUILD_ID}&amp;lt;/build.id&amp;gt;&lt;br /&gt;     &amp;lt;job.name&amp;gt;${JOB_NAME}&amp;lt;/job.name&amp;gt;&lt;br /&gt;     &amp;lt;build.tag&amp;gt;${BUILD_TAG}&amp;lt;/build.tag&amp;gt;&lt;br /&gt;     &amp;lt;executor.number&amp;gt;${EXECUTOR_NUMBER}&amp;lt;/executor.number&amp;gt;&lt;br /&gt;     &amp;lt;workspace&amp;gt;${WORKSPACE}&amp;lt;/workspace&amp;gt;&lt;br /&gt;     &amp;lt;hudson.url&amp;gt;${HUDSON_URL}&amp;lt;/hudson.url&amp;gt;&lt;br /&gt;     &amp;lt;svn.revision&amp;gt;${SVN_REVISION}&amp;lt;/svn.revision&amp;gt;&lt;br /&gt; &amp;lt;/properties&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Create a properties file&lt;/span&gt;&lt;br /&gt;Create a application.properties file under your maven2 projects &lt;span style="font-style: italic;"&gt;src/main/resources&lt;/span&gt; directory.&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now add this to it&lt;br /&gt;&lt;br /&gt;build.number=${build.number}&lt;br /&gt;build.id=${build.id}&lt;br /&gt;job.name=${job.name}&lt;br /&gt;build.tag=${build.tag}&lt;br /&gt;executor.number=${executor.number}&lt;br /&gt;workspace=${workspace}&lt;br /&gt;hudson.url=${hudson.url}&lt;br /&gt;svn.revision=${svn.revision}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1896957855182668227?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1896957855182668227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1896957855182668227' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1896957855182668227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1896957855182668227'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/05/accessing-hudson-variables-with-free.html' title='Accessing Hudson Variables with a Free-Style Project'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1274695016933458505</id><published>2008-05-17T01:06:00.002-05:00</published><updated>2008-05-17T01:29:49.226-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy Sort List</title><content type='html'>I am posting a simple example on how to sort a list in groovy because the examples &lt;a href="http://www.google.com/search?q=groovy+list+sort&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;aq=t&amp;amp;rls=com.ubuntu:en-US:official&amp;amp;client=firefox-a"&gt;google&lt;/a&gt; knows about aren't what I was looking for. With some deep digging I was able to find a clue that eventually solved my problem.&lt;br /&gt;&lt;br /&gt;It's real easy to sort a list of numbers&lt;br /&gt;&lt;br /&gt;assert [1,2,3,4] == [3,4,2,1].sort()&lt;br /&gt;&lt;br /&gt;Or even strings&lt;br /&gt;&lt;br /&gt;assert ['Chad','James','Travis'] == ['James','Travis','Chad'].sort()&lt;br /&gt;&lt;br /&gt;But this was my example&lt;br /&gt;&lt;pre&gt;class Person {&lt;br /&gt;  String id&lt;br /&gt;  String name&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;def list = [new Person(id: '1', name: 'James'),new Person(id: '2', name: 'Travis'), new Person(id: '3', name: 'Chad')]&lt;br /&gt;&lt;br /&gt;list.sort() returns James, Travis, Chad&lt;br /&gt;&lt;br /&gt;The solution is ridiculously simple (not that I thought the previous sort would work; I have to be realistic; groovy can't do everything for me).&lt;br /&gt;&lt;br /&gt;list.sort{it.name} will produce an order of Chad, James, Travis.&lt;br /&gt;&lt;br /&gt;In the previous example note the use of the sort closure sort {} verses the sort() method.&lt;br /&gt;&lt;br /&gt;Now I am not sure, off the top of my head and without a Groovy book handy, the simplest way to sort case insensitive.&lt;br /&gt;&lt;br /&gt;assert ['a1','A1'] == ['A1,'a1'].sort{fancy closure}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1274695016933458505?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1274695016933458505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1274695016933458505' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1274695016933458505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1274695016933458505'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/05/groovy-sort-list.html' title='Groovy Sort List'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7081886425081388444</id><published>2008-05-10T00:19:00.004-05:00</published><updated>2008-05-10T09:48:08.816-05:00</updated><title type='text'>Finally OpenSolaris Installed</title><content type='html'>Finally, after 4 attempts, I got a half way decent install of Solaris. My previous attempts included installing Solaris Express Developer Edition on VMware Server 1.0.4 and VirtualBox 1.5. Both had major issues but I had the best luck with VMware Server, it just took like 15 minutes to boot and I couldn't install vmware tools. So at JavaOne 08 they announced &lt;a href="http://www.opensolaris.com/"&gt;http://www.opensolaris.com&lt;/a&gt; with the version 2008.05. So I thought I would give it a try and their install documentation seemed very thorough (see &lt;a href="http://dlc.sun.com/osol/docs/content/IPS/virtualbox.html"&gt;how to install on virtualbox&lt;/a&gt;). Unfortunately, installing this in virtualbox did not work (would't boot) and so I decided to give it one more shot on VMware Server and I guess I got lucky because it actually worked to my surprise. And it actually boots rather fast compared to my previous experience with solaris.&lt;br /&gt;&lt;br /&gt;Since it uses GNOME it reminded me a lot of my ubuntu system. I was even able to successfully install vmware-tools which I got really excited about because I would have bet against this previously. Compiz is installed by default but I was unable to change the settings yet (it kept rebooting for some reason). Maybe it's because I haven't enable the nvida drivers yet; which was also a surprise that the nvida drivers where already installed.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opensolaris.com/learn/faq/index.html#25"&gt;Here&lt;/a&gt; are some features compared to Linux. I am not a file system guru but &lt;a href="http://opensolaris.org/os/community/zfs/whatis/"&gt;ZFS&lt;/a&gt; sounds interesting.&lt;br /&gt;&lt;br /&gt;Anyways so far so good. I do miss sudo. I am now able to start working efficiently on &lt;a href="http://jlorenzen.blogspot.com/2008/02/volunteering-as-hudson-opensolaris-ips.html"&gt;providing hudson&lt;/a&gt; as a package in solaris. I am assuming that once I get done the below search will actually return a result (me &lt;-- crossing my fingers).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_u6FjI-f0VoU/SCW1guIn8LI/AAAAAAAAAFI/cCglwSoR_gQ/s1600-h/hudson-os.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_u6FjI-f0VoU/SCW1guIn8LI/AAAAAAAAAFI/cCglwSoR_gQ/s400/hudson-os.jpg" alt="" id="BLOGGER_PHOTO_ID_5198760918613749938" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7081886425081388444?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7081886425081388444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7081886425081388444' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7081886425081388444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7081886425081388444'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/05/finally-opensolaris-installed.html' title='Finally OpenSolaris Installed'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_u6FjI-f0VoU/SCW1guIn8LI/AAAAAAAAAFI/cCglwSoR_gQ/s72-c/hudson-os.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-2783749565244041107</id><published>2008-05-08T11:33:00.004-05:00</published><updated>2008-05-08T12:43:41.155-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Why again am I not using JDK 1.6?</title><content type='html'>Why in the world am I still using jdk 1.5? It's almost 4 years &lt;a href="http://www.zefhemel.com/archives/2004/09/30/java-5-released"&gt;old&lt;/a&gt;. Yesterday it just kind of hit me and I said to myself, "James, why not start using jdk 1.6 or java 6?". Is there anything technically preventing jdk 1.5 users from using jdk 1.6? Back in the day, weblogic 6.1 only worked with jdk 1.3 and when I wanted to start using jdk 1.4 it just wouldn't work. So for some reason I still had that same mindset.&lt;br /&gt;&lt;br /&gt;So I started to do a little research and what I found was pleasantly surprising and I immediately downloaded the latest version of java 6 and started using it (verdict still out on that but so far so good). JBoss 4.2.1 seems to start just fine with java 6.&lt;br /&gt;&lt;br /&gt;So what exactly did I find? First, straight from the java 6 &lt;a href="http://java.sun.com/javase/6/"&gt;home page&lt;/a&gt; is the answer to the question&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;b style="font-style: italic;"&gt;Q:&lt;/b&gt;&lt;span style="font-style: italic;"&gt; How is Java SE 6 different from the previous version (J2SE 5.0): what are the improved and updated areas, such as functionality, security, performance?&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;...the release delivers dramatic out-of-the-box benefits without any coding changes or even a re-compile necessary. Simply running existing Java applications on this latest release is all that is needed.&lt;/i&gt;&lt;/blockquote&gt;Now my interests are peaked. So how come I haven't heard this yet. Perhaps I was just content being able to upgrade from 1.4 to 1.5.&lt;br /&gt;&lt;br /&gt;I think this &lt;a href="http://www.javalobby.org/java/forums/t86031.html"&gt;article&lt;/a&gt; by Rick Ross on javalobby has some great points. Here are the ones that interested me:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Java 6 incorporates over 300 bug fixes&lt;/li&gt;&lt;li&gt;Java 6 features general performance improvements while preserving compatibility with older versions&lt;/li&gt;&lt;li&gt;In many cases you may find that your applications run as fast or faster under Java 6 as they would if you spent significant effort tuning heap, thread and garbage collection parameters under Java 5.&lt;/li&gt;&lt;/ul&gt;That last point hits me right at home since we recently went through "significant effort tuning heap, thread, and gc params."&lt;br /&gt;&lt;br /&gt;So what about performance? This &lt;a href="http://blogs.sun.com/dagastine/entry/java_6_leads_out_of"&gt;article&lt;/a&gt; is in an depth analysis of the performance improvements. The summary is it's faster.&lt;br /&gt;&lt;br /&gt;So like mentioned above I downloaded java 6 update 6. Jboss 4.2.1 started just fine. Today I plan on building our EAR using maven 2.0.9 and deploying it to see if there are any issues. See the official compatibility page &lt;a href="http://java.sun.com/javase/6/webnotes/compatibility.html"&gt;here&lt;/a&gt;. Specifically it states "Java SE 6 is upwards binary-compatible with J2SE 5.0 except for the &lt;a href="http://java.sun.com/javase/6/webnotes/compatibility.html#incompatibilities"&gt;incompatibilities&lt;/a&gt; listed below. Except for the noted incompatibilities, class files built with version 5.0 compilers will run correctly in JDK 6."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-2783749565244041107?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/2783749565244041107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=2783749565244041107' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2783749565244041107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2783749565244041107'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/05/why-again-am-i-not-using-jdk-16.html' title='Why again am I not using JDK 1.6?'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6189813749896501991</id><published>2008-05-01T22:00:00.003-05:00</published><updated>2008-05-01T22:18:26.109-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Pimp my Linux: Maven2 Bash Completion</title><content type='html'>Inspired by &lt;a href="http://kasparov.skife.org/blog/stuff/starting-a-meme.html"&gt;this&lt;/a&gt; bash completion for ssh, I wanted to see what it would take to do something similar for maven2. Thanks to google it's already been &lt;a href="http://maven.apache.org/guides/mini/guide-bash-m2-completion.html"&gt;done&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's not perfect, but it's a start. For example, the choices are hard coded in the script. And when I tab after typing &lt;span style="font-style: italic;"&gt;mvn assem&lt;/span&gt; it outputs &lt;span style="font-style: italic;"&gt;mvn assembly\:assembly&lt;/span&gt;. Shouldn't be too hard to find that extra slash.&lt;br /&gt;&lt;br /&gt;Here are some thoughts on how one could improve it. First, maybe it could be improved for at least the core plugins by searching the local repo in /m2/repository/org/apache/maven/plugins. Or searching the local repo for any pom that contains a packing value of maven-plugin (&lt;packaging&gt;maven-plugin&lt;/packaging&gt;). Combine that with the &lt;a href="http://maven.apache.org/plugins/maven-help-plugin/index.html"&gt;help plugin&lt;/a&gt; to get the possible goals and all their parameters and one could probably create a pretty slick and useful bash completion for maven2.&lt;br /&gt;&lt;br /&gt;For example, you can get everything you need for any plugin if you know the groupId and artifactid by running this:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;mvn help:describe -DgroupId=org.apache.maven.plugins -DartifactId=maven-war-plugin -Dfull=true&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;I say all this, but I use a lot of alias's for my maven commands. Here are a few of my favorites:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;alias mci='mvn clean install'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;alias build='mvn clean install -Dmaven.test.skip=true -Dpmd.skip=true -Dcheckstyle.skip=true'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-6189813749896501991?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/6189813749896501991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=6189813749896501991' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6189813749896501991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6189813749896501991'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/05/pimp-my-linux-maven2-bash-completion.html' title='Pimp my Linux: Maven2 Bash Completion'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8353377486521345869</id><published>2008-05-01T12:40:00.006-05:00</published><updated>2008-05-02T08:34:05.381-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Using Maven War Overlays to extend Hudson</title><content type='html'>I just recently found out about one of the neatest features of the &lt;a href="http://maven.apache.org/plugins/maven-war-plugin/index.html"&gt;maven-war-plugin&lt;/a&gt; called &lt;a href="http://maven.apache.org/plugins/maven-war-plugin/overlays.html"&gt;WAR Overlays&lt;/a&gt;. Basically it provides a very simple way to merge multiple WARs together to create an Uber WAR. You simply add a WAR as a dependency in your POM verses adding a JAR, and the maven-war-plugin will take care of the rest. My team uses this ability to extend the &lt;a href="http://www.jspwiki.org/"&gt;JSPWiki&lt;/a&gt; WAR to add in our wiki pages. The result is an Uber WAR including the JSPWiki stuff and our wiki pages. Then when a new JSPWiki WAR is available we just update the dependency version in our POM.&lt;br /&gt;&lt;br /&gt;So for an example, I am going to demonstrate extending my favorite CI tool &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt; since it's freaking awesome and is downloaded as a WAR. Don't try this at home since hudson already provides the &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/Extend+Hudson"&gt;ability&lt;/a&gt; to extend it using plugins (which also rocks by the way).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Create a Simple WAR Project&lt;/span&gt;&lt;br /&gt;First, create a war project using &lt;a href="http://maven.apache.org/plugins/maven-archetype-plugin/"&gt;maven-archetypes&lt;/a&gt;. Execute &lt;span style="font-style: italic;"&gt;mvn archetype:generate&lt;/span&gt; and select #18. Run &lt;span style="font-style: italic;"&gt;mvn clean install&lt;/span&gt; to ensure it builds correctly (I am using maven v2.0.9).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Install hudson into local repository&lt;/span&gt;&lt;br /&gt;Next we need to be able to consume the hudson war in our pom and since I am unware of the hudson war being available on any external repository we are going to just install it manually into our local m2 repository.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://hudson.dev.java.net/servlets/ProjectDocumentList?folderID=2761&amp;amp;expandFolder=2761&amp;amp;folderID=0"&gt;Download&lt;/a&gt; the latest hudson war&lt;/li&gt;&lt;li&gt;Install hudson.war into your local repository using the mvn install plugin by running: &lt;span style="font-style: italic;"&gt;mvn install:install-file -Dfile=hudson.war -DgroupId=hudson -DartifactId=hudson -Dversion=1.0 -Dpackaging=war&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Consume the hudson.war in your pom&lt;/span&gt;&lt;br /&gt;Open up your war's parent pom and add the hudson war as a dependency.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;hudson&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;hudson&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;&lt;br /&gt;  &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Next, since we want to run hudson in embedded mode without a container we need to add to the generated manifest file the Main class since I am too lazy to figure out how to include the original hudson manifest file (even though I am sure its possible). Include the following in your build section:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;build&amp;gt;&lt;br /&gt;&amp;lt;finalName&amp;gt;mywar&amp;lt;/finalName&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-war-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;configuration&amp;gt;&lt;br /&gt;    &amp;lt;archive&amp;gt;&lt;br /&gt;      &amp;lt;manifestEntries&amp;gt;&lt;br /&gt;        &amp;lt;Main-Class&amp;gt;Main&amp;lt;/Main-Class&amp;gt;&lt;br /&gt;      &amp;lt;/manifestEntries&amp;gt;&lt;br /&gt;    &amp;lt;/archive&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;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Build and Run it&lt;/span&gt;&lt;br /&gt;Now build the war again: &lt;span style="font-style: italic;"&gt;mvn clean install&lt;/span&gt;. And your WAR should be merged with the hudson war. In fact for verification, your simple war contained an index.jsp under src/main/webapp and if you extract the war under target you will see your index.jsp.&lt;br /&gt;&lt;br /&gt;Run: &lt;span style="font-style: italic;"&gt;java -jar target/mywar.war&lt;/span&gt;&lt;br /&gt;and go to: http://localhost:8080/index.jsp&lt;br /&gt;&lt;br /&gt;If you are doing this on a serious level, you might want to look into the &lt;a href="http://cargo.codehaus.org/Merging+WAR+files"&gt;maven-cargo-plugins&lt;/a&gt; ability to create Uber wars.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8353377486521345869?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8353377486521345869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8353377486521345869' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8353377486521345869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8353377486521345869'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/05/using-maven-war-overlays-to-extend.html' title='Using Maven War Overlays to extend Hudson'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1943779969486684728</id><published>2008-04-18T15:33:00.004-05:00</published><updated>2008-04-18T16:14:15.123-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jbi'/><title type='text'>Reply: JBI Misses the Mark by Ross Mason</title><content type='html'>I would like to reply to Ross Mason's article titled &lt;a href="http://rossmason.blogspot.com/2008/04/jbi-misses-mark.html"&gt;&lt;span style="font-style: italic;"&gt;JBI Misses the Mark&lt;/span&gt;&lt;/a&gt;. It was too hard to include this in a comment, so I decided to post my reply here.&lt;br /&gt;&lt;br /&gt;Ross,&lt;br /&gt;As a JBI Component Developer and user of ServiceMix and OpenESB I am going to try my best to give some answers to your points with the goal of discussion and not persuasion. I am not a "die-hard" fan trying to push JBI adoption. So hopefully I will come off as unbiased and honest as possible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"It’s been a few years since I read the JBI specification, but here goes."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As evidence by the different ways JBI was implemented by Apache and Sun, just reading the spec alone I think is not sufficient to disregard JBI. For example, I remember when I first read the spec and looked at ServiceMix, I was totally confused. I was asking myself, where are all the WSDLs? Most of the comments I have read from JBI opponents have usually just read the spec or heard from co-workers and have actually never used or seen JBI used. Now I am not saying this person is you Ross; you have obviously done your homework. I believe the biggest failure of JBI has been communicating clearly what JBI is and how to use it. It took me many months until I felt like I actually "understood" JBI. And before that moment happened I thought I knew what JBI was only to find out something new and that I never actually did.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"Adaptive Integration"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Unless I misunderstood it, your definition of Adaptive Integration fits well with my experience with JBI. Using JBI I can build "best-of-breed" integration solutions using any number of the JBI components available with ServiceMix (SM) or OpenESB (OESB). If I need to integrate with JDBC I can do that; or RSS, XMPP, SIP, Corba, and CICS. Perhaps my lack of knowledge of Mule capabilities is making me naive here, but to me I can use JBI to bridge multiple systems together.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"JBI attempts to standardize the container that hosts services, the binding between services, the interactions between services, and how services and bindings are loaded. The problem occurs when the APIs around all these things makes assumptions about how data is passed around, how a service will expose its interface contract and how people will write services."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In a nutshell the only thing I think JBI standardizes on is the interactions between components or put another way the format of a message that goes over the NMR. Beyond that its up to the component developers to do what they wish. For example, with the RSS BC, there are no assumptions that need to be made about incoming requests from the NMR; it's a standard JBI message. Doesn't matter if it came from a SIP, HTTP, Corba. To me that is the beauty of JBI. Once I create my JBI layer in my component anybody in the container can call me.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"Xml messages will be used for moving data around"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As stated above, JBI doesn't say if your legacy system doesn't know XML, then you can't use JBI. The exact opposite is true. To me this is the perfect fit for JBI and Binding Components. My definition of a Binding Component is a translator. It's sole job is to translate protocol X to JBI and translate JBI to protocol X. Perhaps what you are suggesting is that some message types don't "convert" easily to XML since that is what essentially messages over the NMR are. So in your example, a Cobol CopyBook message can't be or shouldn't be attempted to be converted to XML. Not sure I would agree since I would think, given a schema, anything could be represented in predictable XML.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"Data Transformation is always XML-based"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Since everything is converted to XML to be passed over the NMR, the only transformation needed for that is XML. So what you is true, but to a JBI user I guess it doesn't matter. I guess on the other side, if the NMR allowed for other message types, then yes I guess you would need more transformers, but I guess with JBI the transformers are the Binding Components.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"Service contracts will be WSDL"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is a very true statement and I am not exactly a WSDL/XML lover; unless I don't have to deal with it. I think the original intent was there would be a lot of tooling support for JBI to alleviate that burden from the JBI user. To me Sun has done a better job of this than SM, but this is definitely a drawback to JBI. However SM has all but eliminated WSDL's in JBI so users of SM don't need tooling support since they don't actually require WSDLs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"No need for message streaming"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another very true statement of there not being an "easy way to stream messages in JBI". With XML being so verbose I believe SM or OESB would probably dislike a 3 MB XML file getting pumped through it. Especially if that gets copied over and over again from one component to the next. This is where JBI might have difficulties scaling. As a colleague pointed out, the content of a JBI message is XML. And that XML has to be marshalled and unmarshalled. And that process is very heavy and even more so if there are reliability/durability constraints on the Message.&lt;br /&gt;&lt;br /&gt;However, I think its a current tradeoff in order for all components on the NMR to communicate in a predictable fashion. Since that is the main concept of JBI: the ability for all the JBI components communicate. They have to communicate some how. One component can't decide that he expects format A and another decides he requires format B. Then nothing would work. So it sounds like to me XML was that language to guarantee interoperability between components.&lt;br /&gt;&lt;br /&gt;On a side note, JBI components have the ability to set the content of a JBI message that goes on the NMR as anything implementing the interface  &lt;code&gt;javax.xml.transform.Source&lt;/code&gt;. Meaning that they can use streaming XML with the SAX and Streaming implementations. However, once consumed, that stream is gone and is probably represented as DOM (ouch) somewhere in the process. Our components use the Streaming impl when creating JBI Messages, but that doesn't mean the others do.&lt;br /&gt;&lt;br /&gt;Either way, I have to think that smart people like Peter Walker, yourself, and other spec leaders can't come up with something to resolve this and get the best of both worlds.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"You need to implement a pretty heavy API to implement a service"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I disagree that JBI users have to know more about JBI than is necessary, but then again its hard for me to play that person since I am also a component developer. But most of the people that I have taught how to use JBI have been successful in using it without having to know as much as me. I know in SM you can expose a POJO pretty easily. In OESB you can use the Scripting Engine or create an EJB Service to be used in JBI. From what it sounds like though, its much easier with Mule.&lt;br /&gt;&lt;br /&gt;Again I have not had a hard time teaching non JBI users about JBI. However I skip the spec and jump straight to a demonstration of how you can use JBI. This seems to help. I remember the first video I watched when the light bulb finally went off. It was a video on how to use the Sun SMTP BC and creating a Service Assembly with Netbeans. After I watched that video everything just came together for me and my co-workers. This is basically how I start off explaining JBI: It's best explained with an example rather than a bulleted powerpoint.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"It’s not actually that clear what a service engine is in JBI."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Touche. I hear this a lot, even from me. Again, as I stated earlier, the JBI community has done a poor job of training and communicating to its users and developers. My first definition of a Service Engine was basically a Service. I still don't have a good definition of an SE; usually I will just talk about what existing SEs are out there like the BPEL and XSLT SE. To me Binding Components are easy to define so an SE is just everything else (granted not exactly the best definition).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"The JBI specification is obfuscated with lots of new jargon"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Yes, yes, and yes. Again poor job of communicating. However, the JBI user should not be concerned with most of this jargon; only the JBI developer. For example, the JBI user shouldn't need to know about what the NMR is or what it does; but it's important for JBI developers to know.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"This breaks the re-use story since, if I use a JBI Binding Component in one container doesn’t mean it will behave the same way in another container."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ideally JBI was suppose to be this loving community of predictable containers and components. Unfortunately that hasn't exactly happened. I will say this though, from my personal experience of using different components on different containers, for the most part most components and Service Assemblies work in a predictable way on other containers. For example, I have successfully used many SM components in OESB and and I have heard of Sun components working in  SM. However the failure is you can't intermix Sun and SM components (or at least from what I know). For example, you can't use the SM HTTP BC with the Sun BPEL SE. To me this wasn't a failure of JBI; only how the JBI container was implemented. In a perfect world this would have happened but it hasn't.&lt;br /&gt;&lt;br /&gt;Ironically it actually doesn't take that much to get your components to work on both SM and OESB. Of the four components we have written (RSS, SIP, XMPP, and UDDI), XMPP has been modified to work on both. We haven't had a chance to ensure the other 3 can, but hopefully we can get to that or the open source community could help. At the time of development we didn't actually understand JBI that well and consequently when we had our components originally working in SM and tried to port them over to OESB, they worked but only with other SM components. In order for our components to work with Sun components we had to basically rewrite the JBI layer. Unfortunately, due to time constraints it was not our current goal to keep backwards compatibility with SM. It wasn't until after we finished all this that we actually understood JBI and what it meant to create a portable component.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"If you look at every JBI implementation each has written their own JMS, FILE, HTTP, FTP etc Binding components… not exactly what I’d call re-use."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You are exactly right. Each container has implemented their own components for File, JMS, HTTP. Most likely because of the issues I mentioned above. However I don't think this doesn't mean JBI can get there. If these projects wanted to make them portable than we wouldn't have this problem. Instead they focus their efforts on other things.&lt;br /&gt;&lt;br /&gt;As a side note, since my group was using OESB, when I joined a new group, we needed to get OESB working on JBoss. This currently was not supported and my previous group was able to work with Sun to get this working and its currently being incorporated in OESB.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Summary&lt;/span&gt;&lt;br /&gt;IMHO I think a lot of assumptions where made about JBI, but you also addressed some of the issues with JBI. One reason I think JBI has not been adopted is the fact that it didn't have the backing early on of IBM and Bea. From what I recall they dropped out pretty early once they realized it was going to be a competing product. Another reason for a lack of adoption is I think again the lack of communicating what JBI really is.&lt;br /&gt;&lt;br /&gt;I hope I didn't reiterate responses you have heard in the past. I wasn't around when JBI was originally approved, so I don't know a lot of the history. These are just my opinions I have collected through developing components and using SM and OESB.&lt;br /&gt;&lt;br /&gt;I hope it helps and I look forward to your response.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1943779969486684728?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1943779969486684728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1943779969486684728' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1943779969486684728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1943779969486684728'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/reply-jbi-misses-mark-by-ross-mason.html' title='Reply: JBI Misses the Mark by Ross Mason'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4698122993983026193</id><published>2008-04-16T09:23:00.002-05:00</published><updated>2008-04-16T09:25:38.964-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Sharing your folders in Ubuntu</title><content type='html'>Today I needed the ability to modify files on my Linux host machine from my Windows VM instance running in VMWare Server. This was actually pretty easy and once I found this &lt;a href="http://www.simplehelp.net/2007/05/19/how-to-share-files-and-folders-in-ubuntu/"&gt;article&lt;/a&gt; I was able to get it working in about 5 minutes.&lt;br /&gt;&lt;br /&gt;Enjoy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4698122993983026193?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4698122993983026193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4698122993983026193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4698122993983026193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4698122993983026193'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/sharing-your-folders-in-ubuntu.html' title='Sharing your folders in Ubuntu'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-663835928513129487</id><published>2008-04-15T23:28:00.002-05:00</published><updated>2008-04-15T23:36:13.190-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Using Grails and Glassfishv3</title><content type='html'>In case you missed it, an important feature is being worked on in order to support direct deployment of a Grails application in Glassfish v3 (see &lt;a href="http://groovy.dzone.com/news/getting-started-grails-glassfi"&gt;Getting Started with Grails on Glassfish&lt;/a&gt;). According to Mr. Gupta, they are working towards being able to deploy a Grails app to GFv3 using the grails commands (currently Grails uses Jetty). Also they are working on deploying a Grails App for production purposes without having to create a WAR; which is the current method. Both of which will definitely improve developer productivity when using Grails and GFv3.&lt;br /&gt;&lt;br /&gt;And since it was recently &lt;a href="http://blogs.sun.com/theaquarium/entry/glassfish_v3_now_with_osgi"&gt;announced&lt;/a&gt; that GFv3 can run on OSGi, I think GFv3 continues to look very interesting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-663835928513129487?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/663835928513129487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=663835928513129487' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/663835928513129487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/663835928513129487'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/using-grails-and-glassfishv3.html' title='Using Grails and Glassfishv3'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-334685206700947608</id><published>2008-04-10T16:45:00.002-05:00</published><updated>2008-04-10T16:56:12.137-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Update: Always specify a version for Maven2 plugins</title><content type='html'>I previously &lt;a href="http://jlorenzen.blogspot.com/2008/03/always-specify-version-for-maven2.html"&gt;wrote&lt;/a&gt; about specifying a release version for maven plugins in your POM files to have a more stable build and stop depending on SNAPSHOT plugin dependencies. It now seems with the latest version of maven2, version 2.0.9, that maven now comes with release versions for all the commons plugins (see the &lt;a href="http://maven.apache.org/release-notes.html"&gt;release notes&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;MNG-3395 - Starting in 2.0.9, we have provided defaults in the super pom for the plugins bound by default to the lifecycle and a few other often used plugins. This will introduce a bit of stability to your builds because core plugins will not change magically on you when they are released. We still recommend taking control of your plugin versions via pluginManagement declarations as this is the most robust way to future proof your builds. Defaulting the plugins in the superpom was a step towards introducing stability for small builds and new users. A full table of the versions used is shown in the next section.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Note how they still recommend specifying release versions in the pluginManagement section of your POM.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-334685206700947608?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/334685206700947608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=334685206700947608' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/334685206700947608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/334685206700947608'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/update-always-specify-version-for.html' title='Update: Always specify a version for Maven2 plugins'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6012294211522284181</id><published>2008-04-10T15:17:00.008-05:00</published><updated>2008-04-10T15:59:57.274-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javaee'/><category scheme='http://www.blogger.com/atom/ns#' term='ejb3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='jbi'/><category scheme='http://www.blogger.com/atom/ns#' term='webservices'/><title type='text'>Update: Using the JBI JavaEE Service Engine</title><content type='html'>Previously I &lt;a href="http://jlorenzen.blogspot.com/2007/08/using-jbi-javaee-serviceengine.html"&gt;wrote&lt;/a&gt; about how to use the JBI JavaEE Service Engine to increase performance when orchestrating EJB Services created in Glassfish with the BPEL Service Engine in OpenESB. That was almost 8 months ago and Netbeans and OpenESB have changed a lot and consequently I needed to update it.&lt;br /&gt;&lt;br /&gt;So I would like to provide an update using the latest Netbeans (20080402).&lt;br /&gt;&lt;br /&gt;Again, if you haven't already, go ahead and &lt;a href="https://open-esb.dev.java.net/Downloads_OpenESB_Addons_NB6.html"&gt;download&lt;/a&gt; and install OpenESB which includes Netbeans v6 and Glassfish v2.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Create an EJB Module&lt;/li&gt;&lt;ul&gt;&lt;li&gt;File &gt; New Project &gt; &lt;span style="font-style: italic;"&gt;Category&lt;/span&gt; Enterprise &gt; &lt;span style="font-style: italic;"&gt;Projects &lt;/span&gt;EJB Module&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Create a new Web Service&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Right click on your EJB Module project&lt;/li&gt;&lt;li&gt;Choose New &gt; Web Service&lt;/li&gt;&lt;li&gt;Add a new Operation&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Create a new BPEL Module&lt;/li&gt;&lt;ul&gt;&lt;li&gt;File &gt; New Project &gt; &lt;span style="font-style: italic;"&gt;Category&lt;/span&gt; SOA &gt; &lt;span style="font-style: italic;"&gt;Projects &lt;/span&gt;BPEL Module&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Create a new BPEL Process&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Right click on your BPEL Module project&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Choose New &gt; BPEL Process&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Create a new SOAP WSDL&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Right click on your BPEL Module project&lt;/li&gt;&lt;li&gt;Choose New &gt; WSDL Document&lt;/li&gt;&lt;li&gt;Go through the wizard and for the Binding Type make sure its SOAP&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Configure your BPEL Process by dragging the SOAP WSDL onto the left side of the BPEL Process.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Add the standard "buttons" to the BPEL Process Sequence&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Receive&lt;/li&gt;&lt;li&gt;Assign&lt;/li&gt;&lt;li&gt;Invoke&lt;/li&gt;&lt;li&gt;Assign&lt;/li&gt;&lt;li&gt;Reply&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;Utilize the EJB Web Service in the BPEL Process (this is where things are different than in past versions)&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_u6FjI-f0VoU/R_58NOpGQqI/AAAAAAAAAEg/ALXwRkl4b6Q/s1600-h/javaeese.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/R_58NOpGQqI/AAAAAAAAAEg/ALXwRkl4b6Q/s200/javaeese.png" alt="" id="BLOGGER_PHOTO_ID_5187720387488006818" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Right click on the Web Service under the EJB Module and select Generate and Copy WSDL&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Uncheck &lt;span style="font-style: italic;"&gt;Do no copy&lt;/span&gt; if it is checked.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Expand your BPEL Module and copy the WSDL into the BPEL Module's &lt;span style="font-style: italic;"&gt;src&lt;/span&gt; directory.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Now you should have a copy of the Web Service's WSDL in your BPEL Module.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Drag this new WSDL onto the right side of the BPEL Process so that we can tie the Invoke call to it.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Create a Composite Application&lt;/li&gt;&lt;ul&gt;&lt;li&gt;File &gt; New Project &gt; &lt;span style="font-style: italic;"&gt;Category&lt;/span&gt; SOA &gt; &lt;span style="font-style: italic;"&gt;Projects &lt;/span&gt;&lt;span&gt;Composite Application&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Right click on the new Composite Application and select Add JBI Module&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Add both your BPEL Module and EJB Module&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Clean and build the Composite Application (Right click &gt; Clean and Build)&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_u6FjI-f0VoU/R_599OpGQrI/AAAAAAAAAEo/sXMKnFbotTk/s1600-h/javaeese1.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/R_599OpGQrI/AAAAAAAAAEo/sXMKnFbotTk/s200/javaeese1.png" alt="" id="BLOGGER_PHOTO_ID_5187722311633355442" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;View your CASA file by double clicki&lt;/span&gt;&lt;span&gt;ng on the Service Assembly file&lt;/span&gt;&lt;span&gt; under your Composite Application.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span&gt;Your CASA file should look something like this&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_u6FjI-f0VoU/R_5-r-pGQtI/AAAAAAAAAE4/RL8Bt4jksTo/s1600-h/javaeese2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_u6FjI-f0VoU/R_5-r-pGQtI/AAAAAAAAAE4/RL8Bt4jksTo/s320/javaeese2.png" alt="" id="BLOGGER_PHOTO_ID_5187723114792239826" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Now you should be able to start Glassfish and deploy your Composite Application. Now your BPEL Process will utilize the Java EE Service Engine. FYI, do not deploy the EJB Module separately since its included in the Composite Application.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-6012294211522284181?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/6012294211522284181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=6012294211522284181' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6012294211522284181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6012294211522284181'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/update-using-jbi-javaee-service-engine.html' title='Update: Using the JBI JavaEE Service Engine'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_u6FjI-f0VoU/R_58NOpGQqI/AAAAAAAAAEg/ALXwRkl4b6Q/s72-c/javaeese.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7223764490761079236</id><published>2008-04-09T00:12:00.004-05:00</published><updated>2008-04-09T00:19:01.469-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='netbeans'/><title type='text'>Another Netbeans 6 tip</title><content type='html'>I previously &lt;a href="http://jlorenzen.blogspot.com/2008/03/avoid-installing-2-versions-of-netbeans.html-netbeans.html"&gt;wrote&lt;/a&gt; about not installing multiple versions of Netbeans 6 and now I would like to include another tip.&lt;br /&gt;&lt;br /&gt;When installing a new version of Netbeans 6, while uninstalling your previous version make sure you remove the .netbeans directories. Otherwise the support for creating Tests in Composite Applications doesn't work.&lt;br /&gt;&lt;br /&gt;In fact just delete the following before each new install and you will have better luck:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;rm $USER_HOME/.asadminpass&lt;/li&gt;&lt;li&gt;rm $USER_HOME/.asadmintruststore&lt;/li&gt;&lt;li&gt;rm -rf $USER_HOME/.openesbinstaller_[machine_name]&lt;br /&gt;&lt;/li&gt;&lt;li&gt;rm -rf $NETBEANS_HOME/.netbeans&lt;/li&gt;&lt;li&gt;rm -rf $NETBEANS_HOME/.netbeans-derby&lt;/li&gt;&lt;/ul&gt;Note this is on Linux using the most recent version 20080402. Not sure where the directories are placed or called on windows. Also I believe older versions of Netbeans 6 placed the .netbeans* directories under $USER_HOME, so you might check there as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7223764490761079236?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7223764490761079236/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7223764490761079236' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7223764490761079236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7223764490761079236'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/another-netbeans-6-tip.html' title='Another Netbeans 6 tip'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-6214613349805030893</id><published>2008-04-08T13:34:00.003-05:00</published><updated>2008-04-08T13:40:24.440-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='idea'/><title type='text'>IntelliJ Idea able to open Maven2 POMs directly</title><content type='html'>Not sure all my Idea co-workers are aware, but if they are its worth repeating. Now in Idea 7 (I am specifically using 7.0.3) you can quickly open your project in Idea by pointing it to your projects maven2 POM. It works pretty slick and now that saves me from having to run &lt;span style="font-style: italic;"&gt;mvn idea:idea&lt;/span&gt;. It also supports the ability to synch with the maven structure on startup in case you add new dependencies to your POM, you shouldn't have to perform any magic to get Idea to recognize them.&lt;br /&gt;&lt;br /&gt;Jeff Black &lt;a href="http://codebeneath.blogspot.com/2008/02/netbeans-60-maven-integration.html"&gt;reports&lt;/a&gt; the same ability with Netbeans 6. And &lt;a href="http://blogs.jetbrains.com/idea/2008/04/intellij-idea-703-maven-integration-improvements/"&gt;here&lt;/a&gt; is the original Idea post describing this new feature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-6214613349805030893?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/6214613349805030893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=6214613349805030893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6214613349805030893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/6214613349805030893'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/intellij-idea-able-to-open-maven2-poms.html' title='IntelliJ Idea able to open Maven2 POMs directly'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-9132598321084067544</id><published>2008-04-08T13:02:00.002-05:00</published><updated>2008-04-08T13:20:41.319-05:00</updated><title type='text'>Using WebEx to demo from your Linux machine</title><content type='html'>In my unending &lt;a href="http://jlorenzen.blogspot.com/2008/04/ubuntu-remote-desktop.html"&gt;quest&lt;/a&gt; to figure out how to efficiently do a demonstration from my Linux machine, I finally was fortunate enough to come across a solution. Today I did a demonstration for a friends company and they use &lt;a href="http://www.webex.com/"&gt;WebEx&lt;/a&gt;. Luckily enough for me I reluctantly tried it first on my Linux machine, but not expecting it to work, and it worked! I was able to do a demo from my Linux machine and it actually worked seamlessly.&lt;br /&gt;&lt;br /&gt;So if your company consists of different types of operating systems (windows and linux) and you need software that works on both for employees to share and view demonstrations then take a look at WebEx. It is not free so that is a bummer, but neither is Goto Meeting (which is what we currently use).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-9132598321084067544?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/9132598321084067544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=9132598321084067544' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/9132598321084067544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/9132598321084067544'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/using-webex-to-demo-from-your-linux.html' title='Using WebEx to demo from your Linux machine'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-385379053001945944</id><published>2008-04-04T12:35:00.001-05:00</published><updated>2008-04-04T12:37:12.354-05:00</updated><title type='text'>New simple Linux tip for terminal: CRTL+L</title><content type='html'>I just found this out (basically because I saw a coworker clear his terminal window with a keyboard shortcut on his Mac, as opposed to running the &lt;span style="font-style: italic;"&gt;clear&lt;/span&gt; command).&lt;br /&gt;&lt;br /&gt;If you want to clear your terminal screen hit: CTRL+L.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-385379053001945944?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/385379053001945944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=385379053001945944' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/385379053001945944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/385379053001945944'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/new-simple-linux-tip-for-terminal-crtll.html' title='New simple Linux tip for terminal: CRTL+L'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3222718124187100132</id><published>2008-04-04T09:21:00.002-05:00</published><updated>2008-04-04T09:25:24.481-05:00</updated><title type='text'>Ubuntu Remote Desktop</title><content type='html'>As an update to my premature &lt;a href="http://jlorenzen.blogspot.com/2008/04/using-yugma-to-demo-from-your-linux.html"&gt;post&lt;/a&gt; yesterday, I was able to finally use Ubuntu's &lt;a href="http://www.ubuntugeek.com/share-your-ubuntu-desktop-using-remote-desktop.html"&gt;Remote Desktop&lt;/a&gt; ability to share my desktop to a windows machine in order to perform a demonstration. VNC Server did not work and neither did No Machine (for me that is).&lt;br /&gt;&lt;br /&gt;Luckily someone mentioned Ubuntu's Remote Desktop and I was able to VNC from windows using RealVNC's VNC Viewer and presto. Now I will just join a session in Yugma, share out my windows desktop, which is displaying a VNC session into my linux laptop. Wew!&lt;br /&gt;&lt;br /&gt;I can't wait for the day when I can get a Mac or Yugma can share a linux desktop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3222718124187100132?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/3222718124187100132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=3222718124187100132' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3222718124187100132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3222718124187100132'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/ubuntu-remote-desktop.html' title='Ubuntu Remote Desktop'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7418645088795439956</id><published>2008-04-03T15:04:00.005-05:00</published><updated>2008-04-03T15:29:48.546-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='yugma'/><title type='text'>Using Yugma to demo from your Linux machine</title><content type='html'>Currently our company pays to use &lt;a href="http://www.gotomeeting.com/"&gt;Goto Meeting&lt;/a&gt; to coordinate meetings. Unfortunately, Goto Meeting does not work in Linux and consequently I usually connect to meetings from my Windows VMWare instance.&lt;br /&gt;&lt;br /&gt;Today I had the need to do a demonstration with offsite coworkers and I needed to do it within Linux. Since I have used the free service called &lt;a href="http://www.yugma.com"&gt;Yugma&lt;/a&gt; in the past and it supposedly works in Linux I decided to spend some time trying to get it to work.&lt;br /&gt;&lt;br /&gt;Well see for yourself.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_u6FjI-f0VoU/R_U6tNcbRFI/AAAAAAAAAEQ/_AaewXCe5ko/s1600-h/yugma.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/R_U6tNcbRFI/AAAAAAAAAEQ/_AaewXCe5ko/s400/yugma.png" alt="" id="BLOGGER_PHOTO_ID_5185115094364406866" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;It took some time, but with their free online chat Help Desk (which unexpectedly was amazing) we eventually got it to work.&lt;br /&gt;&lt;br /&gt;I image others wouldn't have as many issues as myself, but just in case here are some of the steps I had to perform to get this to work.&lt;br /&gt;&lt;br /&gt;First, if you haven't already created an account, go ahead and create one (&lt;a href="http://www.yugma.com"&gt;http://www.yugma.com&lt;/a&gt;). Then try visiting the Start a Session page. If you haven't already installed the software it should provide a link to download yugma. If not then you have issues like I did. Basically I had an old java version that FireFox was using and I had to update it to JRE 6. I followed their instructions &lt;a href="http://java.com/en/download/help/5000010500.xml#enable"&gt;here&lt;/a&gt;, but that wasn't enough.&lt;br /&gt;&lt;br /&gt;With the help of the Yugma Help Desk I still had to do the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;sudo apt-get install sun-java6-jre sun-java6-plugin sun-java6-bin&lt;/li&gt;&lt;li&gt;update-alternatives --list java&lt;br /&gt;this should print out&lt;br /&gt;/usr/bin/gij-4.1&lt;br /&gt;/usr/bin/gij-4.2&lt;br /&gt;/usr/bin/cacao&lt;br /&gt;/usr/lib/jvm/java-6-sun/jre/bin/java&lt;/li&gt;&lt;li&gt;sudo update-alternatives --config java&lt;br /&gt;[sudo] password for jlorenzen:&lt;br /&gt;&lt;br /&gt;There are 4 alternatives which provide `java'.&lt;br /&gt;&lt;br /&gt;  Selection    Alternative&lt;br /&gt;-----------------------------------------------&lt;br /&gt;          1    /usr/bin/gij-4.1&lt;br /&gt;          2    /usr/bin/gij-4.2&lt;br /&gt;          3    /usr/bin/cacao&lt;br /&gt;*+        4    /usr/lib/jvm/java-6-sun/jre/bin/java&lt;br /&gt;&lt;br /&gt;Press enter to keep the default[*], or type selection number: 4&lt;br /&gt;Using `/usr/lib/jvm/java-6-sun/jre/bin/java' to provide `java'.&lt;/li&gt;&lt;li&gt;Then restart FireFox. Revist the Start a Session page and you should be golden.&lt;/li&gt;&lt;/ul&gt;As a developer I really like Yugma because it has a free version that allows you to invite at least 10 people. Which is perfect for developers. And since our Goto Meeting licenses are controlled its difficult to get a Goto Meeting scheduled on short notice (Although &lt;a href="http://joshuahoover.com/"&gt;Josh Hoover&lt;/a&gt; is the King of Goto Meetings). The other nice thing about Yugma is its easy to start and share a session. I remember in Windows Outlook you could even install a package that put buttons in Outlook and set it all up; very handy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7418645088795439956?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7418645088795439956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7418645088795439956' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7418645088795439956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7418645088795439956'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/04/using-yugma-to-demo-from-your-linux.html' title='Using Yugma to demo from your Linux machine'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_u6FjI-f0VoU/R_U6tNcbRFI/AAAAAAAAAEQ/_AaewXCe5ko/s72-c/yugma.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-588203171945361028</id><published>2008-03-21T00:32:00.008-05:00</published><updated>2008-03-25T14:48:58.553-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven2'/><category scheme='http://www.blogger.com/atom/ns#' term='jmeter'/><title type='text'>Automated Performance Tests using JMeter and Maven</title><content type='html'>Learning how to write and automate performance tests isn't easy. Perhaps that is why I have never actually wrote and automated performance tests; until now. For my latest open source side project, &lt;a href="https://sass4j.dev.java.net/"&gt;sass4j&lt;/a&gt;, I wanted to start the project with some automated performance tests. Since we were already using maven2, I wanted to find a maven2 plugin that allowed me to write complex performance tests and automate them easily in a continuous integration environment such as &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt;. Since I had heard good things about &lt;a href="http://jakarta.apache.org/jmeter/"&gt;JMeter&lt;/a&gt; and there was an existing JMeter plugin, I decided on those technologies. Unfortunately the path this took me down was rather long and annoying, but I eventually figured everything out and that is the reason I would like to document the steps for others to reproduce in less time.&lt;br /&gt;&lt;br /&gt;But first, why would anyone want to spend unnecessary time setting this up? The big advantage I think, is having the ability to compare nightly test results with a baseline and compare them with expectations. If my latest changes caused a major decrease in performance when I only added a few lines of code, then perhaps something is wrong. The second advantage is the sooner a performance issue is found the cheaper it costs to fix it. Think about the change set a developer has to look at if nightly performance tests were ran, compared to finding a performance issue 6 months from when the bug was introduced. With the former scenario, I only have to look at what has changed in the last 24 hours.&lt;br /&gt;&lt;br /&gt;Now onto how to actually do this. I had two references in getting this done: The Official Apache JMeter Maven Plugin &lt;a href="http://wiki.apache.org/jakarta-jmeter/JMeterMavenPlugin"&gt;Site&lt;/a&gt; and a &lt;a href="http://technology.amis.nl/blog/?p=2364"&gt;blog&lt;/a&gt; on AMIS by Robbrecht van Amerongen. Both of which are incomplete, but combined provide enough information.&lt;br /&gt;&lt;br /&gt;Here is an outline of what you need to do. End to end this should take you about 15 minutes to setup; compared to the hours I spent I think you are getting a deal. Also you need to think about doing this in your &lt;a href="http://www.jfrog.org/sites/artifactory/latest/"&gt;artifactory&lt;/a&gt; server or company maven repository and not locally (doing it locally only helps you and not your entire company).&lt;br /&gt;&lt;br /&gt;1) Download the JMeter maven bundle I created containing all the necessary artifacts&lt;br /&gt;2) Install JMeter Plugin dependencies&lt;br /&gt;3) Install the JMeter Plugin&lt;br /&gt;4) Install JMeter&lt;br /&gt;5) Update your maven project&lt;br /&gt;6) Create jmx files and run mvn verify&lt;br /&gt;&lt;br /&gt;The first 3 steps are necessary because there are specific dependencies the JMeter plugin requires that are not available on any public maven repo I can find, nor is the JMeter plugin.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1) Download the JMeter plugin bundle&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://sass4j.dev.java.net/files/documents/8536/91313/jmeter-plugin-bundle-1.0.zip"&gt;Click here&lt;/a&gt; to download the JMeter plugin zip file&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Unzip it&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;2) Install JMeter Plugin dependencies&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;cd to the extracted folder &lt;span style="font-style: italic;"&gt;jmeter&lt;/span&gt;&lt;/li&gt;&lt;li&gt;run the following mvn commands to deploy the jar files locally. Obviously update the location of your local maven2 repository and keep in mind the file paths are specific to linux. Again do this once in your company's maven repository.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;li&gt;mvn deploy:deploy-file -DgroupId=org.apache.jmeter -DartifactId=jmeter -Dversion=2.2 -Dpackaging=jar -Dfile=jmeter-2.2.jar -DpomFile=jmeter-2.2.pom -Durl=file:///home/jlorenzen/.m2/repository/&lt;/li&gt;&lt;li&gt;mvn deploy:deploy-file -DgroupId=jcharts -DartifactId=jcharts -Dversion=0.7.5 -Dpackaging=jar -Dfile=jcharts-0.7.5.jar  -Durl=file:///home/jlorenzen/.m2/repository/&lt;/li&gt;&lt;li&gt;mvn deploy:deploy-file -DgroupId=org.apache.jorphan -DartifactId=jorphan -Dversion=2.2 -Dpackaging=jar -Dfile=jorphan-2.2.jar  -Durl=file:///home/jlorenzen/.m2/repository/&lt;/li&gt;&lt;li&gt;mvn deploy:deploy-file -DgroupId=org.mozilla.javascript -DartifactId=javascript -Dversion=1.0 -Dpackaging=jar -Dfile=javascript-1.0.jar  -Durl=file:///home/jlorenzen/.m2/repository/&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;3) Install the JMeter Plugin&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Unzip the &lt;span style="font-style: italic;"&gt;maven-jmeter-plugin.zip&lt;/span&gt; file that was included in the JMeter plugin bundle.&lt;/li&gt;&lt;li&gt;cd to the &lt;span style="font-style: italic;"&gt;maven-jmeter-plugin&lt;/span&gt; folder&lt;/li&gt;&lt;li&gt;run: mvn install&lt;/li&gt;&lt;li&gt;This will install version 1.0 of the maven-jmeter-plugin. It's important we install a release verses a snapshot because you don't want your project to depend on snapshot plugins because this could have nasty side effects for &lt;a href="http://jlorenzen.blogspot.com/2008/03/always-specify-version-for-maven2.html"&gt;building&lt;/a&gt; and &lt;a href="http://jlorenzen.blogspot.com/2007/09/how-to-create-release-using-maven2.html"&gt;releasing&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;4) Install JMeter&lt;/span&gt;&lt;br /&gt;Now that you have the plugin installed you can actually start modifying your projects pom to use it. You first need to install JMeter because we will need a jmeter.properties file, some XSL files, and you are going to need it to create the .jmx files.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Download and install &lt;a href="http://jakarta.apache.org/jmeter/"&gt;JMeter&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;5) Update your maven project&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;Under your project create the directory: &lt;span style="font-style: italic;"&gt;src/test/jmeter&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;src/test/resources&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Copy the &lt;span style="font-style: italic;"&gt;jmeter.properties&lt;/span&gt; file from the JMeter &lt;span style="font-style: italic;"&gt;bin&lt;/span&gt; folder to &lt;span style="font-style: italic;"&gt;src/test/jmeter&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Update the property &lt;span style="font-style: italic;"&gt;jmeter.save.saveservice.output_format&lt;/span&gt; in the &lt;span style="font-style: italic;"&gt;jmeter.properties&lt;/span&gt; file from csv to xml.&lt;/li&gt;&lt;li&gt;Copy the files &lt;span style="font-style: italic;"&gt;jmeter-results-detail-report_21.xsl&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;jmeter-results-report_21.xsl&lt;/span&gt; from the JMeter &lt;span style="font-style: italic;"&gt;extras&lt;/span&gt; folder to &lt;span style="font-style: italic;"&gt;src/test/resources&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Add the following to your POMs build/plugins section&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;build&gt;&lt;br /&gt;   &amp;lt;plugins&gt;&lt;br /&gt;       &amp;lt;plugin&gt;&lt;br /&gt;           &amp;lt;groupId&gt;org.apache.jmeter&amp;lt;/groupId&gt;&lt;br /&gt;           &amp;lt;artifactId&gt;maven-jmeter-plugin&amp;lt;/artifactId&gt;&lt;br /&gt;           &amp;lt;version&gt;1.0&amp;lt;/version&gt;&lt;br /&gt;           &amp;lt;executions&gt;&lt;br /&gt;               &amp;lt;execution&gt;&lt;br /&gt;                   &amp;lt;id&gt;jmeter-tests&amp;lt;/id&gt;&lt;br /&gt;                   &amp;lt;phase&gt;verify&amp;lt;/phase&gt;&lt;br /&gt;                   &amp;lt;goals&gt;&lt;br /&gt;                       &amp;lt;goal&gt;jmeter&amp;lt;/goal&gt;&lt;br /&gt;                   &amp;lt;/goals&gt;&lt;br /&gt;                   &amp;lt;configuration&gt;&lt;br /&gt;                       &amp;lt;reportDir&gt;${project.build.directory}/jmeter-reports&amp;lt;/reportDir&gt;&lt;br /&gt;                   &amp;lt;/configuration&gt;&lt;br /&gt;               &amp;lt;/execution&gt;&lt;br /&gt;           &amp;lt;/executions&gt;&lt;br /&gt;       &amp;lt;/plugin&gt;&lt;br /&gt;       &amp;lt;plugin&gt;&lt;br /&gt;           &amp;lt;groupId&gt;org.codehaus.mojo&amp;lt;/groupId&gt;&lt;br /&gt;           &amp;lt;artifactId&gt;xml-maven-plugin&amp;lt;/artifactId&gt;&lt;br /&gt;           &amp;lt;version&gt;1.0-beta-2&amp;lt;/version&gt;&lt;br /&gt;           &amp;lt;executions&gt;&lt;br /&gt;               &amp;lt;execution&gt;&lt;br /&gt;               &amp;lt;phase&gt;pre-site&amp;lt;/phase&gt;&lt;br /&gt;               &amp;lt;goals&gt;&lt;br /&gt;                   &amp;lt;goal&gt;transform&amp;lt;/goal&gt;&lt;br /&gt;               &amp;lt;/goals&gt;&lt;br /&gt;               &amp;lt;/execution&gt;&lt;br /&gt;           &amp;lt;/executions&gt;&lt;br /&gt;           &amp;lt;configuration&gt;&lt;br /&gt;               &amp;lt;transformationSets&gt;&lt;br /&gt;                   &amp;lt;transformationSet&gt;&lt;br /&gt;                       &amp;lt;dir&gt;${project.build.directory}/jmeter-reports&amp;lt;/dir&gt;&lt;br /&gt;                       &amp;lt;stylesheet&gt;src/test/resources/jmeter-results-detail-report_21.xsl&amp;lt;/stylesheet&gt;&lt;br /&gt;                       &amp;lt;outputDir&gt;${project.build.directory}/site/jmeter-results&amp;lt;/outputDir&gt;&lt;br /&gt;                       &amp;lt;fileMappers&gt;&lt;br /&gt;                           &amp;lt;fileMapper implementation="org.codehaus.plexus.components.io.filemappers.FileExtensionMapper"&gt;&lt;br /&gt;                               &amp;lt;targetExtension&gt;html&amp;lt;/targetExtension&gt;&lt;br /&gt;                           &amp;lt;/fileMapper&gt;&lt;br /&gt;                       &amp;lt;/fileMappers&gt;&lt;br /&gt;                   &amp;lt;/transformationSet&gt;&lt;br /&gt;               &amp;lt;/transformationSets&gt;&lt;br /&gt;           &amp;lt;/configuration&gt;&lt;br /&gt;       &amp;lt;/plugin&gt;&lt;br /&gt;   &amp;lt;/plugins&gt;&lt;br /&gt;&amp;lt;/build&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;6) Create jmx files and run mvn verify&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Now use JMeter to create your .jmx files and place them under the src/test/jmeter directory.&lt;/li&gt;&lt;li&gt;run: mvn verify to execute your performance tests&lt;/li&gt;&lt;li&gt;run: mvn verify pre-site to execute your performance tests and produce the test results in an HTML report.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;If you want to see a real example of this &lt;a href="https://sass4j.dev.java.net/source/browse/sass4j/trunk/main/system-tests/"&gt;click here&lt;/a&gt;. Now the only step I am leaving out is actually automating it which isn't the hard part luckily. All you need to do in Hudson is create a new job and execute the mvn goals &lt;span style="font-style: italic;"&gt;mvn verify&lt;/span&gt; to get them automated in a CI environment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-588203171945361028?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/588203171945361028/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=588203171945361028' title='30 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/588203171945361028'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/588203171945361028'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/03/automated-performance-tests-using.html' title='Automated Performance Tests using JMeter and Maven'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>30</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-2136205271415926964</id><published>2008-03-10T14:53:00.010-05:00</published><updated>2008-03-10T15:59:04.529-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven2'/><title type='text'>Always specify a version for Maven2 plugins</title><content type='html'>For the past several months my team has been suffering a lot of downtime because our local builds fail and our Continuous Integration environment fails for what appears to be no reason. What makes these issues difficult to debug is what might fail on your machine, won't fail on mine ("works on my machine"). We eventually found the cause and that was we were not specifying a version for plugins in our maven2 poms. Pretty dumb, eh?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wrong way&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;plugin&gt;&lt;br /&gt; &amp;lt;groupid&gt;org.apache.maven.plugins&amp;lt;/groupid&gt;&lt;br /&gt; &amp;lt;artifactid&gt;maven-surefire-plugin&amp;lt;/artifactid&gt;&lt;br /&gt;&amp;lt;/plugin&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Correct way&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;plugin&gt;&lt;br /&gt; &amp;lt;groupid&gt;org.apache.maven.plugins&amp;lt;/groupid&gt;&lt;br /&gt; &amp;lt;artifactid&gt;maven-surefire-plugin&amp;lt;/artifactid&gt;&lt;br /&gt; &amp;lt;version&gt;2.3&amp;lt;/version&gt;&lt;br /&gt;&amp;lt;/plugin&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This matters because if you leave out the version, maven2 defaults to SNAPSHOT. So what was happening is my project &lt;span style="font-weight: bold;"&gt;unknowingly&lt;/span&gt; became automatic beta testers for third party plugins.&lt;br /&gt;&lt;br /&gt;So the moral of the story is always include a version (preferably a stable release version like 2.3 and not 2.3-SNAPSHOT) when defining your plugins. This will go a long ways in making your build more stable. And better yet, define those plugins in your parent pom using the &lt;a href="http://maven.apache.org/pom.html#Plugin_Management"&gt;&amp;lt;pluginManagement&amp;gt;&lt;/a&gt; section. This keeps your versions in one place so that when you do upgrade intentionally to a newer version you only have to modify it in one place for your entire project. For example:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;pluginmanagement&gt;&lt;br /&gt;  &amp;lt;plugins&gt;&lt;br /&gt;      &amp;lt;plugin&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;&amp;lt;groupid&gt;org.apache.maven.plugins&amp;lt;/groupid&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;&amp;lt;artifactid&gt;&lt;/code&gt;&lt;code&gt;maven-surefire-plugin&lt;/code&gt;&lt;code&gt;&amp;lt;/artifactid&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;&amp;lt;version&gt;2.3&amp;lt;/version&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;        &amp;lt;/plugin&gt;&lt;br /&gt;  &amp;lt;plugins&gt;&lt;br /&gt;&amp;lt;/plugins&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Specifically the &lt;a href="http://maven.apache.org/plugins/maven-surefire-plugin/"&gt;maven-surefire-plugin&lt;/a&gt; and &lt;a href="http://maven.apache.org/plugins/maven-war-plugin/"&gt;maven-war-plugin&lt;/a&gt; have cost us a lot already, so recently I updated all our poms to define a version for all the plugins we were using. And one reason I know it would fail for some, but not others, is some prefer to build in offline mode (-o) always which prevented them from seeing the problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-2136205271415926964?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/2136205271415926964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=2136205271415926964' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2136205271415926964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2136205271415926964'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/03/always-specify-version-for-maven2.html' title='Always specify a version for Maven2 plugins'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8142821824503559342</id><published>2008-03-10T00:11:00.003-05:00</published><updated>2008-03-10T00:18:35.065-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='netbeans'/><title type='text'>Avoid installing 2 versions of Netbeans 6</title><content type='html'>Tonight I installed the latest &lt;a href="https://open-esb.dev.java.net/Downloads_OpenESB_Addons_NB6.html"&gt;OpenESB software&lt;/a&gt; (Build 20080303) and was rather confused as a lot has changed since I last used it back in October 2007. I found myself being rather unproductive so I decided to revert to an earlier version. So I downloaded Build 20080214 and installed it, but I did not uninstall the previous version. With the older version I repeatedly received exceptions on just about everything I clicked on. Many of my co-workers battle these issues everyday, but now I might have figured out why. For some reason, Netbeans just doesn't like being installed twice on the same system under the same folder (for me was /workspace/java/openesb). Under there I had 2 netbeans and 2 glassfish folders. Once I uninstalled everything and reinstalled the older version (Build 20080214) it worked perfectly.&lt;br /&gt;&lt;br /&gt;So when you are receiving all those nasty exceptions every 5 seconds in Netbeans, make sure you only have one installed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8142821824503559342?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8142821824503559342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8142821824503559342' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8142821824503559342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8142821824503559342'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/03/avoid-installing-2-versions-of-netbeans.html' title='Avoid installing 2 versions of Netbeans 6'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7531589852247133846</id><published>2008-03-06T15:25:00.005-06:00</published><updated>2008-03-07T13:50:05.157-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='icefaces'/><title type='text'>Challenges using Icefaces</title><content type='html'>I would just like to take a quick moment and inform anyone about &lt;a href="http://www.icefaces.org/"&gt;Icefaces&lt;/a&gt;, and the challenges I have faced using it. Take it from my current experience (version 1.6.1 and 1.6.2) and the &lt;a href="http://www.icefaces.org/JForum/posts/list/7385.page"&gt;words&lt;/a&gt; of an Icefaces developer that since Icefaces "&lt;span style="font-style: italic;"&gt;is a stateful technology......providing enhanced features for the user....&lt;span style="font-weight: bold;"&gt;but require server-side resources to do so&lt;/span&gt;.&lt;/span&gt;" That last statement has been our recent struggle.&lt;br /&gt;&lt;br /&gt;Unfortunately, on my current project we don't have the luxury of lots of server-side resources. It's disappointing to say we have to share a single server that is already running IIS; then we have to run Jboss and MS SQL on the same machine. Obviously this is not by choice and doesn't look to change in the near future.&lt;br /&gt;&lt;br /&gt;It might be Icefaces never intended their framework to run in such a limited environment. But that really doesn't help me now. It would be great if they published information about minimum hardware requirements, especially if they are aware of performance issues. Equally important I am sure we have strayed away from best practices in using Icefaces.&lt;br /&gt;&lt;br /&gt;Please don't ask me why we choose to use Icefaces in the first place (I wasn't with the group at the time). But I assume it was a lack of knowledge of how Icefaces works, and we weren't aware of the environment limitations. Either way, we are facing difficult challenges that are very frustrating.&lt;br /&gt;&lt;br /&gt;For example, we recently had severe problems with an editable table which was sortable (much like an excel spreadsheet).  When users clicked twice on the header to sort, the data appeared to be sent twice and some how our data got corrupted. Consequently we had to disable the ability to sort.&lt;br /&gt;&lt;br /&gt;Also, based on my understanding of Icefaces, it appears that all clients maintain a constant connection with the server. I am assuming this is what the Icefaces developer above was referring to when he says Icefaces is a stateful technology. For some reason, I feel this constant connection would cause challenges for 50-100+ concurrent clients with limited server-side resources.&lt;br /&gt;&lt;br /&gt;Hope it helps someone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7531589852247133846?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7531589852247133846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7531589852247133846' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7531589852247133846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7531589852247133846'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/03/when-not-to-use-icefaces.html' title='Challenges using Icefaces'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-2320602786131216388</id><published>2008-03-04T08:43:00.006-06:00</published><updated>2008-03-04T09:28:22.581-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='extjs'/><title type='text'>How to simulate onblur event for a Panel in Extjs</title><content type='html'>Here is a simple trick in &lt;a href="http://extjs.com/"&gt;Extjs&lt;/a&gt; I borrowed from &lt;span style="font-style: italic;"&gt;Ext.layout.BorderLayout&lt;/span&gt; that simulates listening for the &lt;span style="font-style: italic;"&gt;onblur&lt;/span&gt; event of an &lt;span style="font-style: italic;"&gt;Ext.Panel&lt;/span&gt;. This trick is necessary because unfortunately &lt;span style="font-style: italic;"&gt;Ext.Panel&lt;/span&gt; does not natively support registering for the &lt;span style="font-style: italic;"&gt;onblur&lt;/span&gt; event (or at least I don't know how). We typically use this trick when we show a Panel and want to remove it when the user clicks off, or to state it differently, when the Panel looses focus. This is very similar to how menus work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 1: Register for mousedown event&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;code&gt;this.panel.show();&lt;br /&gt;Ext.getDoc().on("mousedown", this.handleDocMouseDown, this);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;First, we show the panel. Here it is assumed this was created previously. Second, we use &lt;span style="font-style: italic;"&gt;Ext.getDoc()&lt;/span&gt; to return the current HTML document object, and then we register for the &lt;span style="font-style: italic;"&gt;mousedown&lt;/span&gt; event. The second parameter, &lt;span style="font-style: italic;"&gt;this.handleDocMouseDown&lt;/span&gt;, is our function we want called when this event is fired. Notice that we register for the &lt;span style="font-style: italic;"&gt;mousedown&lt;/span&gt; event as opposed to the &lt;span style="font-style: italic;"&gt;click&lt;/span&gt; event. This is intentional because listening for the &lt;span style="font-style: italic;"&gt;click&lt;/span&gt; event will actually call &lt;span style="font-style: italic;"&gt;this.handleDocMouseDown&lt;/span&gt; before your ready because a click involves both &lt;span style="font-style: italic;"&gt;mousedown&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;mouseup&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 2: Handle the event&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;handleDocMouseDown : function(e) {&lt;br /&gt;if (!e.within(this.panel.getEl())) {&lt;br /&gt;   this.panel.destroy();&lt;br /&gt;   Ext.getDoc().un("mousedown", this.handleDocMouseDown, this);&lt;br /&gt;}&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;In our second step we first check to make sure the user didn't click anywhere in the Panel that was just displayed. If it wasn't then we destroy the panel and unregister the &lt;span style="font-style: italic;"&gt;mousedown&lt;/span&gt; event.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-2320602786131216388?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/2320602786131216388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=2320602786131216388' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2320602786131216388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2320602786131216388'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/03/how-to-simulate-onblur-event-for-panel.html' title='How to simulate onblur event for a Panel in Extjs'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1853457474737606778</id><published>2008-02-28T08:42:00.014-06:00</published><updated>2008-02-28T10:24:41.150-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='markupbuilder'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy's MarkupBuilder and Namespaces</title><content type='html'>Yesterday Kit Plummer &lt;a href="http://blogs.rvooz.org/?p=5"&gt;posted&lt;/a&gt; an XML example using Ruby to demonstrate how to include attributes and namespaces. So I went on a quest to duplicate his output using &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; to compare the difference and evangelize.&lt;br /&gt;&lt;br /&gt;Here is the desired output:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;person:person text='test'&gt;&lt;br /&gt;   &amp;lt;name&gt;Jim&amp;lt;/name&gt;&lt;br /&gt;   &amp;lt;phone&gt;555-1234&amp;lt;/phone&gt;&lt;br /&gt;&amp;lt;/person:person&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Using the &lt;a href="http://groovy.codehaus.org/Groovy+Console"&gt;Groovy Console&lt;/a&gt;, and Groovy's ninja-like &lt;a href="http://groovy.codehaus.org/Creating+XML+using+Groovy%27s+MarkupBuilder"&gt;MarkupBuilder&lt;/a&gt;, you can execute the following script to get attributes and namespace prefixes:&lt;pre&gt;&lt;code&gt;import groovy.xml.MarkupBuilder&lt;br /&gt;&lt;br /&gt;def writer = new StringWriter()&lt;br /&gt;def xml = new MarkupBuilder(writer)&lt;br /&gt;&lt;br /&gt;xml.'person:person'(text: 'test') {&lt;br /&gt;   name('Jim')&lt;br /&gt;   phone('555-1234')&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;println writer.toString()&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;If you prefer to define a default namespace instead do this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;xml.person(xmlns: 'http://people.org', text: 'test') {&lt;br /&gt;   name('Jim')&lt;br /&gt;   phone('555-1234')&lt;br /&gt;} &lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/code&gt;&lt;/pre&gt;Finally, here is an example that uses them all:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;xml.'person:person'('xmlns:person': 'http://people.org', xmlns: 'http://people.org', text: 'test') {&lt;br /&gt;   name('Jim')&lt;br /&gt;   phone('555-1234')&lt;br /&gt;} &lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;This will output:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;person:person xmlns:person='http://people.org' xmlns='http://people.org' text='test'&gt;&lt;br /&gt;   &amp;lt;name&gt;Jim&amp;lt;/name&gt;&lt;br /&gt;   &amp;lt;phone&gt;555-1234&amp;lt;/phone&gt;&lt;br /&gt;&amp;lt;person:person&gt;&lt;/code&gt;&lt;/pre&gt;I think it's more readable than the Ruby example and definitely much better than the equivalent Java code.&lt;br /&gt;&lt;br /&gt;By the way, I attempted to use this &lt;a href="http://www.thecomplex.plus.com/highlighter.html"&gt;online syntax highlighter&lt;/a&gt; and did not like it. Does anyone know of a good online syntax highlighter?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1853457474737606778?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1853457474737606778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1853457474737606778' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1853457474737606778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1853457474737606778'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/02/groovys-markupbuilder-and-namespaces.html' title='Groovy&apos;s MarkupBuilder and Namespaces'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8987924600588235097</id><published>2008-02-08T13:02:00.000-06:00</published><updated>2008-02-08T13:12:50.038-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><title type='text'>Volunteering as Hudson OpenSolaris IPS maintainer</title><content type='html'>Starting with an &lt;a href="http://weblogs.java.net/blog/kohsuke/archive/2008/01/ips_maintainer.html"&gt;open request&lt;/a&gt; by &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt; project lead Kohsuke Kawaguchi, I volunteered to be an OpenSolaris IPS package maintainer for Hudson. Not sure I am qualified but I am a huge Hudson advocate and am looking forward to the challenge.&lt;br /&gt;&lt;br /&gt;My main goals are to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Learn more about how open source communities work&lt;/li&gt;&lt;li&gt;Go in the opposite direction of my comfort zone and learn something new&lt;/li&gt;&lt;/ul&gt;Stay tuned on this &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/OpenSolaris+IPS+Package"&gt;Hudson wiki page&lt;/a&gt; I have created to document this effort.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8987924600588235097?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8987924600588235097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8987924600588235097' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8987924600588235097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8987924600588235097'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/02/volunteering-as-hudson-opensolaris-ips.html' title='Volunteering as Hudson OpenSolaris IPS maintainer'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5131495272479397931</id><published>2008-02-07T09:36:00.001-06:00</published><updated>2008-02-07T09:40:20.299-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven2'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails 1.x to add Maven 2 plugin support</title><content type='html'>From an &lt;a href="http://www.infoq.com/news/2008/02/grails-1.0-released"&gt;InfoQ interview&lt;/a&gt; with Grails project lead Graeme Rocher discussing the recent release of Grails 1.0 and its future:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;In addition, we plan to include Maven 2 support out of the box with Grails through a Maven 2 plug-in that hooks Grails into the Maven life cycle. Remember Grails is not just a web framework, but a software stack which aims to solve every part of the software life cycle from the build system to the ORM layer.&lt;/span&gt;&lt;/blockquote&gt;For those of use already using maven2 this is pretty good news. Not that there weren't ways to get around it, but it will be nice to have maven2 support out of the box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5131495272479397931?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/5131495272479397931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=5131495272479397931' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5131495272479397931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5131495272479397931'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/02/grails-1x-to-add-maven-2-plugin-support.html' title='Grails 1.x to add Maven 2 plugin support'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3241269700687121156</id><published>2008-01-24T07:59:00.000-06:00</published><updated>2008-01-24T08:08:54.331-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Maven Groovy Plugin Example</title><content type='html'>&lt;a href="http://www.ronniealleva.org/index.php/2008/01/23/using-the-groovy-maven-plugin-to-do-magic/"&gt;Here&lt;/a&gt; is a powerful example by a co-worker on how to use the &lt;a href="http://mojo.codehaus.org/groovy/groovy-maven-plugin/index.html"&gt;maven-groovy-plugin&lt;/a&gt; in your maven2 POMs. In this example Ron shows how you can embed a Groovy script in your POM to enforce a specific size of the resulting artifact (in this case an EAR).&lt;br /&gt;&lt;br /&gt;This is very valuable because now you can do just about anything in your POM, including adding Java code as in this &lt;a href="http://mojo.codehaus.org/groovy/groovy-maven-plugin/examples/executing.html"&gt;example&lt;/a&gt; (look under Using Java Classes).&lt;br /&gt;&lt;br /&gt;However, with this power comes responsibility and you don't want to get in the habit of using this everywhere. Usually this is a red flag meaning you should create your own plugin to be reused by everyone. We should all be able to recognize the drawbacks of Copy+Paste.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3241269700687121156?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/3241269700687121156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=3241269700687121156' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3241269700687121156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3241269700687121156'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/01/maven-groovy-plugin-example.html' title='Maven Groovy Plugin Example'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1963181604628598287</id><published>2008-01-03T23:00:00.002-06:00</published><updated>2009-03-06T12:31:23.511-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>How to connect to a Grails HSQL Database</title><content type='html'>The following is how you can use &lt;a href="http://www.minq.se/products/dbvis/"&gt;DBVisualizer&lt;/a&gt; to connect to a &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; &lt;a href="http://hsqldb.org/"&gt;HSQL&lt;/a&gt; Database. Grails uses Spring and Hibernate and its default database uses HSQLDB. So why would you want to view the Grails database? Maybe you are curious of how &lt;a href="http://grails.codehaus.org/GORM"&gt;GORM&lt;/a&gt; works; debug your Domains; perhaps you don't trust Grails, or finally you might be a control freak. Or like me you are all of the above.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update Datasource.groovy&lt;/span&gt;&lt;br /&gt;First, if you want to view the development database you need to change the url to not use an in-memory database because DBVisualizer will not have access to the Grails JVM memory. Open up the DataSource.groovy file and locate the development environment section and replace the existing url "jdbc:hsqldb:mem:devDB" with "jdbc:hsqldb:file:devDB;shutdown=true".&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_u6FjI-f0VoU/R33HxmcVdWI/AAAAAAAAADw/MmIROWKxeOk/s1600-h/datasource.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/R33HxmcVdWI/AAAAAAAAADw/MmIROWKxeOk/s400/datasource.png" alt="" id="BLOGGER_PHOTO_ID_5151493203728627042" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Start Grails&lt;/span&gt;&lt;br /&gt;&gt;grails run-app&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Create New Database Connection in DBVisualizer&lt;/span&gt;&lt;br /&gt;Open up DBVisualizer (my version is 6.0.7) and create a new Connection (if you are unable to use DBVisualizer you can also use the HSQL Database Manager - see this &lt;a href="http://www.nabble.com/Anyone-know-of-a-viewing-tool-for-the-in-memory-db--to14235983.html#a14544567"&gt;post&lt;/a&gt;).&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Type in a Connection Name: Grails Development&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Choose HSQLDB as the DatabaseType&lt;/li&gt;&lt;li&gt;Choose HSQLDB embedded as your Driver using the hsqldb.jar located under your Grails home directory ($GRAILS_HOME/lib)&lt;/li&gt;&lt;li&gt;Update the Database URL to include your grails app base directory (jdbc:hsqldb:file:{your-grails-app-base-dir}/devDB). For me this was jdbc:hsqldb:file:/workspace/checkout/netcds-admin/devDB. Note that according to the &lt;a href="http://hsqldb.org/doc/guide/ch01.html#N101A8"&gt;HSQL document&lt;/a&gt;, Window users don't have to specify the C: drive.&lt;/li&gt;&lt;li&gt;Make sure your Userid is sa&lt;/li&gt;&lt;li&gt;Click Connect&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_u6FjI-f0VoU/R33IV2cVdXI/AAAAAAAAAD4/rr9ycSOig4U/s1600-h/dbvis1.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_u6FjI-f0VoU/R33IV2cVdXI/AAAAAAAAAD4/rr9ycSOig4U/s400/dbvis1.png" alt="" id="BLOGGER_PHOTO_ID_5151493826498884978" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;View Tables&lt;/span&gt;&lt;br /&gt;Then on the left you should be able to see your tables under PUBLIC --&gt; TABLE.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_u6FjI-f0VoU/R33I9WcVdYI/AAAAAAAAAEA/vca5fRT8sKg/s1600-h/tables.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_u6FjI-f0VoU/R33I9WcVdYI/AAAAAAAAAEA/vca5fRT8sKg/s400/tables.png" alt="" id="BLOGGER_PHOTO_ID_5151494505103717762" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Special thanks to the Nabble users who responded to my &lt;a href="http://www.nabble.com/Anyone-know-of-a-viewing-tool-for-the-in-memory-db--to14235983.html#a14544567"&gt;question&lt;/a&gt;: Christian Laakmann and Helmut Denk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1963181604628598287?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1963181604628598287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1963181604628598287' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1963181604628598287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1963181604628598287'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2008/01/how-to-connect-to-grails-hsql-database.html' title='How to connect to a Grails HSQL Database'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_u6FjI-f0VoU/R33HxmcVdWI/AAAAAAAAADw/MmIROWKxeOk/s72-c/datasource.png' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-2730499411419614193</id><published>2007-12-28T21:50:00.000-06:00</published><updated>2007-12-29T00:31:32.498-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Justify using Groovy</title><content type='html'>How does one justify using Groovy on a project? To me it's no different than including any other dependency in my project and in the end it has the same result but with a lot more benefits. There are a lot of skeptics out there, specifically among my team members, and I just can't imagine why they wouldn't want to use Groovy in their every day development. I guess in this instance "knowledge is a curse." It's kind of difficult to explain why I believe in what Groovy is doing, but I will at least give it a try.&lt;br /&gt;&lt;br /&gt;First, the biggest initial hurdle people can't get over is they think to start writing Groovy they have to stop writing Java. That couldn't be further from the truth. Groovy was never meant to replace Java. I have used Groovy to write unit tests for my Java code and I have written Groovy code that has used Java code and vic versa. My experience has shown that Groovy and Java just work seamlessly together, especially when using the &lt;a href="http://mojo.codehaus.org/groovy/groovy-maven-plugin/index.html"&gt;maven-groovy-plugin&lt;/a&gt; and the IntelliJ Idea &lt;a href="http://plugins.intellij.net/plugin/?id=1524"&gt;JetGroovy plugin&lt;/a&gt; (for more information see &lt;a href="http://joe.kueser.com/2007/10/13/more-groovy-goodies/"&gt;More Groovy Goodies&lt;/a&gt; by Joe Kueser).&lt;br /&gt;&lt;br /&gt;Secondly, to me the biggest benefit of Groovy, with no cost to the developer, is the hundreds of extra methods added to existing Java classes (see the &lt;a href="http://groovy.codehaus.org/groovy-jdk/"&gt;Groovy JDK&lt;/a&gt;). Just by including a new dependency, I have at my disposal hundreds of new time saving methods that I can start using immediately. For example, there are approximately 50 new methods added to java.lang.String (not sure I will ever use all of them but you get the picture). Now lets say for example you were using some open source project like &lt;a href="http://www.jfree.org/jfreechart/"&gt;JFreeChart&lt;/a&gt;. And you were using version 1.0.8, and 2.0 was out and it included hundreds of new methods. How long would it take you to change the version in your maven2 pom? To me this is not much different than using Groovy to "extend" Java.&lt;br /&gt;&lt;br /&gt;Finally, I want to give a quick example of what the end result of a Groovy class is since Groovy is just complied into Java bytecode. Since I have repeatedly stated that Groovy is no different than including a new dependency in your project let me prove it.&lt;br /&gt;&lt;br /&gt;Borrowing an example from my previous &lt;a href="http://jlorenzen.blogspot.com/2007/11/using-groovy-to-work-with-files-dont.html"&gt;post&lt;/a&gt;, lets say my Groovy class looks something like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class GroovyFileTest {&lt;br /&gt;    def void test() {&lt;br /&gt;        def file = "/workspace/sandbox/grvyfile/src/test.txt"&lt;br /&gt;        println new File(file).text()&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;My next step would be to use the Groovy Complier (groovyc) to compile my Groovy source into Java bytecode (or just use the maven-groovy-plugin). That would produce GroovyFileTest.class. Using a Java decompiler, such as Jad, here is the outcome:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;public void test()&lt;br /&gt;{&lt;br /&gt;    Class class1 = GroovyFileTest.class;&lt;br /&gt;    Class class2 = groovy.lang.MetaClass.class;&lt;br /&gt;    Object file = "/workspace/sandbox/grvyfile/src/test.txt";&lt;br /&gt;    ScriptBytecodeAdapter.invokeMethodOnCurrentN(class1,&lt;br /&gt;        (GroovyObject)ScriptBytecodeAdapter.castToType(this, groovy.lang.GroovyObject.class),&lt;br /&gt;        "println", new Object[] {&lt;br /&gt;            ScriptBytecodeAdapter.invokeMethod0(class1,&lt;br /&gt;                ScriptBytecodeAdapter.invokeNewN(class1, &lt;br /&gt;                java.io.File.class,&lt;br /&gt;                ((Object) (new Object[] {file}))), "text")});&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;For the sake of clarity I am not including all the other information that was decompiled (well.... because it's rather long). But to summarize, my two line Groovy script is convereted to 214 lines of decompiled Java code. Initially you might think that boosts well for Groovy and really shows the benefits of Groovy, but there is a lot of Groovy going on behind the scenes.&lt;br /&gt;&lt;br /&gt;From my perspective this is the only current argument a Groovy skeptic can make: "well look at all that extra junk they are throwing in. Isn't that going to hurt performance?". And at the end it just might. I think it's obvious that Groovy bytecode probably won't run as fast as Java bytecode, but for me the benefits out way that disadvantage.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://graphics.jsonline.com/graphics/sports/brew/img/mar04/bonds327.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px;" src="http://graphics.jsonline.com/graphics/sports/brew/img/mar04/bonds327.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I by no means intended this to be an exhaustive list of Groovy benefits (for that I would recommend reading the excellent but lengthy &lt;a href="http://www.infoq.com/articles/groovy-1.5-new"&gt;article&lt;/a&gt; by Guillaume Laforge on the recent Groovy 1.5 features) . I just wanted to prove that the end result is no different. Hopefully people will respond with questions and criticisms and I can respond intelligently.&lt;br /&gt;&lt;br /&gt;To me Groovy is sort of the legal steroids of programming. Those that use it have an unfair advantage, enabling them to deliver software quicker then their competitors and co-workers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-2730499411419614193?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/2730499411419614193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=2730499411419614193' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2730499411419614193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2730499411419614193'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/12/justify-using-groovy.html' title='Justify using Groovy'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3516893360962013373</id><published>2007-12-25T22:42:00.000-06:00</published><updated>2007-12-25T23:03:30.053-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='history'/><title type='text'>A bit of history. Americans original motivation</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://research.history.org/JDRLibrary/Images/Grand%20Union%20Flag.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px;" src="http://research.history.org/JDRLibrary/Images/Grand%20Union%20Flag.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I absolutely love history. In fact outside of programming and basketball it has to be my favorite hobby (and yes programming to me is a hobby since I enjoy it so much). For Christmas my wife gave me the Illustrated Edition of "&lt;a href="http://www.amazon.com/1776-Illustrated-David-McCullough/dp/1416542108/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1198644385&amp;amp;sr=8-1"&gt;1776&lt;/a&gt;" by David McCullough. I enjoyed the original very much and am looking forward to reading it again along with the 140 images and 37 replicated source documents.&lt;br /&gt;&lt;br /&gt;Learning new things I think is why I enjoy history so much. For example, in his new book, Author McCullough starts by including an image of what it regarded as our countries first flag: &lt;a href="http://en.wikipedia.org/wiki/Grand_union_flag"&gt;The Grand Union&lt;/a&gt;. Also fascinating was the quote by Alison Huber, "Independence from Britain was not as yet what Americans were fighting for, but rather what they felt their rights as freeborn Englishmen." It's real easy to forget something like this and just naturally think our fore fathers started fighting for independence immediately. Instead they were just fighting for the same rights their brothers had back in England.&lt;br /&gt;&lt;br /&gt;Stayed tuned as I plan on posting as I read more of the book; or just hit the space bar in Google Reader if you don't care.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3516893360962013373?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/3516893360962013373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=3516893360962013373' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3516893360962013373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3516893360962013373'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/12/bit-of-history-americans-original.html' title='A bit of history. Americans original motivation'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7440780383509109980</id><published>2007-12-05T22:15:00.001-06:00</published><updated>2007-12-05T22:57:08.931-06:00</updated><title type='text'>Google Readers Discover</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_u6FjI-f0VoU/R1eAeOCXwxI/AAAAAAAAACs/YgnC7yoSK_s/s1600-h/untitled2.bmp"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://1.bp.blogspot.com/_u6FjI-f0VoU/R1eAeOCXwxI/AAAAAAAAACs/YgnC7yoSK_s/s200/untitled2.bmp" alt="" id="BLOGGER_PHOTO_ID_5140718756319183634" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;As if I didn't have enough RSS feeds to read, &lt;a href="http://www.google.com/reader"&gt;Google Reader&lt;/a&gt; went ahead and recently added a neat little feature called Discover (or Top Recommendations). This new feature provides a short list of new feeds generated by comparing my interests with the feeds of users similar to me.  In fact, according to the &lt;a href="http://www.google.com/support/reader/bin/answer.py?hl=en&amp;amp;answer=80468"&gt;Help Center&lt;/a&gt;, it takes into account my current subscriptions as well as information from my &lt;a href="http://www.google.com/support/accounts/bin/topic.py?topic=10470"&gt;Web History&lt;/a&gt; including location. It's actually pretty fascinating and I discovered several interesting feeds that I then subscribed to easily.&lt;br /&gt;&lt;br /&gt;If you are already using Google Reader take a look at your list. If not, then consider using or switching to Google Reader; it's discovertastic!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_u6FjI-f0VoU/R1eAouCXwyI/AAAAAAAAAC0/H6ioi8Ce5Mo/s1600-h/untitled.bmp"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_u6FjI-f0VoU/R1eAouCXwyI/AAAAAAAAAC0/H6ioi8Ce5Mo/s200/untitled.bmp" alt="" id="BLOGGER_PHOTO_ID_5140718936707810082" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7440780383509109980?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7440780383509109980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7440780383509109980' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7440780383509109980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7440780383509109980'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/12/google-readers-discover.html' title='Google Readers Discover'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_u6FjI-f0VoU/R1eAeOCXwxI/AAAAAAAAACs/YgnC7yoSK_s/s72-c/untitled2.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8634504463313561251</id><published>2007-11-29T21:49:00.000-06:00</published><updated>2007-11-29T22:53:35.421-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Using Groovy to work with Files</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://michelemiller.blogs.com/marketing_to_women/eye.bmp"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px;" src="http://michelemiller.blogs.com/marketing_to_women/eye.bmp" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;One of the best applications of &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; I have come across so far is working with Files. Using Groovy to read data from a file can not get any easier. If you are a Groovy skeptic this is the post for you. Using the &lt;a href="http://mojo.codehaus.org/groovy/groovy-maven-plugin/index.html"&gt;maven-groovy-plugin&lt;/a&gt;, which allows you to mix Java and Groovy code seamlessly, you no longer have any more excuses (go &lt;a href="http://joe.kueser.com/2007/10/13/more-groovy-goodies/"&gt;here&lt;/a&gt; for a maven-groovy-plugin how-to).&lt;br /&gt;&lt;br /&gt;Recently I was writing unit tests in Groovy for my Java code and I needed to read in the contents of a file for comparison. In Java this would look something like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;import java.io.BufferedReader;&lt;br /&gt;import java.io.FileReader;&lt;br /&gt;import java.io.FileNotFoundException;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;public class FileTest {&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt; try {&lt;br /&gt;     String file = "/workspace/sandbox/grvyfile/src/test.txt";&lt;br /&gt;     String line = "";&lt;br /&gt;     StringBuilder sb = new StringBuilder();&lt;br /&gt;     BufferedReader br = new BufferedReader(new FileReader(file));&lt;br /&gt;     while ((line = br.readLine()) !=null) {&lt;br /&gt;         sb.append(line);&lt;br /&gt;     }&lt;br /&gt;     System.out.println("sb.toString() = " + sb.toString());&lt;br /&gt; } catch (FileNotFoundException e) {&lt;br /&gt;     System.out.println("e = " + e);&lt;br /&gt; } catch (IOException e) {&lt;br /&gt;     System.out.println("e = " + e);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;If you are still doing this &lt;span style="font-weight: bold;"&gt;STOP RIGHT NOW&lt;/span&gt;! This boiler plate code took me about 5 minutes to write. Since it's not something I do super frequently I don't commit this syntax to memory, and therefore almost always have to reference the API to remember to use things like &lt;span style="font-style: italic;"&gt;java.io.BufferedReader&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Would you like to see the Groovy equivalent? Make sure you don't blink; you might miss it.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def file = "/workspace/sandbox/grvyfile/src/test.txt"&lt;br /&gt;println new File(file).text&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;That is all folks. In fact if you want to test this real quick, use the &lt;a href="http://groovy.codehaus.org/Groovy+CLI"&gt;groovy command line&lt;/a&gt; like the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&gt;cd /workspace/sandbox/grvyfile/src&lt;br /&gt;&gt;groovy -e "println new File('test.txt').text"&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;For those new to Groovy, &lt;span style="font-style: italic;"&gt;.text&lt;/span&gt; is essentially shorthand for calling the &lt;span style="font-style: italic;"&gt;.getText()&lt;/span&gt; method on the File object. The method &lt;span style="font-style: italic;"&gt;getText()&lt;/span&gt; is one of the dozens of new methods added to the JDK (see the &lt;a href="http://groovy.codehaus.org/groovy-jdk.html"&gt;GDK&lt;/a&gt; for more).&lt;br /&gt;&lt;br /&gt;Read my comments in this post (&lt;a href="http://www.blackholelogic.com/2007/11/1/java-laugh-or-cry-your-choice"&gt;Java: Laugh or Cry, Your Choice...&lt;/a&gt;) by Kit Plummer for another good application of Groovy. Here I use the &lt;span style="font-style: italic;"&gt;List&lt;/span&gt; GDK methods &lt;span style="font-style: italic;"&gt;minus()&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;unique()&lt;/span&gt; to decrease the lines of code from ~27 to ~2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8634504463313561251?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8634504463313561251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8634504463313561251' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8634504463313561251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8634504463313561251'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/11/using-groovy-to-work-with-files-dont.html' title='Using Groovy to work with Files'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-498161731927629158</id><published>2007-11-28T00:34:00.000-06:00</published><updated>2007-11-28T00:53:27.468-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Impressive Grails Plugin Architecture</title><content type='html'>I just finished watching the video of &lt;a href="http://graemerocher.blogspot.com/"&gt;Graeme Rocher&lt;/a&gt; explain the Grails Plugin Architecture while at the Grails Exchange in London recently (&lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=47680"&gt;Graeme Rocher on the Grails Plugin Architecture&lt;/a&gt;). I got to say, while long at 53 minutes, it was well worth the time and was pretty impressive.&lt;br /&gt;&lt;br /&gt;Some things I didn't realize was all the default core functionality in grails is plugin based; everything in grails is based on plugins. For example: spring, hibernate, internalionalization, domains, controllers, tab libraries, etc are all plugins.&lt;br /&gt;&lt;br /&gt;On top of that it is really easy to create your own plugin (watch the video above or go &lt;a href="http://grails.codehaus.org/Creating+Plugins"&gt;here&lt;/a&gt;. Here are some of the things you can do with plugins that make them so powerful:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Add new methods, constructors, properties to any class at runtime&lt;/li&gt;&lt;li&gt;Perform runtime Spring configuration instead of depending on some static spring XML file that you wish you could change at runtime&lt;/li&gt;&lt;li&gt;Modify the web.xml on the fly&lt;/li&gt;&lt;li&gt;Add new controllers, domains, tag libraries, etc&lt;/li&gt;&lt;/ul&gt;Here are just a few plugins that already exist:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;XFire - exposes a grails service as a SOAP service&lt;/li&gt;&lt;li&gt;Searchable - integrates compass and lucene search&lt;/li&gt;&lt;li&gt;Remoting - exposes a grails service over RMI, HTTP, or burlap&lt;/li&gt;&lt;li&gt;GWT - integrates grails with Google Web Toolkit&lt;/li&gt;&lt;li&gt;Acegi/JSecurity - adds security support for grails&lt;/li&gt;&lt;li&gt;JMS - exposes grails services as Message Driven Beans&lt;/li&gt;&lt;li&gt;Wicket/JSF/Tapestry - bring in different view frameworks&lt;/li&gt;&lt;li&gt;Dbmigrate - support sql migration&lt;/li&gt;&lt;li&gt;Static resources - helps offload the delivery of static resources to another web server&lt;/li&gt;&lt;li&gt;Jasper Reports - create jasper reports in grails&lt;/li&gt;&lt;/ul&gt;Go here for a complete list: &lt;a href="http://grails.codehaus.org/Plugins"&gt;http://grails.codehaus.org/Plugins&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-498161731927629158?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/498161731927629158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=498161731927629158' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/498161731927629158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/498161731927629158'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/11/impressive-grails-plugin-architecture.html' title='Impressive Grails Plugin Architecture'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-2258131613437276613</id><published>2007-11-21T09:52:00.000-06:00</published><updated>2007-11-21T09:56:57.690-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Best Groovy quote ever</title><content type='html'>I think this pretty much sums up Groovy:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"Groovy is executable psuedo-code"&lt;/span&gt;&lt;br /&gt;Scott Davis&lt;br /&gt;&lt;br /&gt;source http://www.javaworld.com/podcasts/jtech/2007/110107jtech004.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-2258131613437276613?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/2258131613437276613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=2258131613437276613' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2258131613437276613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/2258131613437276613'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/11/best-groovy-quote-ever.html' title='Best Groovy quote ever'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5582702169460191450</id><published>2007-11-16T09:55:00.000-06:00</published><updated>2007-11-16T10:41:18.007-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Javadoc equivalent for Grails (a necessity)</title><content type='html'>Oh yeah! Graeme Rocher and Marc Palmer have done an excellent job creating the Reference Documentation for the &lt;a href="http://grails.codehaus.org/"&gt;Grails Framework&lt;/a&gt; for version 1.0-RC1 (check it out &lt;a href="http://grails.org/doc/RC1/"&gt;http://grails.org/doc/RC1/&lt;/a&gt;). This will be familiar to anyone that has referenced Java's API javadocs like I have for so many years.&lt;br /&gt;&lt;br /&gt;This is an absolute necessity for Grails development IMO due to it's dynamicity (I think I just made that up). Outside of checking out the source, yuck, how else would you know which options are available? This is another piece of the puzzle before the official release of Grails 1.0.&lt;br /&gt;&lt;br /&gt;Here is what the reference documentation covers:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Grails Commands&lt;/span&gt; - detailed usage information for the grails commands like generate-all, test-app, etc.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Constraints&lt;/span&gt; - explains all the current constraints available to Domains like blank, maxSize, etc.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Controllers&lt;/span&gt; - shows all the information available for controllers&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Domain Classes&lt;/span&gt; - shows all methods available to consumers of domain classes like save, validate, find*, etc.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Plugins&lt;/span&gt; - information available for plugins&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Services&lt;/span&gt; - explains things like scope and transactional&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Servlet API&lt;/span&gt; - typicaly servlet stuff like request and response&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Tag Libraries&lt;/span&gt; - information available for tag libraries&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Tags&lt;/span&gt; - tags you can use in your GSP and I am sure, but not certain, in your JSPs.&lt;br /&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/1280619439915049383-5582702169460191450?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/5582702169460191450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=5582702169460191450' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5582702169460191450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5582702169460191450'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/11/javadoc-equivalent-for-grails-necessity.html' title='Javadoc equivalent for Grails (a necessity)'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4300630254665825949</id><published>2007-11-15T08:56:00.000-06:00</published><updated>2007-11-15T08:59:52.836-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>How to remote into Windows from Linux</title><content type='html'>You can easily use rdesktop to remote into a Windows machine from Linux. I am using Ubuntu 7.10 and rdesktop works fast and its easy. The default resolution is really small so here is my command to start it up specifying a different resolution.&lt;br /&gt;&lt;br /&gt;rdesktop -g 1024x800 server&lt;br /&gt;&lt;br /&gt;You can also specify the -f option for full screen mode, but beware it's not easy getting out of rdesktop full mode. Use CRTL+ALT+ENT to exit full screen mode.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4300630254665825949?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4300630254665825949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4300630254665825949' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4300630254665825949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4300630254665825949'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/11/how-to-remote-into-windows-from-linux.html' title='How to remote into Windows from Linux'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-3685006420494714063</id><published>2007-11-05T22:48:00.000-06:00</published><updated>2007-11-05T23:19:08.367-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>New Amazon S3 plugin for Grails</title><content type='html'>Today, &lt;a href="http://www.cantinaconsulting.com/"&gt;Catina Consulting&lt;/a&gt; announced the release of an open source Amazon S3 (Simple Storage Service) &lt;a href="http://www.cantinaconsulting.com/grails-plugins/"&gt;plugin&lt;/a&gt; for &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; with the following goals:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Host and manage file assets on Amazon S3 for storage and performance advantages&lt;/li&gt;&lt;li&gt;Provide easy mechanisms to reference S3-hosted assets in Grails applications&lt;/li&gt;&lt;li&gt;Make most efficient and cost-effective use of S3 hosting resources&lt;/li&gt;&lt;/ul&gt;Their first version appears to be rather useful with some excellent capabilities coming in the future. This first version focuses on managing user uploaded static content. Planned features include supporting different media types, custom bucket schemas, security integration, support for both REST and SOAP (currently only uses REST), and reporting on S3 usage.&lt;br /&gt;&lt;br /&gt;Installation and configuration seem rather simple so it should be rather easy for Grails users to start immediately using this plugin.&lt;br /&gt;&lt;br /&gt;What I think is the most interesting was their ability to reuse the &lt;a href="http://jets3t.s3.amazonaws.com/index.html"&gt;JetS3t Toolkit&lt;/a&gt; which is written in Java. This just goes to show how groovy can really be the glue between Java and how developers can reuse all that existing Java code.&lt;br /&gt;&lt;br /&gt;Go &lt;a href="http://www.amazon.com/S3-AWS-home-page-Money/b/ref=sc_fe_l_2/105-1101932-9816433?ie=UTF8&amp;amp;node=16427261&amp;amp;no=342430011&amp;amp;me=A36L942TSJ2AJA"&gt;here&lt;/a&gt; to learn more about Amazon S3, which is an online storage web service providing unlimited storage through a simple web service interface (REST or SOAP). S3 aims to provide scalability, high availability, and low latency at cheap costs. It accomplishes this by using the same scalable storage infrastructure that amazon.com uses to run its own global e-commerce network.&lt;br /&gt;&lt;br /&gt;For example, &lt;a href="http://smugmug.com/"&gt;Smugmug&lt;/a&gt;, a popular photo sharing web site, is &lt;a href="http://blogs.smugmug.com/onethumb/2006/08/12/amazon-s3-the-holy-grail/"&gt;using it to store and host pictures&lt;/a&gt;. For a simple cost analysis view this &lt;a href="http://jeremy.zawodny.com/blog/archives/007624.html"&gt;post&lt;/a&gt; by Jeremey Zawodny who contemplates using S3 to replace his backup server.&lt;br /&gt;&lt;br /&gt;And finally, I can't leave the Rails community out of this either so &lt;a href="http://www.rubyinside.com/advent2006/1-amazon-s3.html"&gt;here is an article&lt;/a&gt; on using the rails &lt;a href="http://amazon.rubyforge.org/"&gt;AWS::S3 library&lt;/a&gt; (this plugin is more feature complete than the grails plugin).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-3685006420494714063?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/3685006420494714063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=3685006420494714063' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3685006420494714063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/3685006420494714063'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/11/new-amazon-s3-plugin-for-grails.html' title='New Amazon S3 plugin for Grails'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8281458073122304214</id><published>2007-10-31T00:02:00.000-05:00</published><updated>2007-10-31T00:29:16.226-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Using Groovy to easily avoid nasty NullPointerException</title><content type='html'>&lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; supports a pretty neat &lt;a href="http://en.wikipedia.org/wiki/Syntactic_sugar"&gt;syntactic sugar&lt;/a&gt; operator to easily avoid the ugly &lt;span style="font-style: italic;"&gt;NullPointerException&lt;/span&gt;: the question mark '?'.&lt;br /&gt;&lt;br /&gt;Writing this in Java&lt;br /&gt;&lt;pre&gt;&lt;code&gt;if (name != null &amp;amp;&amp;amp; param1 != null &amp;amp;&amp;amp; param1.getUser() != null &amp;amp;&amp;amp; name.equals(param1.getUser().getName()))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;is now replaced by the much more readable Groovy&lt;br /&gt;&lt;pre&gt;&lt;code&gt;if (name &amp;amp;&amp;amp; param1 &amp;amp;&amp;amp; (name == param1.user?.name))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Amazing how a single character can improve readability that much and avoid potential NPEs. Also if you are curious about my use of &lt;span style="font-style: italic;"&gt;==&lt;/span&gt; rather than the Java required &lt;span style="font-style: italic;"&gt;.equals()&lt;/span&gt; see my post on &lt;a href="http://jlorenzen.blogspot.com/2007/10/more-groovy-sugar.html"&gt;More Groovy Sugar&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Most importantly I have inserted a hidden clue in this post and the first to solve the mystery will receive a free pop of their choice not to exceed 0.77 cents. The winner will be the first commenter with the correct answer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8281458073122304214?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8281458073122304214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8281458073122304214' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8281458073122304214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8281458073122304214'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/using-groovy-to-easily-avoid-nasty.html' title='Using Groovy to easily avoid nasty NullPointerException'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4133383122819612527</id><published>2007-10-28T23:47:00.000-05:00</published><updated>2007-10-28T23:59:21.161-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Using maven with Grails</title><content type='html'>By default &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; comes with an &lt;a href="http://ant.apache.org/"&gt;Ant&lt;/a&gt; build file to control your web application. For some of us this seems like a step backwards in technology (although apparently not for &lt;a href="http://graemerocher.blogspot.com/2006/09/vote-to-stop-maven-infesting-spring.html"&gt;Graeme Rocher&lt;/a&gt; the Grails mastermind). Even though Grails doesn't support maven 1 or 2, you can get support for dependency resolution via &lt;a href="http://incubator.apache.org/projects/ivy.html"&gt;Ivy&lt;/a&gt; (see &lt;a href="http://grails.codehaus.org/Ivy+Integration"&gt;Using Ivy for Dependency Resolution&lt;/a&gt;). Another option available is called &lt;a href="http://forge.octo.com/confluence/display/MTG/Home"&gt;Maven Tools for Grails&lt;/a&gt; (MTG). It sounds pretty promising and an improvement over Ivy, but their most recent release (v0.2) appears to work only with Grails 0.5.6 and 0.6; the current release of Grails is 1.0-RC1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4133383122819612527?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4133383122819612527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4133383122819612527' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4133383122819612527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4133383122819612527'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/using-maven-with-grails.html' title='Using maven with Grails'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5326386302184440565</id><published>2007-10-28T23:31:00.000-05:00</published><updated>2007-10-28T23:47:03.740-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails vs Rails comparison</title><content type='html'>While following some of the Grails and Rails tutorials (&lt;span style="font-weight: bold;"&gt;Grails&lt;/span&gt;: &lt;a href="http://www.amazon.com/Definitive-Guide-Grails/dp/1590597583/ref=pd_bbs_1/105-1101932-9816433?ie=UTF8&amp;amp;s=books&amp;amp;qid=1193246191&amp;amp;sr=8-1"&gt;The Definitive Guide to Grails&lt;/a&gt;. &lt;span style="font-weight: bold;"&gt;RoR&lt;/span&gt;: &lt;a href="http://media.rubyonrails.org/video/rails_take2_with_sound.mov"&gt;Creating a weblog in 15 minutes&lt;/a&gt;) I noticed a big difference on how they approach development. Consequently, I started a thread (&lt;a href="http://www.nabble.com/Dynamic-Domain-classes-tf4685827.html#a13391027"&gt;Dynamic Domain classes&lt;/a&gt;) on the Grails &lt;a href="http://grails.codehaus.org/Mailing+lists"&gt;user mailing list&lt;/a&gt; to confirm. What I found, thanks to Tim Pidgen, was that Grails is intentionally domain-centric (ie model-centric) whereas Rails is more database-centric. What's the difference? With Grails you modify the domain classes (models) and the database is updated automatically. So properties are explicitly defined in the Grails domain classes; no database modification. Conversely, with Rails you create your "empty" model class and after you modify the database (add new fields to a table) you can just refresh the page; no need to add variables to your models.&lt;br /&gt;&lt;br /&gt;Not sure either one is right or wrong; just wanted to point out the differences because it is a pretty significant difference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5326386302184440565?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/5326386302184440565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=5326386302184440565' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5326386302184440565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5326386302184440565'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/grails-vs-rails-comparison.html' title='Grails vs Rails comparison'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8274992193688872875</id><published>2007-10-28T22:11:00.000-05:00</published><updated>2007-10-28T23:20:35.780-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='j2ee'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>No more J2EE webapps</title><content type='html'>I got my start in my programming career over 7 years ago developing web applications as part of the intranet group for a Fortune 500 company. The group was switching from developing in Haht (I believe back then it was some type of vbscript) to Java (JSPs and Servlets). I joined the group at the moment they switched to Weblogic 5.1, JDK 1.3, and Oracle 8i (I think). It was a fast paced environment as we cranked out one internal application after another. Of course back then I wasn't the best web developer, but by the time I left I felt pretty confident in being able to hold my own (but humble at the same time).&lt;br /&gt;&lt;br /&gt;One thing that always stayed the same throughout creating each one of those applications was the ability to &lt;span style="font-style: italic; font-weight: bold;"&gt;rapidly develop&lt;/span&gt; them. What do I mean by rapidly develop? To me this means making a change and being able to switch to my browser and verify that change and repeating that hundreds of times a day.&lt;br /&gt;&lt;br /&gt;That is how things were when I moved on 5 years later: (change + save + refresh) x 100s. Now it has been around 2 years since I have developed a real web application and for some reason that process has disappeared. For some reason my fellow J2EE developers have come to accept the process of rebuilding and hot deploying or even restarting the application server FOR EVERY CHANGE! Thousands or even millions of minutes are lost everyday by J2EE developers out there producing software like this. And to that I say, not good enough.&lt;br /&gt;&lt;br /&gt;Maybe I am missing something; if so please enlighten me by commenting to this post. Take the JBoss Application Server (AS) 4.2.1 for example. I have tried finding better ways to deploy a WAR (exploded or bundled) on JBoss with no luck. The best I can come up with is increasing the JVMs PermSpace for better hot deployment (&lt;a href="http://docs.jboss.org/seam/1.2.1.GA/reference/en/html/gettingstarted.html"&gt;article&lt;/a&gt;), but I am still left with having to rebuild the WAR and copying it over. And sooner or later I have to restart the server. What a waste.&lt;br /&gt;&lt;br /&gt;At one time there use to be a really slick &lt;a href="http://www.codeczar.com/products/maven-tomcat-plugin/download.html"&gt;maven 1 tomcat plugin&lt;/a&gt; made by codeczar.com that supported the ability to tell tomcat where your webapp was, preventing you from having to rebuild and redeploy. It was a huge time saver, but unfortunately this plugin is no longer supported (&lt;a href="http://masterdev.dyndns.dk/dev/14.html"&gt;see here&lt;/a&gt;). If you are curious you can still get this plugin &lt;a href="http://64.233.167.104/search?q=cache:31_RXJ0QvQ8J:www.codeczar.com/maven/codeczar-tomcat/plugins/%3FC%3DM%3BO%3DA+codeczar+maven+tomcat+plugin&amp;amp;hl=en&amp;amp;ct=clnk&amp;amp;cd=5&amp;amp;gl=us&amp;amp;client=firefox-a"&gt;here&lt;/a&gt; thanks to Google Cache. The documentation has also been copied &lt;a href="http://masterdev.dyndns.dk/dev/14.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Where does that leave me? Any language that lets me develop at a fast rate. Even if I lose tons of reusable components. I would imagine the time I save not rebuilding/redeploying more than makes up for reusable components and other goodies J2EE offers. In fact that has been the main reason for my personal quest to learn &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; and &lt;a href="http://www.rubyonrails.com/"&gt;Rails&lt;/a&gt;. To me these languages offer the ability to deliver faster and cheaper and I believe this &lt;a href="http://alterlabs.com/technologies/java/grails-vs-rails-the-thrilla-in-manilla-a-study-on-grails-productivity/"&gt;article&lt;/a&gt; supports that. If I had to start a new web project I would definitely look long and hard at either Grails or Rails.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8274992193688872875?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8274992193688872875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8274992193688872875' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8274992193688872875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8274992193688872875'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/no-more-j2ee-webapps.html' title='No more J2EE webapps'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>25</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4840482888815380372</id><published>2007-10-25T23:42:00.000-05:00</published><updated>2007-10-25T23:56:00.569-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Effectively using Groovy Console in Grails App</title><content type='html'>Each chapter in &lt;a href="http://www.amazon.com/Definitive-Guide-Grails/dp/1590597583/ref=pd_bbs_1/105-1101932-9816433?ie=UTF8&amp;amp;s=books&amp;amp;qid=1193246191&amp;amp;sr=8-1"&gt;The Definitive Guide to Grails&lt;/a&gt; continues to impress me. Currently I am on Chapter 4 which discusses The Application Domain. In this chapter the author uses the Groovy console within the grails app to test the domains to get some quick feedback. I got to say this ability is awesome! Not only could you do some quick testing, but I am sure it would be great for debugging purposes as well. Now obviously we want to keep testing in the console at a minimum and continue writing those unit tests, but that isn't until chapter 6. So until then here is how you can use the console in your grails app.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Prerequisites&lt;/span&gt;&lt;br /&gt;1) Already created a grails app: &lt;span style="font-weight: bold;"&gt;grails create-app bookmarks&lt;/span&gt;&lt;br /&gt;2) Created at least one domain: &lt;span style="font-weight: bold;"&gt;grails create-domain-class Bookmark&lt;/span&gt;&lt;br /&gt;3) Added some properties to the Bookmark domain (URL url)&lt;br /&gt;&lt;br /&gt;Now cd into the &lt;span style="font-style: italic;"&gt;bookmarks&lt;/span&gt; directory and run &lt;span style="font-weight: bold;"&gt;grails console&lt;/span&gt;. This will compile your domain class and make it available to the console. Then execute the following (CRTL + R):&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def bookmark = new Bookmark(url: new URL("http://jlorenzen.blogspot.com"))&lt;br /&gt;println 'Bookmark url is ' + bookmark.url&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;You should see the following output:&lt;br /&gt;Bookmark url is http://jlorenzen.blogspot.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4840482888815380372?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4840482888815380372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4840482888815380372' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4840482888815380372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4840482888815380372'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/effectively-using-groovy-console-in.html' title='Effectively using Groovy Console in Grails App'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-4954517320741206277</id><published>2007-10-24T23:22:00.000-05:00</published><updated>2007-10-24T23:30:45.839-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails Tip: Enable SQL Logging</title><content type='html'>Here is a great tip while developing a &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; application to enable SQL logging (I would only recommend this in development mode).&lt;br /&gt;In your grails project add the loggingSql = true property to the development closure and that is it. This was using Grails 1.0-RC1.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;development {&lt;br /&gt;   dataSource {&lt;br /&gt;       dbCreate = "create-drop" // one of 'create', 'create-drop','update'&lt;br /&gt;       url = "jdbc:hsqldb:mem:devDB"&lt;br /&gt;       loggingSql = true              &lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;Then after starting your app (&lt;span style="font-style: italic;"&gt;grails run-app&lt;/span&gt;) the SQL will be displayed. I was actually surprised for some reason when the list action was doing a specific select statement like "&lt;span style="font-style: italic;"&gt;select title, author from book&lt;/span&gt;" rather than "&lt;span style="font-style: italic;"&gt;select * from book&lt;/span&gt;".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-4954517320741206277?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/4954517320741206277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=4954517320741206277' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4954517320741206277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/4954517320741206277'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/grails-tip-enable-sql-logging.html' title='Grails Tip: Enable SQL Logging'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-7224928078752259184</id><published>2007-10-24T16:13:00.000-05:00</published><updated>2007-10-24T16:15:04.906-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Hotswap ability with JavaRebel</title><content type='html'>Here is a good article on using JavaRebel to reload your webapp changes without a hotdeploy like Rails and Grails do.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://stephan.reposita.org/archives/2007/10/11/javarebel-impressions-java-reload-just-like-in-rails/"&gt;http://stephan.reposita.org/archives/2007/10/11/javarebel-impressions-java-reload-just-like-in-rails/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-7224928078752259184?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/7224928078752259184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=7224928078752259184' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7224928078752259184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/7224928078752259184'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/hotswap-ability-with-javarebel.html' title='Hotswap ability with JavaRebel'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-389851913869313375</id><published>2007-10-24T12:58:00.000-05:00</published><updated>2007-10-24T13:04:47.541-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>A Groovy switch/case example</title><content type='html'>Below is an example of Groovy's switch/case feature taken from &lt;a href="http://www.amazon.com/Definitive-Guide-Grails/dp/1590597583/ref=pd_bbs_1/105-1101932-9816433?ie=UTF8&amp;amp;s=books&amp;amp;qid=1193246191&amp;amp;sr=8-1"&gt;The Definitive Guide to Grails&lt;/a&gt; by Graeme Rocher. I am not a regular user of Java's switch/case feature, but if it had been this way perhaps I might have.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;switch (x) {&lt;br /&gt;   case 'James':&lt;br /&gt;       println "yes it is me"&lt;br /&gt;       break&lt;br /&gt;   case 18..65:&lt;br /&gt;       println "ok you are old"&lt;br /&gt;       break&lt;br /&gt;   case ~/Gw?+e/:&lt;br /&gt;       println "your name starts with G and ends in e!"&lt;br /&gt;       break&lt;br /&gt;   case Date:&lt;br /&gt;       println 'got a Date instance'&lt;br /&gt;       break&lt;br /&gt;   case ['John', 'Ringo', 'Paul', 'George']:&lt;br /&gt;       println "Got one of the Beatles"&lt;br /&gt;       break&lt;br /&gt;   default:&lt;br /&gt;       println "Don't know"&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-389851913869313375?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/389851913869313375/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=389851913869313375' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/389851913869313375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/389851913869313375'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/groovy-switchcase-example.html' title='A Groovy switch/case example'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-5283670859893332262</id><published>2007-10-24T12:21:00.001-05:00</published><updated>2007-10-24T12:52:30.198-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>More Groovy Sugar</title><content type='html'>&lt;a href="http://joe.kueser.com/"&gt;Joe Kueser&lt;/a&gt; has some excellent posts on Groovy features (&lt;a href="http://joe.kueser.com/2007/10/06/what-makes-groovy-sogroovy/"&gt;What Makes Groovy...So Groovy&lt;/a&gt; and &lt;a href="http://joe.kueser.com/2007/10/13/more-groovy-goodies/"&gt;More Groovy Goodies&lt;/a&gt;) and I would like to attempt to build on them. He has been nice enough to let me borrow &lt;a href="http://www.amazon.com/Definitive-Guide-Grails/dp/1590597583/ref=pd_bbs_1/105-1101932-9816433?ie=UTF8&amp;amp;s=books&amp;amp;qid=1193246191&amp;amp;sr=8-1"&gt;The Definitive Guide to Grails&lt;/a&gt;, which so far has been an excellent resource for Groovy and Grails (probably one of the best technical books I have read in awhile).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Expando Objects&lt;/span&gt;&lt;br /&gt;Joe does a nice job of explaining this handy new class. Here is another example taken from the Grails book by Rocher:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;fred = new Expando()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;fred.firstName = "Fred"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;fred.lastName = "Smith"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;fred.age = 40&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;fred.happyBirthday = {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fred.age++&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;fred.happyBirthday()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;assert fred.age == 41&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can easily play around with this code with groovy's console (/GROOVY_HOME/bin/groovyConsole). As you can see &lt;span style="font-style: italic;"&gt;Expando&lt;/span&gt; allows you to define an object, its properties, and its methods at run time. Keep in mind that a method is defined by setting a closure to a property that can be later called like a regular method. One immediate use I can see for &lt;span style="font-style: italic;"&gt;Expando&lt;/span&gt; is in unit tests.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy's == operator&lt;/span&gt;&lt;br /&gt;This is very important for existing Java developers. Groovy's &lt;span style="font-style: italic;"&gt;==&lt;/span&gt; operator is different than Java's in that it does not evaluate object identity, rather it delegates to the object's &lt;span style="font-style: italic;"&gt;equals&lt;/span&gt; method. To accomplish object comparison, Groovy introduces a new &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; method: &lt;span style="font-style: italic;"&gt;left.is(right)&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Groovy Truth&lt;/span&gt;&lt;br /&gt;Term used by Rocher in the Grails book and coined by Dierk Koenig, that explains the Groovy concept of what is true and what is not. Here is an example of what can be passed to &lt;span style="font-style: italic;"&gt;if&lt;/span&gt; statements in Groovy and will evaluate to &lt;span style="font-style: italic;"&gt;false:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A &lt;span style="font-style: italic;"&gt;null&lt;/span&gt; reference&lt;/li&gt;&lt;li&gt;An empty or &lt;span style="font-style: italic;"&gt;null&lt;/span&gt; string&lt;/li&gt;&lt;li&gt;The number zero&lt;/li&gt;&lt;li&gt;A regex &lt;span style="font-style: italic;"&gt;Matcher&lt;/span&gt; that doesn't match&lt;/li&gt;&lt;/ul&gt;This makes those nasty Java &lt;span style="font-style: italic;"&gt;if&lt;/span&gt; statements much cleaner.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;if (str != null &amp;amp;&amp;amp; str.length() != 0 )&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;now becomes&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;if (str)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;More &lt;span style="color: rgb(0, 153, 0);"&gt;Mt. Dew&lt;/span&gt; sugar to come.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-5283670859893332262?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/5283670859893332262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=5283670859893332262' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5283670859893332262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/5283670859893332262'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/more-groovy-sugar.html' title='More Groovy Sugar'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1442373275171446865</id><published>2007-10-23T12:07:00.000-05:00</published><updated>2007-10-23T12:17:19.894-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jboss'/><title type='text'>Enabling remote access to JBoss 4.2</title><content type='html'>Today I had an issue remotely accessing my &lt;a href="http://www.jboss.org/products/jbossas"&gt;JBoss&lt;/a&gt; instance running on another machine. Unknowingly, JBoss 4.2 binds specifically to 127.0.0.1 by default (see below for me details). Thankfully they had a simple solution; just append -b 0.0.0.0 to your startup script to bind to all interfaces. So to start JBoss on linux when I know I want to access it remotely I do:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;./jboss/bin/run.sh -b 0.0.0.0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ReadMe.html content on this subject&lt;/span&gt;:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"JBossAS now binds its services to localhost (127.0.0.1) *by default*, instead of binding to all available interfaces (0.0.0.0). This was primarily done for security reasons because of concerns of users going to production without having &lt;/span&gt;&lt;a style="font-style: italic;" href="http://wiki.jboss.org/wiki/Wiki.jsp?page=SecureJBoss"&gt;secured their servers properly&lt;/a&gt;&lt;span style="font-style: italic;"&gt;. To enable remote access by binding JBoss services to a particular interface, simply run jboss with the -b option. To bind to all available interfaces and re-enable the legacy behavior use -b 0.0.0.0. In any case, be aware you still need to &lt;/span&gt;&lt;a style="font-style: italic;" href="http://wiki.jboss.org/wiki/Wiki.jsp?page=SecureJBoss"&gt;secure you server properly&lt;/a&gt;&lt;span style="font-style: italic;"&gt;."&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1442373275171446865?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1442373275171446865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1442373275171446865' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1442373275171446865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1442373275171446865'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/enabling-remote-access-to-jboss-42.html' title='Enabling remote access to JBoss 4.2'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-8604936473297098372</id><published>2007-10-21T23:33:00.000-05:00</published><updated>2007-10-21T22:34:21.596-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Great JetGroovy plugin feature for Idea+Grails</title><content type='html'>Just started using the &lt;a href="http://groovy.codehaus.org/IntelliJ+IDEA+Plugin"&gt;JetGroovy plugin&lt;/a&gt; in Idea and I have to say initially it Rocks! Included is a screenshot of the plugin in Idea version 7 after I created a domain (aka model). Notice how there are nifty buttons for that domains Controller, Views, Domain Tests, and Controller Tests. I was constantly using this ability even in the 5 minutes it took me to create my Hello World grails app. Nice work guys.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_u6FjI-f0VoU/RxwZxDWtdlI/AAAAAAAAACI/xpowF3VIWxE/s1600-h/grails.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_u6FjI-f0VoU/RxwZxDWtdlI/AAAAAAAAACI/xpowF3VIWxE/s400/grails.png" alt="" id="BLOGGER_PHOTO_ID_5123998806545626706" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-8604936473297098372?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/8604936473297098372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=8604936473297098372' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8604936473297098372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/8604936473297098372'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/great-jetgroovy-plugin-feature-for.html' title='Great JetGroovy plugin feature for Idea+Grails'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_u6FjI-f0VoU/RxwZxDWtdlI/AAAAAAAAACI/xpowF3VIWxE/s72-c/grails.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1280619439915049383.post-1799139133048138685</id><published>2007-10-21T22:46:00.000-05:00</published><updated>2007-10-21T21:52:02.096-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Tip for using Grails in Idea</title><content type='html'>Recently I tried creating my first &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; application using the &lt;a href="http://groovy.codehaus.org/IntelliJ+IDEA+Plugin"&gt;JetGroovy plugin&lt;/a&gt; available in &lt;a href="http://www.jetbrains.com/idea/"&gt;Idea&lt;/a&gt; (version 7.0). However, I have Linux (Ubuntu 7.10) and you don't get those nice little icons to start Idea when you install it. Consequently when I tried to create a new Grails project I received the following error:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;grails: JAVA_HOME is not defined correctly; can not execute: java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;How in the world is that possible I thought to myself? What half decent java programmer doesn't have JAVA_HOME set? Oh but then I remembered my special start script responsible for starting Idea. Idea requires the variable JDK_HOME to be set, but Grails within Idea needs JAVA_HOME. Therefore, here is my new script I use to start Idea 7 which allows me to create new Grails projects. And don't forget Idea 7 on Linux requires JDK 1.6.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;sh -c 'export JDK_HOME=/workspace/java/jdk1.6.0_03;export JAVA_HOME=/workspace/java/jdk1.5.0_12;/workspace/java/idea-7361/bin/idea.sh'&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1280619439915049383-1799139133048138685?l=jlorenzen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlorenzen.blogspot.com/feeds/1799139133048138685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1280619439915049383&amp;postID=1799139133048138685' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1799139133048138685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1280619439915049383/posts/default/1799139133048138685'/><link rel='alternate' type='text/html' href='http://jlorenzen.blogspot.com/2007/10/jetgroovy-plugin-tip-in-linux.html' title='Tip for using Grails in Idea'/><author><name>jlorenzen</name><uri>http://www.blogger.com/profile/13635369821860631868</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_u6FjI-f0VoU/RpbmnRO0YmI/AAAAAAAAAAY/UsXUQSqy_5A/s200/jlorenzen.jpg'/></author><thr:total>0</thr:total></entry></feed>
