<?xml version="1.0" encoding="iso-8859-1"?><!-- generator="b2evolution/2.4.5" -->
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Technical Beef -</title>
		<link>http://blog.kornr.net/index.php</link>
		<description></description>
		<language>en-US</language>
		<docs>http://blogs.law.harvard.edu/tech/rss</docs>
		<admin:generatorAgent rdf:resource="http://b2evolution.net/?v=2.4.5"/>
		<ttl>60</ttl>
				<item>
			<title>UpFrost deployed</title>
			<link>http://blog.kornr.net/index.php/2010/04/12/upfrost-deployed</link>
			<pubDate>Mon, 12 Apr 2010 17:44:10 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Misc</category>			<guid isPermaLink="false">49@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;I open-sourced and published today this java persistence library that I've been developing and using for some months now. &lt;br /&gt;
Although I started working on it after switching from hibernate to something lighter for a project where memory footprint was an important constraint, I started using it on most of my projects, and was happy enough with it to share it as open-source.&lt;/p&gt;

&lt;p&gt;The key points of the library are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; JPA-Annotation based. Although it's not JPA at all, it uses a subset of JPA annotations to describe the java/sql mapping. I just hope people won't be misleaded to think this is a JPA library.
&lt;/li&gt;

&lt;li&gt; SQL: I like SQL, I deeply think it's an amazingly powerful query language, and I've always been reluctant to using something else (read: HQL). The point is that I like to test some of my complex queries in my MySQL workbench, and just copy-pasta them in my java project, and that's something really easy to do with plain SQL.
&lt;/li&gt;

&lt;li&gt;No XML. Yurk, I really wanted to avoid using it. I couldn't switch back to iBatis because of it. Now that iBatis 3 has annotations, I guess most of my reluctance should fade away, but I also like the idea of using standard JPA annotations, and have my business objects be compatible with both JPA and UpFrost (provided I stick to the subset).
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's nothing disruptive in this library, but it gathers all the concepts I like, and excludes all the painful stuffs that degrade my productivity (XML, but I also stopped fighting with HQL joins).&lt;/p&gt;

&lt;p&gt;Because I wanted to avoid writing a website, I used the maven &quot;site&quot; feature, and although I wish there were an out-of-the-box support for docbook or some other standard documentation format (rather than this apt thing), the feature is handy to use and flexible enough to let me customize the layout the way I wanted. The maven site:deploy is the killer feature, imho, it deploys the whole site to a remote server with a minimal amount of configuration work.&lt;/p&gt;

&lt;p&gt;Anyway, here's the site: &lt;a href=&quot;http://www.upfrost.org&quot;&gt;http://www.upfrost.org&lt;/a&gt;&lt;/p&gt;</description>
			<content:encoded><![CDATA[<p>I open-sourced and published today this java persistence library that I've been developing and using for some months now. <br />
Although I started working on it after switching from hibernate to something lighter for a project where memory footprint was an important constraint, I started using it on most of my projects, and was happy enough with it to share it as open-source.</p>

<p>The key points of the library are</p>

<ul>
<li> JPA-Annotation based. Although it's not JPA at all, it uses a subset of JPA annotations to describe the java/sql mapping. I just hope people won't be misleaded to think this is a JPA library.
</li>

<li> SQL: I like SQL, I deeply think it's an amazingly powerful query language, and I've always been reluctant to using something else (read: HQL). The point is that I like to test some of my complex queries in my MySQL workbench, and just copy-pasta them in my java project, and that's something really easy to do with plain SQL.
</li>

<li>No XML. Yurk, I really wanted to avoid using it. I couldn't switch back to iBatis because of it. Now that iBatis 3 has annotations, I guess most of my reluctance should fade away, but I also like the idea of using standard JPA annotations, and have my business objects be compatible with both JPA and UpFrost (provided I stick to the subset).
</li>
</ul>

<p>There's nothing disruptive in this library, but it gathers all the concepts I like, and excludes all the painful stuffs that degrade my productivity (XML, but I also stopped fighting with HQL joins).</p>

<p>Because I wanted to avoid writing a website, I used the maven "site" feature, and although I wish there were an out-of-the-box support for docbook or some other standard documentation format (rather than this apt thing), the feature is handy to use and flexible enough to let me customize the layout the way I wanted. The maven site:deploy is the killer feature, imho, it deploys the whole site to a remote server with a minimal amount of configuration work.</p>

<p>Anyway, here's the site: <a href="http://www.upfrost.org">http://www.upfrost.org</a></p>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2010/04/12/upfrost-deployed#comments</comments>
		</item>
				<item>
			<title>Benchmarking Gandi, OVH, Slicehost, and Linode VPS</title>
			<link>http://blog.kornr.net/index.php/2010/01/29/benchmarking-gandi-ovh-slicehost-and-lin</link>
			<pubDate>Fri, 29 Jan 2010 16:24:46 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Misc</category>			<guid isPermaLink="false">48@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;I thought about VPS benchmarking when I was looking for a new server, and found out that Gandi was providing a lot of useful information in their &lt;a href=&quot;http://www.gandi.net/hosting/proposal/benchmark/&quot;&gt;benchmark page&lt;/a&gt;, and they used this &lt;a href=&quot;http://members.cox.net/yikes2000/unixbench-4.1.0-wht.tar.gz&quot;&gt;UnixBench&lt;/a&gt; program to evaluate the processor-equivalence of their shares.&lt;/p&gt;
&lt;p&gt;
Having trust issues myself ^^ I ran the program on a bunch of VPS I manage:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.gandi.net&quot;&gt;Gandi&lt;/a&gt; (of course)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ovh.com&quot;&gt;OVH&lt;/a&gt;, another famous french hosting provider.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.slicehost.com&quot;&gt;Slicehost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.linode.com&quot;&gt;Linode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Myself, as I own a few linux computers at home&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
So here's the result (the higher the score, the better):&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://spreadsheets.google.com/oimg?key=0At1ULWWcCRCRdEh0amF1MGZzTlJMQWgxTDlfeFdiZUE&amp;amp;oid=1&amp;amp;v=1264781185727&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
To get those results, I ran the benchmarks at several hours of the day (to cope with timezone issues impacting the performance of european servers vs. US servers), and always kept the &lt;strong&gt;lowest&lt;/strong&gt; values. Anyway, I never got more than a 10% variation between the results taken at several hours.&lt;br /&gt;
&lt;p&gt;
For the details of the results, check the full table:&lt;br /&gt;
&lt;p&gt;
&lt;script src=&quot;https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA2%25253AJ16%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEh0amF1MGZzTlJMQWgxTDlfeFdiZUE%2526gid%253D0%2526pub%253D1%26up_title%3D%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D1%26up_aggregateby%3D%26up_enablegrouping%3D1%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;amp;height=349&amp;amp;width=601&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;
NOTES:&lt;br /&gt;
&lt;ul&gt;
 &lt;li&gt;Performance are strongly dependant on the host and time of the day, so your mileage may vary. However, all the results I provide were ran several time to check the consistency of the results. I usually got differences &amp;lt;0.3 on the final score.  &lt;/li&gt;
 &lt;li&gt;OVH's RPS are not VPS, they are real servers, but they use network disks. Consequently, the restriction above does not apply, except for the disk usage (shared on their network)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;
I was really surprised by the good performance of linode, but keep in mind that all those providers are excellent, and all provide a very different kind of service, while this benchmark only provides a score on CPU and Disks (not bandwidth, not additional services, not reliability, nor capacity).&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;
I couldn't test all the possible configuration and flavours of these providers, but hopefully it gives a good picture of their respective performance.&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;</description>
			<content:encoded><![CDATA[<p>I thought about VPS benchmarking when I was looking for a new server, and found out that Gandi was providing a lot of useful information in their <a href="http://www.gandi.net/hosting/proposal/benchmark/">benchmark page</a>, and they used this <a href="http://members.cox.net/yikes2000/unixbench-4.1.0-wht.tar.gz">UnixBench</a> program to evaluate the processor-equivalence of their shares.</p>
<p>
Having trust issues myself ^^ I ran the program on a bunch of VPS I manage:<br />
<br />
<ul>
<li><a href="http://www.gandi.net">Gandi</a> (of course)</li>
<li><a href="http://www.ovh.com">OVH</a>, another famous french hosting provider.</li>
<li><a href="http://www.slicehost.com">Slicehost</a></li>
<li><a href="http://www.linode.com">Linode</a></li>
<li>Myself, as I own a few linux computers at home</li>
</ul><br />
<br />
So here's the result (the higher the score, the better):<br />
<br />
<img src="https://spreadsheets.google.com/oimg?key=0At1ULWWcCRCRdEh0amF1MGZzTlJMQWgxTDlfeFdiZUE&amp;oid=1&amp;v=1264781185727" /><br />
<br />
To get those results, I ran the benchmarks at several hours of the day (to cope with timezone issues impacting the performance of european servers vs. US servers), and always kept the <strong>lowest</strong> values. Anyway, I never got more than a 10% variation between the results taken at several hours.<br />
<p>
For the details of the results, check the full table:<br />
<p>
<script src="https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA2%25253AJ16%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEh0amF1MGZzTlJMQWgxTDlfeFdiZUE%2526gid%253D0%2526pub%253D1%26up_title%3D%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D1%26up_aggregateby%3D%26up_enablegrouping%3D1%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;height=349&amp;width=601"></script><br />
<br />
<p>
NOTES:<br />
<ul>
 <li>Performance are strongly dependant on the host and time of the day, so your mileage may vary. However, all the results I provide were ran several time to check the consistency of the results. I usually got differences &lt;0.3 on the final score.  </li>
 <li>OVH's RPS are not VPS, they are real servers, but they use network disks. Consequently, the restriction above does not apply, except for the disk usage (shared on their network)</li>
</ul><br />
<br />
<p>
I was really surprised by the good performance of linode, but keep in mind that all those providers are excellent, and all provide a very different kind of service, while this benchmark only provides a score on CPU and Disks (not bandwidth, not additional services, not reliability, nor capacity).<br />
<br />
<p>
I couldn't test all the possible configuration and flavours of these providers, but hopefully it gives a good picture of their respective performance.</p></p></p></p></p></p>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2010/01/29/benchmarking-gandi-ovh-slicehost-and-lin#comments</comments>
		</item>
				<item>
			<title>Scary fact: 1 java class out of 70 is a Node!</title>
			<link>http://blog.kornr.net/index.php/2009/12/04/title</link>
			<pubDate>Fri, 04 Dec 2009 13:36:27 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Misc</category>			<guid isPermaLink="false">47@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;The other day, I happened to use one of my classes that manages preferences (from a property file). Pretty common, I know. So common, that eclipse popped up the completion window with 11 (eleven) possible classes with that very same name. The class name's &lt;tt&gt;Node&lt;/tt&gt; (because it creates a tree, and I severely lack imagination). &lt;/p&gt;

&lt;p&gt;Wait. ELEVEN just in the path of a single project: I may not be the only one with imagination issues. How many Node classes are there in the world?&lt;/p&gt;

&lt;p&gt;Pretty much impossible to know, but I figured out that checking the whole maven repository may give a rough idea. So I ftp'ed the whole maven2 central repository to grab the jars (that's for SCIENCE, guys!!), and made a script.&lt;/p&gt;

&lt;h3&gt;156 Node classes&lt;/h3&gt;
&lt;p&gt;156, that's the number of classes that are called Node. But Node is also used as a morpheme in 4856 classes, out of the 340K in the whole maven repository. &lt;b&gt;In other words, 1 out of 70 classes contains the morpheme &lt;tt&gt;Node&lt;/tt&gt;&lt;/b&gt;. WOW. I'm feeling less lonely. Thanks, brothers!&lt;/p&gt;

&lt;p&gt;So I extended the script to get the whole figures, and created the Top 100 Java Morphemes with it.&lt;/p&gt;

&lt;h3&gt;Top 100 Java Morphemes&lt;/h3&gt;
&lt;script src=&quot;https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA1%25253AE101%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEJ0a2RDamw4WUFkTjNHMk1vSjVaVGc%2526gid%253D0%2526pub%253D1%26up_title%3DTop%2520100%2520Java%2520Morphemes%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D0%26up_aggregateby%3D%26up_enablegrouping%3D0%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;amp;height=400&amp;amp;width=400&quot;&gt;&lt;/script&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;So 1 class out of 22 contains the morpheme &lt;tt&gt;Impl&lt;/tt&gt;. Haha, so much for those java-bashers that complain we over-engineer with interfaces and abstract classes, this is factual proof that Java coders can also implement real classes, at least 4.43% of the time! Yay!&lt;/p&gt;

&lt;p&gt;
The same Top 100 in a Web Cloud:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://spreadsheets.google.com/gpub?url=http%3A%2F%2Flf01acusmumujvhkfcabkmlu1jrmiv8p.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA2%25253AH2%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEJ0a2RDamw4WUFkTjNHMk1vSjVaVGc%2526gid%253D2%2526pub%253D1%26url%3Dhttp%253A%252F%252Fvisapi-gadgets.googlecode.com%252Fsvn%252Ftrunk%252Fgadget%252Fwordcloud.xml&amp;amp;height=273&amp;amp;width=450&quot;&gt;&lt;/script&gt;
&lt;/p&gt;

&lt;p&gt;Think it looks familiar? Of course, that's what most of your code looks like. Now let's check the classnames, are we doing better?&lt;/p&gt;

&lt;h3&gt;Top 40 Java Classname&lt;/h3&gt;

&lt;script src=&quot;https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA1%25253AC41%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEdVbkxub3FZX2txUEpQMVhLVWR4UGc%2526gid%253D0%2526pub%253D1%26up_title%3D%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D0%26up_aggregateby%3D%26up_enablegrouping%3D0%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;amp;height=342&amp;amp;width=299&quot;&gt;&lt;/script&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The &lt;tt&gt;Token&lt;/tt&gt; morpheme may not be the most used morpheme to create a classname (only #86), but it's the most common classname. We sure like parsing.&lt;/p&gt;

&lt;p&gt;My smartest readers will probably notice some salient data&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;There are 105 &lt;tt&gt;Base64&lt;/tt&gt; classes (not taking into account all the Base64Encoder, Base64Code, Base64Decoder, Base64Utils, etc).&lt;/li&gt;
 &lt;li&gt;There are 99 &lt;tt&gt;StringUtils&lt;/tt&gt; and 65 &lt;tt&gt;StringUtil&lt;/tt&gt;. Besides the fact that java programmers tend to prefer plurals, it probably says something about the lack of String manipulation methods in the standard classes.
&lt;/li&gt;&lt;/ul&gt;

&lt;h3&gt;Utilities classes&lt;/h3&gt;
&lt;p&gt;Regarding *Util* classes, the chart comes out as expected: if you're intenting to create a StringUtil or FileUtil class, chances are there may be some out there that provide something you need, so don't miss out a chance to duplicate it and create your own!&lt;/p&gt;

&lt;script src=&quot;https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA1%25253AC101%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEJ0a2RDamw4WUFkTjNHMk1vSjVaVGc%2526gid%253D1%2526pub%253D1%26up_title%3D%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D0%26up_aggregateby%3D%26up_enablegrouping%3D0%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;amp;height=287&amp;amp;width=299&quot;&gt;&lt;/script&gt;&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;Methodology and script&lt;/h3&gt;

&lt;p&gt;Here's the script used to calculate those numbers. Note that extra care was taken to avoid counting duplicated classnames from the same project (fully-qualified classnames in different jars, or re-jarred, and avoiding duplicates inside the same project -- some developers create myproject.v1.SomeClass and myproject.v2.SomeClass which are just copypasta and don't qualify as two distinct classes).&lt;/p&gt;

&lt;pre class=&quot;sh_java&quot;&gt;
#!/bin/bash

# Where the jars are located
JARFOLDER=ftp

if [[ &quot;clean&quot; == &quot;$1&quot; ]]
then
    echo &quot;Cleaning workfiles...&quot;
    rm -f jars.lst allclasses.lst sorted.lst
    exit 0
fi


if [ ! -f jars.lst ]
then
    echo &quot;Creating jar list...&quot;
    find $JARFOLDER -type f | grep '\.jar$' &amp;gt;jars.lst
else
    echo &quot;Jar list already exists, skipping&quot;
fi

CURRENT=1
TOTAL=`cat jars.lst | wc -l`
echo &quot;found&quot; $TOTAL &quot;jar files&quot;

#
# Extract the list of classes from the jars
# rm -f allclasses.lst

if [ ! -f allclasses.lst ]
then
 cat jars.lst | while read LINE ; do
    zipinfo -1 $LINE | grep -v '^META-INF/' | grep '.class$' | grep -v '^schema.system.' | grep -v '\$' | cut -d. -f1 | tr [/] [.] | sort | uniq &amp;gt;&amp;gt;allclasses.lst
    echo -n -e &quot;done &quot; $CURRENT &quot;/&quot; $TOTAL  \\r
    CURRENT=$((CURRENT+1))
 done
else
    echo allclasses.lst already exists, skipping.
fi

#
# Each line contains &quot;f.q.d ClassName&quot; (3 first domain element + classname)
# then sorted and uniquified, then only the classname is output.
# This prevents classnames duplicated in the same project to appear
# several times, but let them as duplicate if they appear to be from different
# projects (which is the case if the 3 first elements of the full classname 
# are distinct).
#
# For instance, we don't want project.v1.SomeClass and project.v2.SomeClass
# to be counted as 2, because they're from the same project and are likely 
# to be copypasta.
#
if [ ! -f sorted.lst ]
then
  echo &quot;Sorting the classes&quot;
  cat &amp;lt;allclasses.lst | awk &quot;BEGIN{FS=\&quot;.\&quot;;}{ if (length(\$NF)&amp;gt;2) {printf(\&quot;%s.%s.%s %s\n\&quot;,\$1,\$2,\$3,\$NF);}}&quot; | sort | uniq | cut -d' ' -f2 | sort &amp;gt;sorted.lst
fi
echo &quot;found&quot; `cat sorted.lst | wc -l` &quot;distinct classes, now sorting...&quot;

#
# Counts the occurence of each class name, and outputs a CSV line 
# containing the short classname and its appearance count.
echo doing classnames... 
cat sorted.lst | awk &quot;BEGIN{FS=\&quot;.\&quot;; count=1; last=\&quot;\&quot;;}{ C=\$NF; if (last==C) { count++ } else { if (last != \&quot;\&quot;) {printf(\&quot;%s;%d\n\&quot;, last, count);} last=C; count=1; }}&quot; | sort -r -n -t ';' -k 2 &amp;gt;classnames.csv

#
# Extract each word contained in the class name, sort and count, then 
# output a CSV file similar to the one create above.
echo doing morphemes...
cat sorted.lst | awk 'BEGIN{FS=&quot;&quot;;}{for(i=1;i&amp;lt;=NF;i++){if ($i == toupper($i) &amp;amp;&amp;amp; i&amp;gt;1) {printf(&quot;\n&quot;);} printf(&quot;%s&quot;,$i);} printf(&quot;\n&quot;);}' | \
     sort | awk &quot;BEGIN{FS=\&quot;.\&quot;; count=1; last=\&quot;\&quot;;}{ C=\$NF; if (last==C) { count++ } else { if (last != \&quot;\&quot; &amp;amp;&amp;amp; length(last)&amp;gt;1) {printf(\&quot;%s;%d\n\&quot;, last, count);} last=C; count=1; }}&quot; | sort -r -n -t ';' -k 2 &amp;gt;morphemes.csv

#
# All of the above, but just for google :-)
echo doing google...
cat &amp;lt;allclasses.lst | grep '^com\.google\.' | awk &quot;BEGIN{FS=\&quot;.\&quot;;}{ if (length(\$NF)&amp;gt;2) {printf(\&quot;%s.%s.%s %s\n\&quot;,\$1,\$2,\$3,\$NF);}}&quot;| sort | uniq | cut -d' ' -f2 | awk 'BEGIN{FS=&quot;&quot;;}{for(i=1;i&amp;lt;=NF;i++){if ($i == toupper($i) &amp;amp;&amp;amp; i&amp;gt;1) {printf(&quot;\n&quot;);} printf(&quot;%s&quot;,$i);} printf(&quot;\n&quot;);}' | \
     sort | awk &quot;BEGIN{FS=\&quot;.\&quot;; count=1; last=\&quot;\&quot;;}{ C=\$NF; if (last==C) { count++ } else { if (last != \&quot;\&quot; &amp;amp;&amp;amp; length(last)&amp;gt;1) {printf(\&quot;%s;%d\n\&quot;, last, count);} last=C; count=1; }}&quot; | sort -r -n -t ';' -k 2 &amp;gt;google-morphemes.csv

#
# Now some fun with common classes
echo doing base64...
cat sorted.lst | grep &quot;Base64&quot; | awk &quot;BEGIN{FS=\&quot;.\&quot;; count=1; last=\&quot;\&quot;;}{ C=\$NF; if (last==C) { count++ } else { if (last != \&quot;\&quot;) {printf(\&quot;%s;%d\n\&quot;, last, count);} last=C; count=1; }}&quot; | sort -r -n -t ';' -k 2 &amp;gt;base64-classnames.csv

echo doing String...
cat sorted.lst | grep &quot;String&quot; | awk &quot;BEGIN{FS=\&quot;.\&quot;; count=1; last=\&quot;\&quot;;}{ C=\$NF; if (last==C) { count++ } else { if (last != \&quot;\&quot;) {printf(\&quot;%s;%d\n\&quot;, last, count);} last=C; count=1; }}&quot; | sort -r -n -t ';' -k 2 &amp;gt;string-classnames.csv

echo doing Log...
cat sorted.lst | grep &quot;Log&quot; | awk &quot;BEGIN{FS=\&quot;.\&quot;; count=1; last=\&quot;\&quot;;}{ C=\$NF; if (last==C) { count++ } else { if (last != \&quot;\&quot;) {printf(\&quot;%s;%d\n\&quot;, last, count);} last=C; count=1; }}&quot; | sort -r -n -t ';' -k 2 &amp;gt;log-classnames.csv

&lt;/pre&gt;</description>
			<content:encoded><![CDATA[<p>The other day, I happened to use one of my classes that manages preferences (from a property file). Pretty common, I know. So common, that eclipse popped up the completion window with 11 (eleven) possible classes with that very same name. The class name's <tt>Node</tt> (because it creates a tree, and I severely lack imagination). </p>

<p>Wait. ELEVEN just in the path of a single project: I may not be the only one with imagination issues. How many Node classes are there in the world?</p>

<p>Pretty much impossible to know, but I figured out that checking the whole maven repository may give a rough idea. So I ftp'ed the whole maven2 central repository to grab the jars (that's for SCIENCE, guys!!), and made a script.</p>

<h3>156 Node classes</h3>
<p>156, that's the number of classes that are called Node. But Node is also used as a morpheme in 4856 classes, out of the 340K in the whole maven repository. <b>In other words, 1 out of 70 classes contains the morpheme <tt>Node</tt></b>. WOW. I'm feeling less lonely. Thanks, brothers!</p>

<p>So I extended the script to get the whole figures, and created the Top 100 Java Morphemes with it.</p>

<h3>Top 100 Java Morphemes</h3>
<script src="https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA1%25253AE101%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEJ0a2RDamw4WUFkTjNHMk1vSjVaVGc%2526gid%253D0%2526pub%253D1%26up_title%3DTop%2520100%2520Java%2520Morphemes%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D0%26up_aggregateby%3D%26up_enablegrouping%3D0%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;height=400&amp;width=400"></script><p></p>

<p>So 1 class out of 22 contains the morpheme <tt>Impl</tt>. Haha, so much for those java-bashers that complain we over-engineer with interfaces and abstract classes, this is factual proof that Java coders can also implement real classes, at least 4.43% of the time! Yay!</p>

<p>
The same Top 100 in a Web Cloud:<br />
<br />
<script src="https://spreadsheets.google.com/gpub?url=http%3A%2F%2Flf01acusmumujvhkfcabkmlu1jrmiv8p.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA2%25253AH2%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEJ0a2RDamw4WUFkTjNHMk1vSjVaVGc%2526gid%253D2%2526pub%253D1%26url%3Dhttp%253A%252F%252Fvisapi-gadgets.googlecode.com%252Fsvn%252Ftrunk%252Fgadget%252Fwordcloud.xml&amp;height=273&amp;width=450"></script>
</p>

<p>Think it looks familiar? Of course, that's what most of your code looks like. Now let's check the classnames, are we doing better?</p>

<h3>Top 40 Java Classname</h3>

<script src="https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA1%25253AC41%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEdVbkxub3FZX2txUEpQMVhLVWR4UGc%2526gid%253D0%2526pub%253D1%26up_title%3D%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D0%26up_aggregateby%3D%26up_enablegrouping%3D0%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;height=342&amp;width=299"></script><p></p>

<p>The <tt>Token</tt> morpheme may not be the most used morpheme to create a classname (only #86), but it's the most common classname. We sure like parsing.</p>

<p>My smartest readers will probably notice some salient data</p>
<ul>
 <li>There are 105 <tt>Base64</tt> classes (not taking into account all the Base64Encoder, Base64Code, Base64Decoder, Base64Utils, etc).</li>
 <li>There are 99 <tt>StringUtils</tt> and 65 <tt>StringUtil</tt>. Besides the fact that java programmers tend to prefer plurals, it probably says something about the lack of String manipulation methods in the standard classes.
</li></ul>

<h3>Utilities classes</h3>
<p>Regarding *Util* classes, the chart comes out as expected: if you're intenting to create a StringUtil or FileUtil class, chances are there may be some out there that provide something you need, so don't miss out a chance to duplicate it and create your own!</p>

<script src="https://spreadsheets.google.com/gpub?url=http%3A%2F%2Ftngmqk5kknht7idkbhrks3qtltpmeg9f.spreadsheets.gmodules.com%2Fgadgets%2Fifr%3Fup__table_query_url%3Dhttps%253A%252F%252Fspreadsheets.google.com%252Ftq%253Frange%253DA1%25253AC101%2526headers%253D-1%2526key%253D0At1ULWWcCRCRdEJ0a2RDamw4WUFkTjNHMk1vSjVaVGc%2526gid%253D1%2526pub%253D1%26up_title%3D%26up_last_query_hash%3D%26up_groupbycolumn%3D%26up__table_query_refresh_interval%3D300%26up_showfilters%3D0%26up_aggregateby%3D%26up_enablegrouping%3D0%26url%3Dhttp%253A%252F%252Fwww.google.com%252Fig%252Fmodules%252Ftable.xml&amp;height=287&amp;width=299"></script><p></p>

<h3>Methodology and script</h3>

<p>Here's the script used to calculate those numbers. Note that extra care was taken to avoid counting duplicated classnames from the same project (fully-qualified classnames in different jars, or re-jarred, and avoiding duplicates inside the same project -- some developers create myproject.v1.SomeClass and myproject.v2.SomeClass which are just copypasta and don't qualify as two distinct classes).</p>

<pre class="sh_java">
#!/bin/bash

# Where the jars are located
JARFOLDER=ftp

if [[ "clean" == "$1" ]]
then
    echo "Cleaning workfiles..."
    rm -f jars.lst allclasses.lst sorted.lst
    exit 0
fi


if [ ! -f jars.lst ]
then
    echo "Creating jar list..."
    find $JARFOLDER -type f | grep '\.jar$' &gt;jars.lst
else
    echo "Jar list already exists, skipping"
fi

CURRENT=1
TOTAL=`cat jars.lst | wc -l`
echo "found" $TOTAL "jar files"

#
# Extract the list of classes from the jars
# rm -f allclasses.lst

if [ ! -f allclasses.lst ]
then
 cat jars.lst | while read LINE ; do
    zipinfo -1 $LINE | grep -v '^META-INF/' | grep '.class$' | grep -v '^schema.system.' | grep -v '\$' | cut -d. -f1 | tr [/] [.] | sort | uniq &gt;&gt;allclasses.lst
    echo -n -e "done " $CURRENT "/" $TOTAL  \\r
    CURRENT=$((CURRENT+1))
 done
else
    echo allclasses.lst already exists, skipping.
fi

#
# Each line contains "f.q.d ClassName" (3 first domain element + classname)
# then sorted and uniquified, then only the classname is output.
# This prevents classnames duplicated in the same project to appear
# several times, but let them as duplicate if they appear to be from different
# projects (which is the case if the 3 first elements of the full classname 
# are distinct).
#
# For instance, we don't want project.v1.SomeClass and project.v2.SomeClass
# to be counted as 2, because they're from the same project and are likely 
# to be copypasta.
#
if [ ! -f sorted.lst ]
then
  echo "Sorting the classes"
  cat &lt;allclasses.lst | awk "BEGIN{FS=\".\";}{ if (length(\$NF)&gt;2) {printf(\"%s.%s.%s %s\n\",\$1,\$2,\$3,\$NF);}}" | sort | uniq | cut -d' ' -f2 | sort &gt;sorted.lst
fi
echo "found" `cat sorted.lst | wc -l` "distinct classes, now sorting..."

#
# Counts the occurence of each class name, and outputs a CSV line 
# containing the short classname and its appearance count.
echo doing classnames... 
cat sorted.lst | awk "BEGIN{FS=\".\"; count=1; last=\"\";}{ C=\$NF; if (last==C) { count++ } else { if (last != \"\") {printf(\"%s;%d\n\", last, count);} last=C; count=1; }}" | sort -r -n -t ';' -k 2 &gt;classnames.csv

#
# Extract each word contained in the class name, sort and count, then 
# output a CSV file similar to the one create above.
echo doing morphemes...
cat sorted.lst | awk 'BEGIN{FS="";}{for(i=1;i&lt;=NF;i++){if ($i == toupper($i) &amp;&amp; i&gt;1) {printf("\n");} printf("%s",$i);} printf("\n");}' | \
     sort | awk "BEGIN{FS=\".\"; count=1; last=\"\";}{ C=\$NF; if (last==C) { count++ } else { if (last != \"\" &amp;&amp; length(last)&gt;1) {printf(\"%s;%d\n\", last, count);} last=C; count=1; }}" | sort -r -n -t ';' -k 2 &gt;morphemes.csv

#
# All of the above, but just for google :-)
echo doing google...
cat &lt;allclasses.lst | grep '^com\.google\.' | awk "BEGIN{FS=\".\";}{ if (length(\$NF)&gt;2) {printf(\"%s.%s.%s %s\n\",\$1,\$2,\$3,\$NF);}}"| sort | uniq | cut -d' ' -f2 | awk 'BEGIN{FS="";}{for(i=1;i&lt;=NF;i++){if ($i == toupper($i) &amp;&amp; i&gt;1) {printf("\n");} printf("%s",$i);} printf("\n");}' | \
     sort | awk "BEGIN{FS=\".\"; count=1; last=\"\";}{ C=\$NF; if (last==C) { count++ } else { if (last != \"\" &amp;&amp; length(last)&gt;1) {printf(\"%s;%d\n\", last, count);} last=C; count=1; }}" | sort -r -n -t ';' -k 2 &gt;google-morphemes.csv

#
# Now some fun with common classes
echo doing base64...
cat sorted.lst | grep "Base64" | awk "BEGIN{FS=\".\"; count=1; last=\"\";}{ C=\$NF; if (last==C) { count++ } else { if (last != \"\") {printf(\"%s;%d\n\", last, count);} last=C; count=1; }}" | sort -r -n -t ';' -k 2 &gt;base64-classnames.csv

echo doing String...
cat sorted.lst | grep "String" | awk "BEGIN{FS=\".\"; count=1; last=\"\";}{ C=\$NF; if (last==C) { count++ } else { if (last != \"\") {printf(\"%s;%d\n\", last, count);} last=C; count=1; }}" | sort -r -n -t ';' -k 2 &gt;string-classnames.csv

echo doing Log...
cat sorted.lst | grep "Log" | awk "BEGIN{FS=\".\"; count=1; last=\"\";}{ C=\$NF; if (last==C) { count++ } else { if (last != \"\") {printf(\"%s;%d\n\", last, count);} last=C; count=1; }}" | sort -r -n -t ';' -k 2 &gt;log-classnames.csv

</pre>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2009/12/04/title#comments</comments>
		</item>
				<item>
			<title>Announcing Swit 0.9.0</title>
			<link>http://blog.kornr.net/index.php/2009/06/25/announcing-swit-0-9</link>
			<pubDate>Thu, 25 Jun 2009 20:50:44 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Misc</category>			<guid isPermaLink="false">46@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;The release is as early as the version implies, but here it is. Swit 0.9.0 is a small library providing various stuff for Wicket: a button generation engine, with a bunch of skins; a border generator for html/css, and a layout manager for liquid [1-3]-column layouts.&lt;/p&gt;

&lt;p&gt;The fun part implementing it was the button generator, not unlike the various one available around the web, except that here it's primarily meant to be used in java apps to dynamically generate some graphics stuff that are seriously boring to draw manually with the gimp or photoshop.&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;border:1px solid black;&quot; src=&quot;/FILES/images/swit-web-screenshot.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Swit Homepage: &lt;a href=&quot;http://swit.kornr.net&quot;&gt;http://swit.kornr.net&lt;/a&gt;&lt;/p&gt;</description>
			<content:encoded><![CDATA[<p>The release is as early as the version implies, but here it is. Swit 0.9.0 is a small library providing various stuff for Wicket: a button generation engine, with a bunch of skins; a border generator for html/css, and a layout manager for liquid [1-3]-column layouts.</p>

<p>The fun part implementing it was the button generator, not unlike the various one available around the web, except that here it's primarily meant to be used in java apps to dynamically generate some graphics stuff that are seriously boring to draw manually with the gimp or photoshop.</p>

<p><img style="border:1px solid black;" src="http://blog.kornr.net/FILES/images/swit-web-screenshot.jpg" /></p>

<p>Swit Homepage: <a href="http://swit.kornr.net">http://swit.kornr.net</a></p>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2009/06/25/announcing-swit-0-9#comments</comments>
		</item>
				<item>
			<title>Jdbc Jutsu Saves Heap Memory Against Wicket's Stateful Ajax</title>
			<link>http://blog.kornr.net/index.php/2009/06/18/jdbc-jutsu-saves-heap-memory-against-wic</link>
			<pubDate>Thu, 18 Jun 2009 12:41:44 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Misc</category>			<guid isPermaLink="false">45@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;Hey, I hope Quentin Tarantino won't steal my title and make a movie out of it! Anyway, the Wicket's implementation of Ajax is so good that I just stopped using anything else to make my web client communicate with my server. There's this one thing however, that prevents the fine scaling of Wicket sites, that's namely memory consumption. Wicket by itself does not consume that much memory though, but if you want to use the sweet Ajax components, you're stuck with stateful pages. And using stateful pages + lots of visitors usually implies memory issues: it's not just your own data contained in the WebSession object that is stored in memory, but also the current page hosting the ajax components, and the &lt;em&gt;n&lt;/em&gt; last pages visited. If your pages are big, the session are big, that's the point.&lt;/p&gt;

&lt;p&gt;Add to that a specific need to make the session last longer than usual, to allow users to stop using the site, then going back after a long period of time, and still have their session available, and you'd rapidly be waiting your users with fear.&lt;/p&gt;

&lt;p&gt;So, to conciliate long sessions, limited-memory servers, and stateful wicket, the best possible solution, besides asking your users &lt;em&gt;not&lt;/em&gt; to tell their friends, is to apply a Jdbc Jutsu to the session management of your servlet container. At least, that's how I solve my issue.&lt;/p&gt;

&lt;p&gt;Tomcat provides a JDBCStore for its PersistentManager class (which is responsible for managing the sessions): this java jutsu just saved my server's memory from going out of control. Unlike the default &lt;tt&gt;org.apache.catalina.session.StandardManager&lt;/tt&gt; that stores everything in your precious heap memory, the PersistentManager provides a lot of flexibility regarding the session storage. For instance, a typical configuration would keep the sessions in-memory, but passivate them into a database after a few minutes of inactivity (instead of consuming all this good memory for idle or disconnected users until their session expires).&lt;/p&gt;

&lt;p&gt;The Tomcat documentation lacks a few examples, so here's mine: I wanted unlimited sessions, and passivate idle sessions in the JDBC database after 120 seconds of inactivity (lines to customize are yellow).&lt;/p&gt;

&lt;pre class=&quot;sh_java&quot;&gt;
  &amp;lt;Host ......
	  &amp;lt;Context path=&quot;/MYPATH&quot; docBase=&quot;MY-APPLICATION.WAR&quot;&amp;gt;
	    &amp;lt;Manager className=&quot;org.apache.catalina.session.PersistentManager&quot; saveOnRestart=&quot;true&quot; 
		     &lt;span style=&quot;background-color: yellow;&quot;&gt;maxIdleSwap=&quot;120&quot;&lt;/span&gt;
		     minIdleSwap=&quot;-1&quot; 
		     maxActiveSessions=&quot;-1&quot;
		     maxIdleBackup=&quot;-1&quot;&amp;gt;
	      &amp;lt;Store className=&quot;org.apache.catalina.session.JDBCStore&quot;

		     &lt;span style=&quot;background-color: yellow;&quot;&gt;driverName=&quot;com.mysql.jdbc.Driver&quot;&lt;/span&gt;
		     &lt;span style=&quot;background-color: yellow;&quot;&gt;connectionURL=&quot;jdbc:mysql://localhost/MYAPP&quot;&lt;/span&gt;
		     &lt;span style=&quot;background-color: yellow;&quot;&gt;connectionName=&quot;DATABASE-USERNAME&quot;&lt;/span&gt;
		     &lt;span style=&quot;background-color: yellow;&quot;&gt;connectionPassword=&quot;DATABASE-PASSWORD&quot;&lt;/span&gt;

		     sessionTable=&quot;tomcat_sessions&quot;
		     sessionIdCol=&quot;session_id&quot;
		     sessionValidCol=&quot;valid_session&quot;
		     sessionMaxInactiveCol=&quot;max_inactive&quot;
		     sessionLastAccessedCol=&quot;last_access&quot;
		     sessionAppCol=&quot;app_name&quot;
		     sessionDataCol=&quot;session_data&quot;

		     checkInterval=&quot;60&quot;
		    /&amp;gt;
	      &amp;lt;/Manager&amp;gt; 
	  &amp;lt;/Context&amp;gt;
  &amp;lt;/Host&amp;gt;
&lt;/pre&gt;

&lt;div style=&quot;border: 5px solid red; padding:1em; font-weight: bold;font-size:1.1em;&quot;&gt;Note: Remember to put your jdbc driver jar in the &lt;tt&gt;lib/&lt;/tt&gt; folder of Tomcat, or the connection won't work.&lt;/div&gt;
&lt;p&gt;Then in the database and schema specified in the configuration above, just add the following table:&lt;br /&gt;
(from the Tomcat Manual at &lt;a href=&quot;http://tomcat.apache.org/tomcat-6.0-doc/config/manager.html&quot;&gt;http://tomcat.apache.org/tomcat-6.0-doc/config/manager.html&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;sh_java&quot;&gt;
create table tomcat_sessions (
  session_id     varchar(100) not null primary key,
  valid_session  char(1) not null,
  max_inactive   int not null,
  last_access    bigint not null,
  app_name       varchar(255),
  session_data   mediumblob,
  KEY kapp_name(app_name)
);
&lt;/pre&gt;

&lt;p&gt;Well, that's it, no more wicket-related memory issues.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update after Thyzz comment&lt;/b&gt; (see below)&lt;/p&gt;

&lt;p&gt;Wicket can actually use either its original HttpSessionStore (that stores everything in the servlet http session), or its new SecondLevelCacheSessionStore that stores the PageMap on disk. Here is below some metrics I made that compare the memory usage with and without the tomcat's JDBCStore:&lt;/p&gt;

&lt;div style=&quot;text-align:center;&quot;&gt;
&lt;a target=&quot;_blank&quot; href=&quot;/FILES/jdbcstore-metrics.png&quot;&gt;&lt;img style=&quot;width:100%;&quot; src=&quot;/FILES/jdbcstore-metrics.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
(click to enlarge)
&lt;/div&gt;

&lt;p&gt;To get those metrics, I used a web application that makes a moderate memory usage, and changed it so that the SessionStore can be either the HttpSessionStore or the SecondLevelCacheSessionStore. Additionnally, I added a &lt;tt&gt;new byte[1024*500]&lt;/tt&gt; allocation into the session object, so that the memory consumption be artificially higher (for the purpose of testing in this specific configuration, applications with a really low memory footprint of their session behave totally differently, and are unlikely to have any memory-related issue). Then I ran a script on another computer that would make a loop over an http request for the frontpage (and all the resources of that page).&lt;/p&gt;

&lt;p&gt;As a result, both HttpSessionStore and SecondLevelCacheSessionStore end up with an OutOfMemoryException. The memory usage is slightly better when using the SecondLevelCacheSessionStore, but I did not test the http latency; a real benchmark would require to compare both memory and speed, but at least the figures shows that the memory issue is prevented.&lt;/p&gt;</description>
			<content:encoded><![CDATA[<p>Hey, I hope Quentin Tarantino won't steal my title and make a movie out of it! Anyway, the Wicket's implementation of Ajax is so good that I just stopped using anything else to make my web client communicate with my server. There's this one thing however, that prevents the fine scaling of Wicket sites, that's namely memory consumption. Wicket by itself does not consume that much memory though, but if you want to use the sweet Ajax components, you're stuck with stateful pages. And using stateful pages + lots of visitors usually implies memory issues: it's not just your own data contained in the WebSession object that is stored in memory, but also the current page hosting the ajax components, and the <em>n</em> last pages visited. If your pages are big, the session are big, that's the point.</p>

<p>Add to that a specific need to make the session last longer than usual, to allow users to stop using the site, then going back after a long period of time, and still have their session available, and you'd rapidly be waiting your users with fear.</p>

<p>So, to conciliate long sessions, limited-memory servers, and stateful wicket, the best possible solution, besides asking your users <em>not</em> to tell their friends, is to apply a Jdbc Jutsu to the session management of your servlet container. At least, that's how I solve my issue.</p>

<p>Tomcat provides a JDBCStore for its PersistentManager class (which is responsible for managing the sessions): this java jutsu just saved my server's memory from going out of control. Unlike the default <tt>org.apache.catalina.session.StandardManager</tt> that stores everything in your precious heap memory, the PersistentManager provides a lot of flexibility regarding the session storage. For instance, a typical configuration would keep the sessions in-memory, but passivate them into a database after a few minutes of inactivity (instead of consuming all this good memory for idle or disconnected users until their session expires).</p>

<p>The Tomcat documentation lacks a few examples, so here's mine: I wanted unlimited sessions, and passivate idle sessions in the JDBC database after 120 seconds of inactivity (lines to customize are yellow).</p>

<pre class="sh_java">
  &lt;Host ......
	  &lt;Context path="/MYPATH" docBase="MY-APPLICATION.WAR"&gt;
	    &lt;Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true" 
		     <span style="background-color: yellow;">maxIdleSwap="120"</span>
		     minIdleSwap="-1" 
		     maxActiveSessions="-1"
		     maxIdleBackup="-1"&gt;
	      &lt;Store className="org.apache.catalina.session.JDBCStore"

		     <span style="background-color: yellow;">driverName="com.mysql.jdbc.Driver"</span>
		     <span style="background-color: yellow;">connectionURL="jdbc:mysql://localhost/MYAPP"</span>
		     <span style="background-color: yellow;">connectionName="DATABASE-USERNAME"</span>
		     <span style="background-color: yellow;">connectionPassword="DATABASE-PASSWORD"</span>

		     sessionTable="tomcat_sessions"
		     sessionIdCol="session_id"
		     sessionValidCol="valid_session"
		     sessionMaxInactiveCol="max_inactive"
		     sessionLastAccessedCol="last_access"
		     sessionAppCol="app_name"
		     sessionDataCol="session_data"

		     checkInterval="60"
		    /&gt;
	      &lt;/Manager&gt; 
	  &lt;/Context&gt;
  &lt;/Host&gt;
</pre>

<div style="border: 5px solid red; padding:1em; font-weight: bold;font-size:1.1em;">Note: Remember to put your jdbc driver jar in the <tt>lib/</tt> folder of Tomcat, or the connection won't work.</div>
<p>Then in the database and schema specified in the configuration above, just add the following table:<br />
(from the Tomcat Manual at <a href="http://tomcat.apache.org/tomcat-6.0-doc/config/manager.html">http://tomcat.apache.org/tomcat-6.0-doc/config/manager.html</a>):</p>

<pre class="sh_java">
create table tomcat_sessions (
  session_id     varchar(100) not null primary key,
  valid_session  char(1) not null,
  max_inactive   int not null,
  last_access    bigint not null,
  app_name       varchar(255),
  session_data   mediumblob,
  KEY kapp_name(app_name)
);
</pre>

<p>Well, that's it, no more wicket-related memory issues.</p>

<p><b>Update after Thyzz comment</b> (see below)</p>

<p>Wicket can actually use either its original HttpSessionStore (that stores everything in the servlet http session), or its new SecondLevelCacheSessionStore that stores the PageMap on disk. Here is below some metrics I made that compare the memory usage with and without the tomcat's JDBCStore:</p>

<div style="text-align:center;">
<a target="_blank" href="http://blog.kornr.net/FILES/jdbcstore-metrics.png"><img style="width:100%;" src="http://blog.kornr.net/FILES/jdbcstore-metrics.png" /></a><br />
(click to enlarge)
</div>

<p>To get those metrics, I used a web application that makes a moderate memory usage, and changed it so that the SessionStore can be either the HttpSessionStore or the SecondLevelCacheSessionStore. Additionnally, I added a <tt>new byte[1024*500]</tt> allocation into the session object, so that the memory consumption be artificially higher (for the purpose of testing in this specific configuration, applications with a really low memory footprint of their session behave totally differently, and are unlikely to have any memory-related issue). Then I ran a script on another computer that would make a loop over an http request for the frontpage (and all the resources of that page).</p>

<p>As a result, both HttpSessionStore and SecondLevelCacheSessionStore end up with an OutOfMemoryException. The memory usage is slightly better when using the SecondLevelCacheSessionStore, but I did not test the http latency; a real benchmark would require to compare both memory and speed, but at least the figures shows that the memory issue is prevented.</p>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2009/06/18/jdbc-jutsu-saves-heap-memory-against-wic#comments</comments>
		</item>
				<item>
			<title>Tomcat, JSessionID, and subdomains...</title>
			<link>http://blog.kornr.net/index.php/2009/05/29/tomcat-jsessionid-and-subdomains</link>
			<pubDate>Fri, 29 May 2009 13:32:36 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Misc</category>			<guid isPermaLink="false">44@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;Imagine you're developping a web site that manages subdomains for your users, in such a way that all your users automatically get a &lt;a href=&quot;http://user1.example.com&quot;&gt;http://user1.example.com&lt;/a&gt; or &lt;a href=&quot;http://user2.example.com&quot;&gt;http://user2.example.com&lt;/a&gt; subdomain. &lt;/p&gt;

&lt;p&gt;In order to keep the normal session available on all the subdomains, one just needs to make the session cookie associated to the smallest common domain, in this exemple, the example.com domain, so that &lt;a href=&quot;http://www.example.com&quot;&gt;www.example.com&lt;/a&gt; share the same cookie with all the other &lt;a href=&quot;http://[whatever].example.com&quot;&gt;http://[whatever].example.com&lt;/a&gt; subdomains. Piece of cake: &lt;tt&gt;cookie.setDomain(&quot;example.com&quot;)&lt;/tt&gt;, right? Almost. Just, not in a servlet container. Because, you can't.&lt;/p&gt;

&lt;p&gt;It's amazing, but in a servlet container, you just can't tell which domain the JSESSIONID cookie is associated to. Unfortunately, Tomcat provides no container-specific way to modify this behaviour.&lt;/p&gt;

&lt;p&gt;So, here's a simple patch that fixes the issue. It's not suited for all purpose, it just removes any &lt;tt&gt;www&lt;/tt&gt; prefix that appears in the hostname, and use it as cookie domain. If there's no &lt;tt&gt;www&lt;/tt&gt; prefix, the normal behaviour applies.&lt;/p&gt;

&lt;p&gt;In apache-tomcat-6.0.18-src/java/org/apache/catalina/connector/Request.java, find the configureSessionCookie() method, and replace it with this one:&lt;/p&gt;

&lt;pre class=&quot;sh_java&quot;&gt;
    /**
     * Configures the given JSESSIONID cookie.
     *
     * @param cookie The JSESSIONID cookie to be configured
     */
    protected void configureSessionCookie(Cookie cookie) {
        cookie.setMaxAge(-1);
        String contextPath = null;
        if (!connector.getEmptySessionPath() &amp;amp;&amp;amp; (getContext() != null)) {
            contextPath = getContext().getEncodedPath();
        }
        if ((contextPath != null) &amp;amp;&amp;amp; (contextPath.length() &gt; 0)) {
            cookie.setPath(contextPath);
        } else {
            cookie.setPath(&quot;/&quot;);
        }
        if (isSecure()) {
            cookie.setSecure(true);
        }

        // CHANGES BELOW
&lt;pre style=&quot;font-weight:bolder; font-size:1.1em; border-left:4px solid black; margin:1em; background-color: #FFFFAA;&quot;&gt;
	String domain = this.getServerName();
	if (domain != null)
	    {
		if (domain.toLowerCase().startsWith(&quot;www.&quot;))
		    domain = domain.substring(4);
		
		cookie.setDomain(domain);
	    }
&lt;/pre&gt;
    }&lt;br /&gt;
&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now compile (with a JDK 1.5... as of Tomcat 6.0.18 you can't compile it with JDK1.6 because of a DBCP issue), and use this distribution. Or just grab the catalina.jar.&lt;/p&gt;</description>
			<content:encoded><![CDATA[<p>Imagine you're developping a web site that manages subdomains for your users, in such a way that all your users automatically get a <a href="http://user1.example.com">http://user1.example.com</a> or <a href="http://user2.example.com">http://user2.example.com</a> subdomain. </p>

<p>In order to keep the normal session available on all the subdomains, one just needs to make the session cookie associated to the smallest common domain, in this exemple, the example.com domain, so that <a href="http://www.example.com">www.example.com</a> share the same cookie with all the other <a href="http://[whatever].example.com">http://[whatever].example.com</a> subdomains. Piece of cake: <tt>cookie.setDomain("example.com")</tt>, right? Almost. Just, not in a servlet container. Because, you can't.</p>

<p>It's amazing, but in a servlet container, you just can't tell which domain the JSESSIONID cookie is associated to. Unfortunately, Tomcat provides no container-specific way to modify this behaviour.</p>

<p>So, here's a simple patch that fixes the issue. It's not suited for all purpose, it just removes any <tt>www</tt> prefix that appears in the hostname, and use it as cookie domain. If there's no <tt>www</tt> prefix, the normal behaviour applies.</p>

<p>In apache-tomcat-6.0.18-src/java/org/apache/catalina/connector/Request.java, find the configureSessionCookie() method, and replace it with this one:</p>

<pre class="sh_java">
    /**
     * Configures the given JSESSIONID cookie.
     *
     * @param cookie The JSESSIONID cookie to be configured
     */
    protected void configureSessionCookie(Cookie cookie) {
        cookie.setMaxAge(-1);
        String contextPath = null;
        if (!connector.getEmptySessionPath() &amp;&amp; (getContext() != null)) {
            contextPath = getContext().getEncodedPath();
        }
        if ((contextPath != null) &amp;&amp; (contextPath.length() > 0)) {
            cookie.setPath(contextPath);
        } else {
            cookie.setPath("/");
        }
        if (isSecure()) {
            cookie.setSecure(true);
        }

        // CHANGES BELOW
<pre style="font-weight:bolder; font-size:1.1em; border-left:4px solid black; margin:1em; background-color: #FFFFAA;">
	String domain = this.getServerName();
	if (domain != null)
	    {
		if (domain.toLowerCase().startsWith("www."))
		    domain = domain.substring(4);
		
		cookie.setDomain(domain);
	    }
</pre>
    }<br />
</pre><p></p>

<p>Now compile (with a JDK 1.5... as of Tomcat 6.0.18 you can't compile it with JDK1.6 because of a DBCP issue), and use this distribution. Or just grab the catalina.jar.</p>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2009/05/29/tomcat-jsessionid-and-subdomains#comments</comments>
		</item>
				<item>
			<title>Wicket Javadocs in CHM format</title>
			<link>http://blog.kornr.net/index.php/2009/03/16/wicket-javadocs-in-chm-format</link>
			<pubDate>Mon, 16 Mar 2009 11:39:53 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Wicket</category>			<guid isPermaLink="false">43@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;Not that I'm much into Windows development, but I've personnally always preferred using the Microsoft CHM format rather than plain HTML. It's compact, it's fast to open, and pretty fast to search for a specific class or method.&lt;/p&gt;

&lt;p&gt;I took some time this morning to generate the Wicket javadocs WITHOUT the examples packages (I can't see why they are included in the default javadocs, it's just annoying to have them mixed with the Wicket API), and the corresponding CHM file using the &lt;a href=&quot;http://www.burgaud.com/jd2chm/&quot;&gt;jd2chm javadocs-to-chm&lt;/a&gt; converter. This program works amazingly well.&lt;/p&gt;

&lt;p&gt;For those interested, I generated two flavours of the wicket-javadocs:&lt;/p&gt;

&lt;div style=&quot;font-weight:bold;&quot;&gt;(Update for 1.4RC4)&lt;/div&gt;
&lt;ul&gt;
 &lt;li&gt; &lt;a href=&quot;http://blog.kornr.net/FILES/Wicket1.4rc4.chm&quot;&gt;Wicket 1.4rc4&lt;/a&gt; CHM (standard version, 7.76Mb) &lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;http://blog.kornr.net/FILES/Wicket1.4rc4-linksource.chm&quot;&gt;Wicket 1.4rc4&lt;/a&gt; CHM with the linksource option (12.5Mb) &lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;font-weight:bold;&quot;&gt;Previous versions&lt;/div&gt;

&lt;ul&gt;
 &lt;li&gt; &lt;a href=&quot;http://blog.kornr.net/FILES/Wicket1.4rc2.chm&quot;&gt;Wicket 1.4rc2&lt;/a&gt; CHM (standard version, 7.76Mb) &lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;http://blog.kornr.net/FILES/Wicket1.4rc2-linksource.chm&quot;&gt;Wicket 1.4rc2&lt;/a&gt; CHM with the linksource option (12.5Mb) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The linksource option provides a link between a method and its java source code, which makes it a breeze to check what the code does under the water (and that's utterly useful when the documentation of some method is not available).&lt;/p&gt;

&lt;p&gt;Other adjustments I've made to the javadocs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Java API classes link to the online JDK1.6 javadocs&lt;/li&gt;
&lt;li&gt;I've separated the core wicket packages and other extension packages that are bundled in a different jar, so that they appear in different groups&lt;/li&gt;
&lt;/ul&gt;</description>
			<content:encoded><![CDATA[<p>Not that I'm much into Windows development, but I've personnally always preferred using the Microsoft CHM format rather than plain HTML. It's compact, it's fast to open, and pretty fast to search for a specific class or method.</p>

<p>I took some time this morning to generate the Wicket javadocs WITHOUT the examples packages (I can't see why they are included in the default javadocs, it's just annoying to have them mixed with the Wicket API), and the corresponding CHM file using the <a href="http://www.burgaud.com/jd2chm/">jd2chm javadocs-to-chm</a> converter. This program works amazingly well.</p>

<p>For those interested, I generated two flavours of the wicket-javadocs:</p>

<div style="font-weight:bold;">(Update for 1.4RC4)</div>
<ul>
 <li> <a href="http://blog.kornr.net/FILES/Wicket1.4rc4.chm">Wicket 1.4rc4</a> CHM (standard version, 7.76Mb) </li>
 <li> <a href="http://blog.kornr.net/FILES/Wicket1.4rc4-linksource.chm">Wicket 1.4rc4</a> CHM with the linksource option (12.5Mb) </li>
</ul>

<div style="font-weight:bold;">Previous versions</div>

<ul>
 <li> <a href="http://blog.kornr.net/FILES/Wicket1.4rc2.chm">Wicket 1.4rc2</a> CHM (standard version, 7.76Mb) </li>
 <li> <a href="http://blog.kornr.net/FILES/Wicket1.4rc2-linksource.chm">Wicket 1.4rc2</a> CHM with the linksource option (12.5Mb) </li>
</ul>

<p>The linksource option provides a link between a method and its java source code, which makes it a breeze to check what the code does under the water (and that's utterly useful when the documentation of some method is not available).</p>

<p>Other adjustments I've made to the javadocs:</p>
<ul>
<li>The Java API classes link to the online JDK1.6 javadocs</li>
<li>I've separated the core wicket packages and other extension packages that are bundled in a different jar, so that they appear in different groups</li>
</ul>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2009/03/16/wicket-javadocs-in-chm-format#comments</comments>
		</item>
				<item>
			<title>A simple, localized, Wicket country list model</title>
			<link>http://blog.kornr.net/index.php/2009/03/02/wicket-country-list-model</link>
			<pubDate>Mon, 02 Mar 2009 11:26:00 +0000</pubDate>			<dc:creator>nogunner</dc:creator>
			<category domain="main">Misc</category>
<category domain="alt">Wicket</category>			<guid isPermaLink="false">42@http://blog.kornr.net/</guid>
						<description>&lt;p&gt;A quick post just to share a country list model I did a few days ago. It's no big deal, but I think it's worth sharing to avoid my fellow wicketeers the trouble to do it.&lt;/p&gt;

&lt;p&gt;So, it's a standard Wicket Model that uses a standard ISO-3166-1 (2-char long) code to store the country name. The idea is to keep simplicity in my domain object, so the country property is just a String that stores the ISO3166 code. As it's not easily possible to use this ISO3166 code directly in a Wicket DropDownChoice (I want to display a localized country full name, but store the ISO-3166 short code), I had to create a Country object, which is internally used. Note however that the CountryList class provides an adaptor that converts this internally-used Country object into the property string of my domain POJO, so it's transparent.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://blog.kornr.net/media/users/nogunner/wountry.png&quot; alt=&quot;Example screenshot&quot; title=&quot;English locale screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The country list is localized, and comes from the ISO files I found at &lt;a href=&quot;http://www.iso.org/iso/country_codes/iso_3166_code_lists.htm&quot;&gt;http://www.iso.org/iso/country_codes/iso_3166_code_lists.htm&lt;/a&gt;. Unfortunately, the ISO organization only provides english and french locales from the country name, so if you want more, you'll have to translate them yourselves and add the resource file to the jar.&lt;/p&gt;

&lt;p&gt;Actually, using it is pretty straightforward, so I'll just show how to use it in an example.&lt;/p&gt;

&lt;p&gt;The HTML is, as expected, the standard:&lt;/p&gt;

&lt;pre class=&quot;sh_java&quot;&gt;
&amp;lt;select wicket:id=&quot;country&quot;&amp;gt;
 &amp;lt;option value=&quot;US&quot;&amp;gt;United States&amp;lt;/option&amp;gt;
 &amp;lt;option value=&quot;FR&quot;&amp;gt;France&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt; 
&lt;/pre&gt;

&lt;p&gt;The java code instanciates a country list, and uses it as a model for the DropDownChoice element (although it can be used with any component that uses an IModel&amp;lt;List&amp;gt; ).&lt;/p&gt;

&lt;pre class=&quot;sh_java&quot;&gt;
CountryList countrylist = new CountryList(); // (1)
DropDownChoice country = new DropDownChoice(&quot;country&quot;, 
		    countrylist.getAdaptor(new PropertyModel(this.obj, &quot;country&quot;)), // (2)
		    countrylist, // (3)
		    countrylist.getRenderer()); // (4)
form.add(country);
&lt;/pre&gt;

&lt;p&gt;in (1), we instantiate the CountryList class using the default constructor, which uses the Wicket Session locale. It is also possible to pass a Locale object to the constructor.&lt;/p&gt;

&lt;p&gt;in (2), we use the adaptor provided by the CountryList class: this is a very basic IModel&amp;lt;Country&amp;gt; that takes a IModel&amp;lt;String&amp;gt; as its own model to set and get the correct Country element. This allows our POJO to just use a String property, instead of dealing with an annoying Country object.&lt;/p&gt;

&lt;p&gt;in (3), this is actually the list of countries itself&lt;/p&gt;

&lt;p&gt;in (4), this is the ChoiceRenderer that displays the full country names, instead of the short code.&lt;/p&gt;

&lt;h2&gt;Download&lt;/h2&gt;
&lt;ul&gt;
 &lt;li&gt; The full project (includes the jar binary and an example): &lt;a href=&quot;http://kornr.net/wountry/Wountry-1.0.zip&quot;&gt;Wountry-1.0.zip&lt;/a&gt; (100Kb)  &lt;br /&gt;(NOTE: oooops, the file HomePage.java from the example was wrong, please download again if you got the first version of the archive)&lt;/li&gt;
 &lt;li&gt; The jar binary only: &lt;a href=&quot;http://kornr.net/wountry/wountry-1.0.jar&quot;&gt;wountry-1.0.jar&lt;/a&gt; (10Kb)&lt;/li&gt;
&lt;/ul&gt;</description>
			<content:encoded><![CDATA[<p>A quick post just to share a country list model I did a few days ago. It's no big deal, but I think it's worth sharing to avoid my fellow wicketeers the trouble to do it.</p>

<p>So, it's a standard Wicket Model that uses a standard ISO-3166-1 (2-char long) code to store the country name. The idea is to keep simplicity in my domain object, so the country property is just a String that stores the ISO3166 code. As it's not easily possible to use this ISO3166 code directly in a Wicket DropDownChoice (I want to display a localized country full name, but store the ISO-3166 short code), I had to create a Country object, which is internally used. Note however that the CountryList class provides an adaptor that converts this internally-used Country object into the property string of my domain POJO, so it's transparent.</p>

<p><img src="http://blog.kornr.net/media/users/nogunner/wountry.png" alt="Example screenshot" title="English locale screenshot" /></p>

<p>The country list is localized, and comes from the ISO files I found at <a href="http://www.iso.org/iso/country_codes/iso_3166_code_lists.htm">http://www.iso.org/iso/country_codes/iso_3166_code_lists.htm</a>. Unfortunately, the ISO organization only provides english and french locales from the country name, so if you want more, you'll have to translate them yourselves and add the resource file to the jar.</p>

<p>Actually, using it is pretty straightforward, so I'll just show how to use it in an example.</p>

<p>The HTML is, as expected, the standard:</p>

<pre class="sh_java">
&lt;select wicket:id="country"&gt;
 &lt;option value="US"&gt;United States&lt;/option&gt;
 &lt;option value="FR"&gt;France&lt;/option&gt;
&lt;/select&gt; 
</pre>

<p>The java code instanciates a country list, and uses it as a model for the DropDownChoice element (although it can be used with any component that uses an IModel&lt;List&gt; ).</p>

<pre class="sh_java">
CountryList countrylist = new CountryList(); // (1)
DropDownChoice country = new DropDownChoice("country", 
		    countrylist.getAdaptor(new PropertyModel(this.obj, "country")), // (2)
		    countrylist, // (3)
		    countrylist.getRenderer()); // (4)
form.add(country);
</pre>

<p>in (1), we instantiate the CountryList class using the default constructor, which uses the Wicket Session locale. It is also possible to pass a Locale object to the constructor.</p>

<p>in (2), we use the adaptor provided by the CountryList class: this is a very basic IModel&lt;Country&gt; that takes a IModel&lt;String&gt; as its own model to set and get the correct Country element. This allows our POJO to just use a String property, instead of dealing with an annoying Country object.</p>

<p>in (3), this is actually the list of countries itself</p>

<p>in (4), this is the ChoiceRenderer that displays the full country names, instead of the short code.</p>

<h2>Download</h2>
<ul>
 <li> The full project (includes the jar binary and an example): <a href="http://kornr.net/wountry/Wountry-1.0.zip">Wountry-1.0.zip</a> (100Kb)  <br />(NOTE: oooops, the file HomePage.java from the example was wrong, please download again if you got the first version of the archive)</li>
 <li> The jar binary only: <a href="http://kornr.net/wountry/wountry-1.0.jar">wountry-1.0.jar</a> (10Kb)</li>
</ul>]]></content:encoded>
								<comments>http://blog.kornr.net/index.php/2009/03/02/wicket-country-list-model#comments</comments>
		</item>
			</channel>
</rss>
