<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;CkIERXs6fSp7ImA9WhRSFkQ.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728</id><updated>2011-11-19T18:15:04.515+10:00</updated><category term="mvc" /><category term="annotations" /><category term="hibernate" /><category term="jQuery" /><category term="javascript" /><category term="java" /><category term="jpa" /><category term="spring" /><category term="oracle" /><title>just some Java guy</title><subtitle type="html">It isn't ''tisn't' it's 'it isn't' isn't it?</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>71</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/JustSomeJavaGuy" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="justsomejavaguy" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;C0EMSXw-cCp7ImA9WhdXEks.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-7596940287541899160</id><published>2011-08-25T18:41:00.000+10:00</published><updated>2011-08-25T18:41:28.258+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-25T18:41:28.258+10:00</app:edited><title>@Nullable / @Null / @NotNull / @Notnull / @Nonnull / @CheckForNull annotations</title><content type="html">&lt;br /&gt;
Jetbrains never ceases to delight. As of 10.5, their IDE supports not only their own pioneering org.jetbrains.annotations Nullable annotations, but also any other arbitrary @Nullable annotations you&amp;nbsp;decide to use.&lt;br /&gt;
&lt;br /&gt;
Currently the most popular ones are the JSR-305 (javax.annotation)&amp;nbsp;annotations, the FindBugs nullable annotations, and IntelliJ's own&amp;nbsp;nullable annotations.&lt;br /&gt;
&lt;br /&gt;
If you decide to use the Findbugs annotations (which are found in&amp;nbsp;package edu.umd.cs.findbugs.annotations), keep in mind that you&amp;nbsp;probably want to use @CheckForNull instead of @Nullable. By default&amp;nbsp;IntelliJ includes @Nullable for Findbugs, but&amp;nbsp;you should change that to @CheckForNull.&lt;br /&gt;
&lt;br /&gt;
The reason is that @Nullable is all but ignored by Findbugs if you&amp;nbsp;decide to use that as well. Findbugs' annotations seem badly named,&amp;nbsp;but hey that's just the way it is.&lt;br /&gt;
&lt;br /&gt;
On a related subject, be careful not to get the JSR-303 nullable&amp;nbsp;annotations confused with the JSR-305 nullable annotations.&lt;br /&gt;
&lt;br /&gt;
Here is a quick summary of the differences:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;JSR-303&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Used for runtime bean validation, NOT static code analysis&lt;/li&gt;
&lt;li&gt;javax.validation.constraints.NotNull&lt;/li&gt;
&lt;li&gt;javax.validation.constraints.Null&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;JSR-305&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Used for Static code analysis - seems to be all but dead&lt;/li&gt;
&lt;li&gt;javax.annotation.Nonnull&lt;/li&gt;
&lt;li&gt;javax.annotation.Nullable&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Findbugs&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Used by the Findbugs static code analysis tool&lt;/li&gt;
&lt;li&gt;edu.umd.cs.findbugs.annotations.NonNull&lt;/li&gt;
&lt;li&gt;edu.umd.cs.findbugs.annotations.Nullable (Probably not what you want)&lt;/li&gt;
&lt;li&gt;edu.umd.cs.findbugs.annotations.CheckForNull&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;IntelliJ&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Used by IntelliJ IDEA, but also publicly available as a jar&lt;/li&gt;
&lt;li&gt;org.jetbrains.annotations.Nullable&lt;/li&gt;
&lt;li&gt;org.jetbrains.annotations.NonNull&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As usual, IntelliJ's built-in IDE support for nullable is awesome, and Eclipse's is decidedly un-awesome.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="background-color: white; color: #333333; font-family: arial, sans-serif;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div class="nH"&gt;&lt;div class="nH hx" style="color: #333333; padding-bottom: 4px; padding-left: 0px; padding-right: 8px; padding-top: 4px;"&gt;&lt;div class="nH"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-7596940287541899160?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/eG5M-uMWdl4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/7596940287541899160/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=7596940287541899160" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/7596940287541899160?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/7596940287541899160?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2011/08/nullable-null-notnull-notnull-nonnull.html" title="@Nullable / @Null / @NotNull / @Notnull / @Nonnull / @CheckForNull annotations" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0INRX05eip7ImA9WhZbF0w.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-1453241633220623531</id><published>2011-06-22T14:06:00.000+10:00</published><updated>2011-06-22T14:06:34.322+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-22T14:06:34.322+10:00</app:edited><title>FileNotFoundException when running a unit test in IntelliJ</title><content type="html">If you are running a unit test in IntelliJ that needs to load a test file, you might come across this error.&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;java.io.FileNotFoundException: src\test\resources\testFile.xml (The system cannot find the path specified)&lt;/b&gt;&lt;/blockquote&gt;The problem may be that by default, IntelliJ sets the working directory to be the &lt;i&gt;project root. &lt;/i&gt;If you are working on a maven project or something else with a complicated project structure, then you probably want it to look instead at the &lt;i&gt;module root&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
This is easy enough to configure. Simply go to:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;Edit Configurations -&amp;gt; Defaults -&amp;gt; JUnit -&amp;gt; Working Directory&lt;/b&gt;&lt;/blockquote&gt;&lt;br /&gt;
Set this value to &lt;b&gt;$MODULE_DIR$&lt;/b&gt; and you are done!&lt;br /&gt;
&lt;br /&gt;
Also remember to delete any existing JUnit configurations so that it will pick up the default you have just set.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-1453241633220623531?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/i4H_etKRBU0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/1453241633220623531/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=1453241633220623531" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/1453241633220623531?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/1453241633220623531?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2011/06/filenotfoundexception-when-running-unit.html" title="FileNotFoundException when running a unit test in IntelliJ" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;CkIBRno9fyp7ImA9WhZVFEo.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-3436853790920925466</id><published>2011-05-27T14:29:00.000+10:00</published><updated>2011-05-27T14:29:17.467+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-27T14:29:17.467+10:00</app:edited><title>Spring Validation is still pretty dumb</title><content type="html">&lt;b&gt;HOW IT USED TO BE&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
One of the annoying things about Spring MVC 2.5 was the validation. Even Spring themselves have acknowledged it:&lt;br /&gt;
&lt;br /&gt;
"&lt;a href="http://static.springsource.org/spring/docs/3.0.0.RC3/spring-framework-reference/html/ch05s07.html"&gt;In previous versions it was up to the developer to manually invoke validation logic&lt;/a&gt;"&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;HOW IT IS NOW&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
When Spring 3 rolled around, I was looking forward to some clever validator improvements. And Spring delivered!&lt;br /&gt;
&lt;br /&gt;
You no longer have to manually invoke validators, but you can use the JSR-303 @Valid annotation to AUTOMAGICALLY invoke validation on the bean in your controller. Check it out below:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt; @Controller  
 public class MyController {  
   @InitBinder  
   protected void initBinder(WebDataBinder binder) {  
     binder.setValidator(new FooValidator());  
   }  
   @RequestMapping("/foo", method=RequestMethod.POST)  
   public void processFoo(@Valid Foo foo) { ... }  
 }  
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Awesome sauce!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;WHY IT IS STILL DUMB&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Yeah that's cool and all, but that's pretty much all they've done in the way of magic. When it comes to CONFIGURING validators (which is one place we could really use some magic), Spring Validation is still pretty stoopid.&lt;br /&gt;
&lt;br /&gt;
You basically have two options - manually set the validator in your initBinder() (like you can see in the example above), or call setValidator (Validator) on the global WebBindingInitializer. Which looks ike this in the applicationContext.xml:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt; &amp;lt;mvc:annotation-driven validator="globalValidator"/&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
This is pretty dumb too - having a single global validator for all models probably isn't very useful.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;WHY IT IS NOT NORMALLY A PROBLEM&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Now all of this isn't so bad when using Spring Validation with Spring MVC. Normally We have one Model per Controller, which is configured with one Validator (and incidentally one View - which is why it is called (yes you guessed it) MVC ).&lt;br /&gt;
&lt;br /&gt;
So configuring a validator for a controller isn't too bad - we're already configuring the model and view for the contrller, so one more thing is not a problem.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;WHEN IT IS A PROBLEM&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
It becomes a problem when you want to use it OUTSIDE of the MVC framework. When you don't have a controller to configure your validator and model to - how on earth do you wire this stuff up?&lt;br /&gt;
&lt;br /&gt;
Suppose I have an arbitrary model that I want validated with Spring's framework - how do I do it? I don't need any of Spring's Binding facilities. And nothing magical like this seems to exist:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="background-image: URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt; @Autowired MagicalSpringValidationMonkey magicalSpringValidationMonkey;  
 public void myService(MyModel myModel){  
   Errors errors = magicalSpringValidationMonkey.validate(myModel);  
 }  
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
I would expect my Magical Spring validator to do three things:&lt;br /&gt;
1. Run any JSR-303 Bean Validation configured for the model&lt;br /&gt;
2. Find and run the appropriately configured Spring Validator for this model&lt;br /&gt;
3. Return me an errors instance containing all of those errors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;WHY IT SHOULDN'T BE A PROBLEM&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
JSR-303 Validation is configured on the model itself, so Spring should be able to figure out how to run that validation.&lt;br /&gt;
&lt;br /&gt;
Spring Validators (my custom validation classes that implement Spring's Validator interface) are already configured to show which models they support, by means of the supports(Class clazz) method which must be implemented.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;HMMM COME TO THINK OF IT&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Actually now that I think about it, you know what? After writing this long rant, I figured out that it probably wouldn't be too hard for me to write the MagicalSpringValidationMonkey myself.&lt;br /&gt;
&lt;br /&gt;
But you know what else? I'm annoyed that this isn't already there, and that I had to do so much investigation to find out how it works, so I'm not gonna do it. Plus I'm too lazy. And Margaret River is calling me.&lt;br /&gt;
&lt;br /&gt;
I hope you enjoyed this rant.&lt;br /&gt;
&lt;br /&gt;
The end.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-3436853790920925466?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/qL1tpfYH8mg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/3436853790920925466/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=3436853790920925466" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/3436853790920925466?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/3436853790920925466?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2011/05/spring-validation-is-still-pretty-dumb.html" title="Spring Validation is still pretty dumb" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;DUUEQXY_fyp7ImA9Wx9REkU.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-8091534715674153749</id><published>2010-12-14T10:40:00.000+10:00</published><updated>2010-12-14T10:40:00.847+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-14T10:40:00.847+10:00</app:edited><title>Something I didn't (and still don't) know about SQL</title><content type="html">Take this simple Database Table:&lt;br /&gt;
&lt;br /&gt;
&lt;table border="1"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;span class="Apple-style-span" style="background-color: #999999;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Field1&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(null)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;abc&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;xyz&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Here's a test for you. What will the following query return?&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;select * from table1 where field1 like 'a%'&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If you answered &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;abc&lt;/span&gt; you are correct - congratulations!&lt;br /&gt;
Ok now here is the same query slightly modified - what will it return:&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;select * from table1 where not (field1 like 'a%')&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Surprisingly (to me) it doesn't return &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(null)&lt;/span&gt; and &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;xyz&lt;/span&gt;, it only returns &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;xyz&lt;/span&gt;.  If anyone knows why can you please explain in the comments?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-8091534715674153749?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/RGlhjZHHWww" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/8091534715674153749/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=8091534715674153749" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8091534715674153749?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8091534715674153749?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/12/something-i-didnt-and-still-dont-know.html" title="Something I didn't (and still don't) know about SQL" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;CU8HRHo-eip7ImA9Wx5VGEs.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-9091023173193157230</id><published>2010-10-12T16:10:00.000+10:00</published><updated>2010-10-12T16:10:35.452+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-12T16:10:35.452+10:00</app:edited><title>The cause of TeamCity 5 slowness and CPU usage</title><content type="html">Teamcity 5.1.2 was running like a dog for me - with skyrocketing CPU on the server.&lt;br /&gt;
&lt;br /&gt;
The cause of this slowness was a slow network connection to Subversion. You see, by default Teamcity is configured to check for SVN updates every 60 seconds. &lt;br /&gt;
&lt;br /&gt;
If, for some reason (like a slow network connection), it takes longer than 60 seconds to do this check, then the Teamcity svn update jobs will just keep backing up every 60 seconds until there is a whole queue of them slowing down the server.&lt;br /&gt;
&lt;br /&gt;
There are a couple of things you can do:&lt;br /&gt;
&lt;br /&gt;
1. Fix the cause of the network slowness&lt;br /&gt;
2. Change the "Default VCS changes check interval" under Administration -&gt; Server Configuration&lt;br /&gt;
3. Make sure "Clean all files before build" is NOT checked in your build configuration.&lt;br /&gt;
4. Use the slowness as an excuse to request newer hardware :) Then do steps 1, 2 or 3.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-9091023173193157230?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/banX6ZZVkSs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/9091023173193157230/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=9091023173193157230" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/9091023173193157230?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/9091023173193157230?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/10/cause-of-teamcity-5-slowness-and-cpu.html" title="The cause of TeamCity 5 slowness and CPU usage" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D08ESXc_eSp7ImA9Wx5QEUk.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-5687099547185644827</id><published>2010-08-30T15:21:00.001+10:00</published><updated>2010-08-30T15:23:28.941+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-30T15:23:28.941+10:00</app:edited><title>Cached javascript files? A duh moment</title><content type="html">How do you ensure that your users don't have an old cached version of your javascript files?&lt;br /&gt;
&lt;br /&gt;
The answer might come to you straight away, but I'm not ashamed to admit that this problem perplexed me for quite a while. We had problems where the users' browsers were using old cached versions of some javascript files that we had updated. Thus the web application was behaving inconsistently for them.&lt;br /&gt;
&lt;br /&gt;
We flirted with ideas about fiddling with the 'Cache-control' and 'Expires' headers, but it proved troublesome and we didn't want to disable caching completely as a lot of our users are still on dialup connections (yes that's how badly our life-saving Queensland firefighters are treated).&lt;br /&gt;
&lt;br /&gt;
We even thought about writing some sort of script that would find and clear the browser's cache manually each time they logon to the department's network, but for obvious reasons that would be difficult and error-prone. Plus it wouldn't take effect until they log out and log back in.&lt;br /&gt;
&lt;br /&gt;
Then it occurred to me - How does Google do this? They must have heaps of js files and must be rolling out updates all the time!&lt;br /&gt;
&lt;br /&gt;
The answer is very simple. Each time we deploy a new version of the webapp we simply rename the "scripts" folder that contains all our javascript files. Something like appending the version number of the app to the scripts directory name works well.&lt;br /&gt;
&lt;br /&gt;
This will ensure that each time a new version of the app is deployed, each user's browser will be forced to get the latest version of the scripts, solving the caching problem.&lt;br /&gt;
&lt;br /&gt;
Duh!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-5687099547185644827?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/YVaibtQnxec" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/5687099547185644827/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=5687099547185644827" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/5687099547185644827?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/5687099547185644827?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/08/cached-javascript-files-duh-moment.html" title="Cached javascript files? A duh moment" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;AkMBQ3o7eip7ImA9Wx5RGEg.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-6677613167214553051</id><published>2010-08-27T07:34:00.000+10:00</published><updated>2010-08-27T07:34:12.402+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-27T07:34:12.402+10:00</app:edited><title>Selenium and untrusted SSL Certificates</title><content type="html">Our Web App uses SSL and is deployed daily to a development server that has a certificate signed by our internal Certification Authority. This causes some problems with Selenium, as this is essentially an "untrusted" certificate in the eyes of Firefox.&lt;br /&gt;
 &lt;br /&gt;
It is easy to get around this, you just answer the prompt that Firefox throws up and tell Firefox to trust this certificate. But this isn't good enough for an automated build, as Selenium can't answer this prompt for you every time.&lt;br /&gt;
 &lt;br /&gt;
So to get around this I am running my Selenium tests against a custom Firefox Profile that I have created and checked into subversion. There are instructions how to do this &lt;a href="http://seleniumhq.org/docs/05_selenium_rc.html#specifying-the-firefox-profile"&gt;here&lt;/a&gt;. Inside this profile I have told Firefox to trust the certificate, and remember that to "permanently store this exception".&lt;br /&gt;
 &lt;br /&gt;
I found that the "Permanently store this exception" box was greyed out when I first tried this. This was as a result of previously configuring firefox not to save any history. The solution for this problem is this:&lt;br /&gt;
 &lt;br /&gt;
1. Enable History&lt;br /&gt;
2. Permanently store the exception (The box is not greyed out now)&lt;br /&gt;
3. Disable History&lt;br /&gt;
 &lt;br /&gt;
I only needed to do this once - Firefox seems to remember the certificate exception even though I set it to not remember History afterwards.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-6677613167214553051?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/j2zBynYdKTM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/6677613167214553051/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=6677613167214553051" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6677613167214553051?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6677613167214553051?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/08/selenium-and-untrusted-ssl-certificates.html" title="Selenium and untrusted SSL Certificates" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEQHQH09fSp7ImA9Wx5TGEQ.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-2283913668424863869</id><published>2010-07-08T15:57:00.001+10:00</published><updated>2010-08-04T14:32:11.365+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-04T14:32:11.365+10:00</app:edited><title>How to process all the sql files in a directory using ant and sqlplus</title><content type="html">This is useful if you have a build process where you would like to run a bunch of Oracle sql scripts in a directory as part of your build.&lt;br /&gt;
&lt;br /&gt;
In my current project, developers add their schema update scripts to a certain directory each sprint. This ant target will pick up all the scripts in the directory and apply them to the local schema so you (and the continuously integrated build) are always up to date.&lt;br /&gt;
&lt;br /&gt;
It requires the ant-contrib plugin.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    &amp;lt;target name=&amp;quot;developer.scripts.run.all&amp;quot; depends=&amp;quot;db.init&amp;quot;&amp;gt;
        &amp;lt;foreach target=&amp;quot;developer.script.run.single&amp;quot; param=&amp;quot;sqlFile&amp;quot;&amp;gt;
            &amp;lt;fileset dir=&amp;quot;../data/patches/${db.patches.directory}&amp;quot; casesensitive=&amp;quot;no&amp;quot;/&amp;gt;
        &amp;lt;/foreach&amp;gt;
    &amp;lt;/target&amp;gt;
 
    &amp;lt;target name=&amp;quot;developer.script.run.single&amp;quot; depends=&amp;quot;db.init&amp;quot;&amp;gt;
        &amp;lt;exec resolveexecutable=&amp;quot;yes&amp;quot; executable=&amp;quot;sqlplus&amp;quot; failonerror=&amp;quot;true&amp;quot;&amp;gt;
            &amp;lt;arg line=&amp;quot;-s ${db.userid}/${db.password}@${db.database} @${sqlFile}&amp;quot;/&amp;gt;
        &amp;lt;/exec&amp;gt;
    &amp;lt;/target&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br&gt;&lt;br /&gt;
&lt;b&gt;UPDATE 4/8/10 :&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;
&lt;br /&gt;
The code snippet above processes the files in random order. To process the files in alphabetical order, wrap it using sort and path like so:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    &amp;lt;target name=&amp;quot;developer.scripts.run.all&amp;quot; depends=&amp;quot;db.init&amp;quot;&amp;gt;
        &amp;lt;foreach target=&amp;quot;developer.script.run.single&amp;quot; param=&amp;quot;sqlFile&amp;quot;&amp;gt;
            &amp;lt;path&amp;gt;
                &amp;lt;sort&amp;gt;
                    &amp;lt;fileset dir=&amp;quot;../data/patches/${db.patches.directory}&amp;quot; casesensitive=&amp;quot;no&amp;quot;/&amp;gt;
                &amp;lt;/sort&amp;gt;
            &amp;lt;/path&amp;gt;
        &amp;lt;/foreach&amp;gt;
    &amp;lt;/target&amp;gt;
 
    &amp;lt;target name=&amp;quot;developer.script.run.single&amp;quot; depends=&amp;quot;db.init&amp;quot;&amp;gt;
        &amp;lt;exec resolveexecutable=&amp;quot;yes&amp;quot; executable=&amp;quot;sqlplus&amp;quot; failonerror=&amp;quot;true&amp;quot;&amp;gt;
            &amp;lt;arg line=&amp;quot;-s ${db.userid}/${db.password}@${db.database} @${sqlFile}&amp;quot;/&amp;gt;
        &amp;lt;/exec&amp;gt;
    &amp;lt;/target&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-2283913668424863869?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/f3PKMaLqGA0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/2283913668424863869/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=2283913668424863869" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/2283913668424863869?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/2283913668424863869?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/07/how-to-process-all-sql-files-in.html" title="How to process all the sql files in a directory using ant and sqlplus" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CE4HRnY6cCp7ImA9WxFXE04.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-8341054927415660914</id><published>2010-05-20T15:22:00.000+10:00</published><updated>2010-05-20T15:22:17.818+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-20T15:22:17.818+10:00</app:edited><title>Find a person in a group with an LDAP Filter</title><content type="html">I've never before had the joy of trying to authenticate a Java app with LDAP. It turns out you can do all sorts of tricks with an LDAP filter - which is just like a weird query language.&lt;br /&gt;
 &lt;br /&gt;
Most of it made sense to me, but filtering users that belong to a certain group was a little tricky.&lt;br /&gt;
&lt;br /&gt;
Here is a filter that will locate a user that belongs to a specific LDAP Group:&lt;br /&gt;
 &lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;(&amp;amp;(objectClass=user)(sAMAccountName=%u)(memberOf=CN=GROUP_NAME,OU=Security Groups,DC=desqld,DC=internal))
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-8341054927415660914?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/ZiNlGAVojho" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/8341054927415660914/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=8341054927415660914" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8341054927415660914?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8341054927415660914?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/05/find-person-in-group-with-ldap-filter.html" title="Find a person in a group with an LDAP Filter" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CEUBQ3w8fyp7ImA9WxFQEkw.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-2013235977898384098</id><published>2010-05-07T16:04:00.000+10:00</published><updated>2010-05-07T16:04:12.277+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-07T16:04:12.277+10:00</app:edited><title>Using Active Directory for Authentication on a Spring App</title><content type="html">When attempting to connect to a trusted LDAP Server using Spring, you may be confronted with an error like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;org.springframework.ldap.CommunicationException: simple bind failed: SERVERNAME:636; nested exception is javax.naming.CommunicationException: simple bind failed: SERVERNAME:636 [Root exception is javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
The error is fairly difficult to understand, but &amp;nbsp;it does give some clues. Basically, it means that the LDAP Server does not have a server certificate that has been issued by a trusted Certification Authority (e.g. Verisign).&lt;br /&gt;
&lt;br /&gt;
This is fairly typical, as usually organisations will use self signed certificates for their internal servers.&lt;br /&gt;
&lt;br /&gt;
The situation is actually similar to what you would see in a browser when you try to go to a site with an unrecognised SSL certificate. However it will usually give you an option like "I know the risks - just let me in anyway". And that is exactly what we want to do here.&lt;br /&gt;
&lt;br /&gt;
You can import the remote server certificate into your local certificate store by running the following code:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;/*
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;quot;AS
 * IS&amp;quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import static java.io.File.separatorChar;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class InstallLDAPCert {
    private static final int DEFAUL_LDAP_SSL_PORT = 636;

    public static void main(String[] args) throws Exception {
        String host;
        int port;
        char[] passphrase;
        if (args.length == 1 &amp;#124;&amp;#124; args.length == 2) {
            String[] c = args[0].split(&amp;quot;:&amp;quot;);
            host = c[0];
            port = c.length == 1 ? DEFAUL_LDAP_SSL_PORT : Integer.parseInt(c[1]);
            String p = args.length == 1 ? &amp;quot;changeit&amp;quot; : args[1];
            passphrase = p.toCharArray();
        } else {
            System.out.println(&amp;quot;Usage: java InstallLDAPCert &amp;lt;host&amp;gt;[:port] [passphrase]&amp;quot;);
            return;
        }

        File dir = new File(System.getProperty(&amp;quot;java.home&amp;quot;) + separatorChar + &amp;quot;lib&amp;quot; + separatorChar + &amp;quot;security&amp;quot;);

        File file = new File(dir, &amp;quot;cacerts&amp;quot;);

        System.out.println(&amp;quot;Loading KeyStore &amp;quot; + file + &amp;quot;...&amp;quot;);
        InputStream in = new FileInputStream(file);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(in, passphrase);
        in.close();

        SSLContext context = SSLContext.getInstance(&amp;quot;TLS&amp;quot;);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
        SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
        context.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory factory = context.getSocketFactory();

        System.out.println(&amp;quot;Opening connection to &amp;quot; + host + &amp;quot;:&amp;quot; + port + &amp;quot;...&amp;quot;);
        SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
        socket.setSoTimeout(10000);
        try {
            System.out.println(&amp;quot;Starting SSL handshake...&amp;quot;);
            socket.startHandshake();
            socket.close();
            System.out.println();
            System.out.println(&amp;quot;No errors, certificate is already trusted&amp;quot;);
        } catch (SSLException e) {
            System.out.println();
            e.printStackTrace(System.out);
        }

        X509Certificate[] chain = tm.chain;
        if (chain == null) {
            System.out.println(&amp;quot;Could not obtain server certificate chain&amp;quot;);
            return;
        }

        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        System.out.println();
        System.out.println(&amp;quot;Server sent &amp;quot; + chain.length + &amp;quot; certificate(s):&amp;quot;);
        System.out.println();
        MessageDigest sha1 = MessageDigest.getInstance(&amp;quot;SHA1&amp;quot;);
        MessageDigest md5 = MessageDigest.getInstance(&amp;quot;MD5&amp;quot;);
        for (int i = 0; i &amp;lt; chain.length; i++) {
            X509Certificate cert = chain[i];
            System.out.println(&amp;quot; &amp;quot; + (i + 1) + &amp;quot; Subject &amp;quot; + cert.getSubjectDN());
            System.out.println(&amp;quot;   Issuer  &amp;quot; + cert.getIssuerDN());
            sha1.update(cert.getEncoded());
            System.out.println(&amp;quot;   sha1    &amp;quot; + toHexString(sha1.digest()));
            md5.update(cert.getEncoded());
            System.out.println(&amp;quot;   md5     &amp;quot; + toHexString(md5.digest()));
            System.out.println();
        }

        System.out.println(&amp;quot;Enter certificate to add to trusted keystore or 'q' to quit: [1]&amp;quot;);
        String line = reader.readLine().trim();
        int k;
        try {
            k = line.length() == 0 ? 0 : Integer.parseInt(line) - 1;
        } catch (NumberFormatException e) {
            System.out.println(&amp;quot;KeyStore not changed&amp;quot;);
            return;
        }

        X509Certificate cert = chain[k];
        String alias = host + &amp;quot;-&amp;quot; + (k + 1);
        ks.setCertificateEntry(alias, cert);

        OutputStream out = new FileOutputStream(file);
        ks.store(out, passphrase);
        out.close();

        System.out.println();
        System.out.println(cert);
        System.out.println();
        System.out.println(&amp;quot;Added certificate to keystore &amp;quot; + file.getAbsoluteFile() + &amp;quot; using alias '&amp;quot; + alias + &amp;quot;'&amp;quot;);
    }

    private static final char[] HEXDIGITS = &amp;quot;0123456789abcdef&amp;quot;.toCharArray();

    private static String toHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 3);
        for (int b : bytes) {
            b &amp;amp;= 0xff;
            sb.append(HEXDIGITS[b &amp;gt;&amp;gt; 4]);
            sb.append(HEXDIGITS[b &amp;amp; 15]);
            sb.append(' ');
        }
        return sb.toString();
    }

    private static class SavingTrustManager implements X509TrustManager {

        private final X509TrustManager tm;
        private X509Certificate[] chain;

        SavingTrustManager(X509TrustManager tm) {
            this.tm = tm;
        }

        public X509Certificate[] getAcceptedIssuers() {
            throw new UnsupportedOperationException();
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            throw new UnsupportedOperationException();
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            this.chain = chain;
            tm.checkServerTrusted(chain, authType);
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-2013235977898384098?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/5aS4gjT5iQ8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/2013235977898384098/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=2013235977898384098" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/2013235977898384098?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/2013235977898384098?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/05/using-active-directory-for.html" title="Using Active Directory for Authentication on a Spring App" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;CkUNQ3syeSp7ImA9WxFTF0w.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-8941371649430415954</id><published>2010-04-08T17:04:00.000+10:00</published><updated>2010-04-08T17:04:52.591+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-08T17:04:52.591+10:00</app:edited><title>Lazy loading under a Spring OpenSessionInViewFilter without a Transaction</title><content type="html">You can't do it.&lt;br /&gt;
&lt;br /&gt;
Yeah I know it's a pretty dry and boring topic, but this needs to be said.&lt;br /&gt;
&lt;br /&gt;
If you are using an OpenSessionInViewFilter*, then you must use transactions for all data access, even just for readonly access.&lt;br /&gt;
&lt;br /&gt;
They don't make it super clear in the javadoc, but OpenSessionInViewFilter REQUIRES, DEMANDS and EXPECTS all data access to be wrapped in a&amp;nbsp;transaction. If you are getting LazyLoadExceptions and don't know why, then make sure your data access is transactional.&lt;br /&gt;
&lt;br /&gt;
Of course, the transaction can be finished before you try to do the lazy loading; OpenSessionInViewFilter just expects that a transaction&amp;nbsp;happened at some prior point in the request.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: small;"&gt;* and expect to be able to lazily load your data, which is pretty much the point of OSIV&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-8941371649430415954?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/ePQaa5QoOXM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/8941371649430415954/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=8941371649430415954" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8941371649430415954?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8941371649430415954?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/04/lazy-loading-under-spring.html" title="Lazy loading under a Spring OpenSessionInViewFilter without a Transaction" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;AkABQn85eip7ImA9WxBbEEU.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-8156954611734067698</id><published>2010-03-09T08:44:00.004+10:00</published><updated>2010-03-09T08:52:33.122+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-09T08:52:33.122+10:00</app:edited><title>Dr Strangecode, Or: How I Learned to Stop Worrying and Love the Legacy</title><content type="html">&lt;div&gt;Someone recently asked me what technologies I would recommend for the next Enterprise Web Project.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Like a good little software developer, my initial reaction was "I would have to see the requirements first".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And of course that is true. As much as possible I try to fight the tendency to fit requirements around the technology, because I know that I am wont to be enamoured by the latest shiny thing in the software world.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But even though I have no idea what my next job will be, I already know what it is. It will be another Java/Spring/Hibernate enterprise web application for a government department or medium sized corporation, probably replacing one or more existing systems. That is what people want, and that is what I am good at doing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The software nerd in me is repulsed by these things. I would love nothing more than to write my next enterprise web app in Javascript with a NoSQL database and write server side web services in a pure Functional language, which I feel can more directly solve the enterprise problems I have been confronted with in my career so far. But the corporate world is simply not politically or culturally ready for it. I can accept and respect that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So let's get on with the business of writing good Java Web Apps. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Something I have come to observe is that ALL code is legacy code. The moment somebody else looks at it, it is legacy code. Right now, somebody is probably working with my lovingly handcrafted feats of software engineering (in my mind) and thinking "Man, what was this guy on? grumble grumble legacy code..."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So my reasoning goes like this: I love my own code; all of my code is legacy code; therefore I love legacy code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How can I make the legacy code that I write as painless as possible for the next guy? Here are some of my favourite techniques:&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Covert Code Reviews&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Management hates pair programming, but every couple of days just give the guy sitting next to you a 5-10 minute tour of the code you have written. You'll have to swallow your pride the first few times, but it will promote consistency in the codebase, which is the single most important attribute of good legacy code.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Automated Code Test Coverage Tools&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Set a minimum test coverage percentage that will fail your automated build tool when it dips below that value. This will at the very least promote dialogue (probably heated) between developers.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Style Checking Tools&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Like the Test Coverage tools, a set of checkstyle rules that fail the automated build will go a long way towards keeping the codebase consistent.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Frameworks and Code Generation Tools&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Yeah I know we love to hate frameworks. But for all the pain they cause us, at least it forces us to write code in defined and consistent way. One shiny thing that I have in mind is Spring Roo, which I really would like to try on a future project.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Get an end-to-end build process&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Ideally something that runs nightly, deploys the application to your real application server and runs all of your tests.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Don't live with &lt;a href="http://www.artima.com/intv/fixit2.html"&gt;broken windows&lt;/a&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;TestNG for example (I'm not picking on TestNG in particular) allows you to create a test annotation called "broken", which permits the build to ignore tests that are temporarily broken for some reason. DO NOT USE THIS TAG! One broken test will quickly become two, then ten then fifty. Soon it becomes normal practice for developers to mark tests as broken, and the malaise sets in.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Use a decent IDE, get 2 monitors, work on a powerful machine&lt;/b&gt;&lt;/div&gt;&lt;div&gt;These are essential tools for writing good legacy code. Also, IntelliJ &gt; Eclipse (what good is an opinion piece without some controversy?)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-8156954611734067698?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/L_ZRQuBzrhA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/8156954611734067698/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=8156954611734067698" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8156954611734067698?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8156954611734067698?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/03/dr-strangecode-or-how-i-learned-to-stop.html" title="Dr Strangecode, Or: How I Learned to Stop Worrying and Love the Legacy" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;AkcMRngyeSp7ImA9WxBUFUo.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-6707162396457749381</id><published>2010-03-03T10:57:00.002+10:00</published><updated>2010-03-03T11:01:27.691+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-03T11:01:27.691+10:00</app:edited><title>Your data plan costs $1.6 million per GB</title><content type="html">If I was to offer you a data plan that cost the low, low price of $1.6 million per Gigabyte, would you take me up on it?&lt;br /&gt;&lt;br /&gt;No?&lt;br /&gt;&lt;br /&gt;How about if I offered you the same service, but this time it only costs 22 cents per 160 Bytes?&lt;br /&gt;&lt;br /&gt;As you have no doubt figured out, it is the same pricing, and this is what we are being charged for SMS.&lt;br /&gt;&lt;br /&gt;SMS is great, but it costs too much. I think with Twitter and mobile push technology, we can finally abandon SMS. A twitter client on your smartphone with push enabled is a complete replacement for SMS, and has the exact same "feel" as SMS on your phone too.&lt;br /&gt;&lt;br /&gt;If you already have a data connection on your phone, and your family/friends have (or can get) a twitter account, there is no downside to this system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-6707162396457749381?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/mTuKWMssYmc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/6707162396457749381/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=6707162396457749381" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6707162396457749381?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6707162396457749381?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/03/your-data-plan-costs-16-million-per-gb.html" title="Your data plan costs $1.6 million per GB" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;A0QGRnszfip7ImA9WxBVGUg.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-7885907074651267647</id><published>2010-02-23T17:20:00.005+10:00</published><updated>2010-02-24T07:08:47.586+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-24T07:08:47.586+10:00</app:edited><title>An almost overwhelming uneasiness</title><content type="html">Have you ever had this feeling when coding?&lt;br /&gt;&lt;br /&gt;Maybe there's a better name for it than "almost overwhelming uneasiness", but it has happened twice to me in the past week. It only lasts for a split second but the feeling is very distinct.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The first time&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I tried to do a Google Search and got an error page. Then I glanced down at my phone and saw that my 3G data connection had dropped out.&lt;br /&gt;&lt;br /&gt;In that split second, these thoughts went through my head:&lt;br /&gt;&lt;br /&gt;"Oh no, it has finally happened - some hacker has finally unleashed the ultimate virus on the internet. It has destroyed the DNS system or some vital part of infrastructure that no-one thought about and the entire internet is broken. What am I gonna do - I'll lose my job as a programmer, I've got no other marketable skills - I've been programming ever since I left Uni - how am I gonna feed my family..."&lt;br /&gt;&lt;br /&gt;Then I ran the search again and it turned out the internet was fine.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The second time&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The second time was when I was working on a Java codebase and came across this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;t1 = t2;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Again that same "almost overwhelming uneasiness", only for a split second:&lt;br /&gt;&lt;br /&gt;"t1 = t2? What on earth does that mean? I don't understand what's going on here... I'm looking at the code above it and below it and getting more confused - how can you assign a...? I don't understand it, am I not as good a programmer as I thought?"&lt;br /&gt;&lt;br /&gt;Then I remembered that yes, it is possible to re-assign a local variable in Java. I guess I've been hanging around these &lt;a href="http://www.meetup.com/Brisbane-Functional-Programming-Group-BFG/"&gt;Functional Programming nutcases&lt;/a&gt; for so long and my programming style has become so functional that for a split second I had forgotten that variables are mutable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-7885907074651267647?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/yaiiRUNL73M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/7885907074651267647/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=7885907074651267647" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/7885907074651267647?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/7885907074651267647?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/02/almost-overwhelming-uneasiness.html" title="An almost overwhelming uneasiness" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUQGSX84eyp7ImA9WxBWFkQ.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-978953615110627005</id><published>2010-02-09T14:52:00.003+10:00</published><updated>2010-02-09T15:28:48.133+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-09T15:28:48.133+10:00</app:edited><title>How to force HTTPS on the login page with Spring Authentication and a soy bean musing</title><content type="html">&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;The Easy Way&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Just use the Spring &lt;a href="http://static.springsource.org/spring-security/site/docs/2.0.x/reference/ns-config.html"&gt;Security Namespace&lt;/a&gt;. It makes security configuration so easy that it's not worth me writing anything further about it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The Hard Way&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Ok, so like me you are working in a huge enterprise or government department somewhere, and they think they can do security better than Spring.&lt;br /&gt;&lt;br /&gt;For whatever reason, if you need to configure this stuff explicitly by wiring up your own beans, here's what you'll need to do:&lt;br /&gt;&lt;br /&gt;You probably have something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;bean id=&amp;quot;security.local.AuthenticationEntryPoint&amp;quot; class=&amp;quot;org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;loginFormUrl&amp;quot; value=&amp;quot;/public/login.html&amp;quot;/&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;forceHttps&amp;quot; value=&amp;quot;false&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You need to change it to this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;bean id="security.local.AuthenticationEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint"&amp;gt;&lt;br /&gt;   &amp;lt;property name="loginFormUrl" value="/public/login.html"/&amp;gt;&lt;br /&gt;   &amp;lt;property name="forceHttps" value="true"/&amp;gt;&lt;br /&gt;   &amp;lt;property name="serverSideRedirect" value="false"/&amp;gt;&lt;br /&gt;   &amp;lt;property name="portMapper" ref="portMapperImpl"/&amp;gt;&lt;br /&gt;   &amp;lt;property name="portResolver" ref="portResolverImpl"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt; &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then you need to define portMapperImpl and portResolverImpl like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;bean id=&amp;quot;portResolverImpl&amp;quot; class=&amp;quot;org.springframework.security.util.PortResolverImpl&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;portMapper&amp;quot; ref=&amp;quot;portMapperImpl&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;bean id=&amp;quot;portMapperImpl&amp;quot; class=&amp;quot;org.springframework.security.util.PortMapperImpl&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;portMappings&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;map&amp;gt;&lt;br /&gt;            &amp;lt;!--Mappings for all servers can be listed here - Spring just wants to know how which HTTPS port belongs to each HTTP port --&amp;gt;&lt;br /&gt;            &amp;lt;entry key=&amp;quot;8080&amp;quot; value=&amp;quot;8443&amp;quot;/&amp;gt;&lt;br /&gt;            &amp;lt;entry key=&amp;quot;80&amp;quot; value=&amp;quot;443&amp;quot;/&amp;gt;&lt;br /&gt;            &amp;lt;!--SysTest--&amp;gt;&lt;br /&gt;            &amp;lt;entry key=&amp;quot;7001&amp;quot; value=&amp;quot;7002&amp;quot;/&amp;gt;&lt;br /&gt;            &amp;lt;!--Prod--&amp;gt;&lt;br /&gt;            &amp;lt;entry key=&amp;quot;8001&amp;quot; value=&amp;quot;8002&amp;quot;/&amp;gt;&lt;br /&gt;            &amp;lt;!--Sandpit--&amp;gt;&lt;br /&gt;            &amp;lt;entry key=&amp;quot;8051&amp;quot; value=&amp;quot;8052&amp;quot;/&amp;gt;&lt;br /&gt;        &amp;lt;/map&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And then the configuration that forces the login page to be SSL:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;bean id=&amp;quot;channelProcessingFilter&amp;quot; class=&amp;quot;org.springframework.security.securechannel.ChannelProcessingFilter&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;channelDecisionManager&amp;quot; ref=&amp;quot;channelDecisionManager&amp;quot;/&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;filterInvocationDefinitionSource&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;security:filter-invocation-definition-source path-type=&amp;quot;ant&amp;quot;&amp;gt;&lt;br /&gt;            &amp;lt;!--You can configure further rules here about which pages should use SSL.--&amp;gt;&lt;br /&gt;            &amp;lt;security:intercept-url pattern=&amp;quot;/public/login.html&amp;quot; access=&amp;quot;REQUIRES_SECURE_CHANNEL&amp;quot;/&amp;gt;&lt;br /&gt;        &amp;lt;/security:filter-invocation-definition-source&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;bean id=&amp;quot;channelDecisionManager&amp;quot; class=&amp;quot;org.springframework.security.securechannel.ChannelDecisionManagerImpl&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;channelProcessors&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;list&amp;gt;&lt;br /&gt;            &amp;lt;ref bean=&amp;quot;secureChannelProcessor&amp;quot;/&amp;gt;&lt;br /&gt;            &amp;lt;ref bean=&amp;quot;insecureChannelProcessor&amp;quot;/&amp;gt;&lt;br /&gt;        &amp;lt;/list&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;bean id=&amp;quot;secureChannelProcessor&amp;quot; class=&amp;quot;org.springframework.security.securechannel.SecureChannelProcessor&amp;quot;/&amp;gt;&lt;br /&gt;&amp;lt;bean id=&amp;quot;insecureChannelProcessor&amp;quot; class=&amp;quot;org.springframework.security.securechannel.InsecureChannelProcessor&amp;quot;/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've just realized that tofu is over-rated. It's just a curd to me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-978953615110627005?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/s5byqTeqPc0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/978953615110627005/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=978953615110627005" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/978953615110627005?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/978953615110627005?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/02/how-to-force-https-on-login-page-with.html" title="How to force HTTPS on the login page with Spring Authentication and a soy bean musing" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0cAQX0_eyp7ImA9WxBWEkg.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-7200943434834798461</id><published>2010-02-04T12:16:00.003+10:00</published><updated>2010-02-04T12:37:20.343+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-04T12:37:20.343+10:00</app:edited><title>2010 is the year developers take back the database?</title><content type="html">It's difficult for any web developer not to be excited by the prospect of developing with a &lt;a href="http://en.wikipedia.org/wiki/NoSQL"&gt;NoSQL&lt;/a&gt; database.&lt;br /&gt;&lt;br /&gt;What is even more amazing is that in the space of just a few months, three separate startups with three separate (competing?) NoSQL database products have been gaining significant traction with investor funding.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.techcrunch.com/2009/12/10/stealth-startup-relaxed-raises-2-million-from-redpoint-ventures-for-couchdb-support/"&gt;Relaxed Inc raises 2 Million&lt;/a&gt; (&lt;a href="http://apache.couchdb.org"&gt;CouchDB &lt;/a&gt;Database)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.masshightech.com/stories/2010/02/01/daily27-MHT-Exclusive-Basho-maps-unstructured-road-to-web-scalability.html"&gt;Basho raises 4.7 million&lt;/a&gt; (&lt;a href="http://riak.basho.com"&gt;Riak&lt;/a&gt; Database)&lt;br /&gt;&lt;br /&gt;&lt;a href=" http://deals.venturebeat.com/2009/11/02/open-source-database-company-10gen-raises-3-4m/"&gt;10gen raises 3.4 million&lt;/a&gt; (&lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt; Database)&lt;br /&gt;&lt;br /&gt;Exciting times!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-7200943434834798461?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/fkN-oPdUqKg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/7200943434834798461/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=7200943434834798461" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/7200943434834798461?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/7200943434834798461?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/02/2010-is-year-developers-take-back.html" title="2010 is the year developers take back the database?" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEUNSHY-fip7ImA9WxBWEUk.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-6710860977782861461</id><published>2010-02-01T16:35:00.017+10:00</published><updated>2010-02-03T07:31:39.856+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-03T07:31:39.856+10:00</app:edited><title>Enterprise Web Application Architecture 2.0 and kittens</title><content type="html">According to its homepage, &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; is a &lt;span style="font-style: italic;"&gt;distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;That is a boring bunch of words. Here is why it is interesting.&lt;br /&gt;&lt;br /&gt;Typical enterprise web-application architectures that I've worked on in the past look something like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_H9tXH4aTj8g/S2iRPP4rMSI/AAAAAAAAAIY/sgfWY1gQx4Q/s1600-h/step_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 324px; height: 400px;" src="http://2.bp.blogspot.com/_H9tXH4aTj8g/S2iRPP4rMSI/AAAAAAAAAIY/sgfWY1gQx4Q/s400/step_1.png" alt="" id="BLOGGER_PHOTO_ID_5433752641570812194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The grey boxes represent the data format used between each layer. As you can see, the data gets transformed many times in a typical web request from Database to Browser.&lt;br /&gt;&lt;br /&gt;Ok now let's have some fun.&lt;br /&gt;&lt;br /&gt;Imagine that our database was clever enough to do all of our form validation and authentication for us. Our diagram would change to look like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_H9tXH4aTj8g/S2iRZHZUG7I/AAAAAAAAAIg/QooEFDHhK50/s1600-h/step_2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 232px; height: 400px;" src="http://3.bp.blogspot.com/_H9tXH4aTj8g/S2iRZHZUG7I/AAAAAAAAAIg/QooEFDHhK50/s400/step_2.png" alt="" id="BLOGGER_PHOTO_ID_5433752811090484146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And what about if we split up the application layer - we can put all of our business validation logic in database, and push any other leftover application logic into the presentation layer.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_H9tXH4aTj8g/S2iRk4TeIHI/AAAAAAAAAIo/Y1Ho-mdiXgo/s1600-h/step_3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 263px; height: 400px;" src="http://4.bp.blogspot.com/_H9tXH4aTj8g/S2iRk4TeIHI/AAAAAAAAAIo/Y1Ho-mdiXgo/s400/step_3.png" alt="" id="BLOGGER_PHOTO_ID_5433753013197873266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As shown in the diagram, there are typically two methods used to produce HTML, and they are often used together:&lt;br /&gt;&lt;br /&gt;1. Server side view templating - where HTML code is produced on the server and sent directly to the browser (e.g. server side MVC, JSP, Velocity, Freemarker)&lt;br /&gt;&lt;br /&gt;2. AJAX - where only data is sent from the server via an XMLHttpRequest, and Javascript manipulates the DOM directly&lt;br /&gt;&lt;br /&gt;Let's abandon server-side templating, and do all our templating on the client side in Javascript. In fact, let's use Javascript for all our presentation needs:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_H9tXH4aTj8g/S2iRtU5m_9I/AAAAAAAAAIw/9BToYvbD3ZI/s1600-h/step_4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 308px; height: 400px;" src="http://2.bp.blogspot.com/_H9tXH4aTj8g/S2iRtU5m_9I/AAAAAAAAAIw/9BToYvbD3ZI/s400/step_4.png" alt="" id="BLOGGER_PHOTO_ID_5433753158312984530" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then how about we give our Database an HTTP interface, make it speak JSON and store data in JSON format. This will allow us to remove the data access layer and that awful ORM to which we've been shackled for so long.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_H9tXH4aTj8g/S2iR3XU8WRI/AAAAAAAAAI4/ez3rEC1EAqk/s1600-h/step_5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 341px; height: 247px;" src="http://4.bp.blogspot.com/_H9tXH4aTj8g/S2iR3XU8WRI/AAAAAAAAAI4/ez3rEC1EAqk/s400/step_5.png" alt="" id="BLOGGER_PHOTO_ID_5433753330763192594" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What kind of amazing magical database can do all this? Well it turns out that a &lt;a href="http://couchdb.apache.org"&gt;&lt;span style="font-style: italic;"&gt;distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API&lt;/span&gt;&lt;/a&gt; can.&lt;br /&gt;&lt;br /&gt;I'm not claiming any silver bullet here, in fact CouchDB is still relatively immature. But as a potential architecture for a typical Enterprise Web App - it makes you think about whether we really need all of those grey and blue boxes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you'd like to learn more - download CouchDB, try &lt;a href="http://wiki.github.com/jchris/couchapp/manual"&gt;CouchApp&lt;/a&gt;, and try this &lt;a href="http://github.com/danielalexiuc/CouchApp-User-Authentication-Demo"&gt;demo&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Oh and as promised - here are some kittens:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_H9tXH4aTj8g/S2fRY_l1kjI/AAAAAAAAAIQ/VOFAE3yVIHM/s1600-h/kittens.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 230px;" src="http://2.bp.blogspot.com/_H9tXH4aTj8g/S2fRY_l1kjI/AAAAAAAAAIQ/VOFAE3yVIHM/s320/kittens.jpg" alt="" id="BLOGGER_PHOTO_ID_5433541702762992178" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-6710860977782861461?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/q4CbmvjPN8M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/6710860977782861461/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=6710860977782861461" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6710860977782861461?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6710860977782861461?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/02/enterprise-web-application-architecture.html" title="Enterprise Web Application Architecture 2.0 and kittens" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_H9tXH4aTj8g/S2iRPP4rMSI/AAAAAAAAAIY/sgfWY1gQx4Q/s72-c/step_1.png" height="72" width="72" /><thr:total>6</thr:total></entry><entry gd:etag="W/&quot;CU4EQX8zeyp7ImA9WxBQGEo.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-6330107690380254438</id><published>2010-01-19T14:05:00.000+10:00</published><updated>2010-01-19T14:05:00.183+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-19T14:05:00.183+10:00</app:edited><title>GitHub for Windows (L)users</title><content type="html">GitHub is so hot right now, but if you are a windows user, you'll probably feel like a second class citizen amongst all the cool mac/linux people.&lt;br /&gt;&lt;br /&gt;Here's a quick guide on how to get started with your own github repository, if you have been getting errors like these:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;Permission Denied (publickey)&lt;br /&gt;fatal: The remote end hung up unexpectedly&lt;br /&gt;Could not create directory '//.ssh'.&lt;br /&gt;Saving the key failed: //.ssh/id_rsa.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. Install &lt;a href="http://code.google.com/p/msysgit/downloads/list"&gt;mSysGit&lt;/a&gt; Full Installer&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Make sure to select "Use Unix Style Line Endings" instead of the default "Use DOS style line endings".&lt;/li&gt;&lt;li&gt;Also choose the option that allows you to run git commands from the windows command prompt.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. Generate ssh public key&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Run "Git GUI" from the start menu&lt;/li&gt;&lt;li&gt;Help -&gt; Show SSL Key -&gt; Generate Key&lt;/li&gt;&lt;li&gt;Accept all the defaults when generating a key&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. Add the key to your GitHub account&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Account Settings -&gt; Add another public key&lt;/li&gt;&lt;li&gt;Paste the key that msysGit generated into here&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;That should be it - you can now clone your own github repository. Use your favourite IDE that has Git support and you'll be cruising.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-6330107690380254438?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/Q1kvwEl3WhQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/6330107690380254438/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=6330107690380254438" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6330107690380254438?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/6330107690380254438?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2010/01/github-for-windows-lusers.html" title="GitHub for Windows (L)users" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CEIDR345fCp7ImA9WxBRGE4.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-2461898739692051980</id><published>2009-12-15T09:03:00.005+10:00</published><updated>2010-01-07T12:49:36.024+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-07T12:49:36.024+10:00</app:edited><title>Automated testing of Javascript as part of your build</title><content type="html">Have you got 100% test coverage on your Java code? That is very commendable.&lt;br /&gt;&lt;br /&gt;But perhaps you still get the feeling that there is a lot of functionality in all that front end Javascript you have been writing that really should be tested too?&lt;br /&gt;&lt;br /&gt;Well here's how to setup automated testing of your Javascript functions that runs as part of your build along with all your other unit and integration tests. (It is based on the &lt;a href="http://docs.jquery.com/QUnit"&gt;QUnit&lt;/a&gt; library, which is the best option I have evaluated.)&lt;br /&gt;&lt;br /&gt;The Maven Dependencies you'll need:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;net.sourceforge.htmlunit&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;htmlunit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;2.5&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;org.w3c.css&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;sac&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;1.3&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Create a new JUnit test that will run the Javascript test:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;import com.gargoylesoftware.htmlunit.WebClient;&lt;br /&gt;import com.gargoylesoftware.htmlunit.html.HtmlPage;&lt;br /&gt;import junit.framework.TestCase;&lt;br /&gt;&lt;br /&gt;import java.io.File;&lt;br /&gt;&lt;br /&gt;public class MyJavascriptUnitTest extends TestCase {&lt;br /&gt;    private static final String JAVASCRIPT_TESTS_HTML = new File(&amp;quot;src/test/javascript/assert/javascriptTests.html&amp;quot;).getAbsolutePath();&lt;br /&gt;&lt;br /&gt;    public void testJavascriptTestResults() throws Exception {&lt;br /&gt;        final WebClient webClient = new WebClient();&lt;br /&gt;        final HtmlPage page = webClient.getPage(&amp;quot;file://&amp;quot; + JAVASCRIPT_TESTS_HTML);&lt;br /&gt;        assertEquals(&amp;quot;pass&amp;quot;, page.getElementById(&amp;quot;banner&amp;quot;).getAttribute(&amp;quot;class&amp;quot;));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's what javascriptTests.html looks like:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;script src=&amp;quot;jquery-latest.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;link media=&amp;quot;screen&amp;quot; href=&amp;quot;testsuite.css&amp;quot; type=&amp;quot;text/css&amp;quot; rel=&amp;quot;stylesheet&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;script src=&amp;quot;testrunner.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;../../../main/webapp/javascripts/fileUnderTest.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;script&amp;gt;&lt;br /&gt;&lt;br /&gt;        $(document).ready(function() {&lt;br /&gt;            //  **** Add tests here ****&lt;br /&gt;            module(&amp;quot;Currency Formatting&amp;quot;);&lt;br /&gt;&lt;br /&gt;            test(&amp;quot;formatCurrency&amp;quot;, function() {&lt;br /&gt;                equals(formatCurrency(&amp;quot;1&amp;quot;), &amp;quot;$1&amp;quot;);&lt;br /&gt;                equals(formatCurrency(&amp;quot;123&amp;quot;), &amp;quot;$123&amp;quot;);&lt;br /&gt;            });&lt;br /&gt;&lt;br /&gt;        });&lt;br /&gt;&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;h1&amp;gt;JavaScript Tests&amp;lt;/h1&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;h2 id=&amp;quot;banner&amp;quot;&amp;gt;&amp;lt;/h2&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;h2 id=&amp;quot;userAgent&amp;quot;&amp;gt;&amp;lt;/h2&amp;gt;&lt;br /&gt;&amp;lt;ol id=&amp;quot;tests&amp;quot;&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;main&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this example, &lt;span style="font-weight:bold;"&gt;fileUnderTest.js&lt;/span&gt; is your file that you want to test, in this case it contains a function called &lt;span style="font-weight:bold;"&gt;formatCurrency()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;module()&lt;/span&gt; is just a way to group related javascript tests for reporting purposes.&lt;br /&gt;&lt;br /&gt;If you have IntelliJ, you can use &lt;span style="font-weight:bold;"&gt;WebPreview&lt;/span&gt; to open javascriptTests.html - and get instant feedback! And I mean instant - no reloading of anything needs to happen, just modify your Javascript and the WebPreview will instantly show you if it passes or fails.&lt;br /&gt;&lt;br /&gt;Listed below are the other files referred to, for your convenience. You don't need to use these exact files, but it will help get you started:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://alexiuc.com/testsuite.css"&gt;testsuite.css&lt;/a&gt;&lt;br /&gt;&lt;a href="http://alexiuc.com/testrunner.js"&gt;testrunner.js&lt;/a&gt;&lt;br /&gt;&lt;a href="http://alexiuc.com/jquery-latest.js"&gt;jquery-latest.js&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-2461898739692051980?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/7TPPiw74Q_Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/2461898739692051980/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=2461898739692051980" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/2461898739692051980?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/2461898739692051980?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2009/12/automated-testing-of-javascript-as-part.html" title="Automated testing of Javascript as part of your build" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkMHRHk6eip7ImA9WxBTF0k.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-8701511140867599499</id><published>2009-12-14T08:31:00.005+10:00</published><updated>2009-12-14T09:53:55.712+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T09:53:55.712+10:00</app:edited><title>Project estimates are hilarious...</title><content type="html">Taken from a publicly available &lt;a href="http://www.emergency.qld.gov.au/publications/emergency/2005_aug/pdf/Emergency_Aug_05_p26.pdf"&gt;August 2005 newsletter&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;In early 2005, the QFRS undertook the development and implementation of the Operations Management System (OMS)...&lt;br /&gt;&lt;br /&gt;The implementation of OMS is being staged over three phases with a scheduled completion date of mid 2006.&lt;/blockquote&gt;&lt;br /&gt;Despite being in full active development since that newsletter, OMS is currently scheduled for an initial deployment with a cut-down number of features to a small subset of users in March 2010.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-8701511140867599499?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/po3krxYJaHI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/8701511140867599499/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=8701511140867599499" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8701511140867599499?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/8701511140867599499?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2009/12/project-estimates-are-hilarious.html" title="Project estimates are hilarious..." /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0AMRn0zfyp7ImA9WxBTE0Q.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-4498220436463628231</id><published>2009-12-10T07:50:00.003+10:00</published><updated>2009-12-10T07:56:27.387+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-10T07:56:27.387+10:00</app:edited><title>Toolin' around with web applications (Part 2)</title><content type="html">The site below describes the technique that I think makes more sense than our current crop of server side web frameworks (at least for building a reasonably-sized modern web application):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.thinserverarchitecture.com/"&gt;Thin Server Architecture&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Also google "SOFEA" if this appeals to you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-4498220436463628231?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/g8k_k0ZuY9Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/4498220436463628231/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=4498220436463628231" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/4498220436463628231?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/4498220436463628231?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2009/12/toolin-around-with-web-applications.html" title="Toolin' around with web applications (Part 2)" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;Ck4AQnw6fCp7ImA9WxBTEUg.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-4529152046799843091</id><published>2009-12-07T11:46:00.003+10:00</published><updated>2009-12-07T11:55:43.214+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-07T11:55:43.214+10:00</app:edited><title>Australia Post requires the www?</title><content type="html">It has been like this as long as I can remember:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://post.com.au"&gt;post.com.au&lt;/a&gt; &lt;- doesn't resolve&lt;a href="http://www.post.com.au"&gt;&lt;br /&gt;www.post.com.au&lt;/a&gt; &lt;- resolves&lt;br /&gt;&lt;br /&gt;How could this go unnoticed for so long by such a huge company with such a good (short) domain name?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-4529152046799843091?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/ZAKdERgpa2c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/4529152046799843091/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=4529152046799843091" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/4529152046799843091?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/4529152046799843091?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2009/12/australia-post-requires-www.html" title="Australia Post requires the www?" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;Ak4EQHk_fSp7ImA9WxNaEEQ.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-3169858476876439792</id><published>2009-11-25T06:37:00.004+10:00</published><updated>2009-11-25T07:41:41.745+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-25T07:41:41.745+10:00</app:edited><title>Toolin' around with web applications</title><content type="html">I'm currently on holidays. My job around the house for yesterday was to replace the hinges on the pool fence that had rusted. According to Laurie Lawrence, pool fences should be auto closing - Kids alive do the five!&lt;br /&gt;&lt;br /&gt;Anyway I spent almost two hours on this task over two separate days trying to install the hinges. The problem was, I was trying to use the screws that came with the hinges which were clearly not designed for use with a metal gate. &lt;br /&gt;&lt;br /&gt;My toolkit looked like this:&lt;br /&gt;- Wood screws&lt;br /&gt;- Cordless drill&lt;br /&gt;- Drill bits&lt;br /&gt;- Screwdrivers&lt;br /&gt;&lt;br /&gt;But I still had a lot of trouble getting these darned screws to go in. So instead I tracked down an extension cord and pulled out a corded drill, thinking that the underpowered cordless drill wasn't do me any favours.&lt;br /&gt;&lt;br /&gt;The added power of the corded drill certainly made things faster, but ultimately didn't help me succeed. I would either destroy the threads on the screws or end up drilling a hole that was too big for the screws. &lt;br /&gt;&lt;br /&gt;Finally I got hold of some screws designed for metal, and the whole job was done properly in literally less than five minutes.&lt;br /&gt;&lt;br /&gt;The lesson that was reinforced to me is that using a whole bunch of good tools doesn't come anywhere near the efficiency of choosing the one correct tool for the job.&lt;br /&gt;&lt;br /&gt;I get this feeling when writing web applications too. For a basic Java Enterprise Web App, I typically choose a set of technologies like this:&lt;br /&gt;&lt;br /&gt;- A templating language (e.g. Freemarker, Velocity)&lt;br /&gt;- Javascript&lt;br /&gt;- HTML&lt;br /&gt;- A Javascript framework (e.g. jQuery, Prototype)&lt;br /&gt;- Some sort of Widget Library (e.g. jQueryUI, Scriptaculous)&lt;br /&gt;- CSS&lt;br /&gt;- Spring MVC&lt;br /&gt;&lt;br /&gt;This list is extremely abbreviated of course, as anyone involved with Java Web Development will know. The entire list of technologies is probably triple or quadruple that length.&lt;br /&gt;&lt;br /&gt;But these are the core technologies used to display a web page. What bothers me is that the first FIVE of these end up in one file! I end up using 5 tools to accomplish the single goal of displaying the web page.&lt;br /&gt;&lt;br /&gt;This is incredibly difficult to read and understand, especially considering that the technologies are fundamentally different. Some of the code is evaluated on the server side, and some on the client side, some before the page loads and some after the page loads, and yet the code is all mashed up together. Code generating code that generates code that generates code for multiple browsera to interpret.&lt;br /&gt;&lt;br /&gt;Even though this approach works, it still feels like I'm trying to use woodscrews in a metal gate.&lt;br /&gt;&lt;br /&gt;Server side templating seems like the wrong way to do things. I think we need to focus more on client side development toolkits - RESTful services and some better Javascript and Ajax Tools could completely replace our current web frameworks, but I just don't think the tools exist yet. Maybe the entire MVC model could be pushed down into javascript on the client side. Or maybe we could have some better abstractions or DSLs for browser control beyond HTML and javascript.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-3169858476876439792?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/_hdmNytUuRE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/3169858476876439792/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=3169858476876439792" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/3169858476876439792?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/3169858476876439792?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2009/11/toolin-around-with-web-applications.html" title="Toolin' around with web applications" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0EGSXk_fCp7ImA9WxNbFE8.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-5726643272826465349</id><published>2009-11-17T12:33:00.002+10:00</published><updated>2009-11-17T12:40:28.744+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-17T12:40:28.744+10:00</app:edited><title>Dumb analogies in the news</title><content type="html">This just in:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;IBM has created the world's largest business computing "cloud" capable of holding the equivalent of 250 billion iTunes songs. &lt;br /&gt;...&lt;br /&gt;If that amount of information were in the form of text stuffed into four-drawer file cabinets, there would be enough of them to ring the planet, according to IBM.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Are those analogies really useful? Does IBM really think we are impressed by such a nonsensical comparison?&lt;br /&gt;&lt;br /&gt;I enjoyed &lt;a href="http://www.physorg.com/profile/user/x646d63"&gt;x646d63&lt;/a&gt;'s take on it:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Storage capacity: 250 billion iTunes songs&lt;br /&gt;Computing capacity: 800M Chimp-Mensa Candidates&lt;br /&gt;Physical size of network: 300,000 slightly above average elephant toes&lt;br /&gt;Electric consumption: 3.6M 60Hz gerbil wheels&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-5726643272826465349?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/spBz80IHYcw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/5726643272826465349/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=5726643272826465349" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/5726643272826465349?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/5726643272826465349?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2009/11/dumb-analogies-in-news.html" title="Dumb analogies in the news" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0EESXc_fCp7ImA9WxNUEUk.&quot;"><id>tag:blogger.com,1999:blog-616578738157248728.post-1913550428410819420</id><published>2009-11-02T17:05:00.002+10:00</published><updated>2009-11-02T17:06:48.944+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-02T17:06:48.944+10:00</app:edited><title>It's funny cause it's true</title><content type="html">“The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.”—Joe Armstrong&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/616578738157248728-1913550428410819420?l=justsomejavaguy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JustSomeJavaGuy/~4/jkCWNwg-vXg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://justsomejavaguy.blogspot.com/feeds/1913550428410819420/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=616578738157248728&amp;postID=1913550428410819420" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/1913550428410819420?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/616578738157248728/posts/default/1913550428410819420?v=2" /><link rel="alternate" type="text/html" href="http://justsomejavaguy.blogspot.com/2009/11/its-funny-cause-its-true.html" title="It's funny cause it's true" /><author><name>Daniel Alexiuc</name><uri>http://www.blogger.com/profile/00317061160046734390</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry></feed>

