<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-35058937</id><updated>2009-12-03T07:51:03.839-08:00</updated><title type='text'>java.think()</title><subtitle type='html'>Thoughts on Java, Design, Patterns, and Strategies</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default?start-index=26&amp;max-results=25'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>44</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-35058937.post-1686419632504686007</id><published>2009-10-01T08:45:00.001-07:00</published><updated>2009-10-02T06:58:07.336-07:00</updated><title type='text'>A simple load test in Terracotta...</title><content type='html'>This is a response to the following blog in which the author wrote a micro-benchmark and got some pretty bad results using Terracotta &lt;a href="http://zion-city.blogspot.com/2009/10/terracotta-as-distributed-dbms-bad-idea.html"&gt;http://zion-city.blogspot.com/2009/10/terracotta-as-distributed-dbms-bad-idea.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Since the commenting system on blogger doesn't allow code, I am posting the response on my blog with code attached for reference.&lt;br /&gt;&lt;br /&gt;So my approach was to try replicate the author's implementation, to see what kind of performance a straightforward micro-benchmark might achieve.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Reader beware - micro-benchmarks are never a good idea, and not usually indicative of real-world performance.  In this case, based on real-world results I have seen, my results appear to be a lower bound for the kind of performance one should expect since the test isn't concurrent and is running on a single machine - hardly the kind of environment a real world clustered app would exist in)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;So, with that said, I wrote a simple load test against a ConcurrentHashMap, and put 100,000 objects into it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;My results show:&lt;/b&gt;&lt;br /&gt;Avg TPS: ~3,000&lt;br /&gt;Instantaneous TPS as high as: ~7,000&lt;br /&gt;&lt;br /&gt;Here's the code:&lt;pre name="code" class="java"&gt;import java.util.Date;&lt;br /&gt;import java.util.Map;&lt;br /&gt;import java.util.concurrent.*;&lt;br /&gt;&lt;br /&gt;public class Main&lt;br /&gt;{&lt;br /&gt;  static Map&amp;lt;Integer, Foo&amp;gt; map = &lt;br /&gt;    new ConcurrentHashMap&amp;lt;Integer, Foo&amp;gt;();&lt;br /&gt;&lt;br /&gt;  public static class Foo&lt;br /&gt;  {&lt;br /&gt;    public String name;&lt;br /&gt;    public String name2;&lt;br /&gt;    public String name3;&lt;br /&gt;&lt;br /&gt;    public Foo(String name)&lt;br /&gt;    {&lt;br /&gt;      this.name = name;&lt;br /&gt;      this.name2 = name + " 2";&lt;br /&gt;      this.name3 = name + " 3";&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static void main(String[] args)&lt;br /&gt;  {&lt;br /&gt;    long start = System.currentTimeMillis();&lt;br /&gt;&lt;br /&gt;    for (int i = 0; i &lt; 100000; i++) {&lt;br /&gt;      map.put(i, new Foo(new Date().toString()));&lt;br /&gt;    }&lt;br /&gt;    System.out.println("elapsed: " + (System.currentTimeMillis() - start));&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here's the tc-config.xml:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-5.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;application&amp;gt;&lt;br /&gt;    &amp;lt;dso&amp;gt;&lt;br /&gt;      &amp;lt;instrumented-classes&amp;gt;&lt;br /&gt;        &amp;lt;include&amp;gt;&lt;br /&gt;          &amp;lt;class-expression&amp;gt;Main$Foo&amp;lt;/class-expression&amp;gt;&lt;br /&gt;        &amp;lt;/include&amp;gt;&lt;br /&gt;      &amp;lt;/instrumented-classes&amp;gt;&lt;br /&gt;      &amp;lt;roots&amp;gt;&lt;br /&gt;        &amp;lt;root&amp;gt;&lt;br /&gt;          &amp;lt;field-name&amp;gt;Main.map&amp;lt;/field-name&amp;gt;&lt;br /&gt;        &amp;lt;/root&amp;gt;&lt;br /&gt;      &amp;lt;/roots&amp;gt;&lt;br /&gt;    &amp;lt;/dso&amp;gt;&lt;br /&gt;  &amp;lt;/application&amp;gt;&lt;br /&gt;&amp;lt;/tc:tc-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I took a screenshot of the dev console running during the test, to give you an idea of the instantaneous TPS achieved:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HJW28LGpxns/SsTQjPqI9mI/AAAAAAAACug/zkxKa-aH8Zo/s1600-h/Screen+shot+2009-10-01+at+8.52.26+AM.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 312px;" src="http://3.bp.blogspot.com/_HJW28LGpxns/SsTQjPqI9mI/AAAAAAAACug/zkxKa-aH8Zo/s400/Screen+shot+2009-10-01+at+8.52.26+AM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5387660358159234658" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-1686419632504686007?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/1686419632504686007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=1686419632504686007' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/1686419632504686007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/1686419632504686007'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2009/10/simple-load-test-in-terracotta.html' title='A simple load test in Terracotta...'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_HJW28LGpxns/SsTQjPqI9mI/AAAAAAAACug/zkxKa-aH8Zo/s72-c/Screen+shot+2009-10-01+at+8.52.26+AM.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-8013263729427560773</id><published>2009-09-02T19:38:00.000-07:00</published><updated>2009-09-03T00:00:54.454-07:00</updated><title type='text'>Great customer service in the cloud</title><content type='html'>It's interesting to see providers moving to and, by proxy, the rest of us relying on, the cloud.&lt;br /&gt;&lt;br /&gt;I just spent a few hours at &lt;a href="http://www.vmworld2009.com/"&gt;VMWorld&lt;/a&gt;, and judging by the size, sophistication, and variety of providers, vendors, products, and companies, virtualization technologies, and in particular, cloud computing, is here to stay.&lt;br /&gt;&lt;br /&gt;Today, Google apologized for it's GMail outage yesterday, with a completely forthright, mature, and encouraging response.  &lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 10px; font-style: italic;"&gt;&lt;br /&gt;Gmail's web interface had a widespread outage earlier today, lasting about 100 minutes. We know how many people rely on Gmail for personal and professional communications, and we take it very seriously when there's a problem with the service. Thus, right up front, I'd like to apologize to all of you — today's outage was a Big Deal, and we're treating it as such. &lt;a href="http://gmailblog.blogspot.com/2009/09/more-on-todays-gmail-issue.html"&gt;&amp;lt;read the rest of Google's post...&amp;gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And, in a twist of fate, just a few days ago I received an email from Netflix.  Apparently they had some trouble with their network while I was trying to watch a tv show using my XBox 360.  Not only did they figure this out, but they sent me an email that offered to discount my monthly fee by 3%.   This is fantastic customer service!  Here's the email in it's entirety:&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 10px; font-style: italic;"&gt;&lt;br /&gt;&lt;b&gt;We're sorry you may have had trouble watching instantly via your Xbox&lt;/b&gt;&lt;br /&gt;&lt;br /&gt; Dear Taylor,&lt;br /&gt;&lt;br /&gt;Last night, you may have had trouble instantly watching movies or TV episodes via your Xbox due to technical issues.&lt;br /&gt;&lt;br /&gt;We are sorry for the inconvenience this may have caused. If you were unable to instantly watch a movie or TV episode last night via your Xbox, click on this account specific link in the next 7 days to apply your 3% credit on your next billing statement. Credit can only be applied once.&lt;br /&gt;&lt;br /&gt;Again, we apologize for any inconvenience, and thank you for your understanding. If you need further assistance, please call us at 1-866-923-0898.&lt;br /&gt;&lt;br /&gt;-The Netflix Team&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Failures do happen.  And today's scaled-out architectures are designed to be resilient to these failures.  But the fact is that even though these designs exist, and are generally very resilient against failures, giving these services availability times numbered in the &lt;a href="http://en.wikipedia.org/wiki/High_availability"&gt;9's&lt;/a&gt;, mistakes in design, implementation, or execution still do happen.&lt;br /&gt;&lt;br /&gt;I say, give these guys massive cred for owning up to their mistakes, and dealing with the consumer in an open and honest way.  That's the way to build solid relationships, and I for one will not look twice when Yahoo! or Blockbuster sends me that next request to join up on their service.  These guys have it figured out, and have sold me as lifelong* customer, even if they're not perfect.&lt;br /&gt;&lt;br /&gt;If only legacy infrastructure (power, cable (grrr Comcast), telephone (AT&amp;T - I'm looking at you)) and the like could understand the value in this approach.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-size: 9pt"&gt;* lifelong in tech years, which is only about 5 years or so ;-)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-8013263729427560773?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/8013263729427560773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=8013263729427560773' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/8013263729427560773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/8013263729427560773'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2009/09/resonsible-behavior-in-cloud.html' title='Great customer service in the cloud'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-1233249341173150138</id><published>2009-06-17T01:37:00.001-07:00</published><updated>2009-06-17T01:51:08.177-07:00</updated><title type='text'>How To Optimize Performance (or how to do Performance Testing right)</title><content type='html'>Optimizing performance requires you to performance test.&lt;br /&gt;&lt;br /&gt;I'm just going to say it - performance testing is hard.  Really hard.&lt;br /&gt;&lt;br /&gt;Ask anyone that's done it before, and they will agree.  If you haven't done it before, well, yeah, sorry.  It's not easy.  But you've got to do it anyway - because the most important thing you will do as a software engineer is performance test.  It's a bit like when your Dad told you "when you grow up to be my age &amp;lt;insert age old wisdom here&amp;gt;" and you didn't believe him?  &lt;br /&gt;&lt;br /&gt;And now you're old enough that you realize, hey, the guy might have had a point?&lt;br /&gt;&lt;br /&gt;Yeah, trust me.  Performance testing is both the hardest, and most important, thing you will ever do in your software engineering career.  Get it right - you'll be a rockstar.  Don't do it - well, I promise you, you'll always be griping about why the amazing software you write is never actually used for "production" apps.&lt;br /&gt;&lt;br /&gt;So here you go, simple steps to performance engineering:&lt;br /&gt;&lt;br /&gt;1) Set goals - what are you trying to accomplish&lt;br /&gt;2) Measure a baseline&lt;br /&gt;3) Identify a bottleneck&lt;br /&gt;4) Fix said bottleneck&lt;br /&gt;5) Repeat until you meet your performance goals&lt;br /&gt;&lt;br /&gt;Did I miss anything?  Ahhh...yes.  TAKE NOTES.&lt;br /&gt;&lt;br /&gt;Let's try again:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) Set goals - what are you trying to accomplish&lt;br /&gt;1a) Take notes&lt;br /&gt;2) Measure a baseline&lt;br /&gt;2a) Take notes&lt;br /&gt;3) Identify a bottleneck&lt;br /&gt;3a) Take notes&lt;br /&gt;4) Fix said bottleneck&lt;br /&gt;4a) Take notes&lt;br /&gt;5) Repeat until you meet your performance goals&lt;br /&gt;&lt;br /&gt;Step 6) -- Report to your boss how much better your application is.  But because of Step 1, you'll be able to tell him/her why it matters, right? :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-1233249341173150138?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/1233249341173150138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=1233249341173150138' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/1233249341173150138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/1233249341173150138'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2009/06/how-to-performance-test.html' title='How To Optimize Performance (or how to do Performance Testing right)'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-5121935146649860302</id><published>2009-04-24T14:31:00.000-07:00</published><updated>2009-04-24T15:04:37.747-07:00</updated><title type='text'>Terracotta and Spring - Powering High Throughput JEE Applications</title><content type='html'>Recently, Terracotta did a webinar with Spring founder &lt;a href="http://www.springsource.com/people/csampaleanu"&gt;Colin Sampaleanu&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;The webinar starts out by covering the benefits that a Spring+Hibernate+Terracotta application can deliver for your Java JEE application.   The latter half is dedicated to running through a reference application that provides a solid starting point as you explore all that Terracotta+Spring can provide.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Examinator&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The application demonstrated in the webinar is called "Examinator", and was jointly developed by SpringSource and Terracotta.   Briefly, &lt;br /&gt;&lt;br /&gt;&lt;div style="margin: 0ex 4ex; font-style: italic; font-weight: bold"&gt;Examinator is a full stack reference application which demonstrates with code how to build a higly scalable, highly available application using Spring, Hibernate and Terracotta&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Highlights include:&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Frameworks:&lt;/span&gt; Spring MVC, Spring Security, Spring Web Flow, Hibernate&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Scale:&lt;/span&gt; 16 application servers, 20,000 concurrent users&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Latency:&lt;/span&gt; Max of 5 ms response time&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;span style="font-weight:bold;"&gt;Find out more&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For a full-length recording of the Webinar available for free visit &lt;a href="https://terracotta.webex.com/terracotta/lsr.php?AT=pb&amp;SP=EC&amp;rID=1261917&amp;rKey=35185C4070100891"&gt;http://terracottech.webex.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For a complete reference&amp;mdash;everything you need to know including full documentation, how install and run Examinator&amp;mdash; visit &lt;a href="http://www.terracotta.org/web/display/orgsite/Web+App+Reference+Implementation"&gt;http://www.terracotta.org&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;You can also access a live demo of Examinator at &lt;a href="http://reference.terracotta.org/examinator/"&gt;reference.terracotta.org&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;SpringOne 2009&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Speaking of Spring, I'll be attending the Terracotta booth at &lt;a href="http://europe.springone.com/europe-2009/"&gt;SpringOne Europe 2009 &lt;/a&gt;this coming week (April 27-29, 2009) in Amsterdam.  Stop by if you're attending.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-5121935146649860302?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/5121935146649860302/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=5121935146649860302' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5121935146649860302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5121935146649860302'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2009/04/terracotta-and-spring-powering-high.html' title='Terracotta and Spring - Powering High Throughput JEE Applications'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-2448741014319518453</id><published>2009-04-22T08:16:00.001-07:00</published><updated>2009-04-22T13:56:42.679-07:00</updated><title type='text'>A simple tip for new Terracotta users - always run the Terracotta Developer Console</title><content type='html'>With the release of Terracotta 3.0, I hope many of you have or are considering checking out Terracotta to see if it can help with scalability and availability of your Java application.&lt;br /&gt;&lt;br /&gt;Of course &lt;a href="http://www.terracotta.org"&gt;www.terracotta.org&lt;/a&gt; - in particular the &lt;a href="http://www.terracotta.org/web/display/orgsite/Tutorials"&gt;tutorials&lt;/a&gt; section with many simple recipes for exploring the many uses of Terracotta is a good place to get started.&lt;br /&gt;&lt;br /&gt;But before you do any of that, I'd like to point out a best practice for learning and working with Terracotta.  So, here's my tip for whenever you are working with Terracotta:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;TIP: ALWAYS RUN THE TERRACOTTA DEVELOPER CONSOLE&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;It's easy to do, so I recommend before you run any samples, try an recipes, or work with your application, make sure to have the Developer Console running at all times.&lt;br /&gt;&lt;h4&gt;How to run the Terracotta Developer Console&lt;/h4&gt;&lt;br /&gt;Running the Developer Console is easy.  There are many ways depending on your context:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;From the Welcome Application: Click the "Developer Console" link&lt;/li&gt;&lt;br /&gt;&lt;li&gt;From the command line: Run &lt;code&gt;$TC_HOME/bin/dev-console.sh|bat&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;From Maven: Run &lt;code&gt;$ mvn tc:dev-console&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;From Eclipse: Select &lt;code&gt;Show Developer Console&lt;/code&gt; from the Terracotta menu.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;Once you've got the Developer Console running, make sure to select the &lt;code&gt;Connect automatically&lt;/code&gt; checkbox before connecting&amp;mdash;this option will automatically connect the Developer Console to your cluster meaning you don't have to select "connect" every time you run a new cluster instance.  This is very useful during experimentation (running sample demos and recipes) and integration testing.  &lt;br /&gt;&lt;h4&gt;Why should you run the Terracotta Developer Console?&lt;/h4&gt;We designed it so that you have access to a large array of information right at your fingertips.  In particular, let's look at the user interface which is new in Terracotta 3.0:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HJW28LGpxns/Se81_gBGWdI/AAAAAAAACVM/EpKbQ1b5F9k/s1600-h/Picture+1.png"&gt;&lt;img style="margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 400px; height: 238px;" src="http://2.bp.blogspot.com/_HJW28LGpxns/Se81_gBGWdI/AAAAAAAACVM/EpKbQ1b5F9k/s400/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327536249245161938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One thing that I hope jumps out at you immediately is the presence of a new array of "speedo" dials - somewhat like the array of instruments that greets you when you step into the driver's seat of an automobile.&lt;br /&gt;&lt;br /&gt;The resemblance isn't accidental.  Those dials are there to give you up-to-the-second information about what's going on in the cluster - and to help pinpoint a problem - if there is one.  Let's take a closer look:&lt;br /&gt;&lt;h4&gt;Making use of the Speed Dials&lt;/h4&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HJW28LGpxns/Se83WbIdgaI/AAAAAAAACVc/2tDv31q5olM/s1600-h/dials.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 72px;" src="http://4.bp.blogspot.com/_HJW28LGpxns/Se83WbIdgaI/AAAAAAAACVc/2tDv31q5olM/s400/dials.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327537742582481314" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you can see, the dials are arrayed from left to right, giving you vital statistics about the cluster.  The dials are separated into two groups:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Write Transacions&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Impeding Factors&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;The &lt;b&gt;Write Transactions&lt;/b&gt; dial contains a measure of the number of write transactions that are occurring in the system.  Read transactions with Terracotta are exceedingly cheap (so cheap in fact that we don't measure them).  Write transactions are a good measure of work being done in the cluster - so this measure is effectively a measure of how fast your application is running.&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;Impeding Factors&lt;/b&gt; set of dials shows you a set of seven dials that show you statistics about other types of activity in the system.  The activities displayed include such statistics as &lt;i&gt;Object Creation Rate/s&lt;/i&gt;  &amp;mdash; the amount of new objects being added to the clustered heap per second &amp;mdash; and &lt;i&gt;Lock Recalls/s&lt;/i&gt; &amp;mdash; the amount of lock requests that are being transferred from one client node to another.&lt;br /&gt;&lt;h4&gt;Making use of the Runtime Statistics&lt;/h4&gt;Another very useful feature is the Runtime statistics panel.  You can access this feature from the left menu tree by selecting the &lt;code&gt;Runtime Statistics&lt;/code&gt; node.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HJW28LGpxns/Se87eVrWc9I/AAAAAAAACVk/8KBvq8L-wJY/s1600-h/runtime+stats.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 219px;" src="http://1.bp.blogspot.com/_HJW28LGpxns/Se87eVrWc9I/AAAAAAAACVk/8KBvq8L-wJY/s400/runtime+stats.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327542276603671506" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The runtime statistics give you access to a wealth of realtime data with historical views.  Unlike the Speedo Dials, the runtime statistics are kept for a longer period of time and graphed for you so you can see a historical view of how your application has been behaving.&lt;br /&gt;&lt;h4&gt;Putting it all together&lt;/h4&gt;The Speed Dials give you instantaneous information - so they are visible all the time.&lt;br /&gt;&lt;br /&gt;Look at the &lt;i&gt;Write Transactions&lt;/i&gt; to measure your speed, and monitor the &lt;i&gt;Impeding Factors&lt;/i&gt; to make sure nothing is slowing you down.  &lt;br /&gt;&lt;br /&gt; If there's something worth looking at in more detail, switch to the runtime statistics for more detailed information.  &lt;br /&gt;&lt;br /&gt;If there is a problem worth investigating, use the &lt;i&gt;Diagnostics&lt;/i&gt; tools such as the &lt;i&gt;Lock Profiler&lt;/i&gt; or &lt;i&gt;Cluster Wide Thread Dump&lt;/i&gt; to debug further.&lt;br /&gt;&lt;br /&gt;In other words &lt;b&gt;ALWAYS RUN THE TERRACOTTA DEVELOPER CONSOLE!&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-2448741014319518453?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/2448741014319518453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=2448741014319518453' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2448741014319518453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2448741014319518453'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2009/04/simple-tip-for-new-terracotta-users.html' title='A simple tip for new Terracotta users - always run the Terracotta Developer Console'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_HJW28LGpxns/Se81_gBGWdI/AAAAAAAACVM/EpKbQ1b5F9k/s72-c/Picture+1.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-9214944165937237124</id><published>2008-12-14T10:45:00.000-08:00</published><updated>2008-12-15T08:51:37.472-08:00</updated><title type='text'>Simple Java Messaging</title><content type='html'>Following up on my recent post &lt;a href="http://javathink.blogspot.com/2008/12/java-distributed-lock-manager.html"&gt;Java Distributed Lock Manager&lt;/a&gt;, sometimes you just need a simple way to pass messages between Java processes.  &lt;br /&gt;&lt;br /&gt;Messaging is a very useful pattern in Enterprise Integration, and there are many ways to do it.  &lt;a href="http://activemq.apache.org/camel/"&gt;Apache Camel&lt;/a&gt; is a great tool when you need the flexibility and power to manage complex messaging patterns, including routing, filtering and the like.&lt;br /&gt;&lt;br /&gt;If you just want to do something simple, though, that can be a challenge.  The most common solution, JMS, requires quite a bit of boilerplate code, and requires selecting and running a JMS provider, which means selecting a J2EE container, &lt;a href="http://activemq.apache.org/"&gt;Apache ActiveMQ&lt;/a&gt;, or others.&lt;br /&gt;&lt;br /&gt;So what if you just want a drop-dead &lt;a href="http://www.terracotta.org"&gt;simple way of adding messaging to your application&lt;/a&gt;?  Terracotta gives you that.  (And also integrates well with other solutions, like Apache Camel if you need more power later on).  &lt;br /&gt;&lt;br /&gt;Simple messaging in Terracotta is built on the notion of clustering a &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/LinkedBlockingQueue.html"&gt;LinkedBlockingQueue&lt;/a&gt;.  Just as a LinkedBlockingQueue is used to pass messages between threads in a single JVM, it will be used in combination with Terracotta's JVM-level clustering to provide message passing between JVMs.&lt;br /&gt;&lt;br /&gt;To demonstrate, here is a simple example. &lt;pre name="code" class="java"&gt;import java.io.*;&lt;br /&gt;import java.util.concurrent.*;&lt;br /&gt;import java.util.concurrent.locks.*;&lt;br /&gt;&lt;br /&gt;public class SimpleMessage&lt;br /&gt;{&lt;br /&gt;    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();&lt;br /&gt;    private static BlockingQueue&amp;lt;String&amp;gt; queue = new LinkedBlockingQueue&amp;lt;String&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public static void receive() throws InterruptedException&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Receiving messages...");&lt;br /&gt;        while (true) {&lt;br /&gt;            String msg = queue.take();&lt;br /&gt;            System.out.println("msg &amp;gt;&amp;gt; " + msg);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void send() throws Exception&lt;br /&gt;    {&lt;br /&gt;        while (true) {&lt;br /&gt;            System.out.print("Enter a message&amp;gt; "); System.out.flush();&lt;br /&gt;            String msg = new BufferedReader(new InputStreamReader(System.in)).readLine();&lt;br /&gt;            queue.put(msg);&lt;br /&gt;        }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static void main(String[] args) throws Exception&lt;br /&gt;    {&lt;br /&gt;        // we use the presence of a lock to distinguish receiver from sender&lt;br /&gt;        if (lock.writeLock().tryLock()) {&lt;br /&gt;            receive();&lt;br /&gt;        } else {&lt;br /&gt;            send();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The app consist of two modes - a receiver mode and a sender mode.  Normally, you would have an application specific mechanism of choosing whether you wanted to send messages or receive messages.  For this example, we use a simple lock (for more information on using a ReentrantReadWriteLock with Terracotta, read the &lt;a href="http://www.terracotta.org/web/display/orgsite/Recipe?recipe=rrwl"&gt;ReentrantReadWriteLock recipe&lt;/a&gt;).  When free, the lock indicates no processes are receiving messages, so the process takes on the "receiver" mode.  All subsequent processes take on the "sender" mode when the lock is held.&lt;br /&gt;&lt;br /&gt;So let's run it with Terracotta and see how it works.  First, we need to "cluster" the app.  We need the &lt;code&gt;lock&lt;/code&gt; and &lt;code&gt;queue&lt;/code&gt; objects to be the same cluster-wide, which in Terracotta is called a root.  So our Terracotta configuration file looks like:&lt;pre name="code" class="xml"&gt;&amp;lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;application&amp;gt;&lt;br /&gt;    &amp;lt;dso&amp;gt;&lt;br /&gt;      &amp;lt;roots&amp;gt;&lt;br /&gt;        &amp;lt;root&amp;gt;&lt;br /&gt;          &amp;lt;field-name&amp;gt;SimpleMessage.lock&amp;lt;/field-name&amp;gt;&lt;br /&gt;        &amp;lt;/root&amp;gt;&lt;br /&gt;        &amp;lt;root&amp;gt;&lt;br /&gt;          &amp;lt;field-name&amp;gt;SimpleMessage.queue&amp;lt;/field-name&amp;gt;&lt;br /&gt;        &amp;lt;/root&amp;gt;&lt;br /&gt;      &amp;lt;/roots&amp;gt;&lt;br /&gt;    &amp;lt;/dso&amp;gt;&lt;br /&gt;  &amp;lt;/application&amp;gt;&lt;br /&gt;&amp;lt;/tc:tc-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;Now, let's run two JVMs with Terracotta.  First, we start a server instance:&lt;pre&gt;$ start-tc-server.sh&lt;br /&gt;2008-12-14 10:26:18,246 INFO - Terracotta Server has started up as ACTIVE node on&lt;br /&gt;  0.0.0.0:9510 successfully, and is now ready for work.&lt;br /&gt;&lt;/pre&gt;Then, we start our JVMs. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;JVM 1:&lt;/b&gt;&lt;pre&gt;$ dso-java.sh SimpleMessage&lt;br /&gt;Receiving Messages...&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;JVM 2:&lt;/b&gt;&lt;pre&gt;$ dso-java.sh SimpleMessage&lt;br /&gt;Enter a message&gt; &lt;br /&gt;&lt;/pre&gt;Here, we enter a message, and see that it is printed in JVM 1:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JVM 2:&lt;/b&gt;&lt;pre&gt;$ dso-java.sh SimpleMessage&lt;br /&gt;Enter a message&gt; hello world&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;JVM 1:&lt;/b&gt;&lt;pre&gt;$ dso-java.sh SimpleMessage&lt;br /&gt;Receiving Messages...&lt;br /&gt;msg &gt;&gt; hello world&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Further exploration&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Try starting another JVM and see that they can both send messages to JVM 1.  Try killing the receiver JVM and send messages to it.   Then start another JVM.  Since the lock is no longer held (Terracotta automatically releases any locks held by a JVM that exits the cluster) the new JVM will take on the receiver mode.  Any messages sent while there was no receiver will have been queued, and will be printed on the startup of this new node.&lt;br /&gt;&lt;br /&gt;And of course, you can see all the activity in the cluster.  Try taking the receiver down again, send some messages using the sender nodes, then &lt;a href="http://www.terracotta.org/web/display/docs/Admin+Console+Guide"&gt;run the admin console&lt;/a&gt;.  You'll be able to inspect the messages in the queue using the clustered heap browser.&lt;br /&gt;&lt;br /&gt;This is just  a demonstration of course - so to keep it simple I used a &lt;code&gt;String&lt;/code&gt; as the message - but you could use any class.&lt;br /&gt;&lt;br /&gt;For more fun with Terracotta, &lt;a href="http://www.terracotta.org/web/display/orgsite/Tutorials"&gt;try the helpful "recipes" at Terracotta.org&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;(Note, &lt;a href="http://javathink.blogspot.com/2008/03/stupid-simple-jvm-coordination.html"&gt;I've blogged about simple coordination&lt;/a&gt; in the past using Terracotta, which is similar)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-9214944165937237124?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/9214944165937237124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=9214944165937237124' title='37 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/9214944165937237124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/9214944165937237124'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/12/simple-java-messaging.html' title='Simple Java Messaging'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>37</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-7030863533325288227</id><published>2008-12-11T22:14:00.000-08:00</published><updated>2009-03-17T02:20:05.713-07:00</updated><title type='text'>Java Distributed Lock Manager</title><content type='html'>Sometimes you just need a simple way to coordinate activities across more than one java process.  There's a lot of choices out there.  The database, JMX, distributed caches, JMS, filesystems.  It would be nice if there was a simple, easy way to get distributed locks in a J2SE, J2EE, Web, SOAP, or AJAX application?  There is.&lt;br /&gt;&lt;br /&gt;Terracotta provides one of the &lt;a href="http://www.terracotta.org"&gt;easiest ways to get a distributed lock manager in your Java application&lt;/a&gt;.   Terracotta plugs right in to normal Java threading constructs&amp;mdash;&lt;code&gt;synchronized&lt;/code&gt;, &lt;code&gt;wait/notify&lt;/code&gt;, &lt;code&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html"&gt;java.concurrent.locks.ReentrantReadWriteLock&lt;/a&gt;&lt;/code&gt;, and even &lt;code&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html"&gt;java.concurrent.CyclicBarrier&lt;/a&gt;&lt;/code&gt;, which means you basically already know how to use Terracotta as a lock manager.&lt;br /&gt;&lt;br /&gt;To demonstrate, let's work up a simple locking example and then drop Terracotta in.  Our app will consist of acquiring a lock, "do some work" in a simple loop, and repeat.  Here's the code (&lt;code&gt;LockExample.java&lt;/code&gt;):&lt;br /&gt;&lt;pre name="code" class="java"&gt;public class LockExample&lt;br /&gt;{&lt;br /&gt;    private static Object lock = new Object();&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception&lt;br /&gt;    {&lt;br /&gt;        while (true) {&lt;br /&gt;            System.out.print("Waiting for the lock..."); System.out.flush();&lt;br /&gt;            synchronized (lock) {&lt;br /&gt;                System.out.print("I got the lock, doing work");&lt;br /&gt;                for (int i = 0; i &lt; 4; i++) {&lt;br /&gt;                    Thread.currentThread().sleep(1000);&lt;br /&gt;                    System.out.print("."); System.out.flush();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            System.out.println("done");&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;Simple.  If we run this on the command line, we get:&lt;pre&gt;$ javac LockExample.java&lt;br /&gt;$ java LockExample&lt;br /&gt;Waiting for the lock...I got the lock, doing work....done&lt;br /&gt;Waiting for the lock...I got the lock, doing work....done&lt;br /&gt;&lt;/pre&gt;During the "work" part the "."'s are added 1 every second for four seconds.  Fancy.&lt;br /&gt;&lt;br /&gt;Let's add Terracotta.  We need a &lt;code&gt;tc-config.xml&lt;/code&gt; file which tells Terracotta how to provide the appropriate clustering behavior to our application:&lt;pre name="code" class="xml"&gt;&amp;lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;application&amp;gt;&lt;br /&gt;    &amp;lt;dso&amp;gt;&lt;br /&gt;      &amp;lt;locks&amp;gt;&lt;br /&gt;        &amp;lt;autolock&amp;gt;&lt;br /&gt;           &amp;lt;method-expression&amp;gt;void LockExample.main(..)&amp;lt;/method-expression&amp;gt;&lt;br /&gt;        &amp;lt;/autolock&amp;gt;&lt;br /&gt;      &amp;lt;/locks&amp;gt;&lt;br /&gt;      &amp;lt;roots&amp;gt;&lt;br /&gt;        &amp;lt;root&amp;gt;&lt;br /&gt;          &amp;lt;field-name&amp;gt;LockExample.lock&amp;lt;/field-name&amp;gt;&lt;br /&gt;        &amp;lt;/root&amp;gt;&lt;br /&gt;      &amp;lt;/roots&amp;gt;&lt;br /&gt;    &amp;lt;/dso&amp;gt;&lt;br /&gt;  &amp;lt;/application&amp;gt;&lt;br /&gt;&amp;lt;/tc:tc-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;Now, let's run two JVMs with Terracotta.  First, we start a server instance:&lt;pre&gt;$ start-tc-server.sh&lt;br /&gt;2008-12-11 22:26:18,246 INFO - Terracotta Server has started up as ACTIVE node on&lt;br /&gt;  0.0.0.0:9510 successfully, and is now ready for work.&lt;br /&gt;&lt;/pre&gt;Then, we start our JVMs. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;JVM 1:&lt;/b&gt;&lt;pre&gt;$ dso-java.sh LockExample&lt;br /&gt;Waiting for the lock...I got the lock, doing work....done&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;JVM 2:&lt;/b&gt;&lt;pre&gt;$ dso-java.sh LockExample&lt;br /&gt;Waiting for the lock...&lt;br /&gt;&lt;/pre&gt;It's a bit hard to demonstrate in a blog post, but the lock ping-pongs between the JVMs.  That's it!  &lt;br /&gt;&lt;br /&gt;For more fun with distributed lock coordination, try these helpful "recipes":&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.terracotta.org/web/display/orgsite/Recipe?recipe=rrwl"&gt;ReentrantReadWriteLock&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.terracotta.org/web/display/orgsite/Recipe?recipe=cyclicbarrier"&gt;CyclicBarrier&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-7030863533325288227?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/7030863533325288227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=7030863533325288227' title='24 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/7030863533325288227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/7030863533325288227'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/12/java-distributed-lock-manager.html' title='Java Distributed Lock Manager'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>24</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-5215589960458418400</id><published>2008-11-22T20:38:00.001-08:00</published><updated>2009-02-21T19:46:51.487-08:00</updated><title type='text'>Sales 101: The 5 sales archetypes</title><content type='html'>There's a lot they don't teach you in school.  As an engineer, most of the things I rely on day to day they never even so much as mentioned when I was in college, things like bug tracking, revision control, heck even writing error messages.&lt;br /&gt;&lt;br /&gt;If you're an engineer, and in sales, it's even worse.  I have spent the better half of my career in pre and post-sales as a "solutions architect" before moving on to product management.  One thing that I have found to be useful is how to identify the person you are talking to on the other end of the phone.&lt;br /&gt;&lt;br /&gt;I am not talking about figuring out if you are talking to a developer, a manager, an  architect or a CEO.  I mean what kind of person is this - what problems do they have, what kind of ego do they have, but most importantly, are they actually going to spend money.   Like it or not, these considerations make a major contrbution to chances of your success.   &lt;br /&gt;&lt;br /&gt;So here's the 5 kinds of people you are most likely to meet, how to identify them, and what they mean to the bottom-line.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1.  The beard-tugger&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Summary:&lt;/span&gt; The beard-tugger thinks he is smarter than everyone else, and is committed to proving it.  Thus he will spend the entire sales-pitch showing you just how smart he is.  &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Tell tale signs you have a beard-tugger:&lt;/span&gt; For every feature you talk about in your product, the beard-tugger will analyze it in 5 different ways and 10 different contexts.  If he sees the slightest hole in your theory or implementation, he's bound to ask a question about it. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Pros:&lt;/span&gt; If you like to get into the guts of the product with someone, this is a great person to do it with.  Remember though that if you are trying to sell this person, you need to let them "win" - e.g. never show them up to be lesser than the audience, or you risk losing them as a champion of your product.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Cons:&lt;/span&gt; There is no faster way to sink a pitch than to rat-hole on some minor detail of your product.  The beard-tuggers middle name is rat-hole, so be careful.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2.  The tire-kicker&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Summary:&lt;/span&gt; The tire-kicker is out for a good time.  They will take a sales call from anyone, and don't really have an agenda.  They just want to see what you have.  Often, this person thinks of themselves as "knowledgable about the market" so they will talk to you just to get a feel for your product to reinforce that feeling.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Tell tale signs you have a tire-kicker:&lt;/span&gt; if your product can be used in 10 different ways, he wants to know about every one of them.  If you ask them about the specific problem they are looking to solve (and you should) the answer will be vague or none at all.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Pros:&lt;/span&gt; none really.  This person may ultimately be a champion for you when they come around to solving a problem, so don't shun them.  But you should get on with your life as soon as you can.  Pitch your wares succinctly and move on.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Cons:&lt;/span&gt; big time suck.  If you are not careful this person could come back time and time again, without a real problem to solve.  That could be a big time sink for no real opportunity for business, in other words, a real waste of your time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3.  The science-experiment&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Summary:&lt;/span&gt; Similar to the tire-kicker, but a little more involved, the science-experimenter is likely to have a problem in mind and wants to solve it, but there's generally no business behind it.  This person is likely to be "exploring" technologies, but has picked yours as a likely candidate for a solution.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Tell tale signs you have a science-experiment: &lt;/span&gt; this person is allocating resources to a project to test out your product - e.g. run a POC (Proof of Concept).  But if you press them, you will find there are no hard and fast requirements, so everything is either made up or guesswork. This person is likely to be enthusiastic both about their use case, and your product.  They are probably even more enthusiastic about the opportunity for the mutual relationship to grow.  &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Pros:&lt;/span&gt; If you are successful, this could blossom into a sale, and the science-experimenter will probably tell you that at least 5 times in the span of 20 minutes.  &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Cons: &lt;/span&gt; A science-experiment goes nowhere 9 times out of 10.  Stay away because there are no real requirements, and even if you succeed (which is unlikely, given the lack of a real requirement or business driver) there is unlikely to be a pot of gold at the end of this relationship, despite the claims of the science-experimenter to the contrary.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4.  The delusional&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Summary: &lt;/span&gt; This person is trying to use your product either for an outlandish use case, in an extreme way, or worse, in every possible way (e.g. they think you have the silver-bullet to every problem known to man).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Tell tale signs you have a person with delusions of grandeur&lt;/span&gt;  on the line is that they will be obsessed with how successful their product &lt;span style="font-style:italic;"&gt;will&lt;/span&gt; be.  That is to say, they have either no product, or a very small product at the moment, and this person is most likely obsessed with the massive growth they are just about to incur.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Pros:&lt;/span&gt; None.  This is one of the most dangerous people to engage with.  Get out fast.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Cons:&lt;/span&gt; Very likely to be enthusiastic with your product and want to POC it.  This is the most dangerous of people, because they will be pandering to &lt;span style="font-style:italic;"&gt;your&lt;/span&gt; ego, which means you will be very easily swayed by them because they believe in you, and they love your product.  They will spend a very long time in a POC with your product, because the requirements will likely be unrealistic bordering on ridiculous.  If you bend to their whims, you will likely be adding features/fixing bugs that have no bearing on real business.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;5.  Your customer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Summary: &lt;/span&gt; This is the person you want to sell to.  They have a business case, and likely some pain.  When you discover what that pain is, you should have a product that solves that pain, for less money then they are currently spending.  &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Tell tale signs you are talking to your ideal customer:&lt;/span&gt;  at the end of your initial call with this person, they should have asked you how much your product costs, and they should be wary that your product can actually solve their problem (afterall, nothing else has to date), but be slightly optimistic that maybe you can solve their problem, and be willing to try.  They should have a use case that is within the bounds of what your product can solve, and they should be interested in what the next steps are after the call.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Pros:&lt;/span&gt; Sell them quickly - this is where you should be spending your time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Cons:&lt;/span&gt; None - your only challenge is to identify this person.  If you don't, you're losing money.&lt;br /&gt;&lt;br /&gt;Now, go out there and make some money! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-5215589960458418400?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/5215589960458418400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=5215589960458418400' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5215589960458418400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5215589960458418400'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/11/sales-101-5-sales-archetypes.html' title='Sales 101: The 5 sales archetypes'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-3885535513983081863</id><published>2008-11-17T21:58:00.002-08:00</published><updated>2008-11-19T00:52:33.854-08:00</updated><title type='text'>Grails + Quartz + Terracotta</title><content type='html'>1) Grails &lt;a href="http://grails.org/Terracotta+Plugin"&gt;recently added plug-in support for Terracotta&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;2) Grails &lt;a href="http://grails.org/Quartz+plugin"&gt;recently added plug-in support for Quartz&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;3) &lt;a href="http://forge.terracotta.org/releases/projects/tim-quartz/"&gt;Terracotta supports Quartz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So....wouldn't it be possible to demonstrate Grails, Quartz and Terracotta all working together?  Seems like a fun project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-3885535513983081863?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/3885535513983081863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=3885535513983081863' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/3885535513983081863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/3885535513983081863'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/11/grails-quartz-terracotta.html' title='Grails + Quartz + Terracotta'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-2210537051338655707</id><published>2008-09-21T15:59:00.000-07:00</published><updated>2008-09-21T16:50:47.489-07:00</updated><title type='text'>What is a Memoizer and why should you care about it?</title><content type='html'>A Memoizer is a class created by &lt;a href="http://g.oswego.edu/"&gt;Doug Lea&lt;/a&gt;/&lt;a href="http://www.briangoetz.com/"&gt;Brian Goetz&lt;/a&gt;.  It's basically a create-and-store cache.  That is, it has one very useful property:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A Memoizer is a Generic class that encapsulates the process of creating a value, and remembering the value (memoizing it) so that subsequent calls to get the value will return the memoized value, and not call the Factory method to create it.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Why do you care?&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A Memoizer encapsulates the process of "getOrCreate()" which is highly useful  when you are getting a resource that does not change by a key (think cache) and which is generally considered to be expensive to create. &lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;But, you ask, I already can do that, why do I need a Memoizer?  Glad you should ask.  Memoizer is unique in its solution, because it caches a value by key, but its implementation is very efficient.  It has the following additional properties:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Calls to get items are concurrent&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Calls to get items for a particular key are guaranteed to call the Factory method for that key once and only once&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;It's important to understand that what the Memoizer does is both efficient, and correct.  It's relatively easy to roll your own "&lt;code&gt;getOrCreate()&lt;/code&gt;" method that has only one of those properties (and most people do).  It's not so easy - or obvious - to do both and that's why you should use a Memoizer - and not roll your own.&lt;br /&gt;&lt;br /&gt;To review, let's see the strategy most people would use for calling the Factory method once and only once.  Here's how to call the Factory method once and only once:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;/*** SUB OPTIMAL IMPLEMENTATION THAT IS CORRECT, BUT NOT CONCURRENT ***/&lt;br /&gt;private final Factory&amp;lt;A,V&amp;gt; factory = ...;&lt;br /&gt;private final Map&amp;lt;A, V&amp;gt; map = new HashMap&amp;lt;A, V&amp;gt;();&lt;br /&gt;&lt;br /&gt;public V getOrCreate(A key) {&lt;br /&gt;    synchronized (map) {&lt;br /&gt;        if (map.contains(key)) { return map.get(key); }&lt;br /&gt; &lt;br /&gt;        // create&lt;br /&gt;       V value = factory.create(key);&lt;br /&gt;       map.put(key, value);&lt;br /&gt;       return value;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But of course, the line &lt;code&gt;synchronized (map)&lt;/code&gt; should be a tip-off that this implementation is not concurrent &lt;br /&gt;since there is only a single lock protecting access to our map.  Can we do better?  Sure.  Let's use a ConcurrentHashMap to make our &lt;code&gt;getOrCreate()&lt;/code&gt; method concurrent (but as we'll see, will not have the once-and-only-once property):&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;/*** SUB OPTIMAL IMPLEMENTATION THAT IS CONCURRENT, BUT NOT CORRECT ***/&lt;br /&gt;private final Factory&amp;lt;A,V&amp;gt; factory = ...;&lt;br /&gt;private final ConcurrentMap&amp;lt;A, V&amp;gt; map = new ConcurrentHashMap&amp;lt;A, V&amp;gt;();&lt;br /&gt;&lt;br /&gt;public V getOrCreate(A key) {&lt;br /&gt;    if map.contains(key) { return map.get(key); }&lt;br /&gt;    &lt;br /&gt;    // map doesn't contain key, create one -- note that first writer wins,  &lt;br /&gt;    // all others just throw away their value&lt;br /&gt;    map.putIfAbsent(key, Factory.create(key)); &lt;br /&gt;&lt;br /&gt;    // return the value that won&lt;br /&gt;    return map.get(key);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So, those are the two implementations, each implements either correctness (once and only once) or performance (concurrent puts and gets) but neither accomplishes both simultaneously.  Of course, that's the whole point of this article.  To introduce you to Memoizer.  So how does Memoizer ensure correctness (once and only once) while being simultaneously concurrent?&lt;br /&gt;&lt;br /&gt;The trick is to &lt;i&gt;delay&lt;/i&gt; the call to the Factory create method into the future.  We already know how to make the operation concurrent, but making the operation concurrent means that the first writer will win, and all the other writers will lose.  So we &lt;i&gt;delay&lt;/i&gt; the Factory create call by wrapping that call in a FutureTask.  In other words, instead of putting the &lt;i&gt;actual value&lt;/i&gt; into the map, we put a &lt;i&gt;Future&lt;/i&gt; (which is a wrapper for getting the value sometime in the future) into the Map.  &lt;br /&gt;&lt;br /&gt;(Note: If you have not yet become familiar with the &lt;code&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Future.html"&gt;Future&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html"&gt;FutureTask&lt;/a&gt;&lt;/code&gt; classes introduced in the JDK 1.5, you should)&lt;br /&gt;&lt;br /&gt;By putting a Future into the map - and not our actual value - we can move the work of calling the Factory create method into the future - specifically we can move it until &lt;i&gt;after&lt;/i&gt; the winner of the race to put the value into the map has been determined.  That enables us to call get - which calls create on the Factory - on the one and only Future instance that is contained within the Map.&lt;br /&gt;&lt;br /&gt;The full code for Memoizer illustrates this trick.  Note that the &lt;code&gt;Computable&lt;/code&gt; interface specifies a generic "Factory".  Also note that I have not been able to find a library or canonical reference for Memoizer.  The best I have is here: &lt;a href="http://www.javaspecialists.co.za/archive/Issue125.html"&gt;Memoizer.java&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here it is re-created for your convenience (note that I have adjusted it slightly, for example allowing the user to specify the number of segments created in the underlying ConcurrentHashMap):&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public interface Computable&amp;lt;A, V&amp;gt;&lt;br /&gt;{&lt;br /&gt;    V compute(A arg) throws InterruptedException;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Memoizer&amp;lt;A, V&amp;gt; implements Computable&amp;lt;A, V&amp;gt;&lt;br /&gt;{&lt;br /&gt;    private final ConcurrentMap&amp;lt;A, Future&amp;lt;V&gt;&gt; cache;&lt;br /&gt;    private final Computable&amp;lt;A, V&amp;gt; c;&lt;br /&gt;&lt;br /&gt;    public Memoizer(Computable&amp;lt;A, V&amp;gt; c)&lt;br /&gt;    {&lt;br /&gt;        this(c, 16);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Memoizer(Computable&amp;lt;A, V&amp;gt; c, int segments)&lt;br /&gt;    {&lt;br /&gt;        this.cache = new ConcurrentHashMap&amp;lt;A, Future&amp;lt;V&amp;gt;&amp;gt;();&lt;br /&gt;        this.c = c;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public V compute(final A arg) throws InterruptedException&lt;br /&gt;    {&lt;br /&gt;        while (true) {&lt;br /&gt;            Future&amp;lt;V&amp;gt; f = cache.get(arg);&lt;br /&gt;            if (f == null) {&lt;br /&gt;                Callable&amp;lt;V&amp;gt; eval = new Callable&amp;lt;V&amp;gt;() {&lt;br /&gt;                    public V call() throws InterruptedException {&lt;br /&gt;                        return c.compute(arg);&lt;br /&gt;                    }&lt;br /&gt;                };&lt;br /&gt;                FutureTask&amp;lt;V&amp;gt; ft = new FutureTask&amp;lt;V&amp;gt;(eval);&lt;br /&gt;                f = cache.putIfAbsent(arg, ft);&lt;br /&gt;                if (f == null) {&lt;br /&gt;                    f = ft;&lt;br /&gt;                    ft.run();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            try {&lt;br /&gt;                return f.get();&lt;br /&gt;            } catch (CancellationException e) {&lt;br /&gt;                cache.remove(arg, f);&lt;br /&gt;            } catch (ExecutionException e) {&lt;br /&gt;                LaunderThrowable.launderThrowable(e);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You will of course need the &lt;code&gt;LaunderThrowable&lt;/code&gt; implementation to compile this example.  For a full code listing, hop on over to Terracotta, where I show not only a full working example, but demonstrate how it works with Terracotta across two nodes:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.terracotta.org/web/display/orgsite/Recipe?recipe=memoizer"&gt;Full Memoizer Example with Terracotta&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-2210537051338655707?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/2210537051338655707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=2210537051338655707' title='29 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2210537051338655707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2210537051338655707'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/09/what-is-memoizer-and-why-should-you.html' title='What is a Memoizer and why should you care about it?'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>29</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-6155692599760468878</id><published>2008-09-19T13:10:00.001-07:00</published><updated>2008-09-19T13:41:56.323-07:00</updated><title type='text'>What Is Terracotta?</title><content type='html'>There are so many ways to answer this question - of course our &lt;a href="http://www.terracotta.org"&gt;website&lt;/a&gt; has it's own way.  I recently wrote an e-mail to someone who asked me about Terracotta, and I figured why not share it on my blog?&lt;br /&gt;&lt;br /&gt;Here is my response (updated a bit to be more appropriate for a blog)...&lt;br /&gt;&lt;br /&gt;Terracotta clusters at the level of the JVM.  It is a 100% Java solution. We use the Java API and Memory Model as an abstraction layer into which we inject clustering. &lt;br /&gt;&lt;br /&gt;There are some specific differences with the way that we implement clustering and the way that others do (in fact, in that regard, Terracotta is an entirely unique solution, I do not believe there is anything else like it). &lt;br /&gt;&lt;br /&gt;There are two main differences in Terracotta -the programming model and the performance (the two go hand in hand, one cannot be had without the other).  &lt;br /&gt;&lt;br /&gt;For the programmer , Terracotta is injected at the Java level, meaning that programming a "distributed" application with Terracotta is no different than programming a multi-threaded or concurrent application. Terracotta makes use of all of the concurrent facilities built in to the Java language and API so that the definition and operation of those facilities are extended across a cluster - in other words each node that you add to the cluster simply becomes more threads available to your application.&lt;br /&gt;&lt;br /&gt;Put another way, you program plain POJOs, and Terracotta manages replication services of those POJOs, maintains the identity of those POJOs and provides locking services using either synchronized/wait/notify or java.util.concurrent libraries e.g. ReentrantReadWriteLock - all across the cluster.   (Again the model is simply threads in one node are no different than threads in another node - all standard Java operations "just work")&lt;br /&gt;&lt;br /&gt;Of course this doesn't mean that programming across nodes separated by a network is free. Terracotta doesn't believe that an architect doesn't have to know about that interaction.  We do think one has to architect for Terracotta, but we do not believe you should have to *program* to it. The analogy is much like that of the garbage collector - you don't program to the Java Garbage Collector, but you do architect your application around it's presence.  &lt;br /&gt;&lt;br /&gt;From a high level architectural level, Terracotta uses a tiered architecture. All application nodes talk to the Terracotta Server using TCP (never multicast, and never to one another, P2P is provably not scalable to provide coherent locking).  The Terracotta Server can be clustered (called the Terracotta Server Array) for availability and scalability. It's a lot like the Database in that regard - the Terracotta Server (Array) is the composer in the symphony, coordinating the actions of the application nodes, and storing the data safely - all the way to disk in fact just like a database (and transparently from the application nodes perspective).   When you need more availability or scalability, you just add more Terracotta Servers (no changes to your application are required).&lt;br /&gt;&lt;br /&gt;The replicated data in Terracotta is 100% coherent across the cluster, and always stored safely to disk.  This feature is unique to Terracotta given the performance levels it can achieve, which is the other main difference between Terracotta and all other solutions in the same space.&lt;br /&gt;&lt;br /&gt;Other clustering solutions in the same space &lt;i&gt;claim&lt;/i&gt; to have linear scaling, coherent data, and high performance - all delivered at the same time.  That's basically a lie - none of them come even close to delivering all three at the same time (e.g. coherent data is possible but it's really slow, high scale can be achieved, but only for  non-coherent data).  And no product in the same space delivers the same performance that Terracotta does - it is simply in a class of its own since it is the only product that does not rely on brute force replication techniques such as Java Serialization.  Coupled with some really innovative ways to eliminate or reduce network latency for locking, Terracotta provides a solution that can give data coherence guarantees, with amazing performance.&lt;br /&gt;&lt;br /&gt;What all of this translates into is a solution that is flexible (a programmer can pick and choose his/her own programming stack and domain model), fast (no other clustering solution can send delta updates over the network), and more importantly, manageable.  The Terracotta architecture is not an accident - it is an intentional design decision that ensures that managing a Terracotta Cluster is simple and efficient.  Just like the proven 3-tier architecture of web application nodes and database servers, Terracotta stores application clustered memory in a well known location - the Terracotta Server Array.  Loss of application nodes in a Terracotta Server Cluster, like in a 3-tier application, does not risk data-loss in any way, and likewise, loss of the Terracotta Server process(es) does not jeopardize the data in any way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-6155692599760468878?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/6155692599760468878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=6155692599760468878' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/6155692599760468878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/6155692599760468878'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/09/what-is-terracotta.html' title='What Is Terracotta?'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-2150831600682897867</id><published>2008-09-09T10:46:00.000-07:00</published><updated>2008-09-09T11:19:45.848-07:00</updated><title type='text'>Cluster Deadlocks *ROCK* with Terracotta</title><content type='html'>Am I crazy or what?  &lt;br /&gt;&lt;br /&gt;No not really.  You see I just happen to have seen more than one customer run into a cluster deadlock, and it turns out that solving the issue with Terracotta is awesome (actually, Terracotta can automatically detect it in an upcoming version, but shhh don't tell anyone I told you that)&lt;br /&gt;&lt;br /&gt;It's funny, really, because I have been hearing this dumb idea that somehow clustered deadlocks with Terracotta is actually this really scary thing -- ooooh watch out for that complicated Terracotta thing, it uses LOCKING (oh gosh) and that can lead to CLUSTERED DEADLOCKS.  Oh my.  (Anyone know where I can get a clustered deadlock costume, it's almost halloween!)&lt;br /&gt;&lt;br /&gt;Really.  It's like a bad rumor I keep hearing over and over again.  What do they call that when people try to scare other people with rumors that aren't true .... F.....oh nevermind.   Here's why deadlocks truly are better with Terracotta:&lt;br /&gt;&lt;br /&gt;First, what do we get with Terracotta?&lt;br /&gt;- Kill a JVM, release its lock. &lt;br /&gt;- Kill a JVM, don't lose your state&lt;br /&gt;&lt;br /&gt;Why does that matter?  Well what do you do when you see a deadlock with a regular Java application?   Since it's pretty much hosed, you have to restart it (usually you probably debug the hell out of it first and try to fix the deadlock).   But the app is hosed.  Unless you happen to have coded a "stateless" app - you've also lost your app state.  Bummer :(&lt;br /&gt;&lt;br /&gt;Well, not so with an app running on Terracotta.  First of all, you don't have to kill the whole app.  In fact, if you do actually get a clustered deadlock, you just have to kill &lt;span style="font-style:italic;"&gt;one half&lt;/span&gt; of the deadlock (because the locks are released, get it?) and the other half will actually get to complete it's operation.   How do you do that?  Well since the app state is highly available, you can kill any node at will.  &lt;br /&gt;&lt;br /&gt;So it's simple to resolve a clustered deadlock with Terracotta - just do a rolling restart of every client JVM.  That's it.  When you hit one half of the deadlock, and kill that JVM, the lock that the other side of the clustered deadlock wants will be freed, and it will go on its merry way.  &lt;br /&gt;&lt;br /&gt;Now of course, you still need to debug the hell out of your app :).  When you fix the app, just update it in place, do another rolling restart, and voila!   Fixed deadlock with no downtime.&lt;br /&gt;&lt;br /&gt;So to summarize, deadlocks with Java:&lt;br /&gt;- Have to restart&lt;br /&gt;- Lose app state&lt;br /&gt;- Downtime BAD&lt;br /&gt;&lt;br /&gt;Deadlocks with Terracotta (e.g. Clustered Deadlocks):&lt;br /&gt;- Rolling restart of application nodes&lt;br /&gt;- Preserve application state&lt;br /&gt;- No downtime GOOD&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-2150831600682897867?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/2150831600682897867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=2150831600682897867' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2150831600682897867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2150831600682897867'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/09/cluster-deadlocks-rock-with-terracotta.html' title='Cluster Deadlocks *ROCK* with Terracotta'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-9035443774055394126</id><published>2008-09-08T06:57:00.001-07:00</published><updated>2008-09-08T07:11:45.189-07:00</updated><title type='text'>How can I make sure Terracotta is wired into my application?</title><content type='html'>&lt;div&gt;Per the title of this blog post, I'm going to show you how to make sure that Terracotta is enabled in your application.&lt;/div&gt;&lt;div&gt;One of the funny things about Terracotta is that applications typically don't know it's there.  This is normally a really good thing - it means you can use the 'ole &lt;a href="http://blog.slickedit.com/?p=124"&gt;binary search debug trick&lt;/a&gt;.  (Just remove Terracotta from one half of the application one debug session at a time to quickly narrow down the issue).&lt;/div&gt;&lt;div&gt;But of course, in production, we want to make doubly sure Terracotta is actually running - yeah sure the application might be happy as a clam churning out txns, but we want to make sure those txns are getting replicated for high availability, right? :)&lt;/div&gt;&lt;div&gt;Fortunately, finding out if Terracotta is wired into your app is really easy.  We can make use of the fact that most of the regular Java classes are instrumented by default, so we can use reflection to interrogate one of them.  I chose &lt;code&gt;String&lt;/code&gt; since I think it's a well known class.  Here's the code:&lt;/div&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;   public static final boolean isTCEnabled()&lt;br /&gt;   {       &lt;br /&gt;       try {&lt;br /&gt;           String.class.getMethod("__tc_decompress");&lt;br /&gt;           return true;&lt;br /&gt;       } catch (Exception e) {&lt;br /&gt;           return false;&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;That's it!  We just test to see if a special Terracotta method is present, and if so, we know Terracotta is wired in.  All you have to do is put that into your application startup somewhere, and complain loudly if the method returns &lt;code&gt;false&lt;/code&gt; :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-9035443774055394126?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/9035443774055394126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=9035443774055394126' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/9035443774055394126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/9035443774055394126'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/09/how-can-i-make-sure-terracotta-is-wired.html' title='How can I make sure Terracotta is wired into my application?'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-8888640680190605068</id><published>2008-08-20T00:18:00.000-07:00</published><updated>2008-08-20T01:08:54.121-07:00</updated><title type='text'>Return to civilization...re-launch of Terracotta.org</title><content type='html'>It's been a bit since I posted...we've been really busy cranking away on a new site at Terracotta, and &lt;a href="http://www.terracotta.org/"&gt;it's finally out&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'm really pleased with the site, I hope our users are too.  The goals for the site were:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Simple&lt;/li&gt;&lt;li&gt;Clean&lt;/li&gt;&lt;li&gt;Professional&lt;/li&gt;&lt;/ol&gt;and of course, useful! :)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt; What's New&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Everything, really :).  Well, not everything, but a lot.  On the graphics side of things, we added a lot of &lt;a href="http://jquery.com/"&gt;JQuery&lt;/a&gt; magic.  Not so much for the magic itself, but to make the user experience more pleasant.   Where possible, popup windows and user transitions have been replaced by images that zoom in place, and drop-down panels that help keep the focus where it should be - on the task at hand.&lt;br /&gt;&lt;br /&gt;Also of note, although it's of little practical use now, I implemented a nice CSS effect for our menus  that allows for them to look 3d and stylish but only requires one simple transparent png (no, I don't care about IE6.  It's disgusting).   It's basically a minor modification of the transparent text effect described here in &lt;a href="http://www.digital-web.com/articles/web_standards_creativity_png/"&gt;this blog post&lt;/a&gt;.  I'll probably write this up as a separate post.&lt;br /&gt;&lt;br /&gt;But really, we didn't focus that much on the look or the feel, but the design.  The look and feel came primarily from the design, and the goals, so we knew when something worked, and when it didn't.  If it was distracting, complicated, or busy, it didn't make the cut.  I bet I'll be blogging about the design process before long.&lt;br /&gt;&lt;br /&gt;Here's a brief preview of some of the new design elements:&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Clean Simple Menu&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Pretty self evident I think.&lt;br /&gt;&lt;br /&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_HJW28LGpxns/SKvJOLKwrzI/AAAAAAAABt0/f8PUz7H56rw/s400/Picture+8.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5236500237101608754" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Process Oriented Site Flow&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Well, pretty hard to miss, really.  I hope it doesn't get any easier than 1) 2) 3) 4).  &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HJW28LGpxns/SKvJ0cvBroI/AAAAAAAABt8/iimjuEsIZZI/s1600-h/Picture+10.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_HJW28LGpxns/SKvJ0cvBroI/AAAAAAAABt8/iimjuEsIZZI/s320/Picture+10.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5236500894652149378" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Simple Controls, My Terracotta&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Main controls are on every page, easy to find, but hopefully unobtrusive until you need them.  Also this is the preview of "My Terracotta" - expect more.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HJW28LGpxns/SKvKV5n_TLI/AAAAAAAABuE/xdRZSiE1-3g/s1600-h/Picture+11.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_HJW28LGpxns/SKvKV5n_TLI/AAAAAAAABuE/xdRZSiE1-3g/s400/Picture+11.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5236501469342944434" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Drop Down Panels&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;As I mentioned, drop down panels help get stuff done without leaving the context.  I think a site shouldn't need Help, but we added it anyway.  We all really hope it's unnecessary, but if it helps just one person, it's worth it.  We're really committed to getting everyone successful with Terracotta.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HJW28LGpxns/SKvK_cHsl6I/AAAAAAAABuU/QCpVjIccEUE/s1600-h/Picture+12.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_HJW28LGpxns/SKvK_cHsl6I/AAAAAAAABuU/QCpVjIccEUE/s320/Picture+12.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5236502182977378210" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Lots of new content&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;As I said, we worked really hard on trying to capture how someone should come to Terracotta, learn and understand it, integrate, test, tune, deploy and operate it.  The design and the process are integral to the site - so much so that we even embedded some process diagrams to anchor where the user is in the site.  &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HJW28LGpxns/SKvLl0n3iVI/AAAAAAAABuc/F5gl_XwOvsg/s1600-h/Picture+13.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_HJW28LGpxns/SKvLl0n3iVI/AAAAAAAABuc/F5gl_XwOvsg/s320/Picture+13.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5236502842389793106" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Architecture Patterns&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Finally, we put some massive effort into capturing and describing successful architecture patterns, and how they work with Terracotta.  There's a whole section devoted to describing these patterns, and there is a lot more on the way.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HJW28LGpxns/SKvMEV_VLnI/AAAAAAAABuk/dJ8OJe9xfIU/s1600-h/Picture+15.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_HJW28LGpxns/SKvMEV_VLnI/AAAAAAAABuk/dJ8OJe9xfIU/s320/Picture+15.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5236503366742650482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Go check it out for yourself, we're live at &lt;a href="http://www.terracotta.org"&gt;http://www.terracotta.org&lt;/a&gt;.  We'd love to hear your feedback.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-8888640680190605068?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/8888640680190605068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=8888640680190605068' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/8888640680190605068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/8888640680190605068'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/08/return-to-civilizationlaunch-of.html' title='Return to civilization...re-launch of Terracotta.org'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_HJW28LGpxns/SKvJOLKwrzI/AAAAAAAABt0/f8PUz7H56rw/s72-c/Picture+8.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-2001908384036149462</id><published>2008-07-14T11:36:00.001-07:00</published><updated>2008-07-14T11:38:45.099-07:00</updated><title type='text'>Shortcuts using JIRA</title><content type='html'>At &lt;a href="http://www.terracotta.org"&gt;Terracotta&lt;/a&gt;, we use &lt;a href="http://www.atlassian.com/software/jira/"&gt;JIRA&lt;/a&gt; for issue tracking (see here at &lt;a href="http://jira.terracotta.org"&gt;jira.terracotta.org&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Today, I stumbled on a really nice feature.  On a whim, I thought "I wonder if they implement shortcut (hotkeys)?".  So I tried it out - sure enough "Ctrl+e" edits a JIRA issue, and "Ctrl+s" saves it.  NICE!&lt;br /&gt;&lt;br /&gt;+1 for Atlassian.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-2001908384036149462?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/2001908384036149462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=2001908384036149462' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2001908384036149462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2001908384036149462'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/07/shortcuts-using-jira.html' title='Shortcuts using JIRA'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-3582068216419128450</id><published>2008-03-31T08:57:00.000-07:00</published><updated>2008-04-06T09:48:45.059-07:00</updated><title type='text'>Chronicles of a Terracotta Integration: Compass</title><content type='html'>Last week, I met up with &lt;a href="http://www.kimchy.org/"&gt;Shay Banon&lt;/a&gt;, author of &lt;a href="http://www.opensymphony.com/compass/content/about.html"&gt;Compass&lt;/a&gt;, at the &lt;a href="http://javasymposium.techtarget.com/lasvegas/index.html"&gt;The Server Side: Vegas&lt;/a&gt; conference.  We thought it would be great to see if we couldn't crank out an integration between Terracotta and Compass.  You can read more about our integration from &lt;a href="http://www.kimchy.org/compasslucene-terracotta-integration/"&gt;Shay himself&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I wanted to write a log of our efforts, because I thought it might provide some insight for anyone considering integrating &lt;a href="http://terracotta.org/"&gt;Terracotta&lt;/a&gt; into their own project.  I was particularly happy with our effort, because it outlines what I feel is the best approach for developing with Terracotta.  The approach is actually quite simple.  Because Terracotta adds clustering concerns to your application using configuration, you don't write code directly to Terracotta.  Instead, you just write a simple POJO application &lt;span class="Apple-style-span" style="font-style: italic;"&gt;without&lt;/span&gt; Terracotta, and then add the clustering later.  &lt;br /&gt;&lt;br /&gt;So the approach I recommend is the following:&lt;ol&gt;&lt;li&gt;Figure out how to implement the solution using a single JVM.  NO TERRACOTTA.  Use just simple POJOs and threads.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Implement and test your solution.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It helps to have envisioned, beforehand, what part of your implementation will become a Terracotta root.  But it's not necessary.  If your application is stateful, it will have a root.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Using the root, start with a basic Terracotta config file, &lt;a href="http://www.terracotta.org/confluence/display/docs1/Configuring+Terracotta"&gt;and build up the appropriate config file to cover all the instrumentation and locking&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Test your application again, with a single jvm, but this time with Terracotta.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Tune your implementation.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Move to 2 or more JVMs.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;That's it.  So how did this play out for the Compass integration?  Here is my rough recollection of the action.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;10:00 am - Shook Hands&lt;/span&gt; - Shay and I met up at the conference.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;10:05 am - Started coding&lt;/span&gt; - First we chatted a bit about our strategy.  It seemed easiest to start with the existing Lucene RAMDirectory implementation and tune it up a bit.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;10:30 am - Strategy decided&lt;/span&gt; - Based on my knowledge of Terracotta, and Shay's knowledge of Lucene/Compass, we decided on the following:&lt;ul&gt;&lt;li&gt;Start with the Lucene RAMDirectory implementation, but rewrite it as necessary to fit a simple POJO model&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Since RAMDirectory is mostly unmaintained, we knew we had to just go through the implementation and clean it up.  It comprises about 4 classes total, about 100 lines long, so the task was feasible.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Because Terracotta can just "plug" in to a well written application, and Shay has a comprehensive unit test suite (over 1,000 tests), a load test, and a concurrency test, we'd write the implementation first in POJOs&lt;/li&gt;&lt;br /&gt;&lt;li&gt;After verifying that the implementation works as expected in pure POJOs, then we would work on the configuration to inject Terracotta clustering&lt;/li&gt;&lt;br /&gt;&lt;li&gt;After running the solution with Terracotta, we would tune it.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;And finally, we would wrap up various bits and pieces into a Terracotta Integration Module (TIM)&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;11:30 am - POJO Implementation done&lt;/span&gt; - We ended up rewriting the RAMDirectory, which was fine because it was in need of an overhaul anyway.  Rewriting its implementation meant we now had a good understanding of the implementation.&lt;blockquote&gt;Just a quick note - it was a real joy coding with Shay.  He is a super smart guy, and it's great to work with someone like that.  Of note, he really understands synchronization, which is really important to write applications correctly.  Even better, he really got the principle of writing better code by writing less code.  We went through the RAMDirectory implementation with a weed wacker, and what was left was about 1/2 the code.  That was more readable and more maintainable.  And is better performing.  That was fun.&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;12:00 pm  - Unit Tests pass&lt;/span&gt; - With some minor corrections, we had unit tests passing.  We were both running out of power, and hungry, so we took a break to eat lunch, and agreed to resume in the afternoon.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1:30 pm - Write the Terracotta config file&lt;/span&gt; - While writing the POJO implementation, we already knew the key concepts we were going to need for writing up our config file.  We added the appropriate instrumentation.   We added the locking.   A few config statements later, we had a working Terracotta configuration.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2:00 pm - We had Compass running on Terracotta!&lt;/span&gt; - Approx. time elapsed?  2 1/2 hours (most of which was spent rewriting the RAMDirectory implementation)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2:30 pm - Tuning Time&lt;/span&gt;- At first Shay threw me - he said oh man it looks like it's running really fast.  Except it turns out he wasn't testing the right thing.  And then he tells me oh man its really slow!&lt;br /&gt;&lt;br /&gt;Now don't misunderstand this.  I know Terracotta can go really fast.  But I wasn't in the least bit surprised.  And you shouldn't be either.  How many pieces of code have you ever written that compiled and ran correctly - on the first try?  Right.  One, if you are lucky.&lt;br /&gt;&lt;br /&gt;Terracotta is kind of like that.  The first step is to get it right.  And that means synchronization, and locking, and once you have all that, your application runs correctly, but slowly.&lt;br /&gt;&lt;br /&gt;Fortunately, &lt;span style="font-weight: bold;"&gt;it's easy to fix&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;And so I taught Shay how to tune up his Terracotta integration.  Or rather, I showed him the tools he needed, and he went to town.  I just sort of stood by watching, giving the occasional comment or two.&lt;br /&gt;&lt;br /&gt;This was the fun part.  It was time to take out the Admin console.  The Terracotta Admin console gives you a wealth of information about your application.  Of note:&lt;ul&gt;&lt;li&gt;You can browse your clustered data in realtime&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You can monitor realtime statistics - including Terracotta txns/sec, Java Heap Memory, and CPU&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You can access lock statistics using the lock profiler&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You can snapshot over 30 metrics using the Statistics Recorder &lt;span style="font-style: italic;"&gt;and visualize them using the Snapshot Visualizer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;We started first with the object browser.  Once convinced that we had the right data in the cluster, we moved on to performance.&lt;br /&gt;&lt;br /&gt;On our first run, we measured the Terracotta txns/sec.  I was actually pretty impressed to see that our server on his MacBook Pro was cranking out 10k/sec.  But I knew we wanted this number to be &lt;span style="font-style: italic;"&gt;lower&lt;/span&gt;.  A lot lower.&lt;br /&gt;&lt;br /&gt;So here comes the &lt;span style="font-weight: bold;"&gt;first&lt;/span&gt; rule for tuning Terracotta:  adjust your locking to match your workload.  It turns out that we had enabled an autolock for every single byte being written to the Lucene "files" - and this was hurting us pretty bad.  Because we already had a lock on our byte array that we were writing to, we actually just deleted the synchronization, and the lock config from the method that wrote bytes into the "file" - and we observed a big drop in the Terracotta txns/sec.  We went from the aforementioned 10k/sec to about 1750/sec.&lt;br /&gt;&lt;br /&gt;Now what this means is that the Terracotta server was working just about 10x less for the same workload.  And that means we were doing more work/transaction, and so our performance improved accordingly.  You get the same effect with Hibernate - it batches up a bunch of little POJO updates into a single SQL statement - and that means you can do more &lt;span style="font-style: italic;"&gt;real&lt;/span&gt; work because each SQL statement has more data in it.  Lots of little SQL statements means lots of overhead, and maybe more SQL queries executed/sec, but much less application txns/sec.  Same concept here with locking.&lt;br /&gt;&lt;br /&gt;How did we identify what lock(s) to target?  &lt;br /&gt;&lt;br /&gt;That's the &lt;span style="font-weight: bold;"&gt;second&lt;/span&gt; rule of tuning with Terracotta: USE THE ADMIN CONSOLE&lt;br /&gt;&lt;br /&gt;We used the lock profiler feature included in the Admin Console to determine the exact stack trace that generated these locks.  The process is simple:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Enable lock profiling with stack traces in the Admin Console, &lt;/li&gt;&lt;br /&gt;&lt;li&gt;run your application,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;then refresh the view to get a count of the lock acquires/releases/held times etc.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;sort on # of lock acquires, and now you know what lock is being requested the most, what stack trace caused that lock, and what Terracotta config was responsible for making that lock.&lt;/li&gt;&lt;/ul&gt;Armed with this knowledge, Shay set about eliminating most of our superfluous locking.  Turns out that creating a Lucene "file" is a single threaded affair, so were able to create a single lock to cover the entire process of "writing" to a file, and that cut out about 90% of our locking.&lt;br /&gt;&lt;br /&gt;At the end we got down to about 750 Terracotta txns/sec, which improved the application performance quite a bit.&lt;br /&gt;&lt;br /&gt;Still not satisfied, we moved on to the Terracotta Statistics Recorder.  This is a new feature in Terracotta 2.6.&lt;br /&gt;&lt;br /&gt;Turning on this feature records just about everything you ever wanted to know about your application, Terracotta, the JVM, and your system (including CPU, disk stats, and network stats).  You can export these stats as a CSV file, and import them into our &lt;a href="http://www.terracotta.org/confluence/display/orgsite/Get+Snapshot+Visualization+Tool"&gt;Snapshot Visualizer Tool&lt;/a&gt;.  The SVT gives you a view like so:&lt;br /&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px;" src="http://wiki.terracotta.org/confluence/download/attachments/9142540/Picture%202.png" border="0" alt="" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4:30 pm - TIM time&lt;/span&gt; - We were pretty satisfied with the performance.  Even though we wanted more, Shay felt it was best to focus on turning Compass into a TIM (Terracotta Integration Module).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5:30 pm - Time to call it quits&lt;/span&gt; - We had hacked up the ant build.xml file to get ourselves a TIM in no-time - except that it wouldn't quite load correctly.  (Later we learned we had just specified the filename wrong - easy fix).&lt;br /&gt;&lt;br /&gt;Overall, I thought we had a pretty good day.  We wrote and tuned a Terracotta integration in about 6 hours flat.   With a few more hours of work, &lt;a href="http://www.kimchy.org/compasslucene-terracotta-integration/"&gt;Shay was able to complete the integration&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I was really happy to use some of the recent tools we have been building, like the Lock Profiler and the Statistics Recorder.  Seeing the real-world use of those was invaluable, and confirmed that our commitment to enabling the developer to self-tune by providing enhanced visibility is spot on.&lt;br /&gt;&lt;br /&gt;I am looking forward to people &lt;a href="http://www.terracotta.org/confluence/display/orgsite/Download"&gt;downloading 2.6&lt;/a&gt;, trying out these awesome tools for themselves and &lt;a href="http://www.terracotta.org/confluence/display/orgsite/Get+Snapshot+Visualization+Tool"&gt;providing feedback&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-3582068216419128450?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/3582068216419128450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=3582068216419128450' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/3582068216419128450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/3582068216419128450'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/03/chronicles-of-terracotta-integration.html' title='Chronicles of a Terracotta Integration: Compass'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-6780303869962512989</id><published>2008-03-30T20:55:00.000-07:00</published><updated>2008-04-16T07:17:30.775-07:00</updated><title type='text'>Fun with Distributed Programming</title><content type='html'>Something about the nature of distributed programming makes it quite divisive.  You either love it or despise it.   It's rare that I've run into someone who is ambivalent about it.&lt;br /&gt;&lt;br /&gt;Those that love it, love it because it's hard core.  They're proud to know all the ins and outs of dealing with failures, at the system, network, and application level.  All of that specialized knowledge is also what turns off the rest of us.&lt;br /&gt;&lt;br /&gt;It's kind of like database programming.  There are only a select few who really like it.  The rest of us only do it because we have to.&lt;br /&gt;&lt;br /&gt;Well, I honestly think that Terracotta changes the game.  The key is that Terracotta makes distributed programming &lt;span style="font-style: italic;"&gt;fun&lt;/span&gt; because it takes away most of the distributed programming part, leaving you with just the &lt;span style="font-style: italic;"&gt;fun&lt;/span&gt; part.&lt;br /&gt;&lt;br /&gt;It reminds me of when Linux came out.  Everyone loved it because they could just tinker with different schedulers, and not have to think about building an OS from scratch, just to try out a new idea.  That's what Terracotta is like.   It manages all the hard networking and distributed programming parts, so you get to just play with the algorithms.&lt;br /&gt;&lt;br /&gt;Interested? Let's look at a real (if contrived) example. Let's suppose that you have to build the following:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;a service that executes periodically to do some work&lt;/li&gt;&lt;br /&gt;&lt;li&gt;you don't care where this service runs, only that it runs&lt;/li&gt;&lt;br /&gt;&lt;li&gt;it &lt;span style="font-style: italic;"&gt;has&lt;/span&gt; to run, but one and only one system can run it&lt;/li&gt;&lt;br /&gt;&lt;li&gt;you've got a cluster of n systems, you'd like any one of them to be responsible for running the service&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;If it were a single JVM, you could do a thousand things, like use a java.util.Timer, or Quartz, or even your own simple Thread with a delay loop in it.&lt;br /&gt;&lt;br /&gt;But in a cluster?  The choices for synchronizing the behavior of a number of JVMs across a cluster quickly eliminate the &lt;span style="font-style: italic;"&gt;fun&lt;/span&gt; part, leaving just tedious, boring, and mundane work to be done.  Cluster synchronization you're thinking.  What should I use?  TCP?  Multicast?  Shared file system locking?  A shared database?  RMI?  JMS?  EJBs?  Oh dear.&lt;br /&gt;&lt;br /&gt;But wait.  Terracotta provides synchronization primitives that work across the cluster just like in a single JVM.    So  that means getting this right in a single JVM means getting it right across the cluster.   Could it really be that easy?  And &lt;span style="font-style: italic;"&gt;fun&lt;/span&gt;?  Yes!&lt;br /&gt;&lt;br /&gt;Let's have a look.  For the sake of simplicity, let's do the simple thing.  We'll write the delay loop version.  We'll implement it as a Singleton that implements Runnable, so we can pass the Singleton to a Thread. Here it is:&lt;pre name="code" class="java"&gt;public class SimpleWorkRunner implements Runnable&lt;br /&gt;{&lt;br /&gt;    // mark as a Terracotta root&lt;br /&gt;    private static SimpleWorkRunner singleton = new SimpleWorkRunner();&lt;br /&gt;&lt;br /&gt;    // singleton pattern - private constructor so there is only one&lt;br /&gt;    private SimpleWorkRunner() { }&lt;br /&gt;&lt;br /&gt;    public static SimpleWorkRunner instance() { return singleton; }&lt;br /&gt;&lt;br /&gt;    public synchronized void run()&lt;br /&gt;    {&lt;br /&gt;        while (true) {&lt;br /&gt;            // do work&lt;br /&gt;            ...&lt;br /&gt;            try { Thread.sleep(2000); } catch (InterruptedException e) { }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;That's it!  In every JVM, kick off a new thread against the singleton:&lt;pre&gt;&lt;br /&gt;...&lt;br /&gt;new Thread(SimpleWorkRunner.instance()).start();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And we're done!&lt;br /&gt;&lt;br /&gt;You might have noticed one thing - the run method is synchronized.  In a single JVM, this will mean that more than one Thread executed against this Singleton will result in only one Thread winning the synchronization race, and executing the run() method.  &lt;br /&gt;&lt;br /&gt;In a single JVM, this may not be that important, since there might only ever be one Thread.  But with more than one JVM, we will always start at least one Thread per JVM, and that means we have to ensure, per our requirements, that only one Thread ever enters run() at a time.&lt;br /&gt;&lt;br /&gt;Terracotta takes care of that for us.  We just write the synchronized block, and Terracotta converts that into a cluster lock.  And just like in a single JVM, only one Thread - across the cluster - will win the race to enter the run() method.&lt;br /&gt;&lt;br /&gt;(Also of note is that this particular implementation assumes that one and only one Thread should assume control and never relinquish it.  That was the purpose of the implementation, if you wanted to "bounce" the control around the cluster then we should implement the run method differently depending on the requirements.)&lt;br /&gt;&lt;br /&gt;The Terracotta config for this class is trivial.  We need to tell Terracotta that the singleton should be a Terracotta root.  A Terracotta root will always be the same instance across the entire cluster, which is exactly what we want for a singleton.  And we need to autolock the run method so the synchronization is applied to the cluster, not just a local JVM.  Here's the config for that:&lt;pre name="code" class="xml"&gt;&amp;lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;application&amp;gt;&lt;br /&gt;    &amp;lt;dso&amp;gt;&lt;br /&gt;      &amp;lt;locks&amp;gt;&lt;br /&gt;        &amp;lt;autolock&amp;gt;&lt;br /&gt;           &amp;lt;method-expression&amp;gt;void SimpleWorkRunner.run(..)&amp;lt;/method-expression&amp;gt;&lt;br /&gt;        &amp;lt;/autolock&amp;gt;&lt;br /&gt;      &amp;lt;/locks&amp;gt;&lt;br /&gt;      &amp;lt;roots&amp;gt;&lt;br /&gt;        &amp;lt;root&amp;gt;&lt;br /&gt;          &amp;lt;field-name&amp;gt;SimpleWorkRunner.instance&amp;lt;/field-name&amp;gt;&lt;br /&gt;        &amp;lt;/root&amp;gt;&lt;br /&gt;      &amp;lt;/roots&amp;gt;&lt;br /&gt;    &amp;lt;/dso&amp;gt;&lt;br /&gt;  &amp;lt;/application&amp;gt;&lt;br /&gt;&amp;lt;/tc:tc-config&amp;gt;&lt;/pre&gt;&lt;br /&gt;We didn't have to worry about the dirty details.  Teracotta did.  And that means distributed programming becomes &lt;span style="font-style: italic;"&gt;fun&lt;/span&gt; again!&lt;br /&gt;&lt;br /&gt;Find out more:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.terracotta.org/"&gt;Terracotta.org&lt;/a&gt; - home page&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.terracotta.org/confluence/display/orgsite/Start+Using+Terracotta"&gt;Quick Start&lt;/a&gt; - download and see the demos&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.terracotta.org/confluence/display/howto/Cookbook"&gt;Cookbook&lt;/a&gt; - simple recipes that demonstrate Terracotta in action&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Note that this example is very similar to the &lt;a href="http://www.terracotta.org/confluence/display/howto/Recipe?recipe=singleresource"&gt;Single Resource&lt;/a&gt; recipe.  Try it out first to get started.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Extra Credit&lt;/b&gt;&lt;br /&gt;How does another  JVM in the cluster gain control of the task?  (Hint: Is it possible for more than one Thread to enter the critical section in &lt;code&gt;run()&lt;/code&gt;?  In normal Java - no.  But what happens in Terracotta with more than one JVM?)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-6780303869962512989?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/6780303869962512989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=6780303869962512989' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/6780303869962512989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/6780303869962512989'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/03/fun-with-distributed-programming.html' title='Fun with Distributed Programming'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-2761289734000229515</id><published>2008-03-22T15:56:00.000-07:00</published><updated>2008-07-04T11:45:51.922-07:00</updated><title type='text'>A Clustered ClassLoader</title><content type='html'>If you're building a distributed system, or contemplating building a distributed system, you might have run into this one before:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt; You write and compile your classes in Eclipse&lt;br /&gt;  &lt;li&gt; You try out your classes on your laptop -- they work (woohoo!)&lt;br /&gt;  &lt;li&gt; Its a distributed system so you need to make sure your classes work in a true distributed environment&lt;br /&gt;  &lt;li&gt; You publish your classes to the distributed systems&lt;br /&gt;  &lt;li&gt; You try out your classes -- and they don't work (boo!)&lt;br /&gt;  &lt;li&gt; You fix the problem.&lt;br /&gt;  &lt;li&gt; You publish the classes again.&lt;br /&gt;  &lt;li&gt; Rinse, repeat.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;After doing this a few dozen times, you find that publishing your classes to distributed systems is a total &lt;a href="http://www.urbandictionary.com/define.php?term=PITA"&gt;PITA&lt;/a&gt; that you would rather avoid altogether.&lt;br /&gt;&lt;br /&gt;Or, you might have an application, like &lt;a href="http://www.infoq.com/articles/master-worker-terracotta"&gt;Master/Worker&lt;/a&gt; in which you deploy some part of the application at deploy time, but you deploy other parts of it during run-time.  In the Master/Worker case, you deploy the Master and the Worker, but the Work comes and goes, and you'd like to be able to deploy new Work easily and trivially.  In the Master/Worker case, since Masters are usually in control, and there is a farm of Workers, you'd like to deploy some new work to the Master, and let it send the Work to the Workers.  Knowing about the Work up front on the Workers is a non-starter.&lt;br /&gt;&lt;br /&gt;Some solutions to this problem?&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Java has dynamic code loading capabilities already.  Deploy your class files to a shared filesystem like NFS, and deploy your code to a shared directory. &lt;br /&gt;&lt;li&gt;Java also supports loading code from URLs (thanks to it's Applet heritage) so deploy your code to an HTTP server and you're set&lt;br /&gt;&lt;li&gt;Factor your application such that new classes aren't needed - just make the new definitions "data" driven&lt;br /&gt;&lt;li&gt;Embed a scripting engine, so you can pass Strings and interpret them as code - BeanShell, Jython, JRuby, Javascript, and Groovy all come to mind here...&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Those are all fine solutions, but it never hurts to have more tools in your toolbox does it?  Especially if you're already using &lt;a href="http://www.terracotta.org"&gt;Terracotta&lt;/a&gt;, wouldn't it be nice if there was some way to just leverage Terracotta's core clustering capabilities to build a clustered classloader?&lt;br /&gt;&lt;br /&gt;I've done just that.  Here's how it works:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Your application tries to instantiate a class, which means it asks the currently in scope ClassLoader to instantiate the class (by name)&lt;br /&gt;&lt;li&gt; By launching the application under the clustered classloader, it is in scope.&lt;br /&gt;&lt;li&gt; The clustered class loader has a &lt;code&gt;Map&amp;lt;String, byte[]&amp;gt;&lt;/code&gt; that correlates classnames to bytes&lt;br /&gt;&lt;li&gt; The clustered class loader looks in this &lt;code&gt;Map&lt;/code&gt;, if the classname is found, it uses the &lt;code&gt;byte[]&lt;/code&gt; to create the requested class using &lt;code&gt;&lt;a href=""&gt;defineClass()&lt;/code&gt;&lt;/a&gt;&lt;br /&gt;&lt;li&gt; If the class wasn't found in the &lt;code&gt;Map&lt;/code&gt;, then it looks in the filesystem to find the class&lt;br /&gt;&lt;li&gt; If the class bytes are found on the filesystem, then it reads them into a &lt;code&gt;byte[]&lt;/code&gt;, and stashes them in the clustered &lt;code&gt;Map&amp;lt;String, byte[]&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;li&gt; If the bytes aren't found, it just delegates to the parent classloader&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I've omitted some of the finer details.  The &lt;code&gt;Map&lt;/code&gt; used is actually a &lt;code&gt;Map&amp;lt;String, ClassMetaData&amp;gt; &lt;/code&gt; where &lt;code&gt;ClassMetaData&lt;/code&gt; is a class that holds a &lt;code&gt;long modified&lt;/code&gt; and &lt;code&gt;byte[] bytes&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Let's have a look at the important parts of the ClusterClassLoader:&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class ClusterClassLoader extends ClassLoader&lt;br /&gt;{&lt;br /&gt;    private static final String NAME = "ClusterClassLoader";&lt;br /&gt;    &lt;br /&gt;    private static Map&amp;lt;String, Class&amp;gt; classes = new HashMap&amp;lt;String, Class&amp;gt;();&lt;br /&gt;    private static Map&amp;lt;String, ClassMetaData&amp;gt; bytes = new HashMap&amp;lt;String, ClassMetaData&amp;gt;();&lt;br /&gt;    private static transient boolean loaded;&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;/pre&gt;&lt;code&gt;ClusterClassLoader&lt;/code&gt; is defined to extend &lt;code&gt;ClassLoader&lt;/code&gt;.  It has a &lt;code&gt;NAME&lt;/code&gt; field, which will be used to give a name to this classloader.  This is a requirement for a classloader used by Terracotta.  Normally Terracotta does this for you, but we are defining a new classloader, so we have to follow the naming rules for Terracotta (naming gives ClassLoaders across the cluster a unique identity).&lt;br /&gt;&lt;br /&gt;A &lt;code&gt;classes&lt;/code&gt; field is defined, which caches the result of the &lt;code&gt;defineClass&lt;/code&gt; operation in the local JVM only.   A &lt;code&gt;bytes&lt;/code&gt; field is defined.  This field is marked as a root, so that it can be shared with every other instance of ClusterClassLoader in the cluster.&lt;br /&gt;&lt;br /&gt;The constructor detects if Terracotta is loaded using some reflection, and if so registers the classloader and sets a flag to enable cluster classloading features:&lt;pre name="code" class="java"&gt;    public ClusterClassLoader()&lt;br /&gt;    {&lt;br /&gt;        super(ClusterClassLoader.class.getClassLoader());&lt;br /&gt;        try {&lt;br /&gt;            Class namedClassLoader = findClass("com.tc.object.loaders.NamedClassLoader");&lt;br /&gt;            Class helper = findClass("com.tc.object.bytecode.hook.impl.ClassProcessorHelper");&lt;br /&gt;            Method m = helper.getMethod("registerGlobalLoader", new Class[] { namedClassLoader }); &lt;br /&gt;            m.invoke(null, new Object[] { this });&lt;br /&gt;            loaded = true;&lt;br /&gt;        } catch (Exception e) {&lt;br /&gt;            // tc is not present, so don't do anything fancy&lt;br /&gt;            loaded = false;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next, the definition of &lt;code&gt;loadClass&lt;/code&gt; is overridden:&lt;pre name="code" class="java"&gt;    @Override&lt;br /&gt;    public Class&amp;lt;?&amp;gt; loadClass(String name) throws ClassNotFoundException&lt;br /&gt;    {&lt;br /&gt;        return findClass(name);&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;and so is &lt;code&gt;findClass&lt;/code&gt;: &lt;pre  name="code" class="java"&gt;     @Override&lt;br /&gt;    protected Class&amp;lt;?&amp;gt; findClass(String name) throws ClassNotFoundException&lt;br /&gt;    {        &lt;br /&gt;        if (!loaded) {&lt;br /&gt;            return getParent().loadClass(name);            &lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        Class result = null;&lt;br /&gt;        synchronized (classes) {&lt;br /&gt;            result = classes.get(name);&lt;br /&gt;            if (result != null) { return result; }&lt;br /&gt;&lt;br /&gt;            result = loadClassBytes(name);&lt;br /&gt;            if (result == null) { return getParent().loadClass(name); }&lt;br /&gt;            classes.put(name, result);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;This is the bulk of the algorithm.  The loaded flag is set when the class loader is instantiated.  It used a bit of reflection to determine if Terracotta was even present in the JVM.  If not, it is set to false, and the ClusterClassLoader just delegates to the parent class loader.&lt;br /&gt;&lt;br /&gt;If Terracotta is present, then it checks to see if the class has already been defined.  If so, it is returned directly from the classes cache.  If it has not, then it gets the bytes from the loadClassBytes method.  If that cannot find the bytes, then it asks the parent class loader to load the class.&lt;br /&gt;&lt;br /&gt;The bulk of the implementation is done in the &lt;code&gt;loadClassBytes&lt;/code&gt; method:&lt;pre name="code" class="java"&gt;&lt;br /&gt;    private Class loadClassBytes(String name) throws ClassNotFoundException&lt;br /&gt;    {&lt;br /&gt;        ClassMetaData metaData;&lt;br /&gt;        &lt;br /&gt;        synchronized (bytes) {        &lt;br /&gt;            try {&lt;br /&gt;                File f = null;&lt;br /&gt;                metaData = bytes.get(name);&lt;br /&gt;                URL resource = ClassLoader.getSystemResource(name.replace('.',File.separatorChar)+".class");&lt;br /&gt;                // if resource is non null, then the class is on the local fs (in the cp)&lt;br /&gt;                if (resource != null) {&lt;br /&gt;                    f = new File(resource.getFile());        &lt;br /&gt;                }&lt;br /&gt;                &lt;br /&gt;               if (metaData != null) {&lt;br /&gt;                   // if it's cached, but not on the fs, return it.&lt;br /&gt;                   // if it's cached, but on the fs, check to see if it's &lt;br /&gt;                   // up to date&lt;br /&gt;                   if (f == null || metaData.modified &amp;gt;= f.lastModified()) { &lt;br /&gt;                       return defineClass(name, metaData.bytes, 0, metaData.bytes.length, null);&lt;br /&gt;                   }&lt;br /&gt;                }&lt;br /&gt;                &lt;br /&gt;                // load from the fs&lt;br /&gt;                byte[] classBytes = loadClassData(f);&lt;br /&gt;                Class result =  defineClass(name, classBytes, 0, classBytes.length, null);&lt;br /&gt;&lt;br /&gt;                try {&lt;br /&gt;                    result.getDeclaredField("$__tc_MANAGED");&lt;br /&gt;                    // it's managed so cache it&lt;br /&gt;                    bytes.put(name, new ClassMetaData(f.lastModified(), classBytes));&lt;br /&gt;                } catch (NoSuchFieldException e) {&lt;br /&gt;                    // not managed don't cache it&lt;br /&gt;                }&lt;br /&gt;                return result;&lt;br /&gt;            } catch (IOException e){&lt;br /&gt;                return null;&lt;br /&gt;            } &lt;br /&gt;        }&lt;br /&gt;    }    &lt;br /&gt;&lt;/pre&gt;This method looks for the cached bytes, and for a file that corresponds to the class.  If both are found, then it compares the modified date of the two.  If the modified date of the bytes are greater than or equal to the file, then it returns the bytes in the cache.  Otherwise it loads the bytes from the file.  Once the bytes are loaded, &lt;code&gt;defineClass&lt;/code&gt; is called to turn the bytes into a class file.  &lt;br /&gt;&lt;br /&gt;At this point, the ClusterClassLoader can check to see if the class is instrumented by Terracotta.  Every instance of a class that is shared by Terracotta must be instrumented, so it's not necessary to cache class bytes for classes that are not instrumented by Terracotta.  If the class is instrumented by Terracotta, then the ClusteredClassLoader stashes the bytes into the class bytes cache.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://svn.terracotta.org/svn/forge/projects/labs/tim-clusterclassloader/src/main/java/org/terracotta/modules/clusterclassloader/ClusterClassLoader.java"&gt;Click here if you would like to see the source code to ClusterClassLoader in its entirety&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE: This project has been included in the tim-tclib project, and is a runnable sample.  &lt;a href="http://svn.terracotta.org/svn/forge/projects/labs/tim-tclib/trunk/samples/clusterclassloader/readme.html"&gt;More details can be found in the sample readme.html&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I've put the whole thing together as a simple runnable example.  You just have to check out the source for the project, and run a few simple Maven commands.  You can get the demo from here:&lt;pre&gt;&lt;br /&gt;$ svn checkout http://svn.terracotta.org/svn/forge/projects/labs/tim-clusterclassloader clusterclassloader&lt;br /&gt;$ cd clusterclassloader&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The demo defines a main project, and two sub projects.  The first sub project, sample, is responsible for putting classes into a queue.  The second sub project, sample2, reads from the queue.  To test the effectiveness of the cluster class loader, the second sample of course does not have the classes from the first sub project.&lt;br /&gt;&lt;br /&gt;To run the demo:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Build the project:&lt;pre&gt;&lt;br /&gt;$ mvn install&lt;/pre&gt;&lt;li&gt;Cd to the sample directory, compile and start a tc server:&lt;pre&gt;&lt;br /&gt;$ cd sample&lt;br /&gt;$ mvn package&lt;br /&gt;$ mvn tc:start&lt;/pre&gt;&lt;li&gt; Start the sample process:&lt;pre&gt;&lt;br /&gt;$ mvn tc:run&lt;br /&gt;&lt;/pre&gt;&lt;li&gt; In another terminal, cd to the sample2 directory:&lt;pre&gt;&lt;br /&gt;$ cd sample2&lt;/pre&gt;&lt;li&gt;Compile, and run the example:&lt;pre&gt;&lt;br /&gt;$ mvn package&lt;br /&gt;$ mvn tc:run&lt;/pre&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;If you did everything correctly, you should see:&lt;pre&gt;&lt;br /&gt;[INFO] [node] Waiting for work...&lt;br /&gt;[INFO] [node] This is Callable2 calling!&lt;br /&gt;&lt;/pre&gt;In the second terminal (sample2).  The message printed ("This is Callable2 calling!") is printed by a class that is only present in the classpath of the first instance (sample).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-2761289734000229515?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/2761289734000229515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=2761289734000229515' title='28 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2761289734000229515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/2761289734000229515'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/03/clustered-classloader.html' title='A Clustered ClassLoader'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>28</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-3344293269625308454</id><published>2008-03-17T20:39:00.001-07:00</published><updated>2008-04-01T21:43:45.149-07:00</updated><title type='text'>Stupid Simple JVM Coordination</title><content type='html'>If you think cross-jvm coordination is easy - then this post is not for you.  If it makes you cringe inside, just trying to remember the JMS interfaces, or JGroups api, java.io classes, or figuring out how to mess with a database, then carry on, intrepid reader.  This post is for you.&lt;br /&gt;&lt;br /&gt;I'm going to show you how stupid simple it is to use Terracotta to send a message from one JVM to the other.  We'll use two JVMs - a producer and a consumer.  I want the producer to create and send a message to the consumer.  I want the producer to wait for the consumer to consume the message.  When the message is consumed I want the producer to use the return value from the consumer.&lt;br /&gt;&lt;br /&gt;This would be stupid hard if it weren't for two amazing technologies.  The first is the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/package-summary.html"&gt;java.util.concurrent&lt;/a&gt; package.  The second is &lt;a href="http://www.terracotta.org/"&gt;Terracotta JVM Level Clustering&lt;/a&gt;.  Putting them together gives you stupid simple JVM coordination.&lt;br /&gt;&lt;br /&gt;The scenario I outlined is actually ridiculously easy in a single JVM using the java.util.concurrent package.  It was built to handle these scenarios and more at the flick of a wrist.  Instantiate a queue, fire off a couple of threads, use a &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html"&gt;FutureTask&lt;/a&gt;, and you're done.&lt;br /&gt;&lt;br /&gt;And you know what?  Could it get any more simple than writing one line of code to cluster that queue, and move from two threads in one JVM to one thread in two JVMs.  It can't. &lt;br /&gt;&lt;br /&gt;Here's the main method that does it all:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class Main&lt;br /&gt;{&lt;br /&gt;   public static final Main instance = new Main();&lt;br /&gt;&lt;br /&gt;   private AtomicInteger counter = new AtomicInteger(0);&lt;br /&gt;   private BlockingQueue&amp;lt;FutureTask&amp;gt; queue = new LinkedBlockingQueue&amp;lt;FutureTask&amp;gt;();&lt;br /&gt;&lt;br /&gt;   public void listen() throws InterruptedException&lt;br /&gt;   {&lt;br /&gt;       while (true) {&lt;br /&gt;           queue.take().run();&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void run() throws Exception&lt;br /&gt;   {&lt;br /&gt;       if (counter.getAndIncrement() == 0) {&lt;br /&gt;           System.out.println("Waiting...");&lt;br /&gt;           listen();&lt;br /&gt;           return;&lt;br /&gt;       }&lt;br /&gt;     &lt;br /&gt;       FutureTask task = new FutureTask(new MyCallable());&lt;br /&gt;       queue.put(task);&lt;br /&gt;       System.out.println("Task completed at: " + task.get().toString());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static class MyCallable implements Callable&lt;br /&gt;   {&lt;br /&gt;        public Object call() throws InterruptedException&lt;br /&gt;        {&lt;br /&gt;            System.out.println(new Date().toString() + ": Sleeping 2 seconds...");&lt;br /&gt;            Thread.sleep(2000);&lt;br /&gt;            System.out.println("Hello world");&lt;br /&gt;&lt;br /&gt;            return new Date();&lt;br /&gt;        }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public static void main(String[] args) throws Exception&lt;br /&gt;   {&lt;br /&gt;       instance.run();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And the Terracotta config:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&lt;br /&gt; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt; xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;application&amp;gt;&lt;br /&gt;   &amp;lt;dso&amp;gt;&lt;br /&gt;      &amp;lt;instrumented-classes&amp;gt;&lt;br /&gt;        &amp;lt;include&amp;gt;&lt;br /&gt;          &amp;lt;class-expression&amp;gt;Main$MyCallable&amp;lt;/class-expression&amp;gt;&lt;br /&gt;        &amp;lt;/include&amp;gt;&lt;br /&gt;      &amp;lt;/instrumented-classes&amp;gt;&lt;br /&gt;     &amp;lt;roots&amp;gt;&lt;br /&gt;       &amp;lt;root&amp;gt;&lt;br /&gt;         &amp;lt;field-name&amp;gt;Main.instance&amp;lt;/field-name&amp;gt;&lt;br /&gt;       &amp;lt;/root&amp;gt;&lt;br /&gt;     &amp;lt;/roots&amp;gt;&lt;br /&gt;   &amp;lt;/dso&amp;gt;&lt;br /&gt; &amp;lt;/application&amp;gt;&lt;br /&gt;&amp;lt;/tc:tc-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's all there is to it.   Output looks like this:&lt;br /&gt;&lt;br /&gt;Node 1:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ javac *.java&lt;br /&gt;$ start-tc-server &amp;amp;&lt;br /&gt;$ dso-java Main&lt;br /&gt;Waiting...&lt;br /&gt;(after starting other node...)&lt;br /&gt;Mon Mar 17 17:53:45 PDT 2008: Sleeping 2 seconds...&lt;br /&gt;Hello world&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Node 2:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ dso-java Main&lt;br /&gt;Task completed at: Mon Mar 17 17:53:47 PDT 2008&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've actually written this entire example up as a Recipe on Terracotta.org.  Full details and instructions are listed there in the &lt;a href="http://www.terracotta.org/confluence/display/howto/Recipe?recipe=futuretask"&gt;FutureTask recipe&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-3344293269625308454?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/3344293269625308454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=3344293269625308454' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/3344293269625308454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/3344293269625308454'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/03/stupid-simple-jvm-coordination.html' title='Stupid Simple JVM Coordination'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-5012163135643742158</id><published>2008-03-08T13:33:00.000-08:00</published><updated>2008-03-08T13:38:53.777-08:00</updated><title type='text'>The Trouble With Data Partitioning (cartoon)</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HJW28LGpxns/R9MHTGB5PPI/AAAAAAAABZ4/DP3C1-b0ATg/s1600-h/Trouble+With+Data+Partitioning.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_HJW28LGpxns/R9MHTGB5PPI/AAAAAAAABZ4/DP3C1-b0ATg/s400/Trouble+With+Data+Partitioning.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5175488421396298994" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-5012163135643742158?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/5012163135643742158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=5012163135643742158' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5012163135643742158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5012163135643742158'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/03/trouble-with-data-partitioning-cartoon.html' title='The Trouble With Data Partitioning (cartoon)'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_HJW28LGpxns/R9MHTGB5PPI/AAAAAAAABZ4/DP3C1-b0ATg/s72-c/Trouble+With+Data+Partitioning.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-5314108252865036046</id><published>2008-03-05T14:22:00.000-08:00</published><updated>2008-04-01T21:52:50.843-07:00</updated><title type='text'>It's the little things that matter...</title><content type='html'>It's often the little things in a design that make the biggest difference.  Sure you have to get the big things right too, but all too often products suffer from a great idea implemented poorly.&lt;br /&gt;&lt;br /&gt;So at Terracotta, I often have conversations along these very lines.  The job we've carved out for ourselves - clustering the entirety of the Java Virtual Machine, is pretty big.  That's why it's such a great place to work - the challenge we face is enormous, and it's enormously fun to tackle it.   Let me tell you right now, clustering the VM itself isn't going to happen if you don't get the big ideas right.  I'll wager that we have, but only history can prove that one right.  But just as important is getting the little things right.&lt;br /&gt;&lt;br /&gt;Today I just happened to discover one of those little things.  What is it?  Well, if you don't already know, Terracotta maintains &lt;a href="http://blog.terracottatech.com/archive/2005/08/object_identity.html"&gt;Object Identity&lt;/a&gt; across a cluster of JVMs.  That in itself is an amazing feat (no other piece of technology I have ever run into can do this).  So Object Identity is the big thing.  What's the little thing?&lt;br /&gt;&lt;br /&gt;Here goes.&lt;br /&gt;&lt;br /&gt;First, my sample code (Main.java):&lt;pre name="code" class="java"&gt;public class Main&lt;br /&gt;{&lt;br /&gt;    public static final Main instance = new Main();&lt;br /&gt;&lt;br /&gt;    private Map&amp;lt;Object, Object&amp;gt; map = new HashMap&amp;lt;Object, Object&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public void run() throws Exception&lt;br /&gt;    {&lt;br /&gt;        Object key = new Object();&lt;br /&gt;        Object value = new Object();&lt;br /&gt;&lt;br /&gt;        while (true) {&lt;br /&gt;            synchronized (map) {&lt;br /&gt;                map.put(key, value);&lt;br /&gt;            }&lt;br /&gt;            Thread.sleep(500);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception&lt;br /&gt;    {&lt;br /&gt;        instance.run();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Those of you not familiar with Terracotta might wonder what's so interesting about this.  Well, with Terracotta, you can cluster &lt;i&gt;any&lt;/i&gt; Java object, so with the following bit of config, I have done just that:&lt;div&gt;&lt;br /&gt;&lt;br /&gt;tc-config.xml:&lt;pre name="code" class="xml"&gt;&amp;lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;application&amp;gt;&lt;br /&gt;  &amp;lt;dso&amp;gt;&lt;br /&gt;    &amp;lt;locks&amp;gt;&lt;br /&gt;      &amp;lt;autolock&amp;gt;&lt;br /&gt;         &amp;lt;method-expression&gt;void Main.run(..) &amp;lt;/method-expression&amp;gt;&lt;br /&gt;      &amp;lt;/autolock&amp;gt;&lt;br /&gt;    &amp;lt;/locks&amp;gt;&lt;br /&gt;    &amp;lt;roots&amp;gt;&lt;br /&gt;      &amp;lt;root&amp;gt;&lt;br /&gt;        &amp;lt;field-name&amp;gt;Main.instance&amp;lt;/field-name&amp;gt;&lt;br /&gt;      &amp;lt;/root&amp;gt;&lt;br /&gt;    &amp;lt;/roots&amp;gt;&lt;br /&gt;  &amp;lt;/dso&amp;gt;&lt;br /&gt;&amp;lt;/application&amp;gt;&lt;br /&gt;&amp;lt;/tc:tc-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The map in the Main class listed above is now a clustered map (because the root field, &lt;code&gt;instance&lt;/code&gt;, holds a reference to it, and therefore transitively it becomes clustered).  Anything I put in the map is clustered (transitively again), meaning every object I put in the map is available to all other JVMs in the cluster.  That's pretty cool in it's own right (I happen to think), but how is that different from a normal get/put API in a traditional clustered cache, say EHCache, JCS, or OSCache?&lt;br /&gt;&lt;br /&gt;Well, I monitored the number of transactions the little test above generated.  How many would you guess?  1?  100? 1 every 500ms?&lt;br /&gt;&lt;br /&gt;The answer is actually : 1.  Because of Object Identity, after the first iteration through the loop, Terracotta &lt;i&gt;knows&lt;/i&gt; that it can optimize out the subsequent calls - there is no need for Terracotta to "re-put" an object for a key that already has that same relationship in the map - so it can save the roundtrip work to the server.  &lt;br /&gt;&lt;br /&gt;In the clustering world, anything you do on the network is orders of magnitude slower than main memory, so every little thing you can do to keep operations local means a big improvement in latency and throughput.  So it may be a minor optimization, but it's got a big effect on the latency and throughput of this application.  My application may be trivial, but consider if that map was an HTTP Session Context, or a distributed cache. &lt;br /&gt;&lt;br /&gt;Furthermore, this optimization is simply not possible with serialization based solutions (which must implement a copy on read, copy on write strategy), because it's simply not possible for a serialization based approach to track object identity, or changes to objects, and optimize out this kind of a scenario.  &lt;br /&gt;&lt;br /&gt;However because Terracotta is at the VM level, it knows implicitly when objects change, because of Object Identity, so it is not necessary for a caller of the map to "re-put" objects into the map to make sure it's updated (and it's thus valid to eliminate the subsequent put calls that are superfluous).  So in the end - Terracotta would work exactly the same with or without this optimization - the correctness is unaffected by it - but with it, it can, depending on your usage, make your application run orders of magnitude faster. &lt;br /&gt;&lt;br /&gt;So, in summary, you gotta get the big things right.  Object Identity is the big thing.  But it's in getting the little things right - for example optimizing away unnecessary network calls by eliminating redundant map.put() calls, that turn out to take a great idea and make it truly impressive.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Note that I can't take credit for this, since I had nothing to do with creating the feature or even suggesting it.  I just happened to have realized that it's trivial to test to see if it's implemented or not, and I did test it and hoped that you would find the results interesting too.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;To find out more,&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Read about &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Check out some bite-sized code samples in the &lt;a href="http://www.terracotta.org/confluence/display/howto/Cookbook"&gt;cookbook section&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Or just &lt;a href="http://www.terracotta.org/confluence/display/orgsite/Download"&gt;download it already&lt;/a&gt; :)&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Note that the code posted in this demo is 100% runnable - just&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;save it to Main.java and tc-config.xml in a new directory&lt;/li&gt;&lt;br /&gt;&lt;li&gt;type "javac Main.java",&lt;/li&gt;&lt;br /&gt;&lt;li&gt;start the Terracotta server - start-tc-server.sh&amp;amp;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;run the program - dso-java.sh Main&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-5314108252865036046?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/5314108252865036046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=5314108252865036046' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5314108252865036046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/5314108252865036046'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/03/its-little-things-that-matter.html' title='It&apos;s the little things that matter...'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-4061804541066701111</id><published>2008-02-12T15:06:00.000-08:00</published><updated>2008-02-12T15:34:38.829-08:00</updated><title type='text'>Time for a Maven Best Practice</title><content type='html'>I really like Maven.  I think the idea is really solid, and I love the outcome of a project that is factored so well that you can have a working demo in an &lt;a href="http://forge.terracotta.org/downloads/sharededitor/tags/release-1.0.1/sharededitor-1.0.1-src.zip"&gt;80k download&lt;/a&gt;.  That's really powerful!  I use this power to my advantage all the time, building demos for Terracotta that can demonstrate with almost no effort how Terracotta gives you a &lt;a href="http://www.terracotta.org/confluence/display/labs/Distributed-Cache+Webcast"&gt;high performance clustered cache&lt;/a&gt;, or can give &lt;a href="http://www.terracotta.org/confluence/display/labs/Hibernate+Webcast"&gt;Hibernate a performance boost&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;That's awesome stuff, so awesome that I find I just can't code a project with "hard" dependencies anymore.  If I can't download your dependency from my pom.xml, sorry man, it doesn't exist.&lt;br /&gt;&lt;br /&gt;Which is where the frustration comes in - and a time for a best practice to start.  Have you ever come across a new library you want to try out, but cannot find the groupId, the artifactId, or the version that corresponds to the dependency download?  For a while I thought I was the only one...If I just knew these three "coordinates" I could get on with the job at hand...Instead I get bogged down hunting through some obscure project website, svn'ing code and the like.  Ughh!  Turns out some colleagues at Terracotta agreed, and we realized there has to be a better way. &lt;br /&gt;&lt;br /&gt;Well, it's not rocket science, but we figured just printing out the info on the site would do.  So, I present to you the Terracotta Maven best practice, implemented for your convenience on the &lt;a href="http://forge.terracotta.org/"&gt;Terracotta Forge&lt;/a&gt;.  Every project published by Terracotta is required to have a "Maven Coordinates" section in the index page.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Terracotta Maven Best Practice&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Print the groupId, artifactId, and version of the published artifact on the index of the site in a human readable form&lt;br /&gt;&lt;li&gt;Print the groupId, artifactId, and the version of the published artifact on the index of the site in a pom.xml compatible form&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Here's what it looks like in practice:&lt;br /&gt;&lt;br /&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_HJW28LGpxns/R7IrSEU9QbI/AAAAAAAABZU/e16Al6GR6Bg/s400/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5166239311946662322" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-4061804541066701111?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/4061804541066701111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=4061804541066701111' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/4061804541066701111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/4061804541066701111'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/02/time-for-maven-best-practice.html' title='Time for a Maven Best Practice'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_HJW28LGpxns/R7IrSEU9QbI/AAAAAAAABZU/e16Al6GR6Bg/s72-c/Picture+1.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-708972427354322478</id><published>2008-01-22T17:50:00.000-08:00</published><updated>2008-04-01T21:55:19.581-07:00</updated><title type='text'>Stupid JVM Tricks - Read locks from just synchronized</title><content type='html'>I bet if you asked someone in an interview what the synchronized block in Java does, they are likely to answer something along the lines of "protected sections" of code, if you are lucky they might answer with a deeper technical understanding, with terminology such as "atomicity," "mutual exclusion," "monitors," and the like.&lt;br /&gt;&lt;br /&gt;I will further bet that if you asked if it's possible for Java's synchronized keyword to produce read lock semantics (e.g. concurrent access), you would hopefully get a resounding no.  Ok, well, if your interviewee is clever enough, they might tell you that you could &lt;i&gt;build&lt;/i&gt; a read lock mechanism, but that synchronized itself only provides you with write lock semantics - that is to say, mutual exclusion.&lt;br /&gt;&lt;br /&gt;So if I ask you the very same question - what's your answer?&lt;br /&gt;&lt;br /&gt;Mine is ... YES!&lt;br /&gt;&lt;br /&gt;Let me show you how.  First, here's my code (in a file called Main.java):&lt;br /&gt;&lt;pre name="code" class="java"&gt;public class Main implements Runnable&lt;br /&gt;{&lt;br /&gt;    public static final Main instance = new Main();&lt;br /&gt;&lt;br /&gt;    public void run() &lt;br /&gt;    {&lt;br /&gt;        enterMonitor();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public synchronized void enterMonitor() &lt;br /&gt;    {&lt;br /&gt;        System.out.println("I'm in the synchronized block"); System.out.flush();&lt;br /&gt;        try { Thread.currentThread().sleep(5000); } &lt;br /&gt;        catch (InterruptedException ie) { System.out.println("Interrupted"); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception&lt;br /&gt;    {&lt;br /&gt;        for (int i = 0; i &amp;lt; 10; i++) {&lt;br /&gt;            new Thread(instance).start(); &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here's my output:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;I'm in the synchronized block&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(Note that all statements above were printed at the same time, not serially)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Now, I hope you are wondering how I did that.  If not, this post really isn't for you.  If you are, ok, ok, I admit it.  Vanilla synchronized really can't give you read semantics, but with a bit of sleight of hand, &lt;a href="http://www.terracotta.org"&gt;Terracotta&lt;/a&gt; can do it for you.&lt;br /&gt;&lt;br /&gt;The way I made the above output happen is that I configured Terracotta to treat the synchronized block as a read lock.  The rest is simple - Terracotta manages the locking, and since it was told to make the particular lock in question a read lock, lo and behold, I was able to get fully concurrent access to the code inside the synchronized block.&lt;br /&gt;&lt;br /&gt;I know what you are thinking now - holy synchronized block batman!  That could be a disaster for code that wasn't expecting to be run concurrently!  And you'd be right - except Terracotta is smarter than that.  Let's suppose I had accidentally surrounded some code that made field updates (performing a write) to my object with a synchronized block, and told Terracotta to make that into a read lock.  If I do that, and run the code with Terracotta, it will tell me (by throwing an Exception) at the point of modification that I made a mistake and my code was mistakenly trying to make an update to an object under a read lock.  In other words, no, using read locks with Terracotta is not dangerous at all, and it can really boost the performance of your app.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; To see how simple this is, let me post the relevant bit of Terracotta config that converts the above synchronized into a read lock:&lt;pre name="code" class="xml"&gt;&amp;lt;locks&amp;gt;&lt;br /&gt;  &amp;lt;autolock&amp;gt;&lt;br /&gt;    &amp;lt;method-expression&amp;gt;void Main.enterMonitor()&amp;lt;/method-expression&amp;gt;&lt;br /&gt;      &amp;lt;lock-level&amp;gt;read&amp;lt;/lock-level&amp;gt;&lt;br /&gt;   &amp;lt;/autolock&amp;gt;&lt;br /&gt;&amp;lt;/locks&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; &lt;br /&gt;For all the details, see my full write-up in the &lt;a href="http://www.terracotta.org/confluence/display/howto/Cookbook"&gt;Terracotta Cookbook&lt;/a&gt; - a really great place to see simple examples that demonstrate the power of Terracotta.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-708972427354322478?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/708972427354322478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=708972427354322478' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/708972427354322478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/708972427354322478'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/01/stupid-jvm-tricks-read-lock-from-just.html' title='Stupid JVM Tricks - Read locks from just synchronized'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-8171801419551025017</id><published>2008-01-17T09:31:00.000-08:00</published><updated>2008-01-17T09:38:37.735-08:00</updated><title type='text'>In today's world, what is the role of the Application Server?</title><content type='html'>Undoubtedly, you noticed a few changes in the Enterprise world:&lt;br /&gt;&lt;br /&gt;1) &lt;a href="http://www.sun.com/aboutsun/media/presskits/2008-0116/index.jsp?intcmp=hp2008jan16_mysql_learn"&gt;Sun bought MySQL for a reported $1B&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2) &lt;a href="http://www.reuters.com/article/technology-media-telco-SP/idUSN1660673720080117"&gt;Oracle bought BEA for a reported $8.2B&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I've already been asking this question to various individuals, with these recent announcements it occurred to me that I'd be interested in what you, the blog reading public have to say.&lt;br /&gt;&lt;br /&gt;My question is this:&lt;br /&gt;&lt;br /&gt;Given the likes of Spring and Hibernate, how do people consume the Application Server?  Is it all you can eat with JEE still delivering on the promise of writing business logic and letting the App server deal with the infrastructure?  Or do things like Spring, Hibernate, JPA etc. change the game - are people choosing a best of breed approach, with lightweight frameworks (Spring, ActiveMQ, Hibernate etc) and lightweight containers (Tomcat, Jetty etc) allowing developers to build the stack they need, and no more?&lt;br /&gt;&lt;br /&gt;How do the acquisitions mentioned above change the game?  Is BEA still delivering value, or is the App server market completely commoditized?&lt;br /&gt;&lt;br /&gt;I would love to hear your comments!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-8171801419551025017?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/8171801419551025017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=8171801419551025017' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/8171801419551025017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/8171801419551025017'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2008/01/in-todays-world-what-is-role-of.html' title='In today&apos;s world, what is the role of the Application Server?'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35058937.post-4913902253815825810</id><published>2007-10-31T10:53:00.000-07:00</published><updated>2007-10-31T11:42:47.945-07:00</updated><title type='text'>Delicious - Just the Tip of the Iceberg</title><content type='html'>I had a long conversation with my long time friend &lt;a href="http://jameselee.alwaysaskwhy.com/blog/"&gt;James&lt;/a&gt; yesterday.  We spent some time chatting &lt;a href="http://www.pui.ch/phred/archives/2007/10/remembering-on-the-web-5-reasons-why-social-bookmarking-doesnt-work.html"&gt;about a link I&lt;/a&gt; sent to him via &lt;a href="http://del.icio.us/"&gt;del.icio.us&lt;/a&gt;, which posited that social bookmarking is essentially broken.  I like the kind of analysis the author provides - it's nice to see someone &lt;i&gt;thinking&lt;/i&gt; about a problem, so I promptly commented on the blog, noted that for future reference, and sent it to James.&lt;br /&gt;&lt;br /&gt;Unlike James, I like to write my blogs in narrative form.  For me it's just more fun.  If you read through his blog you'll see that he spends a lot of time carefully crafting well written, instructive and informative entries.  I see the value in it - I write emails that way sometimes (and should do it more often) but my personal preference is to tell a story.  My (rambling) point is, if you re-read the entry paragraph, there's actually some interesting information I purposely hid to see if you picked up on it the first time 'round.  By now you've found it no doubt, so let's point it out.&lt;br /&gt;&lt;br /&gt;I said:  "noted that for future reference" and "sent it to James." &lt;br /&gt;&lt;br /&gt;Those are actually two distinct actions that I took, and I used del.iciou.us for both.  Getting back to the title of this post, that's just the tip of the iceberg.  But let's start there, because it's farther than most people take del.iciou.us on any given day.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Action 1: noted that for future reference&lt;/h3&gt;&lt;br /&gt;I actually stored a reminder for myself on del.iciou.us &lt;a href="http://del.icio.us/tgautier/commented"&gt;using a tag called "commented".&lt;/a&gt;  This is an &lt;i&gt;action&lt;/i&gt; tag, it's something I have done.  I'll get to the difference between an action tag, and a &lt;i&gt;classification&lt;/i&gt; tag in a minute.  For now you just need to know that "commented" means that I made a comment somewhere - a blog, a forum, etc.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Action 2: sent it to James&lt;/h3&gt;&lt;br /&gt;I sent the link to James using the built-in "for:&lt;userid&gt;" functionality in del.icio.us.  This is the only instance I know of that illustrates del.icio.us thinks of itself more than just a gigantic classification system for the web.  More on that subject in a minute.  For now, you just need to know that if I tag a link with "for:jameselee", James will see that tag in his "links for you" section in del.iciou.us.  Here's are links tagged for me: &lt;a href="http://del.icio.us/for/tgautier"&gt;http://del.icio.us/for/tgautier&lt;/a&gt;.  What's really handy about this is you can subscribe to an RSS feed in your favorite reader, meaning you don't need to constantly check del.iciou.us for new tags, just let your RSS reader take care of that chore for you.  This kind of tag is an &lt;i&gt;actionable&lt;/i&gt; tag.  Now lets discuss what I'm talking about.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What's a Folksonomy, and why do I care?&lt;/h3&gt;&lt;br /&gt;First, we need to understand a little bit about what exactly is del.icio.us. &lt;br /&gt;&lt;br /&gt;Everyone and their brother that uses del.icio.us today is familiar with using it as a classification system.  Looking at the list of &lt;a href="http://del.icio.us/tag/"&gt;popular tags on del.iciou.us&lt;/a&gt;, they are primarily of the type that adds meta-data about the target link that relates to what the tagger thinks that link &lt;b&gt;&lt;i&gt;is&lt;/i&gt;&lt;/b&gt;.  That's classification.  It's what biologists do when they talk about a certain Monkey belonging in a particular Species, Genus, Family, Order etc.  The difference between a biological taxonomy and a tag taxonomy (or more precisely, &lt;a href="http://en.wikipedia.org/wiki/Folksonomy"&gt;folksonomy&lt;/a&gt;) is that a traditional taxonomy has well-defined rules, definitions and categories to place things.  It's often hierarchical, as in the case of biology, and it is rigid and doesn't change much.  Folksonomies are flexible, and don't follow well-defined rules, they depend on emergent behavior to derive value.   &lt;a href="http://del.icio.us/tag/"&gt;The del.iciou.us popular tags&lt;/a&gt; link shows you what people think of the web.&lt;br /&gt;&lt;br /&gt;But we can be more rigid about our folksonomy, (there aren't any rules which means I am free to make up my own, right?), in fact what I propose is that there is in fact very strong similarities to these activities of classification, and they all fall into a just one part of a larger taxonomy of folksonomies.  That part is the "classifying" part.  They aren't adding any data about their relationship to the link (e.g. I am the author, I commented on it, it makes me feel warm, I like it, I hate it, etc.) and they aren't associating any actionable items with those links either.&lt;br /&gt;&lt;br /&gt;To put it another way, it seems everyone on del.icio.us is busy classifying data according to what they think it is, because the particular part of the folksonomy they see themselves in is just the "classification" part.  It's as if you let a horde of botanists free in a field full of flowers, all of the same Genus, and let them start coming up with Species on their own, no matter who stumbled on what and then tried to sort out all of the data later (the current theory being that a majority of the botanists would converge on a given answer for each specie).&lt;br /&gt;&lt;br /&gt;But there are so many other kinds of meta-data that can be associated with a link, that I think del.icio.us, and the folksonomy community at large, is missing out on the big picture.  Let me try to illustrate it better:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What else can I do with link meta-data?  The bigger picture&lt;/h3&gt;&lt;br /&gt;Let me suggest a rudimentary "higher-order" taxonomy which is super-imposed on smaller order folksonomies.  In this way we can begin to extract some useful, and interesting, new ways to use the meta-data being collected by the masses:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+ Link Meta-Data Taxonomy&lt;br /&gt;  - Classification Folksonomy (e.g. tutorial, howto, tip, webdesign, etc.)&lt;br /&gt;  - Relational Folksonomy (e.g. authored, commented, etc.)&lt;br /&gt;  - Actional Folksonomy (e.g. forterracotta)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Classification Folksonomy&lt;/h3&gt;&lt;br /&gt;The first one is pretty obvious, it's how everyone uses del.iciou.us today.  The goal here is to try to describe what the content of the link &lt;i&gt;is&lt;/i&gt;.  So if it's a tutorial on web design practices, you might tag the link as "tutorial webdesign".&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Relational Folksonomy&lt;/h3&gt;&lt;br /&gt;Less well known.  Describe how you are related to, or see your relationship with, the link.  If you wrote it, you might tag it with "didauthor".  If you commented on it, you might use "didcomment".  James suggested the use of "didxxx" which I like because it tells me right away that this is a relational tag, not a classification tag.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Actional Folksonomy&lt;/h3&gt;&lt;br /&gt;I've not seen much of these around.  We use them for our buzz system on &lt;a href="http://www.terracotta.org"&gt;http://www.terracotta.org&lt;/a&gt; which I &lt;a href="http://javathink.blogspot.com/2007/06/so-you-want-buzz-eh-do-it-in-style-with.html"&gt;blogged about in detail several months back&lt;/a&gt;.   The basic strategy here is to use tags that indicate to other tools scraping your data how to view the link.  So, in the context of the buzz engine, if I encounter a link on the web that is buzz worthy, I simply tag it "forterracotta" and it pops out on the Terracotta .org site.  Similary, I filter important links into my Google homepage via an RSS widget for del.icio.us by tagging them with a combination of &lt;a href="http://del.icio.us/tgautier/my%2Bstartpage"&gt;"my startpage"&lt;/a&gt;.   This means I want my iGoogle page to show the particular set of links tagged with "my" and "startpage" to show on my Google startpage.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What next?&lt;/h3&gt;&lt;br /&gt;The title of this post is "the tip of the iceberg".  I highly doubt that the taxonomy of folksonomies is limited to just three categories.  I'd love to see this idea pushed forward, to find more interesting and creative uses for meta-data about the web.  Del.icio.us is a start, but I suspect we will look back on it  in 5 years and find it horribly primitive.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35058937-4913902253815825810?l=javathink.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javathink.blogspot.com/feeds/4913902253815825810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=35058937&amp;postID=4913902253815825810' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/4913902253815825810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35058937/posts/default/4913902253815825810'/><link rel='alternate' type='text/html' href='http://javathink.blogspot.com/2007/10/delicious-just-tip-of-iceberg.html' title='Delicious - Just the Tip of the Iceberg'/><author><name>Taylor</name><uri>http://www.blogger.com/profile/07193759050963768511</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03580170504223162850'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>15</thr:total></entry></feed>