<?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'><id>tag:blogger.com,1999:blog-4409679843337649442</id><updated>2009-06-17T00:49:01.928-07:00</updated><title type='text'>Into the Garbage Chute, Flyboy</title><subtitle type='html'>What an incredible (code) smell you've discovered!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default?start-index=26&amp;max-results=25'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>36</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-8215587225501734355</id><published>2008-12-22T06:01:00.001-08:00</published><updated>2008-12-22T08:18:35.420-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa'/><title type='text'>Hibernate/JPA objects in an HTTP session</title><content type='html'>Last week I ran into an unexpected problem.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My application has a User object, which contains various fields.  User also has a JPA-managed One-To-Many relationship with something called Store.  This relationship had been working fine (and in fact through this story never stopped working).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the first time, last week, I added a JPA-managed relationship between User and an entity class called QuickListEntry.  QuickListEntry in turn has a relationship with Product, which in turn has plenty of other relationships with other entities.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We're using Struts 2, which is only marginally relevant here.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In Action A, we load up the User object from the SecurityContext, do some stuff with him, and then stuff him into the Session for access later.  In Action B, we pull him out of the session and read his data, including his QuickListEntries.  Well what do you know -- I'm getting a Hibernate LazyInitializationException.  This has never happened before.  It never happed with the User's Stores.  What's going on?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well here's what's going on.  When the User is stuffed into the Session, he is disconnected from the JPA EntityManager.  When he is pulled out of the Session, his extended relationships (User to QuickListEntry to Product) can't be followed, because he is disconnected from the EntityManager.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So the most correct solution in this case is not to stuff the User object into the Session at all.  Either stuff the userid in there (which is probably harmless) and then use the userid to re-load the User from the DB in every Action's prepare() method; or pull the User from the SecurityContext on every page load (again, I'd put this in the prepare() method of every Action class).&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-8215587225501734355?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/8215587225501734355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=8215587225501734355' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/8215587225501734355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/8215587225501734355'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/12/hibernatejpa-objects-in-http-session.html' title='Hibernate/JPA objects in an HTTP session'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-9041023497721038469</id><published>2008-12-17T07:07:00.000-08:00</published><updated>2008-12-17T07:12:10.231-08:00</updated><title type='text'>Eclipse/Tomcat note to self</title><content type='html'>Tomcat stops reading config data.  Error with docBase, directory does not exist or is not readable.  Here's what seemed to help:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Remove Tomcat as a server.  Close and restart Eclipse.  Add Tomcat as a server, with the correct project.  Re-add /Catalina/localhost/my.xml.  Make sure the &lt;context&gt; entry is in my.xml and not in server.xml.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-9041023497721038469?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/9041023497721038469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=9041023497721038469' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/9041023497721038469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/9041023497721038469'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/12/eclipsetomcat-note-to-self.html' title='Eclipse/Tomcat note to self'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-8050315052312845841</id><published>2008-09-26T07:04:00.000-07:00</published><updated>2008-09-26T07:06:13.904-07:00</updated><title type='text'></title><content type='html'>Dear Internet,&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I swear to god I'm going to buy http://www.localhost.com/ just so I can put a bigass message up on port 8080 saying &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;REREAD YOUR URL, DUMBASS&lt;/span&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sincerely yours,&lt;/div&gt;&lt;div&gt;Dumbass&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-8050315052312845841?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/8050315052312845841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=8050315052312845841' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/8050315052312845841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/8050315052312845841'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/09/dear-internet-i-swear-to-god-im-going.html' title=''/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-1725158043112561433</id><published>2008-05-20T11:16:00.000-07:00</published><updated>2008-05-20T11:20:42.970-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sitemesh'/><title type='text'>I'll forget this if I don't save it</title><content type='html'>If you use a framework like Struts, you will find that your internal file paths don't match your external ones.  So you may have /foo/bar/myThingy.action (externally) which is mapped to /WEB-INF/secure/jsps/myThingy.jsp internally.&lt;br /&gt;&lt;br /&gt;If you use SiteMesh, the decorator patterns you put in decorators.xml should be mappings to your internal directory structure, not your external structure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-1725158043112561433?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/1725158043112561433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=1725158043112561433' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1725158043112561433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1725158043112561433'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/05/ill-forget-this-if-i-dont-save-it.html' title='I&apos;ll forget this if I don&apos;t save it'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-580111097132882932</id><published>2008-03-25T16:23:00.000-07:00</published><updated>2008-03-25T16:24:54.324-07:00</updated><title type='text'>The only valid measure of code quality</title><content type='html'>&lt;a href="http://www.osnews.com/story/19266/WTFs_m"&gt;http://www.osnews.com/story/19266/WTFs_m&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-580111097132882932?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/580111097132882932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=580111097132882932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/580111097132882932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/580111097132882932'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/03/only-valid-measure-of-code-quality.html' title='The only valid measure of code quality'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-656596530113850330</id><published>2008-03-21T08:22:00.000-07:00</published><updated>2008-03-21T08:25:40.925-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa'/><title type='text'>Hibernate Session vs. EntityManager</title><content type='html'>The answer to the question below is depressingly easy.  I was overthinking the problem.  Session is Hibernate's custom implementation; EntityManager is the standard JPA creature.  If you want to stick to the standards (in this case, I do, although the odds of our shifting to a different JPA provider are very slender), stick to EntityManager.  The big thing I'm missing out on so far is access to Hibernate's various CascadeTypes; the JPA default CascadeTypes are rather limited.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-656596530113850330?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/656596530113850330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=656596530113850330' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/656596530113850330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/656596530113850330'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/03/hibernate-session-vs-entitymanager.html' title='Hibernate Session vs. EntityManager'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-667064511577183086</id><published>2008-03-21T07:56:00.000-07:00</published><updated>2008-03-21T08:18:17.126-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='general development'/><title type='text'>The way I'm working lately</title><content type='html'>This is actually almost fun.&lt;br /&gt;&lt;br /&gt;Figure out some functionality that needs to exist.  Within a unit test, write the top-level code for it regardless of whether the supporting methods exist or not.  &lt;br /&gt;&lt;br /&gt;List&lt;Person&gt; people = populationDao.getPeople();&lt;br /&gt;&lt;br /&gt;...even if I haven't written populationDao.getPeople() yet.&lt;br /&gt;&lt;br /&gt;Eclipse will complain that I have written references to methods that don't exist.  Hit control-1 and choose the answer that is "create method 'getPeople' in interface 'populationDao'."  Then, of course, PopulationDaoImpl will have errors, because I have a method in populationDao that I haven't implemented.  Open up PopulationDaoImpl, control-1, 'add unimplemented methods,' and write the implementation for getPeople().&lt;br /&gt;&lt;br /&gt;This way I know that getPeople() has at least some test coverage right from the start.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-667064511577183086?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/667064511577183086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=667064511577183086' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/667064511577183086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/667064511577183086'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/03/way-im-working-lately.html' title='The way I&apos;m working lately'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-6976218635552241419</id><published>2008-03-17T07:57:00.000-07:00</published><updated>2008-03-17T08:00:41.334-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><title type='text'>Open Hibernate Question</title><content type='html'>Open question: I see in the Hibernate documentation that &lt;a href="http://www.hibernate.org/397.html"&gt;Hibernate's EntityManager&lt;/a&gt; is "similar to" Hibernate's Session interface.  But it isn't clear when I should be using one versus the other.  I'm using the EntityManager now and everything's going fine.  But I want to make sure I'm doing this The Right Way so that I don't have to rip it apart and rewrite it in three months when I better understand the business problems I'm fighting.  Any readers have any insight?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-6976218635552241419?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/6976218635552241419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=6976218635552241419' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/6976218635552241419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/6976218635552241419'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/03/open-hibernate-question.html' title='Open Hibernate Question'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-2106282274767522181</id><published>2008-03-07T11:20:00.001-08:00</published><updated>2008-03-07T11:29:44.026-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='acegi'/><title type='text'>Acegi: It Makes Sense Now</title><content type='html'>I was trying to write a massive security infrastructure beast.  I don't need to do that.&lt;br /&gt;&lt;br /&gt;The first thing I've done since the last post is to write my own '&lt;span style="font-family: courier new;"&gt;SecurityService&lt;/span&gt;' class that implements the &lt;span style="font-family: courier new;"&gt;UserDetailsService &lt;/span&gt;interface.  &lt;span style="font-family: courier new;"&gt;UserDetailsService &lt;/span&gt;has just one method -- &lt;span style="font-family: courier new;"&gt;UserDetails loadUserByUsername(String)&lt;/span&gt;.  So it takes a username and loads that whole user object.&lt;br /&gt;&lt;br /&gt;Well this confused me.  Where the hell, I thought, does the password get dealt with here?&lt;br /&gt;&lt;br /&gt;The answer is that the password is handled by the Authentication Provider (in this example, an &lt;span style="font-family: courier new;"&gt;org.acegisecurity.providers.dao.DaoAuthenticationProvider&lt;/span&gt;).  So this particular authentication provider accepts a username and password, uses the username to pull the &lt;span style="font-family: courier new;"&gt;UserDetails &lt;/span&gt;data out of the &lt;span style="font-family: courier new;"&gt;UserDetailsService&lt;/span&gt;, and then (in memory) (presumably) compares the submitted password to the password returned from the &lt;span style="font-family: courier new;"&gt;UserDetails &lt;/span&gt;object's &lt;span style="font-family: courier new;"&gt;getPassword()&lt;/span&gt; method.&lt;br /&gt;&lt;br /&gt;I'm not thrilled by this implementation, because &lt;span style="font-style: italic;"&gt;it assumes that passwords will be stored in plaintext&lt;/span&gt;!  They shouldn't be.&lt;br /&gt;&lt;br /&gt;Anyway, I verified all of this by building out a deliberately stupid implementation of the &lt;span style="font-family: courier new;"&gt;UserDetailsService &lt;/span&gt;and wiring it into my application -- specifically I wrote one that always returns the same &lt;span style="font-family: courier new;"&gt;UserDetails &lt;/span&gt;object, with a known and bogus username and password.  I tested this and it worked, so it all makes more sense to me now.  Next step is to rewrite my bogus &lt;span style="font-family: courier new;"&gt;UserDetailsService &lt;/span&gt;to talk to my actual application code and return real user objects.&lt;br /&gt;&lt;br /&gt;Down the road a bit I'm probably going to have to look at the other authentication providers, so that I can handle encrypted passwords.  But in the interim this is good progress.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Stupid side note&lt;/span&gt;: for some reason, whenever I log in, users are getting redirected to an image file the first time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-2106282274767522181?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/2106282274767522181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=2106282274767522181' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/2106282274767522181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/2106282274767522181'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/03/acegi-it-makes-sense-now.html' title='Acegi: It Makes Sense Now'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-4424676636986552717</id><published>2008-03-07T08:09:00.000-08:00</published><updated>2008-03-07T08:17:38.044-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='acegi'/><title type='text'>Back with Acegi</title><content type='html'>After a ColdFusion-induced layoff I'm back hacking at Acegi Security.&lt;br /&gt;&lt;br /&gt;At this point I have a simple (very simple) Struts 2 application in place and I'm applying Acegi Security to it.&lt;br /&gt;&lt;br /&gt;What I've done so far is taken the Acegi &lt;a href="http://www.acegisecurity.org/petclinic-tutorial.html"&gt;Petclinic Tutorial&lt;/a&gt; and applied it to my application.  I used just about the simplest possible security implementation there -- I changed some names in their default users.properties file and implemented properties-file-driven security.&lt;br /&gt;&lt;br /&gt;So far it does work, though -- the login page is exposed to all comers, while the more secure pages deeper in the app are hidden.  Routing to the "landing" page upon login works correctly as well.&lt;br /&gt;&lt;br /&gt;Next I want to change authentication so that it looks at my users table instead of looking at the properties file.  I'll continue to assume just two levels of authorization (anonymous and logged-in user).  The Acegi Security &lt;a href="http://www.acegisecurity.org/guide/springsecurity.pdf"&gt;reference documentation&lt;/a&gt; suggests that I'm going to want to implement the UserDetailsService interface... but of course UserDetailsService doesn't accept a password argument.  So I'm going to have to figure out what to do to really authenticate the user, as opposed to just looking them up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-4424676636986552717?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/4424676636986552717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=4424676636986552717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/4424676636986552717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/4424676636986552717'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/03/back-with-acegi.html' title='Back with Acegi'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-692357706671453003</id><published>2008-02-27T13:23:00.000-08:00</published><updated>2008-02-27T13:29:12.399-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='struts 2'/><category scheme='http://www.blogger.com/atom/ns#' term='acegi'/><title type='text'>Acegi and Struts 2</title><content type='html'>The easy part is done.  Acegi's jar files are in place and they reliably block access to the "protected" part of the application, and redirect users to the login page.  Unfortunately I haven't yet figured out how to connect my login action to Acegi authentication. &lt;br /&gt;&lt;br /&gt;I believe I will have to have my login action point at my own custom implementation of UserDetailsService, which will in turn have a link to my already-existing UserDao.  It will have to put the UserDetails in question into the security context... I think I got it.  Now just to, y'know, write the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-692357706671453003?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/692357706671453003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=692357706671453003' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/692357706671453003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/692357706671453003'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/acegi-and-struts-2.html' title='Acegi and Struts 2'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-2362443443514038411</id><published>2008-02-27T10:56:00.001-08:00</published><updated>2008-02-27T10:57:11.358-08:00</updated><title type='text'></title><content type='html'>First real step was to tell web.xml that I was going to have multiple applicationContext files (applicationContext.xml and securityContext.xml) so that I don't poop all over my application context with security stuff.  Yeesh, there's a lot of configuration there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-2362443443514038411?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/2362443443514038411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=2362443443514038411' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/2362443443514038411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/2362443443514038411'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/first-real-step-was-to-tell-web.html' title=''/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-3758267186701364984</id><published>2008-02-27T10:31:00.000-08:00</published><updated>2008-02-27T10:36:53.433-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='acegi'/><title type='text'>Acegi Security</title><content type='html'>Today I am checking out &lt;a href="http://www.acegisecurity.org/"&gt;Acegi Security&lt;/a&gt; for our app.  I'm slapping it against the application now, early on, rather than trying to shoehorn it in later, after everything works in an insecure fashion.&lt;br /&gt;&lt;br /&gt;I would like to know how the hell it's supposed to be pronounced.&lt;br /&gt;&lt;br /&gt;It certainly looks cool.  Pretty pluggable.  Should fit reasonably well within our current application design; I'm just going to write a UserDetailsService implementation that uses our existing Hibernate configuration.&lt;br /&gt;&lt;br /&gt;More as I actually do it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-3758267186701364984?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/3758267186701364984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=3758267186701364984' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/3758267186701364984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/3758267186701364984'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/acegi-security.html' title='Acegi Security'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-1533063599658756444</id><published>2008-02-22T12:58:00.000-08:00</published><updated>2008-02-22T13:12:43.521-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OOAD'/><title type='text'>Incredibly Basic Design Problem</title><content type='html'>I'm working on a web application.  All noteworthy data in here has been scrubbed appropriately.&lt;br /&gt;&lt;br /&gt;This application has users.  There are both external and internal users.  Each user may have access to a certain subset of the application's functionality, although generally speaking internal users' functionality access is different from external users' functionality access.  For instance, we might have an external user who is a customer, and another external user who is a supplier.  We might have an internal user who is a sales rep, and another who provides support to the logistics team.&lt;br /&gt;&lt;br /&gt;The question I immediately ask myself is this:  Am I looking at an inheritance hierarchy, or am I looking at an opportunity for composition?&lt;br /&gt;&lt;br /&gt;In other words, do I have:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;public abstract class User {...}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;public abstract class InternalUser extends User {...}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;public class LogisticsUser extends InternalUser {...}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;?&lt;br /&gt;&lt;br /&gt;Or should I rely instead on composition?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;public class User {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  Set availableRoles = new HashSet&lt;/span&gt;&lt;function&gt;&lt;span style="font-family:courier new;"&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;User fred = new User();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;fred.addRole(LOGISTICS);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I might consider answering this question with a look at the database tables that I'm relying on, but (1) I'm more concerned with the conceptual problem here than the implementation details and (2) in this particular case the tables are no help at all anyway.&lt;br /&gt;&lt;br /&gt;So here is the core question: Can a user ever fill multiple roles?  Java doesn't support multiple concrete inheritance, so a given user either IS a LogisticsUser or he IS a CafeteriaUser or what-have-you.  If users can fill multiple roles, then I should be assigning them roles rather than slotting them in a particular concrete class.&lt;br /&gt;&lt;br /&gt;And in this particular case, yes, some users do need to fill multiple roles (for instance, we might have a logistics support person who also has administrative authority over some of the website).  So I'll be making a simple User hierarchy with a more complex collection of Roles available.  &lt;br /&gt;&lt;/function&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-1533063599658756444?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/1533063599658756444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=1533063599658756444' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1533063599658756444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1533063599658756444'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/incredibly-basic-design-problem.html' title='Incredibly Basic Design Problem'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-1098768667710118612</id><published>2008-02-20T15:38:00.000-08:00</published><updated>2008-02-20T15:42:11.682-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Today I Am A Real Boy</title><content type='html'>Today a client coworker gave me some Java code of his to work on and finish up, because we're going to need it for forward development.&lt;br /&gt;&lt;br /&gt;So I looked at what stuff could be refactored, wrote a couple of unit tests, refactored some bits out, ran the tests, and...&lt;br /&gt;&lt;br /&gt;Well the code logged a few major exceptions and was unusable.  But the test passed.&lt;br /&gt;&lt;br /&gt;We were conversing about this code in general terms a few minutes later, and I pointed at the screen and hollered "I want that test to fail! Help me make it fail!"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-1098768667710118612?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/1098768667710118612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=1098768667710118612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1098768667710118612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1098768667710118612'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/today-i-am-real-boy.html' title='Today I Am A Real Boy'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-18431592012003290</id><published>2008-02-16T09:57:00.000-08:00</published><updated>2008-02-16T09:59:21.849-08:00</updated><title type='text'>Dippy</title><content type='html'>To go with "ATM machine" we now have "plain POJO," per &lt;a href="http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#entity-mapping"&gt;the Hibernate docs&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-18431592012003290?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/18431592012003290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=18431592012003290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/18431592012003290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/18431592012003290'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/dippy.html' title='Dippy'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-6174789975820844646</id><published>2008-02-14T09:59:00.001-08:00</published><updated>2008-02-14T10:00:55.283-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><title type='text'>Glad to see this works</title><content type='html'>I wasn't sure this would work.  One quick unit test verifies that it does.  Very good to know:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;        Query query = getEntityManager().createQuery("from User order by ?");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        query.setParameter(1, "lastName");&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I don't know why it wouldn't work, really, but I had only used replaceable parameters in the WHERE clause of queries before.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-6174789975820844646?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/6174789975820844646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=6174789975820844646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/6174789975820844646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/6174789975820844646'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/glad-to-see-this-works.html' title='Glad to see this works'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-8488827756239625498</id><published>2008-02-14T06:38:00.000-08:00</published><updated>2008-02-14T06:48:01.682-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='struts 2'/><title type='text'>Thought I was GONE didn't you</title><content type='html'>I've played a bit over the last few days with a simple Struts 2 CRUD app, mostly following the examples given &lt;a href="http://cwiki.apache.org/WW/crud-demo-i.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Right now I have a data table that lists the users of the app and provides an exciting 'edit' link for each one.  The edit link takes you to a pretty standard 'edit' type page for the given user.&lt;br /&gt;&lt;br /&gt;Here's what I'd like to do next (several things, all fairly independent of the others).&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Turn the data table into a submit-driven paging sorting data grid.&lt;/li&gt;&lt;li&gt;Turn the data table into an AJAX-driven paging sorting data grid.&lt;/li&gt;&lt;li&gt;Implement a smart(ish) filter for the data grid.&lt;/li&gt;&lt;li&gt;Change the two-page layout (table, data entry grid) into a one-page AJAX-driven layout (click on a user to open the edit grid for that user next to the table).&lt;/li&gt;&lt;/ul&gt;I think I'm going to start with the first one; I'm going to have to do it eventually anyway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-8488827756239625498?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/8488827756239625498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=8488827756239625498' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/8488827756239625498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/8488827756239625498'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/thought-i-was-gone-didnt-you.html' title='Thought I was GONE didn&apos;t you'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-992049953139805702</id><published>2008-02-07T12:14:00.000-08:00</published><updated>2008-02-07T12:16:49.491-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coldfusion'/><title type='text'>Another thing that drives me berserk about ColdFusion and CFEclipse</title><content type='html'>It is damned near impossible without using the "find" feature and extraordinarily tedious tag-counting (and tag-collapsing) to figure out whether or not a given variable is in scope at a particular part of the page.  I can't control-click to go to the spot where the variable is declared; I get no indication as to whether the variable exists at a given spot; I don't even get a warning telling me that the variable may not have been declared conditionally at a given spot.&lt;br /&gt;&lt;br /&gt;And then I get exceptions thrown when my predecessor's code references a variable that was conditionally declared earlier and the declaration got skipped this time.  Madness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-992049953139805702?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/992049953139805702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=992049953139805702' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/992049953139805702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/992049953139805702'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/another-thing-that-drives-me-berserk.html' title='Another thing that drives me berserk about ColdFusion and CFEclipse'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-2083478786495829270</id><published>2008-02-06T06:25:00.000-08:00</published><updated>2008-02-06T06:50:47.550-08:00</updated><title type='text'>Wrong Ways, first in a series</title><content type='html'>After a few days spent doing ColdFusion support I'm doing some more Struts/Hibernate development today.&lt;br /&gt;&lt;br /&gt;An observation: There's a right way to set up developers' environments, and there are dozens of wrong ways.  I feel like I have a pretty good grasp of some of the wrong ways, and now I'd like to share them with you.  &lt;span style="font-style: italic;"&gt;Critically important note&lt;/span&gt;: These observations do not pertain to my current client or my employer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wrong Way #1&lt;/span&gt;: Stint on hardware.  A consultant costs, let's say, $100/hr.  A fully-loaded full-time employee might be $70/hr. According to newegg, 4 GB of RAM from a no-name vendor costs $100.  If you want to go with a really reliable, trusted vendor, you might spend $200. If you are furnishing a consultant with hardware, a really great Wrong Way to do things would be to save $200 on memory.  Give him a machine with 1 GB or less.  Sure, it takes 15 minutes for his machine to boot every day, and lockups, crashes, and slow response time cost at least an hour a day.  But you saved the cost of that memory!&lt;br /&gt;&lt;br /&gt;(&lt;span style="font-style: italic;"&gt;but seriously&lt;/span&gt;) This is especially and offensively common when different cost centers or different managers are paying for developers' time versus developers' hardware.  The MIS guys saved $150 off their budget but cost the company an additional $6000 in developer productivity over three months. Woo! Way to contribute! Go team!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wrong Way #2&lt;/span&gt;: Lock down that Internet.  Developers can't be trusted with free reign to go to any website they want. Network administrators know what kind of tools, open-source libraries, and reference materials a developer could want.  Let the network guys and their management make that determination.  Blogs? Forget it! Those things are just time sinks, they're like reading the newspaper at work.  And there's no reason to differentiate between a customer service rep and a software developer in terms of Internet access.  If you can't trust a CSR with access to blogspot.com, there's no way a developer needs it. Lock 'em all down.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wrong Way #3&lt;/span&gt;: Shared environments. Software licensing is expensive.  Rather than spring for a development license for each developer, why not set up a shared dev server, with a shared database and everything? Don't give developers local development environments; just make their desktops into glorified terminals.  Also, this way your developers won't have to worry about solving problems when they're away from an Internet connection or when the VPN is down.  That will encourage them to spend more time in the office.&lt;br /&gt;&lt;br /&gt;Oh, I bet there are plenty more of these I could do...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-2083478786495829270?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/2083478786495829270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=2083478786495829270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/2083478786495829270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/2083478786495829270'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/wrong-ways-first-in-series.html' title='Wrong Ways, first in a series'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-4664764291117763758</id><published>2008-02-04T06:43:00.000-08:00</published><updated>2008-02-04T06:46:31.818-08:00</updated><title type='text'></title><content type='html'>Excellent series on developers' database management and putting your db in version control over at &lt;a href="http://odetocode.com/"&gt;http://odetocode.com/&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://odetocode.com/Blogs/scott/archive/2008/01/30/11702.aspx"&gt;Part 1&lt;/a&gt;&lt;br /&gt;&lt;a href="http://odetocode.com/Blogs/scott/archive/2008/01/31/11710.aspx"&gt;Part 2&lt;/a&gt;&lt;br /&gt;&lt;a href="http://odetocode.com/Blogs/scott/archive/2008/02/02/11721.aspx"&gt;Part 3&lt;/a&gt;&lt;br /&gt;&lt;a href="http://odetocode.com/Blogs/scott/archive/2008/02/02/11737.aspx"&gt;Part 4&lt;/a&gt;&lt;br /&gt;&lt;a href="http://odetocode.com/Blogs/scott/archive/2008/02/03/11746.aspx"&gt;Part 5&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-4664764291117763758?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/4664764291117763758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=4664764291117763758' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/4664764291117763758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/4664764291117763758'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/excellent-series-on-developers-database.html' title=''/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-1004873430153169827</id><published>2008-02-01T08:31:00.000-08:00</published><updated>2008-02-01T08:38:41.629-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><title type='text'>Well that was funny</title><content type='html'>I only had to change the URLs in hibernate.cfg.xml and in applicationContext.xml.  That's good and easy.&lt;br /&gt;&lt;br /&gt;Things didn't work for a sec, because in the 'real' database that I'm now using, Users aren't stored in a 'user' table, they are stored in, let's say, a table called 'bogus_user'.  With Hibernate 2 I would have known to go into User.hbm.xml and modify the table name reference, but the current quickstart project uses Hibernate 3 annotations.  I checked the docs quickly, suspecting I need to change the @Entity annotation on the User class.  The docs pointed me at the &lt;a href="http://www.manning.com/bauer2/chapter2.pdf"&gt;free Chapter 2 sample&lt;/a&gt; of the Manning &lt;a href="http://www.manning.com/bauer2/"&gt;&lt;span style="font-style: italic;"&gt;Java Persistence with Hibernate&lt;/span&gt;&lt;/a&gt; book.  It showed that I needed to add @Table(name="bogus_user") to the User class declaration.  I did that, and redeployed.&lt;br /&gt;&lt;br /&gt;This time I ran into a hilarious error.  The bogus_user table has thousands of entries, and my simpleminded script was trying to display all of them at once.  So -- next step -- limit the number of entries returned.  That will be after lunch, as my wife and I are going to meet for lunch for the first time in ages.&lt;br /&gt;&lt;br /&gt;I'll probably be buying that Manning book this weekend.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-1004873430153169827?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/1004873430153169827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=1004873430153169827' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1004873430153169827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/1004873430153169827'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/well-that-was-funny.html' title='Well that was funny'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-5392739347795710356</id><published>2008-02-01T07:46:00.000-08:00</published><updated>2008-02-01T07:52:07.152-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='struts 2'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Changing a data source</title><content type='html'>It's very quiet here this morning.  Snow and ice last night, freezing rain this morning.  A lot of people are working from home today.&lt;br /&gt;&lt;br /&gt;I'm going to try something wacky this morning.  Having successfully finished the 'quickstart' demo provided by the fine Struts 2 folks, I've already changed the names of my packages and classes to match the activities I actually plan to undertake (&lt;span style="font-family: courier new;"&gt;quickstart.service.PersonServiceImpl&lt;/span&gt; changes to &lt;span style="font-family: courier new;"&gt;com.&lt;span style="font-style: italic;"&gt;clientname&lt;/span&gt;.&lt;span style="font-style: italic;"&gt;project&lt;/span&gt;.UserDaoImpl&lt;/span&gt;, for instance).&lt;br /&gt;&lt;br /&gt;Now I'm going to do something more entertaining.  I'm going to try to dump a copy of our dev MySQL database and build it locally, and then point this toy app at it.  I may not have the right privs for that.  So if that doesn't work, I'm going to point my app at our dev database and see what happens.  I'm pretty sure I know what will have to change.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-5392739347795710356?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/5392739347795710356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=5392739347795710356' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/5392739347795710356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/5392739347795710356'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/02/changing-data-source.html' title='Changing a data source'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-4551245783786506681</id><published>2008-01-31T11:17:00.000-08:00</published><updated>2008-01-31T12:14:27.235-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='struts 2'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Onward</title><content type='html'>The rest of the quickstart demo went pretty smoothly.  Not surprising, considering that it was largely a matter of typing (or copy and pasting) sample code into real files.&lt;br /&gt;&lt;br /&gt;But now the fun begins: problems.  The truth is that you don't understand how a technology or combination of technologies works until you've had to fix them when they're supposed to work.&lt;br /&gt;&lt;br /&gt;So, first problem: Exception stack trace in my Tomcat log.  I am not going to drop the entire stack trace into the blog at this point, but let me describe how I'm handling this.  First, I skimmed the stack trace looking for references to code that I know to be mine.  In this case there are no "quickstart." files anywhere in the stack trace, so I know it's not my Java code.  Now, here are the first few lines of the stack trace:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.ParserContext.registerBeanComponent(Lorg/springframework/beans/factory/parsing/BeanComponentDefinition;)V&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Caused by: java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.ParserContext.registerBeanComponent(Lorg/springframework/beans/factory/parsing/BeanComponentDefinition;)V&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser$AopAutoProxyConfigurer.configureAutoProxyCreator(AnnotationDrivenBeanDefinitionParser.java:130)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.parse(AnnotationDrivenBeanDefinitionParser.java:79)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The most obvious problem appears to be an error parsing applicationContext.xml.  Probably I have a typo in there somewhere.  However, I can't find one after glancing over the file for five minutes and that is almost certainly enough time for now.  So I'm going to do something annoying.  I typed this one in by hand and probably fat-fingered something.  So I'm going to copy-and-paste the file contents from the demo and see if that makes the problem go away.  If it doesn't then I'll have to use my brain and nobody wants that.&lt;br /&gt;&lt;br /&gt;That doesn't make the problem go away!  Crap.  Time to do some Google searches on the exception messages.&lt;br /&gt;&lt;br /&gt;And &lt;a href="http://www.raibledesigns.com/"&gt;Matt Raible &lt;/a&gt;comes through again.  Dude is rapidly becoming my hero.  A thread on the AppFuse mailing list suggests that there might be collisions between various Spring jars.  I'm reorganizing my build path, let's see how this works.&lt;br /&gt;&lt;br /&gt;...nope.  OK, time to review my build path, make sure I have everything I need.  Yes, this would have been a good time to have used Maven, I know.&lt;br /&gt;&lt;br /&gt;Hey, it turns out that I ignored a bunch of Hibernate jars earlier -- specifically the Hibernate Annotations and Hibernate Entity Manager jars.  I'll grab them now. And that doesn't solve the problem either.  Same error.&lt;br /&gt;&lt;br /&gt;Clean, refresh, delete the deployment, rebuild, redeploy... and it's a whole new suite of errors!  But these are more comprehensible.  They can go in another post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-4551245783786506681?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/4551245783786506681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=4551245783786506681' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/4551245783786506681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/4551245783786506681'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/01/onward.html' title='Onward'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4409679843337649442.post-413441264631668899</id><published>2008-01-31T09:36:00.000-08:00</published><updated>2008-01-31T09:58:31.279-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='myeclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Continuing the Struts 2 / Spring / Hibernate Toy</title><content type='html'>If you are just joining us, I am working my way through &lt;a href="http://cwiki.apache.org/S2WIKI/struts-2-spring-2-jpa-ajax.html"&gt;this&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'm working on the provided &lt;span style="font-family: courier new;"&gt;PersonServiceImpl&lt;/span&gt;.  Eclipse can't find the &lt;span style="font-family: courier new;"&gt;@Transactional&lt;/span&gt; annotation, which is apparently &lt;span style="font-family: courier new;"&gt;org.springframework.transaction.annotation.Transactional&lt;/span&gt;.  Thought I had all the Spring jars -- guess not.  &lt;a href="http://www.docjar.com/"&gt;http://www.docjar.com/&lt;/a&gt; -- which should be in every developer's bookmark list -- suggests that it is found in &lt;span style="font-family: courier new;"&gt;spring-dao.jar&lt;/span&gt;, which I don't have.   It looks like I don't have it because it doesn't exist.&lt;br /&gt;&lt;br /&gt;I have a hunch here and it turned out to be right.  Rather than relying on Eclipse's Spring enablement guck, I went right to &lt;a href="http://www.springframework.org/download"&gt;the site to download the latest Spring distribution&lt;/a&gt;, and grabbed it.  Unpacked it, grabbed &lt;span style="font-family: courier new;"&gt;spring.jar&lt;/span&gt;, dropped it into my project.  There, right there, is the &lt;span style="font-family: courier new;"&gt;org.springframework.transaction.annotation&lt;/span&gt; package.  I had assumed -- wrongly -- that Eclipse's Spring capability enablement would include &lt;span style="font-family: courier new;"&gt;spring.jar&lt;/span&gt;.  Sigh.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4409679843337649442-413441264631668899?l=jhkiley.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jhkiley.blogspot.com/feeds/413441264631668899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4409679843337649442&amp;postID=413441264631668899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/413441264631668899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4409679843337649442/posts/default/413441264631668899'/><link rel='alternate' type='text/html' href='http://jhkiley.blogspot.com/2008/01/continuing-struts-2-spring-hibernate.html' title='Continuing the Struts 2 / Spring / Hibernate Toy'/><author><name>Jim Kiley</name><uri>http://www.blogger.com/profile/09314989317011003978</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='14683845142180843833'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>