<?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-7850659753537165932</id><updated>2011-12-06T03:04:19.286-05:00</updated><category term='ruby'/><category term='hibernate'/><category term='quartz'/><category term='java'/><category term='speaking'/><category term='schedule'/><category term='books'/><category term='hatred'/><category term='thanks'/><category term='macfu'/><category term='goals'/><category term='interviewer'/><category term='principles'/><category term='conference'/><category term='interview'/><category term='osgi'/><category term='people'/><category term='agile'/><category term='quick'/><category term='opensource'/><category term='software'/><category term='spring'/><category term='kanban'/><category term='pillar'/><category term='jruby'/><category term='testing'/><title type='text'>The Todd on Tech</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>50</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1719196673928181991</id><published>2011-09-01T09:00:00.000-04:00</published><updated>2011-09-01T09:00:01.486-04:00</updated><title type='text'>Show your Debt</title><content type='html'>&lt;p&gt;I had an interesting twitter debate a couple weeks ago with a bunch of people I really respect and admire. A good number of them totally disagreed with what I was saying though, so in order to maintain my large ego, I’m going to chalk it up to 140 character limitations and try to expand on my thoughts here.&lt;/p&gt;  &lt;p&gt;The crux of the discussion is this. Our team had recently imposed a limit on the number of refactoring or technical debt cards in process at any given time in our system. The reason for this was that we had a couple of iterations where we accomplished some significant changes to the code base which will result in longer term savings and easier maintenance, but the product owner and sales organizations that we work with didn’t really get to see much visible progress on the software for a couple of weeks. We felt that we should spread out the tech debt cards so that the product owner and stakeholders could still get to see progress every week, yet still empower our team to play the tech debt cards as they see fit. So my open question on twitter was: &lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh4.ggpht.com/-LFXU4JfLYsI/Tl5GoWkg1yI/AAAAAAAAAOI/CbMDykjuXio/s1600-h/image%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-B-xKvMP_gpg/Tl5GojpZpOI/AAAAAAAAAOM/5MaCkuLvCmE/image_thumb%25255B1%25255D.png?imgmax=800" width="436" height="243" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The consistent push back against my comment was some form of “Why do you have refactoring items on your board?”, as my colleagues mention here:&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/-wZUAGsKhh2E/Tl5Gox04kVI/AAAAAAAAAOQ/z8sEjU2oTT0/s1600-h/image%25255B6%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-kuCCj3mow4U/Tl5GpQ2USaI/AAAAAAAAAOU/9JnJ283Zzj8/image_thumb%25255B2%25255D.png?imgmax=800" width="244" height="143" /&gt;&lt;/a&gt;&lt;a href="http://lh4.ggpht.com/-tSvder24qOg/Tl5GppJvSBI/AAAAAAAAAOY/5vYx8cPwXMY/s1600-h/image%25255B9%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-n5nxvkE7TtI/Tl5Gp2Jf41I/AAAAAAAAAOc/_QyY0rMH_iU/image_thumb%25255B3%25255D.png?imgmax=800" width="244" height="144" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;A lot of people felt that we should just have completed the refactoring as we finished the card. I am not saying that we are not doing refactoring as we are delivering stories and I’m not saying we have an extensive list of refactoring items. We have a solid team with many members who teach and coach others on TDD and the red, green, refactor cycle.&amp;#160; The refactoring items or technical debt that we’re tracking are typically orthogonal to a user story we’re currently working on. Consider a fictional example to illustrate the point.&lt;/p&gt;  &lt;p&gt;Say you are building a website that sells index cards. The website may have some domain objects like a user, product, address, etc… You have decided to use validation framework X to validate the data that users enter for these objects.&amp;#160; This works well until you run into the account domain object. Here there is much more extensive acceptance criteria around the validation of credit card information which isn’t easily accomplished using validation framework X. The team completes a spike and determines that validation framework Y is the right approach so the account creation user story is completed with a new validation framework Y. The team collectively decides that having two validation frameworks is confusing and since Y is the superset of X, that they should standardize on using Y throughout the system. What do you do?&lt;/p&gt;  &lt;p&gt;I think many of my peers seem to be suggesting that we should just complete the validation framework swap while working on the account creation user story. I don’t like this for a number of reasons. First, the completed account creation user story is delayed from moving through the rest of the system. I’d rather my product owner or exploratory tester start hammering on the new story (and validation framework) before I start expanding this to the rest of the system. We would be able to see any deficiencies in the new framework prior to swapping everything over and avoid a potentially painful conversion back. If the validation framework swap was a day or more worth of work, then we’d also run the risk of not demoing a completed user story to the rest of the team when really that work is done.&lt;/p&gt;  &lt;p&gt;I also think the team would be better served to prioritize this work when they feel it is most important. &lt;em&gt;Collectively&lt;/em&gt;. Completing large refactoring or technical work in under the guise of a user story is fairly disingenuous to the product owner. Maybe we’re just lucky because we have a product owner who really sees the potential maintenance costs of not doing these refactorings, but we’ve never felt like we needed to be anything but open and honest about the work that lays ahead. Added bonus here is that if a tech debt card, like swapping out your entire validation framework needs to be played, it can be planned in a way that may not cause significant merge pain for the rest of the team.&lt;/p&gt;        &lt;p&gt;I think the discussion on twitter may have been largely a semantic argument about what is technical debt versus refactoring, but I want to make sure my points here are clear. Whether calling technical cards a user story, refactoring card, or tech debt card, make sure that they are planned, prioritized, and completed in the same visible manner as other cards in the system. The board should be a mirror of the work, the work shouldn’t have to be forced to fit into the board.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1719196673928181991?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1719196673928181991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1719196673928181991' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1719196673928181991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1719196673928181991'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2011/09/show-your-debt.html' title='Show your Debt'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/-B-xKvMP_gpg/Tl5GojpZpOI/AAAAAAAAAOM/5MaCkuLvCmE/s72-c/image_thumb%25255B1%25255D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-2926806872935365177</id><published>2011-08-11T08:30:00.001-04:00</published><updated>2011-08-11T09:11:55.355-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='kanban'/><title type='text'>Why we went Kanban</title><content type='html'>&lt;p&gt;I don’t think any single process is the best fit for all teams. Teams and projects using Scrum, Kanban, Waterfall, or any other custom process you can think of have been successful in the past. In my opinion, the most important thing to keep in mind is that the process should be constantly evolving, similar to the software that you are building.&lt;/p&gt;  &lt;p&gt; We recently started a new project off with 1 week iterations as they seemed to be a good balance between a client who was coming from a waterfall background and our team, who was experienced in agile development eager to get show off completed functionality as soon as possible. A few retrospectives ago, we found a number of us were openly questioning why we weren’t using Kanban. So as any adaptive, continually improving team would do, we switched. There are a number of reasons for moving to a pull based model, but here were the top ones for our team.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Estimates were WASTE&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;We performed our demo, retrospective, and planning on Friday of each week. This was usually accomplished in 4 hours or less but by far, the most significant portion of that time was spent discussing and estimating the stories for the next week. We continually struggled to balance how much discussion was needed to properly understand the solution without totally solving the problem within the discussion. With a team of 4 or more developers, the time spent determining whether or not a card was a 3 pointer or a 5 pointer was not trivial. It was however WASTE, and it leads me to my next point.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-VACITq5Vcbc/Tj__QJx57OI/AAAAAAAAAN0/J8dn_w9RhT0/s1600-h/5846058698_809e782a00_b3.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="5846058698_809e782a00_b" border="0" alt="5846058698_809e782a00_b" align="right" src="http://lh6.ggpht.com/-GZIXzyVA8p8/Tj__QS5ZVZI/AAAAAAAAAN4/fbp09s571fo/5846058698_809e782a00_b_thumb1.jpg?imgmax=800" width="351" height="240" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Track output, not arbitrary numbers&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;We had been tracking overall burn down based on the number of high level stories identified anyway so the specific number of points that we accomplished in any given week were just a number. Across projects that I’ve been a part of recently, the points and further, velocity as a weekly total of those points, generally winds up becoming at best an arbitrary number and at worst a point of contention or undo pressure. Clients wind up believing that the team is gaming the number of points and the team has to listen to the endless sighs and groans when a card is estimated at 5 points. Screw the points. Get rid of them and instead track either how many cards are being accomplished over time, or better yet the cycle time of cards.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Planning sessions are no substitute for conversations&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Another bad habit that we had gotten into was trying to provide cursory information on a card or in TFS work items, discussing that during the planning session, and then just kicking the feature over to the developers to work on during the week. Cards need to be a promise for a future conversation. Without some level of collaboration between product owner and developer, you really don’t get all of the detail flushed out. Further, doing that conversation in a long meeting a few days prior to starting the work inevitably results in details being lost or having to be rehashed in the form of defects or new cards. Since moving to Kanban, we began to execute conversations about the cards in real time much more often. This has inevitably led to less defects or missing requirements coming back into the system.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;What’s going to work?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Teamwork! Our project had a couple iterations where our product owner and QA were frustrated by the lack of time they had to test the application before demoing to end users. Ultimately the team is to blame and should’ve realized that having 8 features partially tested and completed is less valuable than having 4 features DONE. When developers are prohibited from pulling another feature forward until stalled cards in QA are moved to done, they immediately begin helping in areas they might otherwise thumb their nose at. It also facilitates in focusing product owners and BA types on keeping a nice stack of prioritized stories ready for development.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;a href="http://lh4.ggpht.com/-XOKK5TjAZfk/Tj__QmMiJOI/AAAAAAAAAN8/V-zTHqpcKJc/s1600-h/user-stories3.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="user-stories" border="0" alt="user-stories" align="left" src="http://lh6.ggpht.com/-Do3g89sK4H4/Tj__QzJf-AI/AAAAAAAAAOA/CjbJusCswLs/user-stories_thumb1.jpg?imgmax=800" width="375" height="241" /&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Better Stories&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Kanban doesn’t write your user stories or even provide better visibility into your user stories. It does however, eliminate some boundaries that are counter productive. When a team feels that a user story must be decomposed into chunks that fit nicely into iterations they may begin to create cards that have many interdependencies. If a project has a bunch of interdependencies within user stories, it will also have significant issues with stories not being testable until other stories are done. Is it worse to have a story that spans an arbitrary segment of time or to have 4 developers all stepping on each other trying to complete small portions of a single large story? In my opinion the former is much better and Kanban doesn’t prohibit it.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt; I don’t believe everyone should change their process to Kanban. I do believe everyone should evolve their process, though. Kanban definitely seems to be the better fit for our group, but I’m confident it will continue to change before our project is done. In the last couple of weeks using it compared to the prior months of doing weekly iterations, we are communicating more, resolving defects in real time, and collaborating with our product owner much more tightly. This works for us, but as always, use your noodle to determine what works for you. Most importantly, don’t be afraid to change it up!   &lt;p&gt;&lt;em&gt;&lt;font size="1"&gt;Numbers photo courtesy of c a r a m e l on flickr. &lt;/font&gt;&lt;/em&gt;&lt;em&gt;&lt;font size="1"&gt;User Stories photo courtesy of jakuza on flickr.&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-2926806872935365177?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/2926806872935365177/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=2926806872935365177' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2926806872935365177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2926806872935365177'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2011/08/why-we-went-kanban.html' title='Why we went Kanban'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/-GZIXzyVA8p8/Tj__QS5ZVZI/AAAAAAAAAN4/fbp09s571fo/s72-c/5846058698_809e782a00_b_thumb1.jpg?imgmax=800' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-455926635448540158</id><published>2011-07-29T01:24:00.001-04:00</published><updated>2011-07-29T01:24:22.890-04:00</updated><title type='text'>Thank You Coimbatore</title><content type='html'>&lt;p&gt;It’s difficult to put into words what a eye opening experience it’s been coaching our development team in Coimbatore, India over the last three weeks. As with anyone, my view of people and the world is largely limited by lack of experience. An interaction here or there with an India based development team has really been all that I have had to base my experiences on and with this limited experience I’ve come to realize I’ve developed some unrealistic beliefs about IT in India. I’m extremely thankful for the opportunity to dispel many of the myths that I’ve had about this gigantic and growing population of developers in India. Here are the top ones:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Myth #1: Indian Developers are&amp;#160; Subpar&lt;a href="http://lh5.ggpht.com/-1882zNHy3UA/TjJD2dwBiMI/AAAAAAAAANY/eEKHetZOflI/s1600-h/image11.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" align="right" src="http://lh3.ggpht.com/-18SsZSedK_I/TjJD4RBH7OI/AAAAAAAAANc/19UJSXeZeTM/image_thumb4.png?imgmax=800" width="332" height="260" /&gt;&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I had assumed that the caliber of development with the team over here would be pretty substandard. I’ve worked with a couple of different offshoring teams and interacted with a number of people who have done the same. The common lessons learned across those interactions have been, don’t give the offshore team any challenging work and relentlessly review the code when it comes back in. Many people I know attribute this to a lack of technical knowledge with the offshore developers. People believe they are only a year or so out of school and that they don’t&amp;#160; have anywhere close to the amount of programming time that their counterparts in the US have.&lt;/p&gt;  &lt;p&gt;Maybe this holds true for bigger segments of developers, but we were extremely fortunate to have six really talented developers on our team. Additionally, within the sixty developer company where they work they are more the norm than the exception. Each team member was extremely comfortable in C#, .NET, SQL, and a number of other technical skills. When technologies were new to the team, they were able to quickly and effectively pick up working knowledge of the tools with a little help from us. We quickly changed our plan from trying to teach technical skill to teaching craft and improving process within our first couple days here. In my opinion the difference between the developers I work with back home and the ones over here is mainly just experience with test driving development. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Myth #2: Communication Will be Easy&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Everyone speaks English right? Well at least a country that was colonized by England speaks English, right? Uh, no. The difference between the Indians who have frequently interacted with Americans and those who haven’t was astounding. Communicating with our taxi driver was largely primitive grunting and pointing. There were two members of our group were fluent in English and had little trouble understanding us when we slowed our pace of speech down to a reasonable level. The other five members of the team had difficulty understanding us unless we were gesturing, speaking very slowly and enunciating very well. Neither Tim nor I were able to master speaking to this group effectively. &lt;a href="http://lh3.ggpht.com/-pUX6vbQVd1w/TjJD5_UBLUI/AAAAAAAAANg/l152_dbzgRc/IMG_26807.jpg?imgmax=800"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="IMG_2680" border="0" alt="IMG_2680" align="right" src="http://lh4.ggpht.com/-QfQZft9c2f8/TjJD-oxjK0I/AAAAAAAAANk/pJRAGX3_48k/IMG_2680_thumb1.jpg?imgmax=800" width="329" height="253" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;We did find however that everyone on our team was able to read English and all of their code is written in English so we were able to use that as a common denominator. With a little bit of translation help then we were off and running. We’d favor walking through code on a projector as a team and showing by example the practices that we were trying to teach. Ideas and concepts that we felt were extremely important were captured as reference in our wiki on GitHub. It’s a difficult problem to solve when so much of our success relies on frequent, open and honest communication. As we move forward with 8000 miles between us, we’ll leverage IM, shared living documents, and timely feedback with daily standups, weekly retrospectives and demos. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Myth #3: Cultural Differences are not that Wide &lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I knew that there would be cultural differences but I really had no idea how different the people are here from back home. I had brushed up on the differences with a great book, &lt;a href="http://www.amazon.com/Speaking-India-Bridging-Communication-Working/dp/1931930341"&gt;Speaking of India&lt;/a&gt; by Craig Storti, but to understand the impact they have they really must be experienced. The most challenging one to overcome was the rigid hierarchy in the workplace. When the owner of the company was in the room, no team member spoke except for the team lead and he would only reply with a “Yes” or “Yes, sir”. When the team was asked for feedback they would defer to the team lead every time. If he was out of the room, they would defer to the “secondary team lead”.&lt;/p&gt;  &lt;p&gt;This rigid hierarchy was stifling communication which as I mentioned before must be open, direct and honest. We didn’t really try to overcome cultural standards that have been ingrained in this group since the beginning of their lives. Instead we picked our opportunities to have direct conversation with individuals and to solicit feedback from the group as much as possible when they were their most honest (bosses out of the room).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Myth #4: Little Effect can be had in Three Weeks&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I’ve worked with a number of really good trainers, coaches, and teachers of Agile techniques and everyone routinely agrees that to get somewhat proficient at Test Driving, Refactoring, and Emergent Design takes months.&amp;#160; I have no intention of being in India, away from my family for months, so the question of how much change we could enact in three weeks was really concerning. I’m not foolish or egotistical enough to think that the developers we’ve worked with are now proficient at TDD, Refactoring, or anything else that we’ve tried to teach them. Further, I know that they will start to regress once we’ve returned to the states. I do believe, however, that these guys already had an inherent thirst for knowledge. We were able to show them the benefits of every practice we talked about and you could see in their eyes and hear in their conversations that they were excited and eager to continue the voyage. Will they become proficient in the same time as if we were with them? Probably not. Will they continue down the path? Definitely. These guys already had the spark of interest going, the most important thing that we were able to accomplish over here was to just fan the flame.&lt;/p&gt;  &lt;p&gt;In all, this trip has taught me to question all of my preconceived notions about people. I am hopefully returning from India, humbled, grateful, and much more respectful of the great country and it’s people. Despite conditions that many Americans would find below standard, the people of India are as welcoming and hospitable as any I have ever met. I am thankful for the opportunity to learn more about their culture and I look forward to continuing to build some great software with this team.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-UyRxUhixWOQ/TjJD_lhUNJI/AAAAAAAAANo/gs58T_xyW_o/s1600-h/IMG_26907.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="IMG_2690" border="0" alt="IMG_2690" src="http://lh4.ggpht.com/-3tj9QVKGNDM/TjJEA_2u6yI/AAAAAAAAANs/umtnqiGUB7E/IMG_2690_thumb8.jpg?imgmax=800" width="903" height="492" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Senthil, Antony, Chenthil, Perumal, Sathish, Govind, and Priya, you were all extremely gracious and patient with the boisterous Americans. You made us feel very much at home when we were in need and we will forever be thankful!&lt;/p&gt;  &lt;p align="center"&gt;தங்க யு கோயம்புத்தூர்&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-455926635448540158?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/455926635448540158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=455926635448540158' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/455926635448540158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/455926635448540158'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2011/07/thank-you-coimbatore.html' title='Thank You Coimbatore'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-18SsZSedK_I/TjJD4RBH7OI/AAAAAAAAANc/19UJSXeZeTM/s72-c/image_thumb4.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-7360164730541327727</id><published>2011-07-21T09:14:00.001-04:00</published><updated>2011-07-21T09:14:28.496-04:00</updated><title type='text'>Hire Craft over Technology</title><content type='html'>&lt;p&gt;Consider this blog post an open plea with hiring managers and recruiters. The vast majority of you focus on &lt;em&gt;the wrong thing &lt;/em&gt;when trying to hire developers. Really good developers are exponentially more productive than mediocre ones, but you can’t tell the difference because you are looking at &lt;em&gt;the wrong thing&lt;/em&gt;. If you disagree, please ask yourself: “What is the first thing you assess in a candidate when considering them for a project?” I’m sure a few will answer differently but by and large most will say that they are trying to make sure that someone has adequate experience with the technologies in use on the project. I’ve seen hundreds of good, bad and mediocre developers at work and I’m here to tell you that the focus on technical skill should be secondary. Focus instead on hiring developers who embrace quality, take pride in their work, and consistently practice their skill. These developers are &lt;em&gt;craftsmen&lt;/em&gt;, not programmers.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.flickr.com/photos/fixersphotos/3199566032/"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="HAMMER!" border="0" alt="HAMMER!" align="right" src="http://lh5.ggpht.com/-5ddru7k3ORE/TigmMSS7pfI/AAAAAAAAANA/L00KvypzlPo/image%25255B11%25255D.png?imgmax=800" width="364" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Taken at a glance, it doesn’t seem to be a bad thing to focus on technology. Technical skill is mandatory for most development positions. Most hiring managers and recruiters couldn’t fathom bringing someone onto a project written in C# if they professed a novice or rudimentary knowledge of C#. The problem with this mentality however is that there are a number of C# developers who are proficient with the language, yet build very costly systems due to the quality of their code. A developer may know Java inside and out, but it doesn’t mean they know how to build software.&lt;/p&gt;  &lt;p&gt;Put yourself in a different mindset, that of a person hiring potential carpenters to construct your new home. If you were interviewing the carpenters would you quiz them continually on their knowledge of a power nailer? No, you’d ask them more appropriately about the differences in constructing load bearing walls from non-load bearing. How to frame a doorway. What procedures they use for ensuring a square corner and flat walls. These questions are all striving to assess what level of quality the carpenter builds into their final product. Why do we not assess the same thing with developers?&lt;/p&gt;  &lt;p&gt;I believe it namely boils down to either misperception or laziness.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Misperception&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The main misperception in hiring managers is that technical skill equals speed. It may in fact equate to short term speed, but without an additional focus on quality the legacy codebase quickly becomes a giant time sink that is difficult to change. Studies have shown that the vast percentage of our project costs are in the maintenance phase, not the construction phase, yet how many dollars have been lost by companies emphasize saving time on the 20% at the expense of the 80%? Unless you are constructing throwaway code or something that will be extremely short lived, do not focus on the speed to build. Focus instead on the quality and your overall speed will increase. Focus on your speed and your overall quality will decrease.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Laziness&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I actually think the misperception referenced above is being debunked more and more by hiring managers every day. Sadly though, many recruiters and hiring managers I know are in a rut where they still screen development candidates exactly as they did many years ago. They build simple quizzes to screen for technical knowledge, followed by phone interviews that screen for technical skill and the good ones even follow this up with a programming interview that again determines technical knowledge. Whether it’s ignorance, apathy, or laziness I’m not sure, but if these groups want to see an increase in overall quality (and therefore speed), they need to start asking the difficult questions focused on craft, not technology. I still do a decent number of pairing interviews and I never dictate that someone use a specific language in the interview process. I think my most memorable candidate actually used a language and editor that he wasn’t that familiar with and still you could tell that he had intimate knowledge of TDD and emergent design. I immediately wanted to hire him for any project that we had available and I &lt;em&gt;knew&lt;/em&gt; he would be productive and successful regardless of the environment. Can you say the same for the C# developer who has 15 years of experience which are really 1 year projects repeated 15 times?&lt;/p&gt;  &lt;p&gt;Craft is not something that is easily learned. K. Anders Ericsson noted that it takes 10,000 hours of targeted practice to reach mastery. If you happen to get one of those passionate developers who have 10,000 hours under their belt, then consider yourself lucky. If you can’t find those people then do the next best thing and hire someone who truly gives a shit and is practicing their craft. You’ll know you’ve found them when they talk much more about quality than technology.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;font size="1"&gt;Hammer photo courtesy of &lt;strong&gt;thefixer&lt;/strong&gt; on flickr&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-7360164730541327727?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/7360164730541327727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=7360164730541327727' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7360164730541327727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7360164730541327727'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2011/07/hire-craft-over-technology.html' title='Hire Craft over Technology'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/-5ddru7k3ORE/TigmMSS7pfI/AAAAAAAAANA/L00KvypzlPo/s72-c/image%25255B11%25255D.png?imgmax=800' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1895761585946380896</id><published>2011-07-12T22:06:00.001-04:00</published><updated>2011-07-12T22:06:52.764-04:00</updated><title type='text'>Things I Have Learned About Driving in India</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-EgErPjZHKpU/Thz9SuTwTJI/AAAAAAAAALM/2-mD0tzpJnM/s1600-h/IMG_25589.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="IMG_2558" border="0" alt="IMG_2558" src="http://lh3.ggpht.com/-MhZ3oFywucs/Thz9TfbFZyI/AAAAAAAAALQ/yMAl9JpjTSg/IMG_2558_thumb3.jpg?imgmax=800" width="654" height="259" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In our first few days over here in India, we’ve been privy to some of the most exhilarating car rides I’ve ever been a part of. By exhilarating, I mean that we have actually almost had 3 head on collisions and we’ve stopped in front of oncoming traffic to take pictures while we were passing an ox drawn cart. We really believe that our driver could have some success back in the states, so we’re actively recruiting him for NASCAR. Here are a few of the tidbits we’ve learned from this expert:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Lanes are merely a suggestion and should rarely be followed. Instead, find the best opening in the road to position you for massive future&amp;#160; acceleration. &lt;/li&gt;    &lt;li&gt;If you are behind a bus with 230 people in it, pass carefully. They always have the right away. &lt;/li&gt;    &lt;li&gt;If you are behind an elephant in the road, pass carefully. They always have the right away. Also, do not tailgate. &lt;/li&gt;    &lt;li&gt;Horns are by far the best means to communicate that you are on someone’s left, on someone’s right, are about to hit someone, are going to pass someone, are going to ram someone if they don’t let you pass, or that you are sorry for accidentally running into someone. &lt;/li&gt;    &lt;li&gt;If horns are not conveying your intent properly, resort to flipping your headlights at them. &lt;/li&gt;    &lt;li&gt;Motorcycles are by far the easiest way to get around. And they can safely transport a family of four. And they can transport 18 month old children. &lt;/li&gt;    &lt;li&gt;If you are not simultaneously pressing the gas and the break at some point during your drive, then you are doing it wrong. &lt;/li&gt;    &lt;li&gt;When encountering a traffic light which counts down until you can go, do not be a loser and wait for 0. Go at 5 at a minimum, 10 if you are feeling lucky. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Wish us luck for the next few weeks. I’ll have the unbridled joy of this little guy for every ride…&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-wE997MIssSc/Thz9UEK3XvI/AAAAAAAAALU/Dpuw_ct_rk4/s1600-h/IMG_25674.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="IMG_2567" border="0" alt="IMG_2567" src="http://lh5.ggpht.com/-KAFLeUbuv6o/Thz9V6Q5etI/AAAAAAAAALY/dmEGYbbGUbY/IMG_2567_thumb1.jpg?imgmax=800" width="423" height="325" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1895761585946380896?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1895761585946380896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1895761585946380896' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1895761585946380896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1895761585946380896'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2011/07/things-i-have-learned-about-driving-in.html' title='Things I Have Learned About Driving in India'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-MhZ3oFywucs/Thz9TfbFZyI/AAAAAAAAALQ/yMAl9JpjTSg/s72-c/IMG_2558_thumb3.jpg?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-2708018446884863914</id><published>2011-04-27T09:22:00.001-04:00</published><updated>2011-04-27T09:22:30.157-04:00</updated><title type='text'>Trials and Tribulations of getting Jenkins on Windows pulling from GitHub</title><content type='html'>&lt;p&gt;I spent the better part of the last two days getting a Jenkins build which runs on a Windows 2008 server to pull from GitHub. You might think, “Wow, Todd really must be an (idiot|rube|dolt|moron|manager) to need 2 days to setup a CI server”. Well, you might be right, but even a simpleton like myself can google the shit out of a problem and come up with some type of frankensteined solution in a day or less. Apparently though, I am one of 5 people on this planet to actually use the cluster of Jenkins/Windows/Github. In case there are more of you out there, I thought I would try to spell out exactly what I did so that you don’t have to suffer (and so that when I forget how I got this thing to work and the server needs to be rebuilt in a year I can do it).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 0&lt;/strong&gt;: I’m assuming you already have a Windows server with Jenkins up and running on it. I’m also going to assume that you installed it as a service. if you aren’t there yet, follow the instructions here: &lt;a title="https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+as+a+Windows+service" href="https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+as+a+Windows+service"&gt;https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+as+a+Windows+service&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Install yourself some msysgit from here: &lt;a title="http://code.google.com/p/msysgit/" href="http://code.google.com/p/msysgit/"&gt;http://code.google.com/p/msysgit/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt;&amp;#160; Head to Manage Plugins from the main Jenkins menu, select the Git plugin from the list of available plugins, and install that puppy. You’ll need to restart the service for this to take effect.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; I had to explicitly configure Jenkins to use the git.cmd instead of git.exe. I believe this properly sets the HOME variable so that your ssh and netrc files can be located when Jenkins fires off a build. From the Manage Jenkins link at the top level, you should have the option of adding a git installation. Provide the full path to the &amp;lt;GIT_HOME&amp;gt;/cmd/git.cmd file in this line as shown here:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_QxI2aQuFZnk/TbgYkVPZI7I/AAAAAAAAAK4/Dli2mkoG9Xw/s1600-h/image%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_QxI2aQuFZnk/TbgYkhkZLRI/AAAAAAAAAK8/rLYdsnjSuF4/image_thumb%5B2%5D.png?imgmax=800" width="612" height="170" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Generate and upload an ssh key for your github account. Make sure you are logged in as the same user that the Jenkins service runs under. Good instructions here: &lt;a title="http://help.github.com/win-set-up-git/" href="http://help.github.com/win-set-up-git/"&gt;http://help.github.com/win-set-up-git/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Configure a _netrc file and store it in the home directory of the user Jenkins runs under. My _netrc file looks like this:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;machine github.com&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;login pillarci&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;password notmypassword&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt; Set an environment variable for HTTPS_PROXY if you have a firewall.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Step 7:&lt;/strong&gt; Test that you can pull down from the command line. Given your repository name, you should be able to go to the command line and run something like &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;git clone https://github.com/SomeOrg/SomeRepo.git&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Step 8:&lt;/strong&gt; Configure your build on Jenkins. Please note that the repository name should not have the username in it and it should be using the https url, not the git url. Something like this:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_QxI2aQuFZnk/TbgYk7Q6lwI/AAAAAAAAALA/8qG_wS71d4E/s1600-h/image%5B9%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_QxI2aQuFZnk/TbgYlO1i58I/AAAAAAAAALE/bDvQBFyAmo0/image_thumb%5B5%5D.png?imgmax=800" width="581" height="194" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Step 9:&lt;/strong&gt; Kick that build off and pray. At this step I had a number of obtuse error messages and hung builds. If either of those instances occur with you, proceed to steps 10-47.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Possible Step 10 – 47: Check for a .git folder in your workspace without a sibling directory containing your repo. Nuke it if so and retry the build.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;That should be all you need to get up and running. Again, I had some issues, many of which were the fault of the user, many due to the lack of info out on the internets. Luckily I work with a really smart guy named Justin Searls and he had already laid a bunch of this pavement for me. Happy GitHubbing!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-2708018446884863914?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/2708018446884863914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=2708018446884863914' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2708018446884863914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2708018446884863914'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2011/04/trials-and-tribulations-of-getting.html' title='Trials and Tribulations of getting Jenkins on Windows pulling from GitHub'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_QxI2aQuFZnk/TbgYkhkZLRI/AAAAAAAAAK8/rLYdsnjSuF4/s72-c/image_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-6259319410872018934</id><published>2010-02-15T21:10:00.001-05:00</published><updated>2010-02-15T21:10:11.999-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Step 4.5 – Spring DM Extender Logging</title><content type='html'>&lt;p&gt;I’m going to sneak in a bonus blog post in the Enterprise OSGi series as I think some people may have had issues in getting the last step to work and will be relatively stuck without a little help in debugging what the heck is going on with Spring DM Extender. Enabling logging on a bundle that you did not write may seem tricky. Some may even attempt to download the source, tweak it and re-bundle the extender. A cool feature of OSGi is the ability to extend bundles that you’ve not written by developing a Fragment. Fragments allow bundles to be closed for modification, but open for extension. They are typically used to customize web bundles with separate UI skins (as we’ll see later), internationalization, separate OS installations, and a few other niche cases. In our case, we’ll leverage a fragment to customize the log level of the dm extender so that we can figure out what is going on when say, our bundle doesn’t start and there are absolutely zero messages explaining why. Let’s get started by creating another bundle &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_QxI2aQuFZnk/S3n-c-XrBHI/AAAAAAAAAJE/Lwfn9e2EzTM/s1600-h/Screen%20shot%202010-02-15%20at%208.28.05%20PM%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screen shot 2010-02-15 at 8.28.05 PM" border="0" alt="Screen shot 2010-02-15 at 8.28.05 PM" src="http://lh6.ggpht.com/_QxI2aQuFZnk/S3n-di1S8YI/AAAAAAAAAJI/BWJ01rd0_4k/Screen%20shot%202010-02-15%20at%208.28.05%20PM_thumb%5B1%5D.png?imgmax=800" width="728" height="217" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I passed another couple of flags to maven on this command to ensure that it doesn’t create any internal or interface classes that we’ll have to delete. In our simple case of enabling some logging, we really only need to add a single log4j.properties file to get the magic to happen. I placed it in a src/main/resources/ to keep in line with a typical maven project and added some simple verbose logging configuration.&lt;/p&gt;  &lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;log4j.rootLogger=info, A&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;log4j.appender.A=org.apache.log4j.ConsoleAppender&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;log4j.appender.A.layout=org.apache.log4j.PatternLayout&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;log4j.appender.A.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The last order of business is to adjust the manifest to attach this fragment to a host bundle. As usual, we accomplish this task by adding the following line to the BND file&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;Fragment-Host: com.springsource.org.apache.log4j&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Compiling the project and running pax-provision should provide a slew of information regarding the process spring uses to look for bundles and resolve dependencies&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_QxI2aQuFZnk/S3n-ewhfEvI/AAAAAAAAAJM/74PaFRViVgs/s1600-h/Screen%20shot%202010-02-15%20at%208.58.21%20PM%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screen shot 2010-02-15 at 8.58.21 PM" border="0" alt="Screen shot 2010-02-15 at 8.58.21 PM" src="http://lh4.ggpht.com/_QxI2aQuFZnk/S3n-gvIsDJI/AAAAAAAAAJQ/JXYr4n4OYyM/Screen%20shot%202010-02-15%20at%208.58.21%20PM_thumb%5B1%5D.png?imgmax=800" width="724" height="300" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;If you’ve had issues, this will hopefully provide some clues as to why the dm extender was not able to find your dependencies. My most frequent mistake is to misspell the directory containing the context files. In the next post, we’ll resume our regularly scheduled programming by providing a database backed persistence layer in our application.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Examples, as always available on &lt;a href="http://github.com/tkaufman/Codemash-OSGi"&gt;github&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-6259319410872018934?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/6259319410872018934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=6259319410872018934' title='37 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6259319410872018934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6259319410872018934'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2010/02/step-45-spring-dm-extender-logging.html' title='Step 4.5 – Spring DM Extender Logging'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_QxI2aQuFZnk/S3n-di1S8YI/AAAAAAAAAJI/BWJ01rd0_4k/s72-c/Screen%20shot%202010-02-15%20at%208.28.05%20PM_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>37</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-8145013602944364263</id><published>2010-02-11T09:29:00.001-05:00</published><updated>2010-02-11T09:31:45.752-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Step 4 – Spring Dynamic Modules</title><content type='html'>&lt;p&gt;Our &lt;a href="http://toddkaufman.blogspot.com/2010/02/step-3-service-consumption.html"&gt;previous&lt;/a&gt; installment finally began to show the benefits of OSGi. Service production, consumption and registry were all accomplished programmatically with the APIs of the OSGi specification. While this does provide the benefit of reduced coupling and improved cohesion in an enterprise application, the end result was an invasive and difficult to test implementation. Surely there has to be a better way?&lt;/p&gt;  &lt;p&gt;The good people at SpringSource asked the same question and they came up with a solution that feels very natural to Spring developers: Spring Dynamic Modules. Spring DM provides OSGi developers with a declarative means of wiring bundles together in much the same manner that the Spring framework allows developers to wire together Java classes. Getting up and running requires a couple of new repositories and an import from the root project level.&lt;/p&gt;  &lt;p&gt;Up until now we’ve been able to download the few OSGi bundles that we’ve needed from the typical maven repositories. When we begin to use the Spring extender for OSGi, a number of other bundles will come into the picture. Downloading these bundles from the maven repositories can be hit or miss, so instead let’s use the &lt;a href="http://www.springsource.com/repository/app/"&gt;SpringSource Enterprise Bundle Repository&lt;/a&gt; as our main repository for OSGi bundles. EBR is basically a collection of commonly used libraries for Java in valid OSGi bundle form.&amp;#160; Add the two repository locations with pax construct using the following commands from the root directory:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;pax-add-repository \&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;-i com.springsource.repository.bundles.release \&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;-u http:&lt;span style="color: #008000"&gt;//repository.springsource.com/maven/bundles/release&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;pax-add-repository \&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;-i com.springsource.repository.bundles.external \&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;-u &lt;a href="http://repository.springsource.com/maven/bundles/external"&gt;http:&lt;span style="color: #008000"&gt;//repository.springsource.com/maven/bundles/external&lt;/span&gt;&lt;br /&gt;&lt;/a&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Then we can slightly adjust the pax import command to pull in the Spring DM extender and all of it’s dependencies in one fell swoop.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_QxI2aQuFZnk/S3QUQL5wV6I/AAAAAAAAAIw/JlH0rx5BMlg/s1600-h/Screen%20shot%202010-02-11%20at%207.34.37%20AM%5B4%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screen shot 2010-02-11 at 7.34.37 AM" border="0" alt="Screen shot 2010-02-11 at 7.34.37 AM" src="http://lh4.ggpht.com/_QxI2aQuFZnk/S3QUQ2CkS-I/AAAAAAAAAI0/ZL-hSSwcTCE/Screen%20shot%202010-02-11%20at%207.34.37%20AM_thumb%5B2%5D.png?imgmax=800" width="624" height="144" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This command is a little different from prior imports in that we have added a couple of properties to the maven command. The importTransitive property instructs pax-construct to not only pull in the spring-osgi-extender, but also all of the other bundles that it depends on. The widenScope property instructs it to import not only those compile time bundles, but also the runtime dependencies as well. This should result in a slew of downloads occurring in your main project directory.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Using Spring DM extender will remove the OSGi programmatic approach to wiring and activating bundles, in favor of autowiring bundles together in a Spring context. By default the extender will look in META-INF/spring for any .xml files that it can sink it’s teeth into. I follow the pattern of using an OSGi specific context and an other file for all the rest. Change to the directory of the service bundle and from there create a src/main/resources/META-INF/spring directory. Within that directory, we’ll create two application context files. The first, service-context.xml will just declare the service implementation as a bean:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;beans&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/beans&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;schemaLocation&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/beans&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;bean&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;raffleService&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #ff0000"&gt;class&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;com.pillartech.raffle.service.internal.RaffleServiceImpl&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;beans&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The osgi-context.xml is fairly straightforward as well:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #c71585"&gt;beans&lt;/span&gt;:&lt;span style="color: #800000"&gt;beans&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/osgi&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;beans&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/beans&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;schemaLocation&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/osgi&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/osgi/spring-osgi.xsd&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/beans&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;service&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ref&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;raffleService&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #ff0000"&gt;interface&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;com.pillartech.raffle.service.RaffleService&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #c71585"&gt;beans&lt;/span&gt;:&lt;span style="color: #800000"&gt;beans&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This context decalres the osgi namespace as the default and can then simply publish the service to OSGi via the &amp;lt;service&amp;gt; tag. You’ll note it uses a reference to the raffleService bean in the other context, make sure these match. With these two files in place the activator for this bundle is no longer necessary. Remove that entire file and you should be able to compile and deploy.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;OSGi also provides a means for consuming services. Let’s change the Rigged bundle to make use of it. Start by creating the same src/main/resources/META-INF/spring structure so that the dm extender will find all of the contexts. The OSGi context for a consumer is very similar to the producer:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #c71585"&gt;beans&lt;/span&gt;:&lt;span style="color: #800000"&gt;beans&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/osgi&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;beans&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/beans&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;schemaLocation&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/osgi&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/osgi/spring-osgi.xsd&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/beans&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;reference&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;raffleService&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #ff0000"&gt;interface&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;com.pillartech.raffle.service.RaffleService&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #c71585"&gt;beans&lt;/span&gt;:&lt;span style="color: #800000"&gt;beans&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The major change is that instead of using a service tag to produce a service, we use a reference tag to consume one. The rigged activator class will need changed to consume this service via dependency injection. Let’s tweak that class so that all OSGi based lookups are removed and replace it with a simple setter. While we’re in here, let’s also remove the APIs for bundle activation as well. The end result is a ServiceBasedRiggedRaffleActivator that looks like this&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;package com.pillartech.raffle.rigged.internal;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;import java.util.Set;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;import com.pillartech.raffle.service.RaffleService;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; final &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ServiceBasedRiggedRaffleActivator {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; RaffleService service;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; RaffleService getRaffleService() {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; service;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; setRaffleService(RaffleService svc) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    service = svc;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; start() throws Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (service != null) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      addEntrants();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;Unable to rig the raffle, cannot get a handle on the service&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; addEntrants() {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;Adding entrants&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    final &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; COUNT = 10;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; COUNT; i++) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      service.addEntry(&amp;quot;&lt;span style="color: #8b0000"&gt;Todd(&lt;/span&gt;&amp;quot;+i+&amp;quot;&lt;span style="color: #8b0000"&gt;)&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color: #8b0000"&gt;toddkaufman@gmail.com&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(COUNT + &amp;quot;&lt;span style="color: #8b0000"&gt; entries added to the raffle.&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; stop() throws Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;And the winner of the raffle is ...&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    Set&amp;lt;String&amp;gt; winners = service.pickWinners(1);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (String winner : winners) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      System.out.println(winner + &amp;quot;&lt;span style="color: #8b0000"&gt; won!&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can tell by the imports that this code now has zero reliance on OSGi APIs so it is easier to understand and maintain, with the benefit of also being able to be tested in isolation. The final step in getting this to work is to create a context file that wires up the rigged class with it’s dependency on the external service bundle. The rigged-context.xml is&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;beans&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/beans&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;schemaLocation&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.springframework.org/schema/beans&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;bean&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;riggedActivator&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #ff0000"&gt;class&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;com.pillartech.raffle.rigged.internal.ServiceBasedRiggedRaffleActivator&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #ff0000"&gt;init&lt;/span&gt;-&lt;span style="color: #ff0000"&gt;method&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;start&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;destroy&lt;/span&gt;-&lt;span style="color: #ff0000"&gt;method&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;stop&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;property&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;raffleService&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ref&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;raffleService&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;bean&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;beans&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Here we make use of the init-method and destroy-method properties of a spring bean to automatically kick off the raffle and shut it down, just as we did with the bundle’s OSGi start/stop lifecycles. One last item of cleanup is to tweak the BND files for both bundles to reflect the removal of a BundleActivator. While we’re in there I would add the following line so that Spring does not expose the bundle’s context to other services:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;Spring-Context: META-INF/spring/*.xml;publish-context:=false&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Executing a mvn clean install and pax-provision command should provide you with a more verbose lifecycle to these bundles, but the main functionality remains the same. Starting and stopping the rigged service will create a raffle and pick a winner as you would hope.&amp;#160; We’ve deleted a slew of code and added just a handful of configuration to the application to get a simpler and easier to test set of bundles. In the next installment we’ll build upon the use of Spring DM from this point on by adding some database interaction as 90% of the apps we write would.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Source is available as always on &lt;a href="http://github.com/tkaufman/Codemash-OSGi"&gt;githhub&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-8145013602944364263?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/8145013602944364263/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=8145013602944364263' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8145013602944364263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8145013602944364263'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2010/02/step-4-spring-dynamic-modules.html' title='Step 4 – Spring Dynamic Modules'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_QxI2aQuFZnk/S3QUQ2CkS-I/AAAAAAAAAI0/ZL-hSSwcTCE/s72-c/Screen%20shot%202010-02-11%20at%207.34.37%20AM_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-6161412663444421123</id><published>2010-02-01T15:05:00.001-05:00</published><updated>2010-02-01T15:05:32.272-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Step 3 – Service Consumption</title><content type='html'>&lt;p&gt;OSGi has often been referred to as SOA inside a JVM and I think that’s a fair analogy. The beauty of OSGi is that you do not have to deal with much of the &amp;lt;ceremony /&amp;gt; involved in traditional web services approaches. Comparing OSGi to traditional SOA implementations shows that the complexity is lower, performance is better, and all of the power is still there with OSGi. The one exception to this rule is when your application needs to connect to non-JVM based dependency, you’ll still need to use web services.&lt;/p&gt;  &lt;p&gt;In the last few posts, we’ve managed to create a domain bundle and create a rigged raffle bundle that makes use of it. Let’s change this implementation to have a domain agnostic service layer that can leverage the domain bundle under the hood (or a database, web service provider, or something else in the future). Attentive readers will know the drill by now. Start out by creating a service bundle using pax-create-bundle from the project directory.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_QxI2aQuFZnk/S2cz_hGoAWI/AAAAAAAAAH4/_gNOW3s4JZk/s1600-h/Screen%20shot%202010-02-01%20at%202.15.40%20PM%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screen shot 2010-02-01 at 2.15.40 PM" border="0" alt="Screen shot 2010-02-01 at 2.15.40 PM" src="http://lh6.ggpht.com/_QxI2aQuFZnk/S2c0AX1tXLI/AAAAAAAAAH8/ZvX45n07Cxo/Screen%20shot%202010-02-01%20at%202.15.40%20PM_thumb%5B1%5D.png?imgmax=800" width="609" height="224" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Creating the service is pretty straightforward. We’ll provide a publicly accessible interface in the com.pillartech.raffle.service package.&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;package&lt;/span&gt; com.pillartech.raffle.service;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; java.util.Set;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; RaffleService {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; addEntry(String name, String email);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Set&amp;lt;String&amp;gt; pickWinners(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; numOfWinners);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This service allows a consumer to add an entry, and pick&amp;#160; a certain number of winners which is all our rigged consumer really needs at this point. A common practice in OSGi is to create an &lt;em&gt;internal&lt;/em&gt; package underneath this main package to store all of non-public classes. Only packages explicitly exposed in the manifest will be made public for other bundles, not directories underneath, so we’ll store our service implementation and activators in this internal directory. Create a com.pillartech.raffle.service.internal package and define a class within this package that implements the service interface. My implementation is fairly straightforward:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;package&lt;/span&gt; com.pillartech.raffle.service.internal;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; java.util.Date;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; java.util.HashSet;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; java.util.Set;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; com.pillartech.raffle.domain.Entry;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; com.pillartech.raffle.domain.Raffle;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; com.pillartech.raffle.service.RaffleService;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RaffleServiceImpl &lt;span style="color: #0000ff"&gt;implements&lt;/span&gt; RaffleService {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Raffle raffle = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; RaffleServiceImpl() {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    raffle = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Raffle();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; addEntry(String name, String email) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    Entry e = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Entry();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    e.setName(name);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    e.setEmail(email);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    e.setCreated(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Date());&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    raffle.addEntry(e);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Set&amp;lt;String&amp;gt; pickWinners(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; numOfWinners) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    raffle.setNumberOfWinners(numOfWinners);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    Set&amp;lt;Entry&amp;gt; winners = raffle.pickWinners();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    Set&amp;lt;String&amp;gt; winnerNames = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HashSet&amp;lt;String&amp;gt;();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (Entry entry : winners) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      winnerNames.add(entry.getName());&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; winnerNames;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;As you can see, this trivial example just stores the domain objects internally and translates the simplistic arguments passed in to domain objects within the raffle. This may seem like a zero sum gain compared to our last implementation and in all honesty it is. It does pave the way for our service bundle to do things like leveraging a database, and managing transactions across separate DAOs which we’ll accomplish in due time.&amp;#160; Now, we are one activator away from having a viable service published in our container. In the internal directory create an activator class and plumb in some code like this:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;package&lt;/span&gt; com.pillartech.raffle.service.internal;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; org.osgi.framework.BundleActivator;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; org.osgi.framework.BundleContext;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; com.pillartech.raffle.service.RaffleService;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RaffleServiceActivator &lt;span style="color: #0000ff"&gt;implements&lt;/span&gt; BundleActivator {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; start(BundleContext bc) &lt;span style="color: #0000ff"&gt;throws&lt;/span&gt; Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    bc.registerService(RaffleService.&lt;span style="color: #0000ff"&gt;class&lt;/span&gt;.getName(),&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RaffleServiceImpl(), &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; stop(BundleContext bc) &lt;span style="color: #0000ff"&gt;throws&lt;/span&gt; Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;This activator leverages the BundleContext passed into the start method to register the service. We’re using the common practice of publishing the service using the fully qualified class name of the interface. At this time we could provide a file location, database connection, or other such dependency into the constructor of the implementation, but we’ll get to that soon enough. If you do provide such dependencies, make sure that they are cleaned up and destroyed in the stop method of the activator as well. All that is left is to update the BND file to the name of your activator and you should have a deployable service bundle. Feel free to run mvn install and pax-provision to test the waters. &lt;br /&gt;&lt;br /&gt;&lt;p&gt;Publishing the service is the easy part, we still need to consume this service from the rigged raffle bundle. From the rigged bundle directory, run a pax-import-bundle, providing the information used when creating the service.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_QxI2aQuFZnk/S2c0AwUwqLI/AAAAAAAAAIA/OoQ8ku5AzwA/s1600-h/Screen%20shot%202010-02-01%20at%202.40.00%20PM%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screen shot 2010-02-01 at 2.40.00 PM" border="0" alt="Screen shot 2010-02-01 at 2.40.00 PM" src="http://lh3.ggpht.com/_QxI2aQuFZnk/S2c0BZfStPI/AAAAAAAAAIE/ejlpCG6VW0s/Screen%20shot%202010-02-01%20at%202.40.00%20PM_thumb%5B1%5D.png?imgmax=800" width="554" height="195" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Now, we need to re-implement the activator in the rigged bundle to take advantage of the beautiful service waiting out there for us. My updated copy is this:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;ackage com.pillartech.raffle.rigged.internal;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; java.util.Set;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; org.osgi.framework.BundleActivator;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; org.osgi.framework.BundleContext;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; org.osgi.util.tracker.ServiceTracker;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; com.pillartech.raffle.service.RaffleService;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;final&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ServiceBasedRiggedRaffleActivator &lt;span style="color: #0000ff"&gt;implements&lt;/span&gt; BundleActivator {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; ServiceTracker tracker;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; RaffleService service;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; start(BundleContext bc) &lt;span style="color: #0000ff"&gt;throws&lt;/span&gt; Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;Grabbing a handle on the raffle service&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    tracker = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ServiceTracker(bc, RaffleService.&lt;span style="color: #0000ff"&gt;class&lt;/span&gt;.getName(), &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    tracker.open();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    service = (RaffleService) tracker.getService();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (service != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      addEntrants();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;Unable to rig the raffle, cannot get a handle on the service&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; addEntrants() {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;Adding entrants&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;final&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; COUNT = 10;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; COUNT; i++) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      service.addEntry(&amp;quot;&lt;span style="color: #8b0000"&gt;Todd(&lt;/span&gt;&amp;quot;+i+&amp;quot;&lt;span style="color: #8b0000"&gt;)&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color: #8b0000"&gt;toddkaufman@gmail.com&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(COUNT + &amp;quot;&lt;span style="color: #8b0000"&gt; entries added to the raffle.&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; stop(BundleContext bc) &lt;span style="color: #0000ff"&gt;throws&lt;/span&gt; Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;And the winner of the raffle is ...&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    Set&amp;lt;String&amp;gt; winners = service.pickWinners(1);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (String winner : winners) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      System.out.println(winner + &amp;quot;&lt;span style="color: #8b0000"&gt; won!&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;Releasing handle on the raffle service.&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    tracker.close();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You’ll notice in this example we now have to make use of a ServiceTracker to access the published service. In OSGi land, services can come and go at any time. ServiceTracker’s can be used to grab a handle to a service and optionally wait if one is not available.&amp;#160; Leveraging the service tracker we then access the published service via the interface and interact with it as any normal java class would. Also, take note that we need to close the service tracker in the stop method to ensure that the integration of the two bundles is gracefully decoupled should the rigged raffle go away. If we would prefer to wait for the service should it not be available, we would call tracker.waitForService instead of getService and provide a time in ms to wait should the service not be available immediately. Craig Walls warns against waiting for services in the activator in his Modular Java book though as it may cause a traffic jam of bundles waiting to activate on startup. You should be able to execute a mvn install on the entire project and a pax-provision from the main directory to see everything up and running. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_QxI2aQuFZnk/S2c0B6aZtOI/AAAAAAAAAII/sCfbn9M_IlE/s1600-h/Screen%20shot%202010-02-01%20at%202.55.18%20PM%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screen shot 2010-02-01 at 2.55.18 PM" border="0" alt="Screen shot 2010-02-01 at 2.55.18 PM" src="http://lh4.ggpht.com/_QxI2aQuFZnk/S2c0Cv9q7VI/AAAAAAAAAIM/Ljw8IDvFHZI/Screen%20shot%202010-02-01%20at%202.55.18%20PM_thumb%5B1%5D.png?imgmax=800" width="506" height="407" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Beauty! We have a working consumer interacting with a service all through the OSGi container.&amp;#160; We’re starting to see how modular bundles can interact within an OSGi container, but if you are like me you are probably feeling pretty dirty about the amount of OSGi APIs that are leaking into your code. Testing these bundles in isolation would require a significant amount of mocking now and we had to manually construct a service implementation using the new keyword. Fear not, there are better, less invasive ways of accomplishing this and we’ll go through them in the next installment.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Examples as always available on &lt;a href="http://github.com/tkaufman/Codemash-OSGi"&gt;github&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-6161412663444421123?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/6161412663444421123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=6161412663444421123' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6161412663444421123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6161412663444421123'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2010/02/step-3-service-consumption.html' title='Step 3 – Service Consumption'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_QxI2aQuFZnk/S2c0AX1tXLI/AAAAAAAAAH8/ZvX45n07Cxo/s72-c/Screen%20shot%202010-02-01%20at%202.15.40%20PM_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1834686430729465063</id><published>2010-01-24T22:32:00.001-05:00</published><updated>2010-01-24T22:32:45.166-05:00</updated><title type='text'>Step 2 – Importing Bundles</title><content type='html'>&lt;p&gt;The &lt;a href="http://toddkaufman.blogspot.com/2010/01/step-1-creating-your-domain.html"&gt;previous post&lt;/a&gt; in this series covered a lot of ground on setting up a project with pax-construct, creating a domain bundle, and then embedding another jar file as part of that bundle. At the end of the day we had a simple bundle deployed to our OSGi container, but it didn’t have any external dependencies or an activator so we’ve only developed a traditional jar file and deployed it somewhere new. Let’s change that by creating another bundle that relies on the domain.&lt;/p&gt;  &lt;p&gt;From the main directory of the project, run pax-create-bundle as we did last time. If you would like to omit the generated code or interfaces, you can pass flags directly to maven. In this example I’ve advised maven to not bother creating a dummy activator class. &lt;/p&gt;  &lt;p&gt;&lt;/p&gt; &lt;a href="http://lh5.ggpht.com/_QxI2aQuFZnk/S10Qzz3E5tI/AAAAAAAAAHE/LFaGg8LzZLU/s1600-h/Screen%20shot%202010-01-24%20at%209.42.14%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Screen shot 2010-01-24 at 9.42.14 PM" border="0" alt="Screen shot 2010-01-24 at 9.42.14 PM" src="http://lh4.ggpht.com/_QxI2aQuFZnk/S10Q0kN0NqI/AAAAAAAAAHI/OYblrBeA7mI/Screen%20shot%202010-01-24%20at%209.42.14%20PM_thumb%5B1%5D.png?imgmax=800" width="741" height="218" /&gt;&lt;/a&gt;  &lt;p&gt;I’ve titled this bundle “rigged” as we’re going to rig our raffle to consistently pick one winner… me. The code to rig the raffle is pretty straightforward as it just makes use of the business logic in the domain classes we created last time. Unfortunately, we have no references to those classes yet, so we need to import that bundle. From the rigged sub-directory run the pax-import-bundle command, passing in the group, artifact, and version information used when creating the domain bundle.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_QxI2aQuFZnk/S10Q1CkgDFI/AAAAAAAAAHM/IGUiTIVB3H0/s1600-h/Screen%20shot%202010-01-24%20at%209.48.08%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Screen shot 2010-01-24 at 9.48.08 PM" border="0" alt="Screen shot 2010-01-24 at 9.48.08 PM" src="http://lh5.ggpht.com/_QxI2aQuFZnk/S10Q168ImOI/AAAAAAAAAHQ/9EgahKrPrB8/Screen%20shot%202010-01-24%20at%209.48.08%20PM_thumb%5B1%5D.png?imgmax=800" width="770" height="233" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Pax will update the poms appropriately so that the dependency points to the domain bundle within the same project. Now we can code up a simple activator that will add some raffle entries on startup and pick a winner on shutdown.&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;package&lt;/span&gt; com.pillartech.raffle.rigged.internal;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; java.util.Set;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; org.osgi.framework.BundleActivator;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; org.osgi.framework.BundleContext;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; com.pillartech.raffle.domain.Entry;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;import&lt;/span&gt; com.pillartech.raffle.domain.Raffle;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;final&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; SimpleRiggedRaffleActivator &lt;span style="color: #0000ff"&gt;implements&lt;/span&gt; BundleActivator {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Raffle raffle = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; start(BundleContext bc) &lt;span style="color: #0000ff"&gt;throws&lt;/span&gt; Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;Adding entrants&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    raffle = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Raffle();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    raffle.setNumberOfWinners(1);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 10; i++) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      Entry e = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Entry();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      e.setName(&amp;quot;&lt;span style="color: #8b0000"&gt;The Todd(&lt;/span&gt;&amp;quot; + i + &amp;quot;&lt;span style="color: #8b0000"&gt;)&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      e.setEmail(&amp;quot;&lt;span style="color: #8b0000"&gt;toddkaufman@gmail.com&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      raffle.addEntry(e);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(raffle.getEntries().size()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        + &amp;quot;&lt;span style="color: #8b0000"&gt; entries added to the raffle.&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; stop(BundleContext bc) &lt;span style="color: #0000ff"&gt;throws&lt;/span&gt; Exception {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    System.out.println(&amp;quot;&lt;span style="color: #8b0000"&gt;And the winner of the raffle is ...&lt;/span&gt;&amp;quot;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    Set&amp;lt;Entry&amp;gt; winners = raffle.pickWinners();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (Entry winner : winners) {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      System.out.println(winner.getName());&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The code to implement an activator is not complex. Implementing the BundleActivator interface necessitates a start and stop method, each taking a BundleContext as a parameter. We don’t need to use the BundleContext just yet so we’ll just get by with some simple rigging of the raffle and system.out.println calls. The only last thing to update is the osgi.bnd file so that the manifest generated correctly points to the activator. The bnd file can make use of properties set by maven so it remains relatively simple.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;#-----------------------------------------------------------------&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;# Use this file to add customized Bnd instructions for the bundle&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;#-----------------------------------------------------------------&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;Bundle-Activator: ${bundle.namespace}.internal.SimpleRiggedRaffleActivator&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Running mvn clean install and pax-provision at the project layer should get you a success message and something that looks like this&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_QxI2aQuFZnk/S10Q2cvQ2lI/AAAAAAAAAHU/GZkRS1KVdTs/s1600-h/Screen%20shot%202010-01-24%20at%2010.20.20%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Screen shot 2010-01-24 at 10.20.20 PM" border="0" alt="Screen shot 2010-01-24 at 10.20.20 PM" src="http://lh3.ggpht.com/_QxI2aQuFZnk/S10Q3M3p_xI/AAAAAAAAAHY/pV-aSxJOgF8/Screen%20shot%202010-01-24%20at%2010.20.20%20PM_thumb%5B1%5D.png?imgmax=800" width="576" height="304" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can see that the activator kicked off on the rigged bundle and it added some entries into the raffle. You can look at how the bundles are viewed differently by the container by running bundle and headers commands on the two. Domain will show relatively little, while the rigged bundle will display the import of the domain bundle and the class name specified as the activator. Stopping the raffle will correctly award the raffle prize to me.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So to this point we’ve created a couple of bundles, imported one to the other, and leveraged the activator to execute some logic when the bundle is started or stopped. Importing other bundles is obviously useful, but to really show the power of OSGi, we need to get bundles talking together in a service / consumer fashion. Stay tuned.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Examples as always, available via &lt;a href="http://github.com/tkaufman/Codemash-OSGi"&gt;github&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1834686430729465063?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1834686430729465063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1834686430729465063' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1834686430729465063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1834686430729465063'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2010/01/step-2-importing-bundles.html' title='Step 2 – Importing Bundles'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_QxI2aQuFZnk/S10Q0kN0NqI/AAAAAAAAAHI/OYblrBeA7mI/s72-c/Screen%20shot%202010-01-24%20at%209.42.14%20PM_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-6227952598012226905</id><published>2010-01-20T22:59:00.001-05:00</published><updated>2010-01-20T22:59:44.259-05:00</updated><title type='text'>Step 1 - Creating your Domain</title><content type='html'>&lt;p&gt;The most common question I've heard regarding OSGi is how do I carve my application into bundles? There is no clear cut answer, but I typically look at functional subsystems within the enterprise (shipping, fulfillment, billing, etc...) and then at the horizontal slices within those systems (presentation, services and persistence). This will tend to provide a good balance for dealing with change and running efforts in parallel without introducing too much complexity. In order to share business objects across separate bundles within the system, we'll need to carve out a domain bundle that others can use. &lt;/p&gt;  &lt;p&gt;I'll use &lt;a href="http://www.ops4j.org/projects/pax/construct"&gt;pax-construct&lt;/a&gt; in these examples as it provides bundle management on top of maven in a relatively intuitive and easy to use fashion. The steps are relatively short to get up and running with a domain bundle.&lt;/p&gt;  &lt;p&gt;Start out by creating the project using pax-create-project&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_QxI2aQuFZnk/S1fRH5R1oGI/AAAAAAAAAGQ/hyHAzg7Q7QA/s1600-h/Screen%20shot%202010-01-20%20at%209.32.42%20PM%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screen shot 2010-01-20 at 9.32.42 PM" border="0" alt="Screen shot 2010-01-20 at 9.32.42 PM" src="http://lh6.ggpht.com/_QxI2aQuFZnk/S1fRJDpKaBI/AAAAAAAAAGU/N0viJqDXtww/Screen%20shot%202010-01-20%20at%209.32.42%20PM_thumb%5B1%5D.png?imgmax=800" width="729" height="305" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;This command will setup a maven project for this OSGi system using an OSGi archetype. From here you may want to update the main pom.xml to generate eclipse project and classpath files, update the compiler version used by Maven, and switch it to use equinox over felix as the OSGi container. The main pom.xml will then resemble this&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;?&lt;/span&gt;xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;&lt;span style="color: #0000ff"&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;project&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi&lt;/span&gt;:&lt;span style="color: #ff0000"&gt;schemaLocation&lt;/span&gt;=&lt;span style="color: #0000ff"&gt;&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;modelVersion&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;modelVersion&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;groupId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;com.pillartech.raffle&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;groupId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;artifactId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;raffle&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;artifactId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;com.pillartech.raffle (OSGi project)&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;description&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Generated using Pax-Construct&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;description&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;properties&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;org.osgi.service.http.port&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;8080&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;org.osgi.service.http.port&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;org.osgi.service.http.port.secure&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;8443&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;org.osgi.service.http.port.secure&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;properties&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;packaging&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;pom&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;packaging&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;modules&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;module&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;poms&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;module&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;module&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;provision&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;module&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;module&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;domain&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;module&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;modules&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;build&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;plugins&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;plugin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;artifactId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;artifactId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;          &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;source&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1.6&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;source&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;          &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;target&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1.6&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;target&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;plugin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;plugin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;groupId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;org.ops4j&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;groupId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;artifactId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;maven-pax-plugin&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;artifactId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1.4&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;          &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;provision&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;param&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;--platform=equinox&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;param&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;          &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;provision&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;executions&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;          &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;execution&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;ide-support&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;goals&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;              &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;goal&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;eclipse&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;goal&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;goals&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;          &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;execution&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;executions&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;      &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;plugin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;plugins&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;build&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;project&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;After the main project is created pax-runner will be able to start an osgi container from this folder and automatically deploy any homemade or imported bundles automatically. Before we do that, let’s give it something to deploy. Run pax-create-bundle from the main project directory, keeping the group id the same as the one you used when creating the project.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_QxI2aQuFZnk/S1fRJSreN7I/AAAAAAAAAGY/CW-WenC0z38/s1600-h/Screen%20shot%202010-01-20%20at%209.47.36%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Screen shot 2010-01-20 at 9.47.36 PM" border="0" alt="Screen shot 2010-01-20 at 9.47.36 PM" src="http://lh6.ggpht.com/_QxI2aQuFZnk/S1fRKk_c0II/AAAAAAAAAGc/geneVq4MXEU/Screen%20shot%202010-01-20%20at%209.47.36%20PM_thumb%5B1%5D.png?imgmax=800" width="713" height="316" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The pax-create-bundle command will create a familiar project structure for anyone who has used maven. From here you can explore the sample code, delete it when ready and then create your domain classes. My simple example just has two domain classes an Entry and a Raffle. If you are creating domain objects that are not anemic, you’ll probably have a good chance of needing some third party libraries. In my code I planned on using the commons-lang libraries for their equals and hashcode builders. When presented with the need for an external jar in an OSGi environment, you have to ask yourself if this should be embedded into your own bundle as a dependency or installed as a separate bundle within the container. Both have pros and cons, but the decision boils down to whether you feel this jar will be used by other bundles within the system. The commons-lang jars are only useful right now in our domain bundle so we’ll embed. Just update your pom.xml file with the dependency and maven will take care of bringing the external jar into a repository and ensuring that it’s compiled into your bundle. Now is also a good time to add a test dependency on TestNG or JUnit and write some unit tests around the logic in your domain classes.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;One other thing to note before deploying this bundle. Pax Construct will make use of BND to generate the manifest file. BND scans the source files, generates an import list, and provides sensible defaults for the manifest so that you don’t have to roll it by hand each time. Since we are just using our domain bundle as a standalone bundle to be consumed by others and it doesn’t have a service or activator, you can simply nuke the generated line in the osgi.bnd file. If all has gone according to plan so far, the last thing is to fire it up. From the main project directory you can run mvn install to compile the domain and then run pax-provision to start up the container and deploy your bundle. Hopefully you get a slew of nifty ascii art indicating that pax-runner has successfully started up and you are greeted with an OSGi prompt. Issuing a short status command if you are using equinox should result in 2 happily active bundles:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_QxI2aQuFZnk/S1fRLDCBh1I/AAAAAAAAAGg/MRRyQf_j2Bg/s1600-h/Screen%20shot%202010-01-20%20at%2010.26.15%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Screen shot 2010-01-20 at 10.26.15 PM" border="0" alt="Screen shot 2010-01-20 at 10.26.15 PM" src="http://lh6.ggpht.com/_QxI2aQuFZnk/S1fRLg_AFrI/AAAAAAAAAGk/N3mrfXx-Aqw/Screen%20shot%202010-01-20%20at%2010.26.15%20PM_thumb%5B1%5D.png?imgmax=800" width="702" height="254" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So far we’ve created a project, learned how to use pax-construct, embedded a third party jar, and created a bundle that is relatively useless by itself. In the next post, we’ll see how to make use of that bundle from another.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Code samples are available on &lt;a href="http://github.com/tkaufman/Codemash-OSGi"&gt;github&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-6227952598012226905?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/6227952598012226905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=6227952598012226905' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6227952598012226905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6227952598012226905'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2010/01/step-1-creating-your-domain.html' title='Step 1 - Creating your Domain'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_QxI2aQuFZnk/S1fRJDpKaBI/AAAAAAAAAGU/N0viJqDXtww/s72-c/Screen%20shot%202010-01-20%20at%209.32.42%20PM_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-8012568857235580371</id><published>2010-01-11T14:33:00.008-05:00</published><updated>2010-01-20T23:03:53.110-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Step 0 - Simple OSGi</title><content type='html'>OSGi is a longstanding framework for building modular applications. I won't go into the details as I'm assuming you are somewhat interested in the framework to have found my blog. Two of the best resources I've found are:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.jroller.com/habuma"&gt;Craig Walls' blog&lt;/a&gt;&lt;br /&gt;&lt;a href="http://techdistrict.kirkk.com/"&gt;Kirk Knoerschild's blog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Craig and Kirk are helping many (including myself) to grok the benefits of OSGi and dispel the myths around it's adoption. Specifically, Craig's  &lt;a href="http://www.jroller.com/habuma/date/20090413"&gt;post&lt;/a&gt; refuting the challenges with OSGi covers almost all of the issues usually brought up.&lt;br /&gt;&lt;br /&gt;Now that that's settled, let's get a simple example up and running.&lt;br /&gt;&lt;br /&gt;I'm going to be using Equinox for my examples. Primarily because it supports all of the features we'll need and also because it's bundled with Eclipse so you can easily find it and get it started.&lt;br /&gt;&lt;br /&gt;Download equinox from &lt;a href="http://download.eclipse.org/equinox/"&gt;here&lt;/a&gt;. You can just get by with the framework jar. You can start the eclipse container with &lt;br /&gt;&lt;br /&gt;java -jar org.eclipse.osgi_3.5.1.R35x_v20090827.jar  -console&lt;br /&gt;&lt;br /&gt;Issuing a short status command with ss shows&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QxI2aQuFZnk/S0zAX6CdriI/AAAAAAAAAEI/j21QWy5PltI/s1600-h/Screen+shot+2010-01-12+at+11.33.06+AM.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 133px;" src="http://3.bp.blogspot.com/_QxI2aQuFZnk/S0zAX6CdriI/AAAAAAAAAEI/j21QWy5PltI/s320/Screen+shot+2010-01-12+at+11.33.06+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5425923168023719458" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Since we haven't built a bundle yet, the only thing available is the osgi core bundle. A bundle is simply no more than a jar file with a quirky META-INF/MANIFEST.MF file. Building the equivalent of Hello World can be done with this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class='linenum'&gt;    1&lt;/span&gt; &lt;span class="source source_java"&gt;&lt;span class="meta meta_package meta_package_java"&gt;&lt;span class="keyword keyword_other keyword_other_package keyword_other_package_java"&gt;package&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_package storage_modifier_package_java"&gt;com.pillartech&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_java"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;    2&lt;/span&gt; &lt;br /&gt;&lt;span class='linenum'&gt;    3&lt;/span&gt; &lt;span class="meta meta_import meta_import_java"&gt;&lt;span class="keyword keyword_other keyword_other_import keyword_other_import_java"&gt;import&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_import storage_modifier_import_java"&gt;org.osgi.framework.BundleActivator&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_java"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;    4&lt;/span&gt; &lt;span class="meta meta_import meta_import_java"&gt;&lt;span class="keyword keyword_other keyword_other_import keyword_other_import_java"&gt;import&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_import storage_modifier_import_java"&gt;org.osgi.framework.BundleContext&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_java"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;    5&lt;/span&gt; &lt;br /&gt;&lt;span class='linenum'&gt;    6&lt;/span&gt; &lt;span class="meta meta_class meta_class_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;public&lt;/span&gt; &lt;span class="meta meta_class meta_class_identifier meta_class_identifier_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_java"&gt;SuperSimple&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_definition meta_definition_class meta_definition_class_implemented meta_definition_class_implemented_interfaces meta_definition_class_implemented_interfaces_java"&gt;&lt;span class="storage storage_modifier storage_modifier_implements storage_modifier_implements_java"&gt;implements&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_java"&gt;BundleActivator&lt;/span&gt; &lt;/span&gt;&lt;span class="meta meta_class meta_class_body meta_class_body_java"&gt;{&lt;br /&gt;&lt;span class='linenum'&gt;    7&lt;/span&gt; &lt;br /&gt;&lt;span class='linenum'&gt;    8&lt;/span&gt;     &lt;span class="meta meta_method meta_method_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;public&lt;/span&gt; &lt;span class="meta meta_method meta_method_return-type meta_method_return-type_java"&gt;&lt;span class="storage storage_type storage_type_primitive storage_type_primitive_array storage_type_primitive_array_java"&gt;void&lt;/span&gt; &lt;/span&gt;&lt;span class="meta meta_method meta_method_identifier meta_method_identifier_java"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_java"&gt;start&lt;/span&gt;(&lt;span class="storage storage_type storage_type_java"&gt;BundleContext&lt;/span&gt; &lt;span class="variable variable_parameter variable_parameter_java"&gt;ctx&lt;/span&gt;)&lt;/span&gt; &lt;span class="meta meta_throwables meta_throwables_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;throws&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Exception&lt;/span&gt; &lt;/span&gt;&lt;span class="meta meta_method meta_method_body meta_method_body_java"&gt;{&lt;br /&gt;&lt;span class='linenum'&gt;    9&lt;/span&gt;         &lt;span class="storage storage_type storage_type_java"&gt;System&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_dereference keyword_operator_dereference_java"&gt;.&lt;/span&gt;out&lt;span class="keyword keyword_operator keyword_operator_dereference keyword_operator_dereference_java"&gt;.&lt;/span&gt;println(&lt;span class="string string_quoted string_quoted_double string_quoted_double_java"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_java"&gt;"&lt;/span&gt;Starting Up!&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_java"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;span class="punctuation punctuation_terminator punctuation_terminator_java"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;   10&lt;/span&gt;     &lt;/span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;   11&lt;/span&gt;     &lt;br /&gt;&lt;span class='linenum'&gt;   12&lt;/span&gt;     &lt;span class="meta meta_method meta_method_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;public&lt;/span&gt; &lt;span class="meta meta_method meta_method_return-type meta_method_return-type_java"&gt;&lt;span class="storage storage_type storage_type_primitive storage_type_primitive_array storage_type_primitive_array_java"&gt;void&lt;/span&gt; &lt;/span&gt;&lt;span class="meta meta_method meta_method_identifier meta_method_identifier_java"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_java"&gt;stop&lt;/span&gt;(&lt;span class="storage storage_type storage_type_java"&gt;BundleContext&lt;/span&gt; &lt;span class="variable variable_parameter variable_parameter_java"&gt;ctx&lt;/span&gt;)&lt;/span&gt; &lt;span class="meta meta_throwables meta_throwables_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;throws&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Exception&lt;/span&gt; &lt;/span&gt;&lt;span class="meta meta_method meta_method_body meta_method_body_java"&gt;{&lt;br /&gt;&lt;span class='linenum'&gt;   13&lt;/span&gt;         &lt;span class="storage storage_type storage_type_java"&gt;System&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_dereference keyword_operator_dereference_java"&gt;.&lt;/span&gt;out&lt;span class="keyword keyword_operator keyword_operator_dereference keyword_operator_dereference_java"&gt;.&lt;/span&gt;println(&lt;span class="string string_quoted string_quoted_double string_quoted_double_java"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_java"&gt;"&lt;/span&gt;Shutting Down!&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_java"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;span class="punctuation punctuation_terminator punctuation_terminator_java"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;   14&lt;/span&gt;     &lt;/span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class='linenum'&gt;   15&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_class punctuation_section_class_end punctuation_section_class_end_java"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is just a java file though until we add the magic to a MANIFEST.MF file and jar the thing up. Here is a simple manifest to get started:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class='linenum'&gt;    1&lt;/span&gt; &lt;span class="text text_plain"&gt;&lt;span class="meta meta_paragraph meta_paragraph_text"&gt;Bundle-ManifestVersion: 2&lt;br /&gt;&lt;span class='linenum'&gt;    2&lt;/span&gt; Bundle-SymbolicName: com.pillartech.SuperSimple&lt;br /&gt;&lt;span class='linenum'&gt;    3&lt;/span&gt; Bundle-Name: SuperSimple&lt;br /&gt;&lt;span class='linenum'&gt;    4&lt;/span&gt; Bundle-Version: 1.0.0&lt;br /&gt;&lt;span class='linenum'&gt;    5&lt;/span&gt; Bundle-Activator: com.pillartech.SuperSimple&lt;br /&gt;&lt;span class='linenum'&gt;    6&lt;/span&gt; Import-Package: org.osgi.framework&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As long as you include the symbolic name of the bundle it should work, but the rest of it gives you a feel of the meaning of the manifest. It provides all of the information used by other bundles to consume it, and also a list of the other bundles that it imports.&lt;br /&gt;&lt;br /&gt;Compiling this class and jar-ing the class and manifest together allows you to deploy it and start it&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QxI2aQuFZnk/S0zBx1jBxQI/AAAAAAAAAEQ/JDDZWKeY4Zg/s1600-h/Screen+shot+2010-01-12+at+1.38.23+PM.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 190px;" src="http://3.bp.blogspot.com/_QxI2aQuFZnk/S0zBx1jBxQI/AAAAAAAAAEQ/JDDZWKeY4Zg/s320/Screen+shot+2010-01-12+at+1.38.23+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5425924713006351618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;From there you can see descriptive information about this bundle and it's manifest with the bundle and headers commands&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QxI2aQuFZnk/S0zCU1isi0I/AAAAAAAAAEY/vRpcpyXz-Uo/s1600-h/Screen+shot+2010-01-12+at+1.40.41+PM.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 185px;" src="http://2.bp.blogspot.com/_QxI2aQuFZnk/S0zCU1isi0I/AAAAAAAAAEY/vRpcpyXz-Uo/s320/Screen+shot+2010-01-12+at+1.40.41+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5425925314300382018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Stopping the bundle will produce an equally productive message and return it to the INSTALLED state. Finally issuing an exit command will shutdown the container.&lt;br /&gt;&lt;br /&gt;So with this example we've done the simplest thing we can to get a bundle installed, started, described, and stopped in equinox. These commands are the core to developing and manipulating bundles in a runtime with OSGi. We'll leverage them further in the subsequent examples to build our solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-8012568857235580371?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/8012568857235580371/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=8012568857235580371' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8012568857235580371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8012568857235580371'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2010/01/enterprise-osgi-step-0.html' title='Step 0 - Simple OSGi'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QxI2aQuFZnk/S0zAX6CdriI/AAAAAAAAAEI/j21QWy5PltI/s72-c/Screen+shot+2010-01-12+at+11.33.06+AM.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-3250344677685383833</id><published>2010-01-11T14:20:00.010-05:00</published><updated>2010-02-15T21:12:54.794-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Enterprise OSGi in 10 steps</title><content type='html'>I'm presenting a Modular Java pre-compiler session at Codemash and in preparing I have learned a good deal about OSGi. My mode of learning was to take small granular steps towards a front to back solution to a typical project problem, but with the benefit of using OSGi. If you want to follow my footsteps, the best thing you can do is come to Codemash and attend the pre-compiler. If you aren't fortunate enough to get there, I'm going to post 10 blog posts to build up your knowledge of OSGi and the accompanying tools. This post will serve as a table of contents.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toddkaufman.blogspot.com/2010/01/enterprise-osgi-step-0.html"&gt;Step 0 - Simple Bundle&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toddkaufman.blogspot.com/2010/01/step-1-creating-your-domain.html"&gt;Step 1 - Creating your Domain&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toddkaufman.blogspot.com/2010/01/step-2-importing-bundles.html"&gt;Step 2 - Importing from another Bundle&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toddkaufman.blogspot.com/2010/02/step-3-service-consumption.html"&gt;Step 3 - Service Oriented OSGi&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toddkaufman.blogspot.com/2010/02/step-4-spring-dynamic-modules.html"&gt;Step 4 - Spring DM&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toddkaufman.blogspot.com/2010/02/step-45-spring-dm-extender-logging.html"&gt;Step 4.5 - Spring DM Extender Logging&lt;/a&gt;&lt;br /&gt;Step 5 - Persistence&lt;br /&gt;Step 6 - Integration Testing&lt;br /&gt;Step 7 - Web Development&lt;br /&gt;Step 8 - Skinning a UI&lt;br /&gt;Step 9 - Deploy Time Configuration&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-3250344677685383833?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/3250344677685383833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=3250344677685383833' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3250344677685383833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3250344677685383833'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2010/01/enterprise-osgi-in-10-steps.html' title='Enterprise OSGi in 10 steps'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-7362376671657699393</id><published>2009-11-13T21:18:00.002-05:00</published><updated>2010-01-03T08:30:13.659-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='macfu'/><title type='text'>My Mac Tools</title><content type='html'>I recently started over from scratch on a shiny new 15" macbook pro. What I didn't realize is how many tools I've accumulated on the old machine. While downloading 4 separate tools at once, I thought it would be a good time to track my favorites for posterity's sake (and to help my friend &lt;a href="http://www.timwingfield.com"&gt;Tim&lt;/a&gt; who is in a similar scenario).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://adium.im/"&gt;Adium&lt;/a&gt; - IM client of choice&lt;br /&gt;&lt;a href="http://www.blacktree.com/"&gt;Quicksilver&lt;/a&gt; - I have trouble interfacing with my mac without it&lt;br /&gt;&lt;a href="http://www.tweetdeck.com/"&gt;TweetDeck&lt;/a&gt; - My favorite twitter client&lt;br /&gt;&lt;a href="http://culturedcode.com/things/"&gt;Things&lt;/a&gt; - My method for Getting Things Done&lt;br /&gt;&lt;a href="http://willmore.eu/software/isolator/"&gt;Isolator&lt;/a&gt; - Tool for improving focus&lt;br /&gt;&lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; - Great lightweight editor&lt;br /&gt;&lt;a href="http://www.springsource.com/products/sts"&gt;SpringSource Tool Suite&lt;/a&gt; - Great heavyweight editor&lt;br /&gt;&lt;a href="http://tomcat.apache.org/"&gt;Tomcat&lt;/a&gt; - Java webserver&lt;br /&gt;&lt;a href="http://dev.mysql.com/downloads/"&gt;MySQL&lt;/a&gt; - Powerful open source database&lt;br /&gt;&lt;a href="http://www.sequelpro.com/"&gt;Sequel&lt;/a&gt; - Very nice client for SQL&lt;br /&gt;&lt;a href="http://www.skype.com/"&gt;Skype&lt;/a&gt; - You know&lt;br /&gt;&lt;a href="http://jumpcut.sourceforge.net/"&gt;JumpCut&lt;/a&gt; - Better copying tool&lt;br /&gt;&lt;a href="http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html"&gt;SuperDuper&lt;/a&gt; - Backups that work&lt;br /&gt;&lt;a href="http://cyberduck.ch/"&gt;Cyberduck&lt;/a&gt; - FTP, webDAV, Cloud Client&lt;br /&gt;&lt;a href="https://www.dropbox.com/"&gt;Dropbox&lt;/a&gt; - Ass kicking Cloud storage&lt;br /&gt;&lt;a href="http://iterm.sourceforge.net/"&gt;iTerm&lt;/a&gt; - My preferred terminal client&lt;br /&gt;&lt;a href="http://www.evernote.com/"&gt;Evernote&lt;/a&gt; - Quick note taking&lt;br /&gt;&lt;a href="http://www.vmware.com/products/fusion/"&gt;VMWare Fusion&lt;/a&gt; - Better than Parallels IMHO&lt;br /&gt;&lt;br /&gt;And that's about it. I'll try to update as I remember others, but these are the tools that I really missed in the first two days of using my new mac.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-7362376671657699393?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/7362376671657699393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=7362376671657699393' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7362376671657699393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7362376671657699393'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/11/my-mac-tools.html' title='My Mac Tools'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-4931148320073497669</id><published>2009-11-11T20:44:00.007-05:00</published><updated>2009-11-12T12:08:46.877-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pillar'/><title type='text'>5 Reasons I Work at Pillar Technology</title><content type='html'>&lt;span style="font-weight:bold;"&gt;People&lt;/span&gt;&lt;br /&gt;I've been aware of Pillar Technology for some time and I thought that they had some good people here and there, but I've been astounded by the amount of talent that I've had the pleasure of working with in my short time here. Up and down the organization I've met elite software developers, agile coaches, team leaders, and many others who excel at what they do. One of our .NET leaders informed me that his rate for recommending new hires is at about 8%. 92% of the candidates he interviews are not at the level needed to work for Pillar. If, like me, you want to elevate your career, go work with a team of people that you can learn from.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Process&lt;/span&gt;&lt;br /&gt;I've contended for some time that Agile and Lean software development techniques will be more common than Waterfall within the next 5 years for some very simple reasons. Agile techniques result in working systems, with fewer defects, delivered faster, and with a lower total cost of ownership than the alternatives. We are already starting to see a backlash against some of the short term, cheap construction solutions that have proven time and again to be less efficient and more expensive than previously thought. As more and more companies begin adopting Agile as a cure to their failing projects, look for consulting companies like Pillar that are leaders in this space to grow exponentially.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Collaboration&lt;/span&gt;&lt;br /&gt;In the first week of working at Pillar, I've had the pleasure of offering my ideas on where we could take this company to our CEO, COO, multiple VPs, my peers, my team, my wife, my kids, and everyone else who will listen.I was a part of no less than 4 meetings in the first week focused on taking our company to the next level. Ideas at Pillar are solicited, not criticized. True openness and collaboration in an organization is hard to come by, but it is crucial for long term, strategic growth.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Focus&lt;/span&gt;&lt;br /&gt;The companies that have grown in this economy have shared a few traits. One of them is to know what you are good at, and you focus on taking that to market better than anyone else. Pillar is extremely good at applying elite software development teams using Agile methodologies, to solve problems. Everything that we do here in the next 10 years will be in line with that focus. Companies that attempt to react to every opportunity presented to them have historically diluted their talent and weakened their position in the market place.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;No Boundaries&lt;/span&gt;&lt;br /&gt;Applying the core capability referenced above to as broad a population as you can has been a pattern of success for organizations for well over a century. Nike didn't start out by thinking they could sell tennis shoes to a few high schools in Oregon. Microsoft was focused on delivering computers to every home in the world at a time when the market was really only medium or large businesses. Pillar is at a point where the company is transforming from a regional focus to a national focus and I have every confidence we'll be successful. Sit tight, it may not be that long until we're international.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-4931148320073497669?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/4931148320073497669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=4931148320073497669' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4931148320073497669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4931148320073497669'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/11/5-reasons-i-work-at-pillar-technology.html' title='5 Reasons I Work at Pillar Technology'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-8636797985019096140</id><published>2009-10-30T10:20:00.004-04:00</published><updated>2009-10-30T15:44:52.254-04:00</updated><title type='text'>Thank You QSI</title><content type='html'>About 6 years ago I began my first consulting assignment with the idea that I would bounce around from client to client, build my network, and begin to determine what type of company I wanted to work for. A strange thing happened however, I began to realize that my consulting company, &lt;a href="http://www.quicksolutions.com"&gt;Quick Solutions&lt;/a&gt;, was exactly the type of company that I wanted to work for. They valued people above all else and built a staff of passionate leaders in technology that I was proud to be a part of. They realized that software development is most successfully done with TEAMS and not individuals so they fostered a team culture that made me excited to go to work every day. They understood that our company should be built with a mentality of ownership and provided benefits that cultivated that mindset across the organization. For the past six years I have been extremely privileged to work at QSI and it is with a heavy heart that I announce my departure from this great organization.&lt;br /&gt;&lt;br /&gt;All things change and eventually come to an end, but words are not capable of articulating how hard this decision has been.  I hope all of my great friends at QSI know that they made this decision gut wrenching and I am only able to make it knowing that I will keep in touch and continue to work, drink beer, talk shop, or golf with them in the future. The number of people at QSI who have helped change and crystalize my views on software development are too many to list here, but I sincerely thank all of you for the career altering opportunity to work with you. We will always be bound by our shared hatred of Lotus Notes.&lt;br /&gt;&lt;br /&gt;TK&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-8636797985019096140?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/8636797985019096140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=8636797985019096140' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8636797985019096140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8636797985019096140'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/10/thank-you-qsi.html' title='Thank You QSI'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-2653183691695869885</id><published>2009-10-12T20:15:00.002-04:00</published><updated>2009-10-12T20:21:02.082-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='speaking'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>OSGi Talks</title><content type='html'>I'll be presenting at the Central Ohio Java User's Group tomorrow, 10/13 on Modular Java with OSGi. This talk will be a discussion of why OSGi is needed with enough demo code and meat to leave the attendees ready to start exploring OSGi on their own.&lt;br /&gt;&lt;br /&gt;I've also been fortunate enough to be selected to present a 1/2 day pre-compiler at &lt;a href="http://codemash.org"&gt;Codemash&lt;/a&gt; on OSGi. This talk will quickly cover the gaps in Java that necessitate OSGi in addition to exploring, via hands on construction, the patterns and tools for successful OSGi adoption. We'll basically spend 3+ hours building an enterprise Java system with OSGi from scratch! I'm pumped and honored to be hosting the pre-compiler so please sign up if you want to get a 1/2 day submersion into building better Java applications that are more flexible, maintainable and testable than previously thought.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-2653183691695869885?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/2653183691695869885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=2653183691695869885' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2653183691695869885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2653183691695869885'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/10/osgi-talks.html' title='OSGi Talks'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1686271694143990578</id><published>2009-08-22T21:33:00.003-04:00</published><updated>2009-08-22T22:18:14.014-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='principles'/><category scheme='http://www.blogger.com/atom/ns#' term='interview'/><title type='text'>Interviewing Tip #3 - Focus on Fundamentals</title><content type='html'>Apologies for the significant delay, but I wanted to pick up the interviewing tips to get at least two more topics off my chest before turning to other posts.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jonkruger.com/blog"&gt;Jon Kruger&lt;/a&gt; is a coworker of mine and I'd clone him and staff 5 of him on every project if I could. Lately, I've been striving to understand what the qualities are in Jon and some other elite developers I've worked with that increase the velocity of the teams they work on. I'll expand more on the positive and negative characteristics of elite developers in later posts, but in regards to interviewing, one of the big things that I now focus on are fundamentals.&lt;br /&gt;&lt;br /&gt;I was fortunate to have some good mentors early in my career who pushed me to truly understand the pros and cons of every possible solution. That drive lead me into study of object oriented programming, evolutionary design, and foundational principles of development like &lt;a href="http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf"&gt;SOLID&lt;/a&gt;. Uncle Bob, Bertrand Meyer, Martin Fowler, and others instilled within me, if nothing else, enough questions to keep pushing to look at solutions from all angles. I'm far from being the authoritative source on which solution is "best", but I will always continue to ask questions to try to find pros and cons of different approaches.&lt;br /&gt;&lt;br /&gt;I've at times let people slide in an interview without much pressure on their foundational knowledge, but no more. I could care less at this point if you know whether SQLException is a Checked or Runtime exception in Java. You better be able to talk through the tradeoffs of having it either way, though. I used to dismiss Bruce Eckel's suggestion of asking potential candidates "What's the object model of a chicken?". I have used it a number of times though and it's a great question to start probing how someone may decompose a business domain into OO concepts. If you get scheduled for an interview with me and you can't argue why you would or wouldn't favor composition over inheritance, then we're not ready to work together. I'm not naive enough to think that all interviewers are like me, but if you can talk at a foundational level on design tradeoffs, I can't imagine an interviewer not wanting to talk further with you or hire you the very same day. &lt;br /&gt;&lt;br /&gt;Jon's post &lt;a href="http://jonkruger.com/blog/2009/07/26/what-should-you-learn-next"&gt;here&lt;/a&gt; is a great call to arms for software devs. If your interviewer focuses on the APIs of Silverlight or MVC, and not on the benefits or drawbacks of either solution, you need to question whether you are interviewing with the right company. Similarly, if you can't articulate a number of outstanding refactoring items from your last project, or openly debate the benefits and drawbacks of some design decision you made on that project, then you probably need to brush up more on the fundamentals of programming and design before you look at making a career change.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1686271694143990578?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1686271694143990578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1686271694143990578' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1686271694143990578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1686271694143990578'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/08/interviewing-tip-3-focus-on.html' title='Interviewing Tip #3 - Focus on Fundamentals'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-8229423068217842520</id><published>2009-05-04T20:41:00.005-04:00</published><updated>2009-05-21T22:50:56.488-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interview'/><title type='text'>Interviewing Tip #2 - Don't be a Commodity</title><content type='html'>Never forget that the interview process is no different than any other sales process. You are selling your goods to the interviewer and trying to convince them that you are the best candidate for the job. If you read &lt;a href="http://toddkaufman.blogspot.com/2009/04/interviewing-tip-1-become-interviewer.html"&gt;the last tip&lt;/a&gt; then you know that you are also a consumer in this process, looking for the best career opportunity. The selling goes both ways, but for now, we'll focus on what the interviewer is looking for in a candidate.&lt;br /&gt;&lt;br /&gt;In these times, it's a given that there are a number of viable candidates. It is inevitable that many of the competition will adequately answer the technically focused questions that are thrown at you. The fact that you know Spring, NHibernate, Cucumber, or MVC does not separate you from the competition. Ok, well if you know Cucumber it probably does, but what are the odds that you'll get questioned about it? My point is that Java developers who know Spring and Hibernate are commodities. Candidates need to articulate the other, softer skills that they bring to the table because they stand out.&lt;br /&gt;&lt;br /&gt;Separate yourself from the pack by showing your passion for software development. The fact that you are learning Erlang in your own time may not be applicable to my immediate project need, but it surely shows that you are honing your skills in your own time. Furthermore it shows that you are trying to get better at what you do and that you have some ability to learn independently. Employees like that are assets in any organization.&lt;br /&gt;&lt;br /&gt;Covering the technologies used on your past projects doesn't have nearly as much impact as communicating how you stepped into the QA role on the project because there was a resource gap. Or how you were able to reduce the time spent in system testing by setting up a CI server to eliminate defects. Or how you worked over the weekend to fix an issue with the production system that had plagued the company for years. These instances tell a story that your technical responses never do.&lt;br /&gt;&lt;br /&gt;Leadership, passion, independence, and drive are the factors that sway decision makers. Don't let yourself get continually attacked with technical questions. Answer them accurately and succinctly, but steer the interview towards the softer skills and show where you've gone beyond your role to ensure success on your projects. That is where you'll separate yourself from the commodity and win the job!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-8229423068217842520?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/8229423068217842520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=8229423068217842520' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8229423068217842520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8229423068217842520'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/05/interviewing-tip-2-dont-be-commodity.html' title='Interviewing Tip #2 - Don&apos;t be a Commodity'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1401896178629578877</id><published>2009-04-30T10:23:00.002-04:00</published><updated>2009-04-30T16:39:13.232-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interviewer'/><title type='text'>Interviewing Tip #1 - Become the Interviewer</title><content type='html'>This economy blows. Let's be clear about that. Nationwide unemployment rose to nearly 9% in April and IT is not immune. I've had the first hand experience of letting people go who I would love to work with again and I cannot describe how painful that experience is. We've had a number of clients cut projects short, shelve them completely, or force a reduction in rates regardless of their contract. IT and consulting jobs specifically have become extremely competitive as a result.&lt;br /&gt;&lt;br /&gt;This post (and some subsequent ones) will be targeted to anyone who is currently out of work or in a consulting role, interviewing for one of the precious few jobs out there. Please don't kid yourself, you will be one of many potential candidates who are vying for jobs and a lot of candidates are out of work and willing to come in at a lower salary/bill rate. Separating yourself from the masses is even more critical in this environment.&lt;br /&gt;&lt;br /&gt;I have the unique position of sitting on both sides of the interview desk. I interview about 50 people per year and also compete as a candidate for some consulting engagements. I'm going to try to let people know mistakes that I, my consultants, or my candidates have made and areas where we've excelled.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Tip #1 - Become the Interviewer&lt;/span&gt;&lt;br /&gt;As an interviewer, if I don't feel like I want to work with you, I probably won't hire you. More importantly, if I don't feel that you want to work with us, I definitely won't hire you. I've worked with people who have no passion to come in on a day to day basis and help me solve problems, and they are a huge anchor to our team's productivity. They create tension and animosity among teammates, they slow the overall velocity of our team down, and generally do more harm than good.&lt;br /&gt;&lt;br /&gt;If you want to dispel that feeling in your interviewer, then you need to let them know that you are eager to work in the position in front of you. I end every interview by asking a candidate if I can answer any questions that they have. If the candidate has not asked any questions to that point and still has nothing to ask me, I'm pretty much assured that they have no real interest in building a career at our organization. They are looking to fill a monetary gap in their life and I have no interest in helping them out.&lt;br /&gt;&lt;br /&gt;Conversely, if the candidate responds with questions about the team, the environment, the projects, the challenges, the organizational structure, the benefits, the strategic direction, the color of the walls, the quality of the seats, the use of Lotus Notes, etc... then I know that they have a genuine interest in working with QSI and they are doing their homework. Further, they obviously are looking at making an educated decision on their &lt;span style="font-style:italic;"&gt;career&lt;/span&gt; and not just getting a job. The interview should always be bi-directional, don't just get peppered by the interviewer.&lt;br /&gt;&lt;br /&gt;Also, please recognize that the astute interviewer will draw some conclusions about you based on the questions you are asking. Candidates need to focus on asking the questions that are most important and critical in determining whether they want to work on this project. If you are only asking me about money, vacation time, health benefits, and the like I am pretty confident that your deciding factor is strictly based on compensation. I personally get much more excited when I'm interviewing someone and they are asking about the team makeup, type of project, challenges, technologies in use, and opportunity for career growth. Just please, don't ask me about our use of Lotus Notes, I don't want to scare you away.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1401896178629578877?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1401896178629578877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1401896178629578877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1401896178629578877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1401896178629578877'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/04/interviewing-tip-1-become-interviewer.html' title='Interviewing Tip #1 - Become the Interviewer'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-4503002617894667758</id><published>2009-01-21T20:25:00.002-05:00</published><updated>2009-01-21T20:36:35.289-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='goals'/><title type='text'>2009 Goals</title><content type='html'>My good friend &lt;a href="http://jeffblankenburg.com/default.aspx"&gt;Jeff&lt;/a&gt; tagged me to blog my goals for the year. I'm glad he gave me a little inspiration for this as my personal goals are something that's been floating around in my head for some time. With the exception of the first two they are in no order. Here they are, etched in the annals of the internet.&lt;br /&gt;&lt;br /&gt;1.) Delight my wife&lt;br /&gt;2.) Be a better father to my 2 girls&lt;br /&gt;3.) Exceed the expectations of every customer I come in contact with&lt;br /&gt;4.) Blog every other week&lt;br /&gt;5.) Speak every quarter at a user group or conference&lt;br /&gt;6.) Contribute to an open source project&lt;br /&gt;7.) Hire 5 people smarter than myself (low barrier, I know)&lt;br /&gt;8.) Exercise 3 times a week&lt;br /&gt;9.) Read 12 books&lt;br /&gt;10.) Brew 4 times&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-4503002617894667758?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/4503002617894667758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=4503002617894667758' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4503002617894667758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4503002617894667758'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2009/01/2009-goals.html' title='2009 Goals'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-3006787676835748591</id><published>2008-12-14T20:28:00.003-05:00</published><updated>2008-12-14T20:33:01.292-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='macfu'/><title type='text'>Burning Media from Mac OSX</title><content type='html'>Repeat after me, "Sissies use GUIs. Sissies use GUIs. Sissies use GUIs."&lt;br /&gt;&lt;br /&gt;Okay, now that we have that covered here is the command I continue to forget when trying to burn an iso onto a CD from my macbook pro.&lt;br /&gt;&lt;span style="font-weight:bold;font-style:italic;"&gt;&lt;br /&gt;hdiutil burn ~/Downloads/ubuntu-8.10-desktop-i386.iso&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Beats fumbling around with Finder any day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-3006787676835748591?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/3006787676835748591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=3006787676835748591' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3006787676835748591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3006787676835748591'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/12/burning-media-from-mac-osx.html' title='Burning Media from Mac OSX'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-6286118191377833795</id><published>2008-12-09T08:23:00.002-05:00</published><updated>2008-12-09T10:30:08.695-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Howdy Parnter!</title><content type='html'>I'm pleased to announce that Quick Solutions, Inc. is now a certified Systems Integration Partner with SpringSource.&lt;br /&gt;&lt;br /&gt;The Spring framework is the standard for Java development. SpringSource has built upon that momentum with a keen vision in developing products and services that benefit enterprise customers using Spring. Whether it is the OSGi enabled dm Server, an instrumented version of the Spring offering with a common monitoring application, or a support model that bests Oracle, IBM, or JBoss, the future of Java development is a very clearly dominated by Spring and SpringSource.&lt;br /&gt;&lt;br /&gt;Quick Solutions is driven by providing software based solutions to our customer's problems. We strive to do this in a manner that passes the most value on to our clients. Partnering with SpringSource will allow us to clearly articulate and demonstrate the value that their products generate within Enterprise Java development. We look forward to working closely with Rod and the gang in 2009 and beyond.&lt;br /&gt;&lt;br /&gt;Stay tuned for some more information on making best use of the products in the SpringSource umbrella.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-6286118191377833795?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/6286118191377833795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=6286118191377833795' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6286118191377833795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6286118191377833795'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/12/howdy-parnter.html' title='Howdy Parnter!'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-4722304544436991559</id><published>2008-10-14T10:55:00.008-04:00</published><updated>2008-10-15T14:02:44.160-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='thanks'/><category scheme='http://www.blogger.com/atom/ns#' term='opensource'/><title type='text'>Thank You SchemaSpy</title><content type='html'>I love open source contributors. These people are the geeks who bypass reality shows, online gaming, and time with their families so that they can bring you something that will make your life better. They get nothing in return but a "atta boy/girl" and a pat on the back.&lt;br /&gt;&lt;br /&gt;I am taking it upon myself to give thanks to a few of these open source contributors over the coming months. I am a typically just a taker when it comes to open source, but I would like to at least let the givers know, that I appreciate their hard work and commitment.&lt;br /&gt;&lt;br /&gt;The first shout out goes to the kind contributors of &lt;a href="http://schemaspy.sourceforge.net"&gt;SchemaSpy&lt;/a&gt;. SchemaSpy allows you to generate a web based ERD of an entire database, that is easily navigated by clicking on images throughout the web application. It's a simple jar file that can be downloaded and executed on any platform that has java installed. It supports a wide variety of databases and produces a ton of information in an easy to digest medium. The first thing you'll be presented is the table listing:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_QxI2aQuFZnk/SPYof0nBA7I/AAAAAAAAAC8/sflDTiRI4Vw/s1600-h/Picture+2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_QxI2aQuFZnk/SPYof0nBA7I/AAAAAAAAAC8/sflDTiRI4Vw/s320/Picture+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5257434142164976562" /&gt;&lt;/a&gt;&lt;br /&gt;This view gives you all of the tables in the system, the number of rows in each table, and a number of other tables directly related via foreign key to this table.&lt;br /&gt;&lt;br /&gt;When you click on one of the table names you are presented with the more specific table view:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_QxI2aQuFZnk/SPYn7yKcJ3I/AAAAAAAAAC0/VsNS97PNxtc/s1600-h/Picture+1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_QxI2aQuFZnk/SPYn7yKcJ3I/AAAAAAAAAC0/VsNS97PNxtc/s320/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5257433523032958834" /&gt;&lt;/a&gt;&lt;br /&gt;The top level of information is like a describe of the table, but checking some of the boxes will allow you to see navigable parent and child rows for each of the columns.If you click on the images in the mini-ERD at the bottom of the page, it will navigate to the appropriate tables. Also note that you can expand the mini-ERD to 2 degrees of relationships.&lt;br /&gt;&lt;br /&gt;These features in and of themselves are enough reason to automatically document your database with this tool, but another really applicable portion of the tool is the ability to identify anomalies within the database. Clicking on that tab provides you with this view:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_QxI2aQuFZnk/SPYudaJVloI/AAAAAAAAADE/izVZWe7tpyU/s1600-h/Picture+3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_QxI2aQuFZnk/SPYudaJVloI/AAAAAAAAADE/izVZWe7tpyU/s320/Picture+3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5257440697771202178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here you'll see a number of bad database smells very quickly. Unleash a DBA worth their weight on this page and you'll have some table alterations done very quickly.&lt;br /&gt;&lt;br /&gt;I honestly see no reason to not use SchemaSpy on any project that we have. It is extremely easy to use, can be integrated into a build, and provides better reference documentation on the database than the vast majority of projects I've worked on. Well done SchemaSpy crew, and a sincere THANKS!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-4722304544436991559?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/4722304544436991559/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=4722304544436991559' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4722304544436991559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4722304544436991559'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/10/thank-you-schemaspy.html' title='Thank You SchemaSpy'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QxI2aQuFZnk/SPYof0nBA7I/AAAAAAAAAC8/sflDTiRI4Vw/s72-c/Picture+2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-4247609506925205593</id><published>2008-10-11T16:00:00.000-04:00</published><updated>2008-10-11T16:00:00.309-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book Review: The Productive Programmer</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QxI2aQuFZnk/SO0eDff5EQI/AAAAAAAAACk/X7MMKTZdjUM/s1600-h/productiveprogrammer.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_QxI2aQuFZnk/SO0eDff5EQI/AAAAAAAAACk/X7MMKTZdjUM/s320/productiveprogrammer.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5254889385554940162" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When I heard that Neal Ford was releasing a book on programmer productivity, I anxiously went to Amazon to pre-order it. Problem was that it was almost two years ago and Neal's busy schedule has kept him from finishing it for quite some time. Now that it is finally out and I've read through it (twice actually), I would highly recommend it to anyone doing software development on a daily basis.&lt;br /&gt;&lt;br /&gt;I've seen Neal speak at a number of conferences like &lt;a href="http://www.codemash.org"&gt;Codemash&lt;/a&gt;, &lt;a href="http://www.nofluffjuststuff.com"&gt;NoFluffJustStuff&lt;/a&gt;, and &lt;a href="http://www.erubycon.com"&gt;eRubycon&lt;/a&gt;, and I've always walked away with something that will improve me as a software developer. The reason is fairly simple, Neal is at his core a developer, and more than many other speakers, he understands the problems and challenges that face developers.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.amazon.com/Productive-Programmer-Theory-Practice-OReilly/dp/0596519788/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1223498131&amp;sr=8-1"&gt;The Productive Programmer&lt;/a&gt; is really two smaller books slammed together.&lt;br /&gt;&lt;br /&gt;The first part is focused on tools and techniques that help you work. I actually re-read the book a couple of times because I did a horrible job of keeping track of the utilities and power toys that I wanted to download my first time through. The second time I went through it I started putting post-its on the pages where I wanted to remember a command or download a utility that made sense. The book was littered with post its by the end of it. Neal provides a number of utilities and techniques for both Mac and Windows platforms that will allow you to work more efficiently in your day to day environment. *nix environments are notably absent here, but the command line advice provided for Macs, are obviously equally useful across any *nix distro.&lt;br /&gt;&lt;br /&gt;The second part of the book is largely focused on how you build software. A large majority of Neal's talks at conferences carry this common theme. Neal is adept at identifying and explaining principles and patterns of development that yield the best results. Metaprogramming, TDD, Fluent Interfaces, Polyglot programming and many other topics are covered in an easy to digest manner that harkens back to the bible of software development: The Pragmatic Programmer. Neal is able to provide concrete examples throughout the book, based on his vast experience in consulting through the years.&lt;br /&gt;&lt;br /&gt;The productive programmer is easy to read, full of valuable information, and applicable to junior developers and seasoned veterans alike. Again, I would highly recommend it to anyone developing software on a daily basis.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-4247609506925205593?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/4247609506925205593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=4247609506925205593' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4247609506925205593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4247609506925205593'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/10/book-review-productive-programmer.html' title='Book Review: The Productive Programmer'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QxI2aQuFZnk/SO0eDff5EQI/AAAAAAAAACk/X7MMKTZdjUM/s72-c/productiveprogrammer.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-838091215399277077</id><published>2008-10-06T22:13:00.003-04:00</published><updated>2008-10-06T22:57:51.936-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quick'/><category scheme='http://www.blogger.com/atom/ns#' term='people'/><title type='text'>Looking for Smart People</title><content type='html'>I tend to mention my company, Quick Solutions, very little in order to keep some sense of journalistic integrity with this blog. Unfortunately, I'm not a journalist so I'm going to skip the pretense for at least one post.&lt;br /&gt;&lt;br /&gt;I started working at Quick Solutions 5 years ago this month for the sole reason that I was largely unchallenged in my daily job. My thinking at the time was consulting would expose me to a variety of businesses, technologies, and projects. I was fortunate enough to prove my commitment to the company and demonstrate a sufficient breadth of knowledge that I was offered an opportunity to work within the solutions group. At the time I thought that the only difference was the type of work (project versus role based consulting).&lt;br /&gt;&lt;br /&gt;I quickly realized however that there was something else about the group that was different. This group was choc-ful-o-geeks. And I mean that in the most sincere way possible. Conversations within the group revolved around continuous integration offerings, Java and .NET trade offs, best practices for SOA, and dynamic language use instead of the typical bitching about a lack of requirements and rehashing of the previous night's reality show. The group was filled not necessarily with Mensa members, but instead with very bright software engineers who cared about their craft. Egos are checked at the door and you could be sure that every person in the door shared a passion and ability to learn that tends to permeate good software developers.&lt;br /&gt;&lt;br /&gt;Our company has grown throughout the years and even in a downturn of the economy, we are in dire need of people who meet the above description. If you like working with smart, passionate people please drop me a line. We are always looking to bring people in who show a passion for technology, an ability to learn, and a nack for solving problems. Additionally, if your specialty is Java development, I can give you your choice of 3 different, exciting projects, right now.&lt;br /&gt;&lt;br /&gt;If you think you meet these criteria and are interested in working with more people of your ilk, email me at tkaufman at quicksolutions.com.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-838091215399277077?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/838091215399277077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=838091215399277077' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/838091215399277077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/838091215399277077'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/10/looking-for-smart-people.html' title='Looking for Smart People'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-45387787197736804</id><published>2008-09-19T15:52:00.003-04:00</published><updated>2008-09-19T16:04:23.692-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quartz'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Clustered Scheduling with Spring and Quartz</title><content type='html'>I initially cut my teeth as a Java programmer writing some batch JDBC programs to update various sets of data. We were deployed in a Unix environment so we traditionally wrapped all of the JDBC programs in a bash shell script and kicked that thing off via a Cron entry. This environment was successful for the most part but there were issues. If our batch machine was taken offline due to upgrades, failed disk, or coffee spill then our batch process just did not run. If we wanted it to run after the fact we had to create another 1 time cron entry to kick the thing off. This typically took about 2 hours because the first hour and a half was spent with me trying to decrypt the cron syntax (minutes first or seconds? need a question mark here but star there? comma or dash between my minutes?).&lt;br /&gt;&lt;br /&gt;Fast forward to 2008 and I have just completed a week long adventure with a coworker finally getting Spring and Quartz up and running to kick off some batch programs in a clustered environment. Failover is automatic, ad hoc runs are possible, and I still wind up spending an hour and a half each time I have to add a cron entry. I thought I would post some code snippets with explanation so that you kind reader, could maybe trim this process down to about a day.&lt;br /&gt;&lt;br /&gt;1.) Download Spring 2.5.5 and only use the Quartz 1.6.1 RC1 jar that is bundled within the lib directory of it. DO NOT USE A PREVIOUS VERSION OF QUARTZ.&lt;br /&gt;&lt;br /&gt;2.) Execute your appropriate database script. They can be found in the quartz distro under the docs\dbTables subdirectory. Make sure that indexes are setup as outlined &lt;a href="http://www.opensymphony.com/quartz/wikidocs/FAQ.html#FAQ-jdbcPerf"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;3.) Wrap a batch processing service with some form of Quartz. Here's the wrapper we used:&lt;br /&gt;&lt;pre style="line-height: 100%;font-family:monospace;background-color:#ffffff;"&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;public&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;class&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; GenericQuartzJob &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;extends&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; QuartzJobBean&lt;br /&gt;{&lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;protected&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; Logger &lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;logger &lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;= &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;new&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; Logger(getClass(), Constants.&lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;"&gt;LOGGER_APP_NAME)&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;private&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; String &lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;batchProcessorName;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;    &lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;public&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; String getBatchProcessorName() {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;return&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; &lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;batchProcessorName;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;    }&lt;br /&gt;    &lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;public&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;void&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; setBatchProcessorName(String name) {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;this&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;.&lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;batchProcessorName &lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;= name;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;protected&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;void&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; executeInternal(JobExecutionContext jobCtx) &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;throws&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; JobExecutionException&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;try&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; {&lt;br /&gt;            SchedulerContext schedCtx = jobCtx.getScheduler().getContext();&lt;br /&gt;            ApplicationContext appCtx = &lt;br /&gt;                (ApplicationContext) schedCtx.get(&lt;/span&gt;&lt;span style="color:#008000;background-color:#ffffff;font-weight:bold;"&gt;"applicationContext"&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;);&lt;br /&gt;            IBatchProcessor proc = (IBatchProcessor) appCtx.getBean(&lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;batchProcessorName)&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;;&lt;br /&gt;            proc.invoke();            &lt;br /&gt;        }&lt;br /&gt;        &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;catch&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; (Exception ex) {&lt;br /&gt;            &lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;logger.&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;error(&lt;/span&gt;&lt;span style="color:#008000;background-color:#ffffff;font-weight:bold;"&gt;"Unable to complete execution of "&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; + &lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;batchProcessorName,&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; ex);&lt;br /&gt;            &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;throw&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; &lt;/span&gt;&lt;span style="color:#000080;background-color:#ffffff;font-weight:bold;"&gt;new&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; JobExecutionException(&lt;/span&gt;&lt;span style="color:#008000;background-color:#ffffff;font-weight:bold;"&gt;"Unable to execute batch job: "&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; + &lt;/span&gt;&lt;span style="color:#660e7a;background-color:#ffffff;font-weight:bold;"&gt;batchProcessorName,&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt; ex);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;} &lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;With that wrapper, you can execute any batch processor that is wired up in Spring, that implements the homegrown IBatchProcessor interface (which typically only has some variant of an execute or invoke method). You don't need to manage the dependencies of those batch processes as they themselves are just beans defined a Spring app context somewhere. Additionally, the base class jumps through the various contexts that you must navigate to get a properly wired bean from the Spring factory.&lt;br /&gt;&lt;br /&gt;4.) Configure the Job Detail in your Spring app context with an xml snippet resembling this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="line-height: 100%;font-family:monospace;background-color:#ffffff;"&gt;&lt;span style="background-color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;bean&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;id=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"someJobDetail"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;class=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.springframework.scheduling.quartz.JobDetailBean"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"jobClass"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;value=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"com.some-company.batch.GenericQuartzJob"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; /&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"jobDataAsMap"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;map&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;entry&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"batchProcessorName"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;value=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"SomeJobBean"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; /&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;map&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;bean&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;This definition creates an instance of GenericQuartzJob (which fulfills the contract required by JobDetailBean), and plugs in the bean name of a batch processor defined somewhere else in the app context with all of it's necessary dependencies.&lt;br /&gt;&lt;br /&gt;5.) Configure the Trigger in your Spring app context. A simple cron based version would look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="line-height: 100%;font-family:monospace;background-color:#ffffff;"&gt;&lt;span style="background-color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;bean&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;id=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"someCronTrigger"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;class=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.springframework.scheduling.quartz.CronTriggerBean"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"jobDetail"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;ref=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"someJobDetail"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; /&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="color:#808080;background-color:#ffffff;font-style:italic;"&gt;&amp;lt;!-- Cron expression runs at 1am and 1pm --&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"cronExpression"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;value=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"0 0 1,13 * * ?"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;bean&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;And yes, it did take me an hour and a half to get that cron syntax working correctly. Some habits die hard.&lt;br /&gt;&lt;br /&gt;6.) Configure the SchedulerFactoryBean&lt;br /&gt;&lt;br /&gt;&lt;pre style="line-height: 100%;font-family:monospace;background-color:#ffffff"&gt;&lt;span style="background-color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;bean&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;id=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"scheduler"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;class=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.springframework.scheduling.quartz.SchedulerFactoryBean"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;lazy-init=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"false"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;     &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"applicationContextSchedulerContextKey"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;value=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"applicationContext"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; /&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"dataSource"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;ref=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"qtzTxDataSource"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"transactionManager"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;ref=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"transactionManager"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"overwriteExistingJobs"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;value=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"true"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"autoStartup"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;value=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"true"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; /&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"triggers"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;list&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;ref&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;bean=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"someCronTrigger"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; /&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;list&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;        &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;name=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"quartzProperties"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;props&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.scheduler.instanceName"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;SomeBatchScheduler&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.scheduler.instanceId"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;AUTO&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.jobStore.misfireThreshold"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;60000&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.jobStore.class"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;org.quartz.impl.jdbcjobstore.JobStoreTX&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.jobStore.driverDelegateClass"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.jobStore.tablePrefix"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;qrtz_&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.jobStore.isClustered"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;true&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.threadPool.class"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;org.quartz.simpl.SimpleThreadPool&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.threadPool.threadCount"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;25&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;                &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt; &lt;/span&gt;&lt;span style="color:#0000ff;background-color:#efefef;font-weight:bold;"&gt;key=&lt;/span&gt;&lt;span style="color:#008000;background-color:#efefef;font-weight:bold;"&gt;"org.quartz.threadPool.threadPriority"&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;font-weight:bold;"&gt;5&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;prop&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;            &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;props&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;      &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;property&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="background-color:#ffffff;"&gt;    &lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#000080;background-color:#efefef;font-weight:bold;"&gt;bean&lt;/span&gt;&lt;span style="background-color:#efefef;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;That configuration while lengthy does a few very important things. Let's go through them. The applicationContextSchedulerContextKey property will ensure that the app context is available to all of those instances of the GenericQuartzJob wrappers. The dataSource and transaction manager are necessary in order to ensure that the database is updated in a safe manner (many server instances may be updating the database at once). Their bean definitions are pretty much typical for Spring, checkout the &lt;a href="http://static.springframework.org/spring/docs/2.5.x/reference/index.html"&gt;Spring reference docs&lt;/a&gt; if you need more info there.  OverwriteExistingJobs will make sure that every time the scheduler is started it will use the list of triggers found internally to overwrite any existing ones that may have been changed in the database. AutoStartup makes sense, but I'm not entirely sure it's necessary. &lt;br /&gt;&lt;br /&gt;The quartz properties can be maintained in a separate file, but I prefer they are inline with the scheduler definition. They are all pretty much self explanatory, and explained in greater detail, but nested deeply in the &lt;a href="http://www.opensymphony.com/quartz/wikidocs"&gt;Quartz docs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Hopefully this article will advance you to the point of configuring a clustered, database backed, scheduling system within hours instead of days. This configuration will get you a set of spring enabled batch processes that have dependencies wired as normal, with the added benefit that their schedule is persisted and fault tolerant across nodes in the cluster. This also leaves the door open for a couple of methods of doing ad hoc runs of the jobs. We'll cover that in a part 2 article shortly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-45387787197736804?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/45387787197736804/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=45387787197736804' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/45387787197736804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/45387787197736804'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/09/clustered-scheduling-with-spring-and.html' title='Clustered Scheduling with Spring and Quartz'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1811272805825611917</id><published>2008-08-16T09:22:00.006-04:00</published><updated>2008-09-07T22:45:36.959-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>eRubycon 2008 - Severely Belated Wrap Up</title><content type='html'>I had the good fortune of attending eRubycon a few weekends ago and I can honestly say that I've never seen more value in a conference. My previous rant on how NFJS is letting the level of their speakers slip was only more evident in the 3 days spent at eRubycon. Neal Ford, Stu Halloway, Joe O'Brien, Jim Weirich, Charles Nutter and many others contributed valuable sessions that left me wishing the conference went on for a few more days.&lt;br /&gt;&lt;br /&gt;The great thing about eRubycon was that it very rarely focused on what is typically the gateway drug in adopting Ruby, the Ruby on Rails framework. Rails is a multitude of patterns and practices that are worthwhile regardless of your current language, but it sometimes overshadows the true core of "beautiful code", Ruby.&lt;br /&gt;&lt;br /&gt;The conference left me wanting to learn more about Ruby and to generally spend more of my time at work adopting Ruby. The challenge I (and many others have) is to do this while still meeting client requirements. Brian Sam-Bodden gave a great visual representation of how a Java project can incrementally adopt Ruby as a build language, scripting language, and testing framework. I missed half his presentation as I was so focused on pulling in buildr and some other utilities into my current project.&lt;br /&gt;&lt;br /&gt;I think the two biggest topics covered though were essence vs ceremony and testing your application versus testing your framework. Stu Halloway gave a great keynote on essence vs ceremony and while his Java examples were typically very dated, his points remained true. Java (and C# by extension) force you to type crap that is just clutter or ceremony. The less ceremony in our applications, the easier they are to test, maintain, and actually produce on time. I don't recall who initially mentioned the difference between testing your framework and testing your application, but it was a point that haunted me all weekend. It's a very gray line typically between the two and one that can drastically impact a project schedule. Unfortunately, there is no easy answer to this one, so be sure to be cognizant of it when writing your unit, functional, and integration tests.&lt;br /&gt;&lt;br /&gt;In summary, eRubycon far exceeded my expectations for a conference under $300. Speakers, content, hallway discussions, and after hours scotch induced discussions were all way above what I had hoped. Keep it up Joe, I'll see you there next year.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1811272805825611917?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1811272805825611917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1811272805825611917' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1811272805825611917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1811272805825611917'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/08/erubycon-2008-severely-belated-wrap-up.html' title='eRubycon 2008 - Severely Belated Wrap Up'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-6347665865877040419</id><published>2008-07-27T09:08:00.002-04:00</published><updated>2008-07-28T10:11:41.822-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>NFJS - Day 3</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Spring Talks by Keith Donald&lt;/span&gt;&lt;br /&gt;Spring has largely been my focus for the last few years so I was happy to see one of the Spring Source crew stepping up at NFJS. Keith Donald is the lead of almost all Spring web related technologies and he tends to give a very down to earth, code centric presentation so I devoted all of my final day to his talks.&lt;br /&gt;&lt;br /&gt;Someone in the audience asked Keith if he missed the common XML file that shows exactly how all your beans are wired when you move to annotation driven POJOs and that question is an important one. I've recently become much more comfortable with developing Spring applications due to the Spring Facet in IntelliJ. Moving to annotations tends to make me question exactly which resource or component is plumbed in to fill a dependency. Keith mentioned that an emerging best practice is to use  annotations for self describing application dependencies, XML for infrastructure concerns. He also gave a soft sell for Spring IDE to show a nice dependency graph regardless of annotations or XML.&lt;br /&gt;&lt;br /&gt;Spring 2.5 is downright giddy with it's extensive use of annotations and it didn't really dawn on me until Keith's talk that it might be the better way to go in some scenarios. I've traditionally balked a little bit at the extensive use of annotations as it feels very invasive to the code at hand, especially when the annotations are Spring specific. More importantly, swapping out facilities for testing purposes is not trivial when you are doing component scanning and autowiring with annotations. I think Keith articulates an appropriate scenario for use though. Swapping out mock classes via XML is not a benefit that is needed as much for application dependencies as it is one that is needed for infrastructure (data access, email service, file reader, etc...). Go nuts with annotations at the app level, but use a good editor and keep the XML where it belongs for infrastructure pieces.&lt;br /&gt;&lt;br /&gt;Keith spent a good amount of time in all of his talks using an IDE focused on Spring MVC controllers. The thing that stood out to me was how Spring web controllers are truly just POJOWAs now (I know that's not a term that will stick but a distinction needs to be made between POJOs and POJOs with annotations). This means that you will rarely see HttpServletRequest or ModelAndView type classes in these POJOs. What's the benefit here? You don't have to waste many of your test cycles mocking up the container objects. Wanna test your login method on the controller? Send in a User object and a String password and then validate whether you are getting a success or error redirect back. Very simple, and anything that we can do to lower the barrier of entry to good testing is well worth it.&lt;br /&gt;&lt;br /&gt;Keith demonstrated another key change in coding Spring apps is the impact that Rails has had on the Spring community. The focus has shifted in Spring 2.5 to more sensible defaults and a true convention over configuration model. Controllers in Spring web apps now mimic Rails controllers in URL and request parameter resolution. Additionally, there are a set of special parameter types that are automagically injected. An arg of type Principal will be supplied by the container if the user is already logged in. Very cool.&lt;br /&gt;&lt;br /&gt;One final note on the Spring web side. Why do we have another javascript framework? If you have improvements to make to DOJO, please just contribute them to DOJO. Don't create an abstraction layer over DOJO that does what you need. We have finally whittled the .js framework comparison down to a handful in my mind (prototype/scriptaculous, dojo, jquery, yui, and ext). Don't lead us back in the other direction.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conference conclusion&lt;/span&gt;&lt;br /&gt;NFJS again provided some immediate exposure to worthy technologies and processes. I was able to touch base with a lot of people in the Java community that I hadn't seen in some time and I feel like I have more tools in my belt than when the conference started. A special note to the organizers though. If the prices go up again next year while the number of conferences goes up as well, then you won't see me there for the first time in 4 years. It was evident to me this year that the conference is not the value that it was 2 and 3 years ago. If the trend continues, I'd rather spend my training dollars on codemash, erubycon, and books.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-6347665865877040419?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/6347665865877040419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=6347665865877040419' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6347665865877040419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6347665865877040419'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/07/nfjs-day-3.html' title='NFJS - Day 3'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-2855599004040199671</id><published>2008-07-26T09:12:00.007-04:00</published><updated>2008-07-26T16:48:17.704-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>NFJS - Day 2</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Stu Halloway's Refactoring Javascript&lt;/span&gt; was a topic I did not expect to see at NFJS this year, but I walked away truly impressed. Stu presented a totally different mindset on developing, testing and refactoring javascript code. The gist of it is to use a mock browser that will allow you to run tests against your javascript code in an automated environment. &lt;a href="http://ejohn.org/blog/bringing-the-browser-to-the-server/"&gt;Here&lt;/a&gt; is the mock browser but it is still in a beta state so expect to have to bend it to your will. Stu made extensive use of &lt;a href="http://code.google.com/p/jsspec/"&gt;JSSpec&lt;/a&gt; for writing BDD specs against an existing javascript framework (livepipe). It was truly telling in the presentation that the first hour was spent trying to get a solid safety net of tests up and passing before we even began thinking about refactoring. Stuart accurately identified this as the norm when refactoring legacy code and it lines up directly with my experience as well. Refactoring can't be done w/o that safety net. When we finally did get around to refactoring, Stuart boiled it down to four areas:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Extract and Shorten&lt;/span&gt;&lt;br /&gt;- If your method does more than one thing it does too much&lt;br /&gt;- Keep method size to around 5 - 7 lines&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Reduce Clutter&lt;/span&gt;&lt;br /&gt;- Nix out of scope variables&lt;br /&gt;- Keep the effort to duplicate a method greater than the effort to understand it&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Choose Good Names&lt;/span&gt;&lt;br /&gt;- Probably the most difficult of the refactorings&lt;br /&gt;- Definitely the refactoring most in need of pair programming&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Use Existing Libraries&lt;/span&gt;&lt;br /&gt;- If you are typing document.getElementById then punch yourself first and download prototype.js second.&lt;br /&gt;&lt;br /&gt;The talk was extremely hands on and valuable and made me wish I had a bucket of crappy javascript to go back to on Monday. Other things mentioned included another mock browser env: &lt;a href="http://www.thefrontside.net/crosscheck"&gt;Crosscheck&lt;/a&gt;. Stu also mentioned a lack of code coverage tools for Javascript, but I found &lt;a href="http://siliconforks.com/jscoverage/"&gt;one&lt;/a&gt; during his talk. One last thing, he mentioned a very important refactoring anti pattern. Mirror methods (get and set on cookie) used in each others tests. If you are testing the get method on a cookie object don't explicitly use the mirror method (set). Instead, roll it by hand as a bug in code shared by these methods could offset each other in the test execution.&lt;br /&gt;&lt;br /&gt;The second talk I went to was &lt;span style="font-weight:bold;"&gt;Stu's GIT&lt;/span&gt; talk. I've been looking into GIT for a little while and Stu gave a good gentle intro into it by basically walking through scenarios at a command prompt for 90 minutes. That format doesn't necessarily translate to a blog so here are some highlights:&lt;br /&gt;&lt;br /&gt;- When using GIT, think less in terms of verbs&lt;br /&gt;- GIT is not SVN++&lt;br /&gt;- It's crazy fast. Branching and tagging for instance are instantaneous&lt;br /&gt;- The entire source history is in every copy of the repo&lt;br /&gt;- It doesn't store deltas, it stores the begin and end and calculates the deltas.&lt;br /&gt;- You are forced to tell git what you are committing. It's not tracking it like SVN&lt;br /&gt;- GIT encourages agility. You may not know what makes a package/release/hunk of functionality until sometime in the future. Additionally, you can stash your current task deliverables, go do something else, and come back to them later.&lt;br /&gt;- Bisecting allows you to do a binary search through releases of code to identify the release that caused a bug. Kick ass.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Metaprogramming in Groovy by Brian Sam-Bodden&lt;/span&gt; was the third session I attended. BSB did a good job of going over the major metaprogramming techniques in Groovy. Additionally he had enough examples of Groovy code with TextMate that forced my hand to download it and see if it will cure what ails me with IntelliJ in dealing with Rails and Grails. Stream of conscience notes on metaprogramming with Groovy:&lt;br /&gt;- Much simpler than using dynamic proxies in Java&lt;br /&gt;- Similar to ruby it allows on the fly evaluation of code via evaluate&lt;br /&gt;- Duck typing like ruby with respondsTo&lt;br /&gt;- See yesterday's bits on methodMissing and invokeMethod&lt;br /&gt;- obj."$methodToCall"() is valid Groovy code that will try to call the contents of methodToCall as a method on obj. In my opinion that code is utterly disgusting.&lt;br /&gt;&lt;br /&gt;Also, the inevitable Ruby v Groovy topic came up as it did at lunch with me and a few others. There still seem to be zealots on both sides and I wish for the life of me they would just shut up.&lt;br /&gt;&lt;br /&gt;My 2 cents are this. Use whatever makes most sense for your environment and team. At my consulting company, that is Ruby b/c I have a lot of .NET fellas that I would like to roll into and out of projects whether it is deployed on MRI, JVM, or DLR. The differences at my admittedly noob perspective are few and far between with the two languages. If it was a room full of Java developers, Groovy might make more sense because it is an easier transition for Java heads. I don't care what you choose for your environment, just quit bitching about the other side.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;EJB3 Testing by Joseph Nusairat&lt;/span&gt; was my final session of the day. Joseph covered a wealth of testing frameworks in a very code centric presentation. The session was very interactive and covered some cool mocking techniques outside of the realm of EJB3, like dealing with mocking static methods. My attention span was slipping this late in the day, but here is a set of highlights:&lt;br /&gt;- Easymock provides the typical set expectations, record and playback functionality. It is still probably the most proven, well documented, and easy to learn of the mock frameworks.&lt;br /&gt;- JMockIt is a relatively new player with some cool support for AOP and Hibernate. Please notice the IT at the end of the name. JMock is a different framework. Unlike EasyMock and JMock, JMockIt is a very small and straightforward API that can be used to test methods w/o dynamic proxies or cglib.&lt;br /&gt;- EJB3Unit has some very cool facilities. It provides an in memory database out of the box (HSQLDB), uses CSV files for populating the data and provides mocks of almost everything that you would need in an EJB 3 bean. If you have to use EJB3, this framework seems like a valid contender.&lt;br /&gt;- Embedded JBoss is the last one covered and it seems like a good fit for mocking out an entire container when necessary and using JBoss. &lt;br /&gt;- Mocking for unit testing, other tools still necessary for integration and functional tests.&lt;br /&gt;&lt;br /&gt;I'm tired. See you tomorrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-2855599004040199671?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/2855599004040199671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=2855599004040199671' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2855599004040199671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2855599004040199671'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/07/nfjs-day-2.html' title='NFJS - Day 2'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-7637292646768239730</id><published>2008-07-25T12:30:00.006-04:00</published><updated>2008-07-26T11:29:57.113-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>NFJS - Day 1</title><content type='html'>&lt;span style="font-weight:bold;"&gt;PreConf&lt;/span&gt; Arrived at NFJS. 2 cents before the conference gets started. Having the conference in two places like Phoenix and Columbus on the same weekend is diluting the talent (and the costs have gone up). Phoenix wound up with a few of my favorite speakers on the planet: Neal Ford, Venkat Subramaniam, and Ted Neward. Please don't get me wrong, listening to Stu Halloway, Scott Davis, and Keith Donald among others still makes for an excellent conference. However, in previous years, having to choose between Justin Ghetland, Stu Halloway, Dave Thomas, or Ted Neward all in the same time slot was a nice problem to have. If NFJS is to keep it's mantra as a value driven conference with A+ speakers then it needs to keep it's shows to 1 city per weekend.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Scott Davis - Groovy the Blue/Red Pill&lt;/span&gt;&lt;br /&gt;Scott Davis has a presentation style that is really conducive to learning new technologies. He speaks at a very measured pace with a number of pauses, yet still with a passion that gets users excited. His first two talks were Groovy, how it is similar to Java and then how it breaks the mold.&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;Groovy - The Blue Pill&lt;/span&gt; covered the language at a high level and how it is seamlessly integrated with Java. I spent a good portion of this talk weighing whether that is a good or bad thing. I as a 10 year Java veteran have developed a very Java centric mind and it continues to bite me in the arse. When anonymous inner classes become natural for you in a programming environment, you have issues. Ruby seems to allow me to make a clean break from this mold. Groovy is a step up, but not in the same sense. That being said, I think it's seamless integration with Java make it an easier sell to management types. Hopefully the JRuby guys can keep up. Stream of conscience thoughts on the talk:&lt;br /&gt;- GStrings while oddly named are very elegant&lt;br /&gt;- Mixing in Groovy based unit tests is a no brainer for ease of adoption and powerful mocking&lt;br /&gt;- Triple quotes surrounding XML blocks makes you ignore quotes and newlines (Cool for XML)&lt;br /&gt;- Groovy converts all checked exceptions to unchecked exceptions&lt;br /&gt;- Powerful scripting: s.class.methods.each{println it}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;Groovy - The Red Pill&lt;/span&gt; covered some of the more interesting pieces of meta-programming in Groovy. Here is where the obvious Ruby influence shows up in Groovy. The ExpandoMetaClass accommodates closures in a syntax that is less intuitive then blocks in Ruby to me. It's called ExpandoMetaClass though so bonus points there. The keyword delegate can be used to access the thing within EMC. Overloading operators is limited to a specific set and done in a manner that is less than intuitive (implement putAt(b,c) for a to get a[b]=c). Groovy also provides methodMissing and invokeMethod to get peeps closer to Ruby like syntax. My conclusion after this session was I'll use Ruby wherever I can, then Groovy, and finally Java.&lt;br /&gt;&lt;br /&gt;Scott Davis did such a nice job presenting the first two Groovy talks, I stuck around for his &lt;span style="font-style:italic;"&gt;Grails for Struts Losers&lt;/span&gt; talk. That wasn't the exact title, but I think I captured the gist of it. This was a gentle intro to Grails and managed to show it's benefits quite nicely over existing Java web frameworks (struts in this case). The framework is very clearly alot of the concepts of Rails that work well in a Java/Groovy centric environment. I spent the session trying to get Grails up and running in my environment and stumbled into an issue that clearly articulated Grails v Rails. I left parens off a method call and it blew up. WTF? Basically it was trying to find a property of that name instead of finding a method. Luckily, I had a Grails book co-author next to me to help troubleshoot. For those of you keeping track at home, Rails 1,  Grails 0.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-7637292646768239730?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/7637292646768239730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=7637292646768239730' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7637292646768239730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7637292646768239730'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/07/nfjs-day-1.html' title='NFJS - Day 1'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-7714216815925294539</id><published>2008-07-21T09:00:00.002-04:00</published><updated>2008-07-21T09:07:41.809-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='schedule'/><title type='text'>Tech Ridden Month</title><content type='html'>I have 3 different blog posts in the making right now and I unfortunately don't see myself having enough time to complete them in the next month. A wide variety of activities are chewing up almost all of my free time, but most of it is tech related. Here's a look at my schedule:&lt;br /&gt;&lt;br /&gt;7/22 - Speaking about Spring at the Cincinnati Java User's Group&lt;br /&gt;&lt;br /&gt;7/25 - 7/27 - Attending NoFluffJustStuff in Columbus&lt;br /&gt;&lt;br /&gt;7/31 - 8/4 - Vacationing with wife in Cabo San Lucas (WOOHOO!)&lt;br /&gt;&lt;br /&gt;8/15 - 8/17 - Attending eRubycon in Columbus&lt;br /&gt;&lt;br /&gt;I'm extremely excited about all of these opportunities but it will nonetheless continue my procrastination of blogging. Please sit tight and check back in mid August for more content on Spring, Ruby, IntelliJ, and IT Leadership.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-7714216815925294539?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/7714216815925294539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=7714216815925294539' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7714216815925294539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7714216815925294539'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/07/tech-ridden-month.html' title='Tech Ridden Month'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-2384045665309376459</id><published>2008-06-10T20:22:00.001-04:00</published><updated>2008-06-10T20:22:33.749-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Ruby Integration with Spring</title><content type='html'>I recently gave a presentation at &lt;a href="http://www.cojug.org"&gt;COJUG&lt;/a&gt; on ten facilities in Spring that you may not know much about. I saved my favorite for the last. Dynamic Language integration. This facility has been around since Spring's 2.0 release, but has been mired in the relative obscurity of &lt;a href="http://static.springframework.org/spring/docs/2.5.x/reference/dynamic-language.html"&gt;Chapter 24&lt;/a&gt; of their docs.&lt;br /&gt;&lt;br /&gt;While many IT managers might be hesitant to adopt a language like Groovy or Ruby for their production environment due to misconceptions about performance, security, or what have you. The management types should have very little concern with testing code making extensive use of dynamic languages. If Ruby or Groovy provides a lower barrier of entry for complex testing or mocking, why not make use of it?&lt;br /&gt;&lt;br /&gt;Spring provides the typical DI goodness of abstracting away the underlying implementation and allowing the developer to switch from mock to production code without changing client code. In the case of Ruby backed implementations, JRuby provides the hooks to allow the .rb file to be recognized as an implementation of the Java interface.&lt;br /&gt;&lt;br /&gt;Here's a simple interface implemented in Java with which I've created a Java and a JRuby implementation.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_QxI2aQuFZnk/SE7r0PMp3mI/AAAAAAAAABk/aGIk6QqAepI/s1600-h/CM+Capture+2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_QxI2aQuFZnk/SE7r0PMp3mI/AAAAAAAAABk/aGIk6QqAepI/s320/CM+Capture+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5210361101579574882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A JRuby based implementation of this only has a few tricks like including the library and calling a method to include the class&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_QxI2aQuFZnk/SE7uR3vLgdI/AAAAAAAAABs/PWf6Ydg3ir8/s1600-h/CM+Capture+1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_QxI2aQuFZnk/SE7uR3vLgdI/AAAAAAAAABs/PWf6Ydg3ir8/s320/CM+Capture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5210363809701265874" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Finally, with the spring integration facilities, a few lines of xml locates the file and plumbs in the implementation. Client code accesses the Java interface, none the wiser to the Ruby implementation.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_QxI2aQuFZnk/SE7vN1aIm9I/AAAAAAAAAB0/Y2ZLoMMscRg/s1600-h/CM+Capture+3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_QxI2aQuFZnk/SE7vN1aIm9I/AAAAAAAAAB0/Y2ZLoMMscRg/s320/CM+Capture+3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5210364839868275666" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are a couple of gotchas to keep in mind with JRuby/Groovy Spring integration:&lt;br /&gt;- JRuby 1.1 is not supported until Spring Framework 3.0, use JRuby 1.0&lt;br /&gt;- Model code after what I have above, not what is in the Spring reference docs. At last check the docs were somewhat confusing in the use of include versus include_class&lt;br /&gt;- AOP can be used to wrap the dynamic beans just as if they were POJOs. The one big caveat here is to make sure they are implementing an interface. Class based proxies will not work&lt;br /&gt;&lt;br /&gt;Spring's support for dynamic language beans is pretty powerful in it's simplicity. The uses of this technology are much farther reaching than just mock scenarios, though. JRuby or Groovy files can be polled and reloaded without compilation or server restarts. This can be immensely useful for dynamic portions of applications like lightweight rules, environment configuration, validation, or even web site navigation.&lt;br /&gt;&lt;br /&gt;Hope this helps get you started with integrating dynamic languages into your Java code. Please leave a comment with your scenario if you are using or planning on using dynamic languages integrated with Spring.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-2384045665309376459?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/2384045665309376459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=2384045665309376459' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2384045665309376459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/2384045665309376459'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/06/ruby-integration-with-spring.html' title='Ruby Integration with Spring'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_QxI2aQuFZnk/SE7r0PMp3mI/AAAAAAAAABk/aGIk6QqAepI/s72-c/CM+Capture+2.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-639428505312681835</id><published>2008-06-09T09:08:00.005-04:00</published><updated>2008-06-09T10:07:27.304-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>Software Development Meme</title><content type='html'>&lt;a href="http://www.jeffblankenburg.com/2008/06/software-development-meme.html"&gt;Mark Blankenship&lt;/a&gt; posted his own personal history of software development and charged a few of us with posting the same. Here's my background:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;How old were you when you started programming?&lt;/span&gt;&lt;br /&gt;I remember my first official "programming" class was my sophomore year in high school so roughly age 15. I was officially playing around with a Commodore 64 as early as age 8 though. While that was mostly gaming, the memory and file models puzzled and intrigued me back then. My cousin and I would waste hours playing Mission Impossible on the C64 though. That tended to get in the way of any real programming back in the day, establishing a pattern of gaming over real work that plagues me still.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;How did you get started in programming?&lt;/span&gt;&lt;br /&gt;My brother is 5 years older and he was already starting to see some serious need for programmers while he was off at college. I was but a young lad in high school, focused more intently on sports, girls, and parties at the time. When I took my first real course at his advice though, I was hooked. So, brotherly encouragement coupled with a strong background in math. My father is a science teacher as well so he was always giving me a slight kick in the rear to pursue any and all topics that stoked my interest.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What was your first language?&lt;/span&gt;&lt;br /&gt;BASIC, baby! I remember sitting next to a guy in that first course who nearly had the mental capacity to bend spoons and levitate people. He scored a 35 on his ACTs and a 1520 on his SATs, no joke. He was scary smart. I believe he later became a nuclear physicist, but I'm not totally sure. Anyway, he wrote a 5 level Zork type game in that class in the first two days we were there. That opened my eyes to the power of programming. Thanks Bill!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What was the first real program you wrote?&lt;/span&gt;&lt;br /&gt;The first open canvas program I wrote was in a computer graphics class my junior year in high school. I built a dart board type game that allowed two people to compete to see who could get the dart closest to the center. By compete I mean that you merely alternated pressing a button to throw darts and they went to random spots on the board but it was still pretty cool.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What languages have you used since you started programming?&lt;/span&gt;&lt;br /&gt;Probably missing some but here goes:&lt;br /&gt;BASIC&lt;br /&gt;Pascal&lt;br /&gt;Modula-2&lt;br /&gt;C&lt;br /&gt;C++&lt;br /&gt;Java&lt;br /&gt;Smalltalk&lt;br /&gt;Lisp&lt;br /&gt;Fortran&lt;br /&gt;SQL&lt;br /&gt;HTML/Javascript&lt;br /&gt;Ruby&lt;br /&gt;C#&lt;br /&gt;ASP.NET&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;What was your first professional programming gig?&lt;/span&gt;&lt;br /&gt;I hired on as a paid intern thanks again to my bro. I was told I would be working on a C/C++/SQL based project for a retail services company. Instead I was working on an S1032 database with Fortran code literally printing off reams of green bar code snippets. If that place didn't have a ping pong table on site that rolled out every day at 5pm I would've probably gone postal. That assignment nearly made me into a history major.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;If you knew then what you know now, would you have started programming?&lt;/span&gt;&lt;br /&gt;No question about it. If anything I would've been more driven to succeed in this profession and spent more of my free time learning and pushing my limits. I was largely a slacker through high school and college and it set me behind starting out in the real work force. While it did enable me to thoroughly dominate OSU's entire campus in NHL 93 on the sega genesis, it also nearly caused me to drop out, become disowned, and live life in a van down by the river. I was lucky to find my niche once again but I wonder what I would've accomplished if I would've truly applied myself.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;If there is one thing you learned along the way that you would tell new developers, what would it be?&lt;/span&gt;&lt;br /&gt;Get comfortable with change and figure out the best way for you to learn. Change comes at you at all times from all directions in this field. Requirements are never set in stone, business direction can sometimes sway with the wind, and technology will certainly never be static. While Java has been around for 14 years now, the language it is today is worlds apart from what Gosling and co pushed out to us in the form of crApplets in 1994. All of the people in this field that I want to surround myself are quick learners and very adaptive. If you can roll with the punches figure out things quickly, then you'll never cease being marketable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;What's the most fun you've ever had ... programming?&lt;/span&gt;&lt;br /&gt;I'm not sure I've ever had a moment of euphoria while writing a piece of code, but there was one time when I solved a huge showstopper of a bug that was visible at every level of our company. We had been seeing our application lock up the server completely on a random basis for about 2 weeks. After code inspection day 10 I finally stumbled upon an infinite recursive subroutine that was nested 142 levels deep in app server that was impossible to debug. Finally getting it resolved wasn't fun as much as it was like someone moving a car that had been parked on your foot.&lt;br /&gt;&lt;br /&gt;That being said, I think I've had fun at every programming job I've ever been in. I attribute that solely to the various people that I've worked with, though. I have yet to work at a client yet where I've woken up with an utter feeling of dread. Maybe I'm just lucky, but I can rattle off a number of people from every client I've been at who I could call right now to go grab a beer. I think the problem solving is always fun and gratifying but working with people you genuinely want to be around is priceless.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Next up:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm throwing the guantlet down for another group of peeps to answer these questions:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://marquand.net"&gt;Matt Marquand&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.munc.com/kevin.html"&gt;Kevin Munc&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://stevenharman.net"&gt;Steve Harman&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jonkruger.com/blog/"&gt;Jon Kruger&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blog.stevehorn.cc/"&gt;Steve Horn&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-639428505312681835?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/639428505312681835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=639428505312681835' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/639428505312681835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/639428505312681835'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/06/software-development-meme.html' title='Software Development Meme'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1541989259196000137</id><published>2008-05-05T09:44:00.002-04:00</published><updated>2008-05-05T09:50:03.624-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>And then there were 3</title><content type='html'>Oracle has &lt;a href="http://www.oracle.com/bea/index.html"&gt;now&lt;/a&gt; officially acquired BEA, leaving the app server marketplace for Java EE at 3 major vendors with IBM and JBoss completing the trinity. After having personal experience with both BEA WebLogic and Oracle's Application Server, I plea to Oracle, just use BEA's app server and don't mess with it. Orion was a good product and you turned it into a trainwreck. There is no reason that an application server install should take 4 days and 300 gb of memory. JSPs shouldn't be stored in the database. Oh, and your installer should not need to install JDK 1.2 to run. Leave it alone Oracle and focus on improving your DB.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1541989259196000137?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1541989259196000137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1541989259196000137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1541989259196000137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1541989259196000137'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/05/and-then-there-were-3.html' title='And then there were 3'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-3796632843898213909</id><published>2008-05-01T10:34:00.004-04:00</published><updated>2008-05-01T10:53:13.974-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>A Polarized Community?</title><content type='html'>The &lt;a href="http://www.springsource.com/web/guest/products/suite/applicationplatform"&gt;news&lt;/a&gt; that SpringSource announced yesterday regarding their application server is not surprising but possibly very concerning to many developers in the Java landscape. We see now a very clear divide between people's perception of what is standard for Java Enterprise Development. Is the standard the open source platform that is used in a greater number of projects or is the standard the framework released by the Java Community Process? In my opinion it is very clearly the former.&lt;br /&gt;&lt;br /&gt;I'm in the fortunate position of seeing every Java requirement that comes in to my consulting company and guess what? The number of Spring requirements far outweighs the number of EJB, let alone JSF reqs. I still see more Struts requirements than JSF and EJB reqs combined. So now, is the news that not only is there a non-standard framework, but also a non-standard application server something to be concerned with? Hell no.&lt;br /&gt;&lt;br /&gt;How many developers have actually taken advantage of the fact that your app can be ported to different app servers with "no code change"? I've been on one project in the last 10 years that did so and guess what? We still had to change a lot of XML to make sure that stuff didn't break. Portability is a farce at the app server level and it's largely unnecessary.&lt;br /&gt;&lt;br /&gt;So if there is no need to port my SpringAppServer application to JBoss or WebLogic or god help me WebSphere, what are the issues with adopting SpringSource Application Platform? It surely will present some amount of a learning curve. It may not be adopted by many of my clients initially who continue to write checks to IBM and BEA for inferior products that lag behind the so-called standards.&lt;br /&gt;&lt;br /&gt;On the flip side, it will provide the ability to roll out smaller, componentized versions of your applications. It will let you keep multiple versions of the same components running on the same server. It will let you deploy your app without restarting your server. It will cost about $15k per cpu less than BEA or IBM products. Oh, and it will not force you to use JDK 1.4 or prior in order to run on the system.&lt;br /&gt;&lt;br /&gt;Is it really a polarized community if everyone is heading in one direction?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-3796632843898213909?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/3796632843898213909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=3796632843898213909' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3796632843898213909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3796632843898213909'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/05/polarized-community.html' title='A Polarized Community?'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-6966680984729344666</id><published>2008-02-28T09:11:00.005-05:00</published><updated>2008-02-28T13:39:25.124-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>ACID Principles Applied to Testing</title><content type='html'>Sometimes you don't realize that you have built your house on a fault line. Then the tectonic plates shift and you are left in a pile of rubble wondering, WTF just happened?&lt;br /&gt;&lt;br /&gt;I recently found myself in that very position, as it applies to testing applications. We had been focused on writing unit, integration, and functional tests and automating them for a .NET application that was really nothing more than CRUD but with some significantly complex business rules thrown in. We made some mistakes along the way though that finally came to a head earlier this week when 3 out of 3 of our builds were broken, we were running a day late in releasing an application to UAT and we had made a significant number of refactoring changes that could have very well broken 50% of our functionality, but we couldn't tell for sure. Amidst the rubble, I took a moment to reflect on what got us to that point so that I could share with you, kind reader, the err of our ways.&lt;br /&gt;&lt;br /&gt;Our biggest mistake in writing tests was not making sure that they were Isolated. I've always been kind of a persistence geek though, so I naturally started noticing how the ACID principles of database transactions apply so well to testing. For reference, the ACID properties are Atomic, Consistent, Isolated, and Durable, see &lt;a href="http://en.wikipedia.org/wiki/ACID"&gt;wikipedia&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Atomic - Can't be broken into smaller parts.&lt;br /&gt;&lt;br /&gt;Good unit and integration tests should be atomic. Not so much for functional tests as they are typically the assembly of multiple atomic parts into one whole. The unit and integration tests, however, should be focused on testing one feature of any target. Nothing more, nothing less. This makes the tests cleaner, it makes uncovering causes to failures easier, and it helps to differentiate functional tests from unit and integration tests.&lt;br /&gt;&lt;br /&gt;Consistent - Repeated execution results in the same outcome.&lt;br /&gt;&lt;br /&gt;Consistency, or the lack thereof, typically rears it's head in the integration and functional tests and in my experience, the cause is often broken dependencies. Database integration tests mysteriously start failing because another developer went in and updated some data that your test depends on.  Making integration tests consistent requires some work. Typically it involves automatically prepping a database with all of the values and foreign keys populated so that your test follows it's directed path. This can be made much easier with a framework like DBUnit in Java which preps and removes data as needed. &lt;br /&gt;&lt;br /&gt;Isolated - Concurrent operations do not have an affect on one another.&lt;br /&gt;&lt;br /&gt;As mentioned earlier, this one was a biggie for us. We found that any person running tests while the build was also running them, caused both to fail. This was due to some poor choices in how we were trying to cleanup after ourselves (blindly searching by a non primary key field that picked up data from other tests). The easiest solution in many instances is to use a pattern provided by the bright fellas over at Spring, and start a transaction in your setup method and then roll that puppy back in your tear down method. This allows everything running in that test to see changes made by the code (assuming it uses the same connection as your tests), but it removes the sometimes complex logic of undoing your changes by hand. Additionally, it ensures that even if the same two tests are running at the same time, each will be on a separate connection and totally unaware of the other's changes. See AbstractTransactionalContextTests in Spring.&lt;br /&gt;&lt;br /&gt;Durable - Once successful it is permanent.&lt;br /&gt;&lt;br /&gt;It should really take a change in business logic or interface design to get a test breaking once it's in a successful state. This goes hand in hand with the previously mentioned anti-pattern, so don't let data or systems outside of your control muck with your tests. Make your functional tests fully dependent on mocks, stubs, or dummies instead of external systems or databases. Make sure your integration tests are completely responsible for setting up all of the data that they need before running. This will lower the probability of environmental issues throwing up a false negative on your CI server.&lt;br /&gt;&lt;br /&gt;I've made a distinction throughout this article with Unit/Functional/Integration tests. Make sure you know the difference between them and be adamant about treating them differently. &lt;br /&gt;&lt;br /&gt;Unit tests should never interact with a database, email server, web service, or other disparate system. Unit tests should be automated and run upon every code delivery. They should be extremely fast to keep ADD developers from staring blindly out the window or surfing the net while waiting for the tests to complete. &lt;br /&gt;&lt;br /&gt;Integration tests should never be mocking the integrated system and in many cases should only be run on a daily or semi daily basis. Unless your database or external system is being modified multiple times throughout the day, just set these to run up when the lights go off at night. If someone is actively changing your entire persistence layer, they should have the common sense to run these manually before checking in.&lt;br /&gt;&lt;br /&gt;Functional tests should almost solely rely on mocks, dummies, or stubs instead of external dependencies and since they'll be pretty zippy if you write your mocks correctly. If they are in the "runs in less than 5 minutes" category, then run them at every check in so that the staff is well aware of any issues as soon as a delivery is made.&lt;br /&gt;&lt;br /&gt;Keep in mind the ACID principles when testing your code. They'll hopefully keep you away from the fault lines and in the happy state of green builds.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-6966680984729344666?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/6966680984729344666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=6966680984729344666' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6966680984729344666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/6966680984729344666'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/02/acid-principles-applied-to-testing.html' title='ACID Principles Applied to Testing'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1694084703497203221</id><published>2008-02-06T21:47:00.000-05:00</published><updated>2008-02-06T22:05:33.028-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='hatred'/><title type='text'>Failing to Fail Early</title><content type='html'>A coworker and I stumbled across some weird behavior with NHibernate today that totally surprised me. I come from the Hibernate world which tends to be about a version to a version and a half ahead of NHibernate. So I'm used to going to look for excellent support for stored procedures and realizing I'm SOL.&lt;br /&gt;&lt;br /&gt;Today though we found an issue that wasn't lack of support, but just a horrible design decision that differs between the two frameworks. In a nutshell, Session.Load was being called with an ID that didn't exist and we weren't receiving an exception. Huh? The difference between Get and Load in my mind was always, same behavior if the PK passed in exists in the database, if it doesn't Get returns null silently, and Load throws ObjectNotFoundException, violently alerting you that your PK is not what you think it is. In this case we were getting back a proxied object that would immediately throw ObjectNotFoundException whenever one of it's getter methods were called. Nice. I assumed that we were misusing the Interceptor functionality or something to cause this but a little googlage revealed this description of the ObjectNotFoundException class in the NHibernate docs:&lt;br /&gt;&lt;br /&gt;"Thrown when ISession.Load() fails to select a row with the given primary key (identifier value). This exception might not be thrown when Load() is called, even if there was no row on the database, because Load() returns a proxy if possible..."&lt;br /&gt;&lt;br /&gt;Come again? What use do I have for a proxied object that is just going to throw ObjectNotFoundException the moment I start accessing it? Even worse, what if I have a business method that checks a private attribute for null on this object. You shouldn't be able to do anything to this object because according to the database IT DOESN'T EXIST. When all else fails, go to the pragmatic programmers for advice and listen when they tell you to FAIL EARLY. Give me null or give me exceptions, don't fool me into thinking my row is there when it isn't.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1694084703497203221?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1694084703497203221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1694084703497203221' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1694084703497203221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1694084703497203221'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/02/failing-to-fail-early.html' title='Failing to Fail Early'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1057019305667287762</id><published>2008-01-24T22:17:00.000-05:00</published><updated>2008-01-24T22:32:04.297-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>Code Mash Recap</title><content type='html'>Codemash came and went over a week ago but I've been hoarding my free time so the blog has gone by the way side. I must say that codemash is as unique a conference as you can find and the organizers do a superb job of providing valuable content and access to bright people. The speakers I saw were very good overall and made you question how the conference is not pummeled with only charging $200 or less.&lt;br /&gt;&lt;br /&gt;The highlight for me had to be speaking with Jim Weirich on a couple of occasions about Ruby and his work at EdgeCase. He's the man behind Rake, XmlBuilder, FlexMock, and other pieces to the Ruby puzzle I'm sure I'm forgetting. He was extremely down to earth and very practical about using the appropriate language for the job. He's like DHH with his passion for Ruby and Rails, but without the arrogance.&lt;br /&gt;&lt;br /&gt;Additionally, I was reminded why I really enjoy working with the people I do at QSI. We sent no less than 30 people there, had a couple of speaker/organizers, had the most rocking booth of all the vendors, and most importantly had great discussions about software over beer every night there. At least 5 people made comments to me about their desire to learn Ruby and/or Rails. We'll hopefully capitalize on this passion by forming a 12 step program to get us familiar with Ruby (first and foremost) and then Rails. I'll keep the blog updated through the journey to beautiful code...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1057019305667287762?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1057019305667287762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1057019305667287762' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1057019305667287762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1057019305667287762'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/01/code-mash-recap.html' title='Code Mash Recap'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-3698390943936427357</id><published>2008-01-02T09:11:00.000-05:00</published><updated>2008-01-02T09:27:36.958-05:00</updated><title type='text'>CodeMash Coming Up</title><content type='html'>I was fortunate enough last year to attend CodeMash in it's inaugural event. I can say without a doubt that it is the most unique conference I've had the pleasure of attending. I'm somewhat odd in that I code daily in .NET and Java and usually play with Ruby in the wee hours of the evenings. CodeMash is the only conference I know of where I can go to sessions for all of these topics and still learn about other topics like Python, Groovy, Android, etc...&lt;br /&gt;&lt;br /&gt;The speakers aren't just slobs off the street either. Neal Ford, Jim Weirich, Bruce Eckel, and many others will present at CodeMash this year. Always cool to go to a session of someone whose book you have on your shelf. Being able to see speakers of this caliber for less than $200 does not happen often.&lt;br /&gt;&lt;br /&gt;I'm always up for a beer after the sessions, so let me know if you'll be attending. I'll get &lt;a href="http://jeffblankenburg.com"&gt;Mark Blankenship&lt;/a&gt; to buy us a round.&lt;br /&gt;&lt;br /&gt;Oh, and did I mention it's at a waterpark? That's right, 2 conferences within a month for me where I get to hammock up!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-3698390943936427357?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/3698390943936427357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=3698390943936427357' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3698390943936427357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3698390943936427357'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2008/01/codemash-coming-up.html' title='CodeMash Coming Up'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-7154017029116049675</id><published>2007-12-19T14:03:00.000-05:00</published><updated>2007-12-19T14:59:40.531-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Practices of an Agile Developer</title><content type='html'>On the flights down to FL, I was able to read a book that my team will be reviewing in the upcoming months, Practices of an Agile Developer by Venkat Subramaniam and Andy Hunt. &lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.pragprog.com/images/covers/190x228/pad.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;The authors chose a style that I think captures the bipolar disorder shared by most cognizant software developers. It presents topics both from the perspective of the devil who might encourage us to "just duplicate this code, don't bother keeping the system DRY" and the angel who would give us a gentle reminder that "duplication is just a shortcut, and you will have to maintain both sets of code later on". It's amazing how many times you find yourself listening to that devil on a daily basis.&lt;br /&gt;&lt;br /&gt;The book is very easy to read even if you don't have a ton of time to devote to it. Chapters are usually 30 pages or under and each one is broken into a number of atomic topics. 'Fixed Prices are Broken Promises' and 'Architects Must Write Code' were two which immediately struck a chord with me.&lt;br /&gt;&lt;br /&gt;Additionally, the book has a ton of good quotes that should be tattooed on the back of our hands or at least put on a whiteboard in plain view. My favorites are "Blame doesn't fix bugs", "Negativity kills innovation", and "Blindly picking a framework is like having kids to save taxes".&lt;br /&gt;&lt;br /&gt;All in all, a very good read and immediately applicable to developers both agile and not.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-7154017029116049675?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/7154017029116049675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=7154017029116049675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7154017029116049675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7154017029116049675'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/12/practices-of-agile-developer.html' title='Practices of an Agile Developer'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-7944581868091692528</id><published>2007-12-15T14:39:00.001-05:00</published><updated>2008-01-24T22:32:33.984-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>The Spring Experience - Day 4</title><content type='html'>Day 4 started much like Day 3 with another good presentation from Ben Alex regarding Spring Security. This session focused on the enhancements provided in Spring Security 2:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Annotation driven security that allows a developer to specify required roles directly above a method declaration&lt;/li&gt;&lt;br /&gt;&lt;li&gt;User management API for creating users and default implementations for JDBC and LDAP backed stores&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Hierarchical roles. UPDATE_ALL implicitly grants you UPDATE_CUSTOMER, UPDATE_ORDER, etc...&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Many other features like NTLM support, Portlet Security integration, and Automatic login page generaton&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;The second session I hit was RESTful web services in Spring by Arjen Poutsma. This session was a combination introduction to REST (Representational State Transfer) and highlight of facilities coming soon for developing clients and providers of these web services. It was great to see how similar the EndPoints Arjen displayed were to the Controller classes shown by Keith Donald earlier in the week in the RESTful web sites talk. Despite the number of disparate people working on these separate Spring based sub-projects, they are all adhering to a few common designs that make it very easy for a Spring developer to become productive in each of the environments.&lt;br /&gt;&lt;br /&gt;OSGi was next up, presented by Adrian Colyer and Costin Leau. OSGi will provide Java application developers with a facility for deploying and managing separate versions of the same subsystems or libraries. The examples shown were somewhat contrived, but the concepts of OSGi are extremely powerful and immediately useful in at least two of the last three Java clients I've worked at. If you've ever found yourself trying to juggle version collision of components in your application, be sure to investigate OSGi.&lt;br /&gt;&lt;br /&gt;Final talk of the conference for me was Spring Batch Internals by David Syer and Lucas Ward. They covered a plethora of the common issues facing batch processing systems and the solutions provided to these issues by Spring Batch. Batch processing seems to be the red headed step child of software development. Continually neglected while SOA and AJAX based applications win all of the adoration of the parents. Regardless, it is still a significant portion of the software projects out there and there are a wealth of common patterns that can be pulled up a level into a framework like Spring Batch. I'd go into more detail on it but I am seriously exhausted and my head hurts from the amount of information presented at this conference.&lt;br /&gt;&lt;br /&gt;In a nutshell, the content at this conference was great and the majority of the speakers were very good. Only downside was that I didn't win an iPhone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-7944581868091692528?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/7944581868091692528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=7944581868091692528' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7944581868091692528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7944581868091692528'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/12/spring-experience-day-4.html' title='The Spring Experience - Day 4'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-8227967212070215036</id><published>2007-12-14T10:08:00.000-05:00</published><updated>2008-01-24T22:32:52.695-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>The Spring Experience - Day 3</title><content type='html'>Started off day three with Spring Security directly from it's creator, Ben Alex. The session provided a good intro to Spring Security but I felt bad for Ben as he got peppered with 4011 questions during the talk. Even with all of the tangents, Ben did a good job of presenting the core benefits of Spring Security. An example of it's power is to have a configuration that intercepts a method, say getEbayItemListing() and checks to see before execution if the user is authorized to perform this action. This can be a complex check that even validates if the current requester is actually seller of the item (instance level authorization). Then upon method completion, the after advice will mask the minimum sale amount by nulling it out on the object if the requester is not the original seller. With this being performed at the method level, it doesn't matter if the request comes from a website, web service, or other Java program. Very powerful.&lt;br /&gt;&lt;br /&gt;Rob Harrop gave a talk on concurrency in Java that was very in depth coverage of the Java 5 concurrency objects. There was a ton of info in that session that I'll not cover here other than to say if you are developing in a multi-threaded environment in Java 5, please review the docs in the java.util.concurrency package.&lt;br /&gt;&lt;br /&gt;The third session I attended was from one of my favorite tech speakers Venkat Subramaniam. Venkat covered Spring's facilities for integrating dynamic language objects like Ruby and Groovy classes into your Java framework as plain beans. I had no idea that this facility existed and as with most things Spring, it is accomplished very painlessly with a little configuration. A great use case for this is on the fly loading of dynamic processing logic (like rules) without stopping your application or server. Want some small dynamic rules processing without dealing with a full blown rules engine like JRules or JBoss rules? Here's your answer (and you don't need to wait for your company to deploy Java6). The second half of his talk covered using the GroovyObjectCustomizer object from Spring to implement a DSL. This also seemed relatively simple, but it was surprising how much more complex it was to implement in straight Java versus Groovy. I still prefer Ruby though.&lt;br /&gt;&lt;br /&gt;The final talk before 500 pasty, flabby geeks descended upon the Hollywood, FL beach was Spring Web Services by Arjen Poutsma. I didn't gather a ton of info out of this session but a couple of nuggets were useful. The speaker advocated the opposite approach of XFire. Basically that you should start with the contract and work back towards mapping to your domain which I think makes sense in all but some of the more trivial cases. Additionally it seems that once you get the gist of Spring and the annotations provided in 2.5, moving from Spring MVC and WebFlow to something like Spring WebServices is rather trivial.&lt;br /&gt;&lt;br /&gt;Time to hammock up!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-8227967212070215036?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/8227967212070215036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=8227967212070215036' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8227967212070215036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8227967212070215036'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/12/spring-experience-day-3.html' title='The Spring Experience - Day 3'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-712621392363952253</id><published>2007-12-14T08:41:00.001-05:00</published><updated>2008-01-24T22:33:22.467-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>The Spring Experience - Day 2</title><content type='html'>I focused on web framework related sessions today and came away with a wealth of knowledge and a long list of technologies to investigate further. Keith Donald gave a presentation on full stack web frameworks that was very interesting. He gave a very unbiased perspective on how frameworks like Grails, Rails, Django and others excel and lag with respect to about 10 criteria that comprise a "full stack" web framework (AJAX, REST, data binding, security, testability, etc...). He offered that Spring really doesn't have a full stack web framework, but instead acts as a foundation for them (Grails being built on top of it for instance). That is changing however as Spring MVC and WebFlow are adapting and integrating with some other technologies to really provide a complete offering. &lt;br /&gt;&lt;br /&gt;I attended a few other sessions that focused on REST with Spring, AJAX offerings, JSF and WebFlow based apps, and Reasonable Server Faces. They all provided ton of information outside of my traditional area of expertise (middleware and persistence). &lt;br /&gt;&lt;br /&gt;I think the most striking thing that I realized in these sessions though was how much of a huge step up in productivity there is in Spring 2.5. Annotations seem like a much better fit for metadata and being able to tell the container to only autowire a few certain dependencies right at their declaration point is immensely useful. Spring Security (formerly ACEGI) has gone from around a minimum of 150 lines of configuration to about 15 for the simplest cases by making use of these constructs. Spring 2.5 maintains backwards compatibility as well, so run, don't walk to the download if you haven't already.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-712621392363952253?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/712621392363952253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=712621392363952253' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/712621392363952253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/712621392363952253'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/12/spring-experience-day-2.html' title='The Spring Experience - Day 2'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-3435204369464868991</id><published>2007-12-13T10:25:00.000-05:00</published><updated>2008-01-24T22:33:44.330-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>The Spring Experience - Day 1</title><content type='html'>Day one of TSE was just registration, dinner, and a keynote by Rod Johnson but it was a great evening for a couple reasons.&lt;br /&gt;&lt;br /&gt;Rod's keynote focused on the changing of the guard and disruption for the Java EE landscape. Most notably, his contention was that the committee driven process that we have now is largely failing. EJB 3.0 being just the latest example. OpenSource is a much more dynamic and user driven process that nearly immediately produces software and frameworks that a lot of users need. The committees by contrast are steered by people who try to sell application servers and move at the pace of a Columbus driver in a 1/2 inch of snow (aka very s l o w l y). I think his point here was right on and I think it might signal a very polar divide between users and committee.&lt;br /&gt;&lt;br /&gt;Additionally, the conference passed out Rod Johnson bobblehead dolls complete with the pose from this book cover:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://ecx.images-amazon.com/images/I/51599JVEZXL._BO2,204,203,200_PIsitb-dp-500-arrow,TopRight,45,-64_OU01_AA240_SH20_.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;Classic!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-3435204369464868991?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/3435204369464868991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=3435204369464868991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3435204369464868991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/3435204369464868991'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/12/spring-experience-day-1.html' title='The Spring Experience - Day 1'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-8915760728358155123</id><published>2007-12-10T13:00:00.000-05:00</published><updated>2007-12-10T13:23:25.386-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>Christmas Comes Early for Spring Fanboy</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_QxI2aQuFZnk/R12DsAGZwGI/AAAAAAAAABM/IYUsis2E9-o/s1600-h/ScreenHunter_04+Dec.+10+13.06.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_QxI2aQuFZnk/R12DsAGZwGI/AAAAAAAAABM/IYUsis2E9-o/s320/ScreenHunter_04+Dec.+10+13.06.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5142411141491310690" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Wednesday I leave balmy Ohio (currently 38 degrees with showers) for Hollywood, FL (currently 82 degrees). Weather aside, I am extremely excited as I'm going there for the Spring Experience conference. As big a fanboy as I am with Spring, I'm somewhat daunted by the sheer volume of information that will be coming at me this week. There are 70 1.5 hour sessions crammed into 3 full days and I've got more than a passing interest in attending about 50 of them.&lt;br /&gt;&lt;br /&gt;TSE is organized by Jay Zimmerman of NoFluffJustStuff fame, so I've got high expectations. I've been to NFJS conferences the last four years and every time I come back to work re-energized and armed with a bevy of new tools and techniques that are immediately applicable to my daily work. NFJS typically brings only noted authors and thought leaders in as speakers for these conferences and this one is no different with Rod Johnson, Juergen Hoeller, Rob Harrop, Ben Alex, Ramnivas Laddad, and a slew of other Spring contributors and experts speaking at the conference.&lt;br /&gt;&lt;br /&gt;I'm going to have the laptop with me and battery willing, I'll be able to share my impressions throughout the conference.&lt;br /&gt;&lt;br /&gt;Time to get packing. Now where did I put the old banana hammock...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-8915760728358155123?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/8915760728358155123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=8915760728358155123' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8915760728358155123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/8915760728358155123'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/12/springapalooza.html' title='Christmas Comes Early for Spring Fanboy'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_QxI2aQuFZnk/R12DsAGZwGI/AAAAAAAAABM/IYUsis2E9-o/s72-c/ScreenHunter_04+Dec.+10+13.06.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-4265247795933617678</id><published>2007-12-07T11:16:00.001-05:00</published><updated>2007-12-07T11:31:49.530-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='hatred'/><title type='text'>The Long and Winding Road</title><content type='html'>I've started back up on a new phase of a project and it's rekindling my hatred for extensive documentation. I'm beginning to feel that most developers are just not inherently good at writing documentation, myself especially. We're just not wired that way and I think people generally despise doing tasks that they are not good at.&lt;br /&gt;&lt;br /&gt;In this instance maybe it's just more painful because there is no challenge involved. It's a straight migration of an existing system so there is none of the excitement involved in finding out what the business domain entails and trying to mate technologies to the problems facing the users of the system.&lt;br /&gt;&lt;br /&gt;Luckily we're always running an Agile project at QSI, and this particular client is open to documenting only what is needed and not wasting money on anything more. Unfortunately this brings up the question, what are the bare essentials when it comes to documenting a system? In this instance specifically, what is the minimum amount of documentation needed to capture the state of an existing code base? How valuable is any documentation? It's always the first thing thrown out the door when timelines get compressed and it's typically the last thing updated after maintenance or enhancements are performed on a system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-4265247795933617678?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/4265247795933617678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=4265247795933617678' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4265247795933617678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4265247795933617678'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/12/long-and-winding-road.html' title='The Long and Winding Road'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-4087647690951921920</id><published>2007-11-21T09:51:00.000-05:00</published><updated>2007-11-29T14:02:35.523-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>The first of many Spring kicks arse posts</title><content type='html'>In my opinion, nothing has brought life into Java development like the Spring Framework. Enterprise development in Java 4 years ago had me scratching my head. Why do I need to implement methods in this interface when I don't declare I implement it? Why do I need Entity Beans? Which of the 8 web frameworks should I be using? Why does it take so long to go from fixing a bug to actually testing that it worked? Spring has in some way, shape, or form answered all of these questions. Well except for the 8 web frameworks one.&lt;br /&gt;&lt;br /&gt;Spring started with a couple of developers who were as frustrated as I was with the complexity inherent in Java enterprise development. Fortunately for our community, they were and are much smarter and driven than I am and they wound up with a set of tools that simplify almost every aspect of development in a Java enterprise. I think one of the keys of Spring's success has been focusing on simplifying advanced concepts and providing extremely useful tools out of the box. This example shows how Spring has simplified Aspect Oriented Programming which was a rather radical shift for Java developers in the early days of AspectJ. Additionally it provides something that 90% of all Java projects would want out of the box. Simple entered/exited logging and performance monitoring.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_QxI2aQuFZnk/R08MqlkLksI/AAAAAAAAABE/wtJ2oj2p7WQ/s1600-h/ScreenHunter_02+Nov.+27+09.33.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_QxI2aQuFZnk/R08MqlkLksI/AAAAAAAAABE/wtJ2oj2p7WQ/s320/ScreenHunter_02+Nov.+27+09.33.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5138339625630929602" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This code in it's current state will provide good trace logging for any bean named *DAO or *Service. Change or add the interceptor name to PerformanceTraceInterceptor and it will provide performance metrics using the JAMon performance monitoring utility. All of this provided out of the box with Spring. Stay tuned for more Spring fanboy-ism in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-4087647690951921920?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/4087647690951921920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=4087647690951921920' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4087647690951921920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/4087647690951921920'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/11/first-of-many-spring-kicks-arse-posts.html' title='The first of many Spring kicks arse posts'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_QxI2aQuFZnk/R08MqlkLksI/AAAAAAAAABE/wtJ2oj2p7WQ/s72-c/ScreenHunter_02+Nov.+27+09.33.gif' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-1742576464067024556</id><published>2007-11-20T11:09:00.000-05:00</published><updated>2007-11-20T11:27:33.831-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>Hibernate Hijinks</title><content type='html'>I've been tasked with optimizing some slowly performing transactions in a system that has been built upon Hibernate. Yesterday I ran across an interesting situation where a single transaction was resulting in 6 separate queries to the database. This may not necessarily be bad, but when the transaction was performing as slowly as it was, we needed to take whatever means we could to speed it up. What was unique to me was that we eliminated all but 2 queries, and we eliminated each one in very different ways.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Use the second level cache for largely read only data. There was a table that had slipped through the cracks of our investigation that will rarely be updated. A couple of configuration entries later and it will be stored in a second level cache and refreshed on a weekly basis instead of causing an extra query hundreds or thousands of times per day.&lt;/li&gt;&lt;li&gt;Eagerly fetch associations that are needed every time the transaction is called. The Criteria API in Hibernate allows the user to specify the fetch mode for every association, effectively overriding the default behavior provided by the mapping file. Setting the fetch mode to Eager for this association resulted in an extra left outer join, but it eliminated an extra query per result row.&lt;/li&gt;&lt;li&gt;Don't haphazardly access collections that are not needed by all of your clients. The transaction in it's previous state would call off to a dependent collection and call the size() method on it to determine how many child records were linked to the parent. This caused every child record in that collection to be loaded by Hibernate, even though very few of the clients actually needed to know the size of this collection. Adding a property to the incoming request to determine if the transaction actually needed to fetch that count and then doing it by simply executing a separate projection based query resulted in much speedier performance for all clients.&lt;/li&gt;&lt;/ol&gt;This scenario illustrates the flexibility of Hibernate and also the ease with which you can misuse this powerful framework. Always output the SQL generated by Hibernate in development, and make it a regular part of your design, develop, test cycle to inspect that SQL to ensure that it is doing what you think it is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-1742576464067024556?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/1742576464067024556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=1742576464067024556' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1742576464067024556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/1742576464067024556'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/11/hibernate-hijinks.html' title='Hibernate Hijinks'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7850659753537165932.post-7477175629240831294</id><published>2007-11-20T10:53:00.000-05:00</published><updated>2007-11-20T10:54:46.821-05:00</updated><title type='text'>Hello World</title><content type='html'>I've finally been coerced into starting a blog. Thanks BHP!&lt;br /&gt;&lt;br /&gt;Stay tuned for my thoughts on Beer, Software Development, Family, and Friends.  Mostly beer though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7850659753537165932-7477175629240831294?l=toddkaufman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toddkaufman.blogspot.com/feeds/7477175629240831294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7850659753537165932&amp;postID=7477175629240831294' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7477175629240831294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7850659753537165932/posts/default/7477175629240831294'/><link rel='alternate' type='text/html' href='http://toddkaufman.blogspot.com/2007/11/hello-world.html' title='Hello World'/><author><name>Todd Kaufman</name><uri>http://www.blogger.com/profile/00460924846469563813</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/-Ixu6hevYlUI/Th2BONg_1UI/AAAAAAAAALk/vlloI9ibGkY/s220/First%2Bhalf.jpg'/></author><thr:total>0</thr:total></entry></feed>
