<?xml version="1.0"?>
<rss version="2.0">
<channel>
  <title>The Kitchen in the Zoo - tomcat tag</title>
  <link>http://blog.maxant.co.uk:80/pebble/tags/tomcat/</link>
  <description>&lt;small&gt;A blog where Ant writes about anything he finds interesting! &lt;a href=&#039;http://www.linkedin.com/in/maxant&#039;&gt;&lt;font color=&#039;white&#039;&gt;Who is Ant?&lt;/font&gt;&lt;/a&gt;      &lt;a href=&#039;/pebble/pages/copyright.html&#039;&gt;&lt;font color=&#039;white&#039;&gt;Copyright 2005-2012 Ant Kutschera&lt;/font&gt;&lt;/a&gt;&lt;/small&gt;</description>
  <language>en</language>
  <copyright>Ant Kutschera</copyright>
  <lastBuildDate>Thu, 10 May 2012 20:07:00 GMT</lastBuildDate>
  <generator>Pebble (http://pebble.sourceforge.net)</generator>
  <docs>http://backend.userland.com/rss</docs>
  
  
  <item>
    <title>Tomcat, WebSockets, HTML5, jWebSockets, JSR-340, JSON and more</title>
    <link>http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html</link>
    
      
        <description>
          &lt;p&gt;On my recent excursion into non-blocking servers I came across Comet, server push technologies and then Web Sockets. I was late arriving at the Comet party, but I think I have arrived at the Web Sockets party just in time.   The final standard is still being evovled and at the time of writing, the only browser supporting it by default is Chrome. So to get started, I had a look at what was around.  Initially, I wasn&#039;t going to write a blog article about it, I just wanted to learn about this new thing.&lt;br /&gt;
&lt;br /&gt;
My only requirement was that the server implementation was Java based.  The reason is simple - my entire technology stack is based on Java EE  and I want to be able to integrate all my existing stuff into any new server, without the need for an integration bus.  I like being able to  drop a JAR file from one project into another one and to be up and running immediately.&lt;br /&gt;
&lt;br /&gt;
So I had a quick look at jWebSockets, Grizzly (Glassfish), Jetty and Caucho&#039;s Resin.  All similar, yet all somewhat different.  Most different, was  jWebSockets, because they have gone to the extent of building their own server, instead of basing their solution on an existing server.  I had a  good long rant about that kind of thing when I blogged about node.js, so I won&#039;t start again.  But jWebSockets has a real issue to face in the  coming years.  &lt;a target=&#034;_blank&#034; href=&#034;http://www.jcp.org/en/jsr/detail?id=340&#034;&gt;JSR-340&lt;/a&gt; talks about support for web technologies based around HTML5 and there is talk that this JSR will be part of Servlet 3.1 and be included in Java EE 7 at the end of next year.  If that happens,  jWebScokets will have the problem that their server implementation will become deprecated.  And because their server doesn&#039;t offer anything else from Java EE, it is likely to lose a large part of it&#039;s market share.  Don&#039;t get me wrong, they are still innovating on the client side, with a bridge to allow any browser to use websockets, and creating things like Java SE web socket clients.  But server side isn&#039;t looking so hot -  just take a look at the huge config file which you need to supply to get your plugins to work.&lt;br /&gt;
&lt;br /&gt;
Anyway, I wasn&#039;t really enthusiastic about any of the solutions I saw.  Some are servlet based (which is good), and all rely on you creating a  new instance of a  listener, handler, plugin or whatever they choose to call it.  But what struck me was, by doing that, you lose the benefits of running  inside the container.  What I mean by this is that if you think about a servlet or an EJB (and I&#039;m talking Java EE 6 and beyond here),  the components you write have the benefit that the container can take care of cross cutting concerns like transactions, security and concurrency as  well as provide you with injected resources, so that all you have left to do is write business code.  So the reason I was not enthusiastic about  any of the solutions listed above, was that what I felt to be glaringly obvious, has been missed.  Sure, an inner class within a servlet could  make use of resources from the servlet, but nothing I found on the net suggested that should be the normal way to program a web socket solution. And I&#039;m not convinced that a reference in an inner class to a resource from the servlet couldn&#039;t go stale between messages received.   I would rather the container always injected fresh resources just before my event handling method gets called, just as happens in the lifecycle of a servlet or EJB instance.  Just think about a database connection timeout occurring between messages?  If the container ensured the connection was always fresh, then the app developer wouldn&#039;t need to worry about technicalities.&lt;br /&gt;
&lt;br /&gt;
An &lt;code&gt;HttpServlet&lt;/code&gt; has methods for handling GETs, POSTs, et al.  Why shouldn&#039;t a component handling a Web Socket not be a  &lt;code&gt;WebSocketServlet&lt;/code&gt; and have methods for handling the events for handshaking, opening, messaging, closing and error handling? I would benefit, because the servlet could have resources injected into it before the event handler methods get called, and the container  could start any transactions that are required, or check security, etc.&lt;br /&gt;
&lt;br /&gt;
So without realising that this would actually be quite hard to implement, I set upon taking Tomcat 7 apart, and building web sockets into it, in  a way which fulfilled my requirements.&lt;br /&gt;
&lt;br /&gt;
What resulted was (what I think is) a pretty sexy servlet solution.  Please take a few minutes to study the  code and especially the comments below, because it is the essence of this article. &lt;/p&gt;
&lt;div style=&#034;border: thin none; overflow: auto; width: 525px; height: 300px; background-color: rgb(255, 255, 255);&#034;&gt;
&lt;pre&gt;
/**
 * a demo of what a web socket servlet could look like
 */
@WebServlet(urlPatterns={&amp;quot;/TestServlet&amp;quot;})
@ServletSecurity(@HttpConstraint(rolesAllowed = &amp;quot;registered&amp;quot;))
public class TestServlet extends WebSocketsServlet&amp;lt;CommandContainer&amp;gt; {

  @WebServiceRef
  private PricingSystem pricingSystem;
  
  @EJB
  private SalesLog salesLog;
  
  @Override
  protected void doJSONMessage(
      WebSocketsServletRequest&amp;lt;CommandContainer&amp;gt; request,
      WebSocketsServletResponse response) throws IOException {
    
    //see how generics is helping me here, 
    //when i grab the request payload?
    //CommandContainer is a class defined in the app!
    CommandContainer c = request.getDataObject();
    
    if(&amp;quot;CLOSE&amp;quot;.equals(c.getCommand())){
    
      //closing connection to client
      response.close();

      //handle updates to say my model or whatever      
      actualClose(EventSubType.SESSION_END, request.getSession());
      
      return;

    }else if(&amp;quot;PRICE&amp;quot;.equals(c.getCommand())){

      //hey wow - a call to an injected web service!
      BigDecimal price = pricingSystem.getPrice(c.getData());
      c.setResult(price.toString());

    }else if(&amp;quot;BUY&amp;quot;.equals(c.getCommand())){
      
      //data is e.g. GOOG,100@200.25 - equally I could have 
      //put it in the model
      int idx = c.getData().indexOf(&#039;,&#039;);
      String shareCode = c.getData().substring(0, idx);
      idx = c.getData().indexOf(&#039;@&#039;);
      String numShares = c.getData().substring(shareCode.length()+1, idx);
      String price = c.getData().substring(idx+1, c.getData().length()-1);

      //awesome - a call to an injected EJB!
      salesLog.logPurchase(shareCode, 
                           new BigDecimal(price), 
                           Integer.parseInt(numShares));
      
      //and again cool - I can access the logged in user
      //in a familiar way (security)
      c.setResult(&amp;quot;sold &amp;quot; + numShares + &amp;quot; of &amp;quot; + shareCode + 
                  &amp;quot; for &amp;quot; + request.getUserPrincipal().getName());

    }else{
      
      c.setResult(&amp;quot;unknown command &amp;quot; + c.getCommand());
      
    }

    log(&amp;quot;handled command &amp;quot; + c.getCommand() + &amp;quot; on session &amp;quot; + 
                 request.getSession().getId() + &amp;quot;: &amp;quot; + c.getResult());
  
    //the response takes care of the outputstream, framing, 
    //marshalling, etc - my life is really easy now!
    response.sendJSONResponse(c);
  }

  @Override
  protected void doError(EventSubType eventSubType, 
                         WebSocketsSession session, 
                         Exception e) {

    System.out.println(&amp;quot;error: &amp;quot; + eventSubType + 
                       &amp;quot; on session &amp;quot; + session.getId() + 
                       &amp;quot;.  ex was: &amp;quot; + e);
  }

  @Override
  public void doClose(EventSubType eventSubType, 
                      WebSocketsSession session) {

    actualClose(eventSubType, session);
  }

  /** 
   * this is a method where we might do stuff like
   * tidy up our model, free resources, etc.
   */  
  private void actualClose(EventSubType eventSubType,
                           WebSocketsSession session) {
  
    System.out.println(&amp;quot;closed session &amp;quot; + 
                       session.getId() + &amp;quot;: &amp;quot; + eventSubType);
  }

}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
To me, this is what a serverside web socket component should look like.  It is really similar to a sevlet or an EJB or a web service - things we are now familiar with.  The learning curve is mini.&lt;br /&gt;
&lt;br /&gt;
But getting Tomcat to use this thing was a little harder.  First off, my approach was to simply write a new Connector and configure it in the  &lt;code&gt;server.xml&lt;/code&gt;.  I gave it a port number and Tomcat willingly instantiated my new class:&lt;/p&gt;
&lt;div style=&#034;border: thin none; overflow: auto; width: 525px; height: 120px; background-color: rgb(255, 255, 255);&#034;&gt;
&lt;pre&gt;
  &amp;lt;!-- NIO WebSockets connector --&amp;gt;    
    &amp;lt;Connector port=&amp;quot;8082&amp;quot; protocol=&amp;quot;org.apache.coyote.http11.WebSocketsNioProtocol&amp;quot; 
               connectionTimeout=&amp;quot;20000&amp;quot; 
             /&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
Of course, I cheated here a bit and stuck my class in a Coyote package.  To get this to work, I unzipped the Tomcat 7.0.14 source and told Eclipse where to find it.  I set up the build folder and added that to the classpath in the &lt;code&gt;catalina.bat&lt;/code&gt; batch, before any of the other  JARs on the classpath, and I did this just near the end of the batch where the call to the Java process is made.  I then ran my modified Tomcat by simply starting the catalina batch, using remote debugging to make life easier.&lt;br /&gt;
&lt;br /&gt;
I initially based my non-blocking connector on the non-blocking server which I have written and extended for my past few blog articles.   My idea was intercept any web socket handshake requests that arrived and to quickly return a self built handshake response.  I would then call the requested servlet and run it using Servlet 3.0 async support, so that the container would keep the connection open.  The messages  which the client then sent after the handshake would be handled by that servlet.&lt;br /&gt;
&lt;br /&gt;
The idea didn&#039;t quite work though, because the servlet used the async support and my connector got  callbacks from Tomcat in order for me to do stuff with threads, handle events and state changes.  I was a little lost because I didn&#039;t  understand the implementation details of Tomcat well enough, and after a while I gave up, because it was becoming clear that I would have  to build quite a lot of stuff that already existed in the HTTP connectors which shipped with Tomcat.  I came to realise that instead of  reinventing the wheel, I would do better by creating my own versions (or even sub-classes) of the Coyote &lt;code&gt;Http11NioProcessor&lt;/code&gt; and  &lt;code&gt;Http11NioProtocol&lt;/code&gt; which Tomcat uses to implement the HTTP connectors.  While these are somewhat complicated, the advantages of  specialising them are firstly that I am not reinventing the wheel, and secondly that I would get HTTPS (or WSS as it is with Web Sockets) for free (theoretically, I haven&#039;t yet tested it, but it is simply encapsulated so it should work with almost no problems).&lt;br /&gt;
&lt;br /&gt;
While it was straight forward to copy the two relevant classes, the next headache was to get the browser to accept the handshake response. I wasn&#039;t sending the handshake response as a self built String like I had with my own non-blocking connector.  Instead I was making as much use of servlet technology as I could, and building the response by setting the relevant headers on it and pushing the 16 byte response key onto the output stream of the response.  Unlike a normal HTTP response, the browser expects any handshake  responses to stick to a pretty strict specification.  Things like a simple date header in the response (which Tomcat kindly sends by default)  cause the browser to close the web socket.  So with a bit of fiddling in the &lt;code&gt;WebSocketsNioProcessor#prepareResponse()&lt;/code&gt; method, I soon had the response header looking perfect, and the browser started to play along.&lt;br /&gt;
&lt;br /&gt;
But the next problem wasn&#039;t as simple to fix.  The message handling didn&#039;t work, at all.  Connections kept getting closed quickly and I couldn&#039;t figure out what was going on.&lt;br /&gt;
&lt;br /&gt;
After a few headaches, I thought back to how Comet is implemented in Tomcat.  I slowly realised, that what I needed was to simply piggy back  the Comet infrastructure in Tomcat.  In Tomcat, you create a Comet handler by simply implementing the &lt;code&gt;CometProcessor&lt;/code&gt; interface in your servlet. The container checks during the initial request whether the servlet which will service the request implements the interface,  and if it does, the request is marked as being a comet request.  That means the container keeps the connection open and forwards future events  (e.g. bytes / messages) to the relevant handler method which your servlet implements.  I made my base servlet (&lt;code&gt;WebSocketsServlet&lt;/code&gt;) implement the &lt;code&gt;CometProcessor&lt;/code&gt; interface, and added the &lt;code&gt;event(CometEvent event)&lt;/code&gt; method using the final keyword, so that  application developers wouldn&#039;t ever think of overriding it, meaning they were protected from having the option of knowing about Comet.   This base class servlet then encapsulated the web sockets events by hiding the fact that I had cheated by using Comet.  The event method from  the Comet processor simply passes the event on to the relevant doXXX method in my base servlet, which application programmers would subclass.   This is pretty much what the &lt;code&gt;HttpServlet&lt;/code&gt; base class does in it&#039;s service method.&lt;br /&gt;
&lt;br /&gt;
So, my &lt;code&gt;WebSocketsServlet&lt;/code&gt; is the Web Sockets equivalent of the &lt;code&gt;HttpServlet&lt;/code&gt;, and as such, I put it into the  &lt;code&gt;javax.servlet.websockets&lt;/code&gt; package - i.e. to be supplied as part of the JSR which gets around to specifying the way in  which Java EE containers should handle web sockets.&lt;br /&gt;
&lt;br /&gt;
The &lt;code&gt;WebSocketsServlet&lt;/code&gt; also deals with &lt;code&gt;WebSocketServletRequest&lt;/code&gt;, &lt;code&gt;WebSocketServletResponse&lt;/code&gt; and  &lt;code&gt;WebSocketSession&lt;/code&gt; objects, rather than HTTP equivalents.  Each of these derives from the relevant &lt;code&gt;ServletXXX&lt;/code&gt; rather than &lt;code&gt;HttpServletXXX&lt;/code&gt; object, because when handling a web socket frame, it makes no sense what so ever to  be able to do things like setting the headers on the response.  Headers are only relevant to the handshake, and not anything which an  application developer needs to concern themselves with.  Again, these interfaces also sit in the &lt;code&gt;javax.servlet.websockets&lt;/code&gt; package, because they are the analagous classes belonging to the specification, rather than just Tomcat.  Sadly, the &lt;code&gt;ServletRequest&lt;/code&gt; class has stuff in it which is too specific to HTTP, like &lt;code&gt;getParameter(String)&lt;/code&gt;, as well as other stuff which I would prefer to  hide for web sockets, like &lt;code&gt;getInputStream()&lt;/code&gt;.  In order to make the &lt;code&gt;WebSocketsServletRequest&lt;/code&gt; fit really well into the  &lt;code&gt;javax&lt;/code&gt; package, I think the &lt;code&gt;ServletRequest&lt;/code&gt; might need to be broken into a super and a sub-class.  Whether that would be  possible, considering the billions of lines of Java code already out there, I don&#039;t know... &lt;br /&gt;
&lt;br /&gt;
Things like wrapping the response String (bytes) in a web socket frame (i.e. leading 0x00 and trailing 0xFF byte) are also handled transparently by the &lt;code&gt;WebSocketsServletResponse&lt;/code&gt; implementation.  In fact, I went a step further.  After listening to two interesting videos  (with Jerome Dochez, the Architect of Glassfish -  &lt;a target=&#034;_blank&#034; href=&#034;http://www.infoq.com/presentations/The-Future-of-Java-EE&#034;&gt;The Future of Java EE&lt;/a&gt; and &lt;a target=&#034;_blank&#034; href=&#034;http://www.infoq.com/interviews/jerome-dochez-ee7&#034;&gt;Jerome discusses early plans for Java EE 7&lt;/a&gt;) I was inspired by some of the things he talked about.  He spoke about not wanting to mess around with parsing strings and getting the container to handle XML and JSON.  So... I added that to Tomcat too.  You&#039;ll notice in the code near the top, the handler method which is called for handling message events is called &lt;code&gt;doJSONMessage(WebSocketsServletRequest, WebSocketsServletResponse)&lt;/code&gt; rather than say simply &lt;code&gt;doMessage&lt;/code&gt;.  The reason is, the web sockets client (running in the browser) lets you send a header  containing the protocol which it will use.  This protocol appears to be a free text which the application can choose.  In my implementation I  went with XML, JSON, TEXT and BIN (binary), although XML and BIN aren&#039;t fully implemented.  So when the client creates the web socket like this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;new WebSocket(&amp;quot;ws://localhost:8085/nio-websockets/TestServlet&amp;quot;, &amp;quot;JSON&amp;quot;);&lt;/code&gt; &lt;br /&gt;
&lt;br /&gt;
that JSON parameter is used by the container to decide which exact handler method in the servlet it will call.  It gets better too,  because instead of then having to manually handle the JSON string, the container does the magic, and from the &lt;code&gt;WebSocketsServletRequest&lt;/code&gt;  which is passed into the message handler method, I can retrieve the object, using the &lt;code&gt;#getDataObject()&lt;/code&gt; method.  And thanks to generics, it even passes that object back to me without me having to use a cast - the application servlet which implements the  &lt;code&gt;WebSocketsServlet&lt;/code&gt; base servlet specifies what type of data object it expects.&lt;br /&gt;
&lt;br /&gt;
How does that magic work, I hear you asking?  Well, its not that complicated.  The base servlet receives a byte array from the Comet event. It looks at the original request header and realises it should treat that request as a JSON object.  It then uses &lt;a target=&#034;_blank&#034; href=&#034;http://xstream.codehaus.org/&#034;&gt;XStream&lt;/a&gt; which knows XML as well as JSON to unmarshal the incoming request. One last bit of magic that is required is that it needs to know which class say a &amp;quot;container&amp;quot; object in the JSON string maps too - i.e. which class should it use to stick the JSON data into?  Well, XStream lets you define such aliases.  I had a think about where else this happens, and JAX-Binding does this.  So instead of the &lt;code&gt;@XmlType&lt;/code&gt; annotation for JAXB, I create the  &lt;code&gt;javax.json.bind.annotation.JsonType&lt;/code&gt; annotation, which is applied to data objects, like this:&lt;/p&gt;
&lt;div style=&#034;border: thin none; overflow: auto; width: 525px; height: 200px; background-color: rgb(255, 255, 255);&#034;&gt;
&lt;pre&gt;
@JsonType(name=&amp;quot;container&amp;quot;)
public class CommandContainer {

  private String command;
  private String result;
  private String data;
.
.
.
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
Here, the &amp;quot;name&amp;quot; attribute of the annotation says that this class is mapped to JSON objects whose name is &amp;quot;container&amp;quot;.  So JSON like this: &lt;/p&gt;
&lt;div style=&#034;border: thin none; overflow: auto; width: 525px; height: 150px; background-color: rgb(255, 255, 255);&#034;&gt;
&lt;pre&gt;
var data = {&amp;quot;container&amp;quot;:
               {&amp;quot;command&amp;quot;: &amp;quot;BUY&amp;quot;, 
                &amp;quot;data&amp;quot;: &amp;quot;GOOG,100@200.25&amp;quot;, 
                &amp;quot;result&amp;quot;: &amp;quot;sold&amp;quot;}
           };
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
is simply unmarshalled into an instance of the &lt;code&gt;CommandContainer&lt;/code&gt; class, so that the Java application can use the object immediately, rather than screwing around with strings and unmarshalling itself. The Tomcat container parses annotations during startup and I simply stuck some extra code in there to note down these mappings so that when the base servlet sets the raw data into the request, the request implementation (which is a Coyote object, rather than a javax object) can use something like XStream and these mappings to do the unmarshalling.  I had to watch out for the class loader here to - luckily XStream lets you set the classloader, because if you don&#039;t set it, you are stuck with one that doesn&#039;t know the webapp.  I simply took the classloader from the servlet context (which I got out of the &lt;code&gt;HttpServletRequest&lt;/code&gt; which the container actually passes to the Comet processor in the Comet Event), and it has a classloader which knows the webapp classes.  Regardless of whether such JSON annotated data classes are in the web-inf/classes  folder, or in jars, the container can deal with them.&lt;br /&gt;
&lt;br /&gt;
So what else is left?  Well, security for starters.  Chrome is very descent and because the Web Sockets path resides (in this case) under the same host as the one which serves the HTML containing the Javascript which opens the socket, it sends the JSESSIONID to the server during the  Web Sockets handshake.  That is really great, because so long as you had to log in to get the HTML, all web socket requests occur in the same session - so application developers have full access to the security framework supplied by Java EE!  Hence I can mark my Servlet as  requiring the user to be in a specific role in order to use it, as well as check their roles programmatically in my handler methods, using the  request object.  If the browser had not been so kind, my plan was to send the session ID to the server in the handshake as a request parameter in  the query string of the requested URL, by putting the session ID into the URL using JSP.&lt;br /&gt;
&lt;br /&gt;
On small problem with this security solution is that if the user isn&#039;t logged in, there is no way for the browser to handle the return code in the handshake properly.  At least not in Chrome.  In Chrome, the connection is simply closed, and the Javascript error console shows a  slightly cryptic message indicating that a 403 code was returned.  To avoid each browser implementing their own way to handle such problems,  the IETF web sockets specification needs to clearly state that such problems should be sent as an event to the client&#039;s &lt;code&gt;onerror&lt;/code&gt; callback method.  Let&#039;s cross our fingers hey?&lt;br /&gt;
&lt;br /&gt;
Resources, like EJBs, Entity Managers (JPA) and Web Services are also easily used - because in Java EE 6 I can inject them all using the container. While Tomcat doesn&#039;t support EJBs/WebServices per se, I still stuck some into the above example, to illustrate how such a servlet might look  in a fully fledged Java EE app server.  To make it work, I hacked Tomcat to look for those annotations and if nothing was found in the JNDI tree,  it simply injected a new instance of the class - ok, its cheating, but great for a proof of concept ;-)&lt;br /&gt;
&lt;br /&gt;
Note that while the servlet shown above might not be a typical application needing web sockets (because its a basic request/response app),  it demonstrates the way I would like to see web sockets added to Java EE.  It wouldn&#039;t be hard at all to write a servlet like this which handled a chat app, or for example an app where a user draws on their screen, and all other members see the drawing update on their screens in pretty much realtime.  I might go on to play with something like that, but  &lt;a target=&#034;_blank&#034; href=&#034;http://java.dzone.com/articles/websocket-chat&#034;&gt;this article&lt;/a&gt; already discusses some of the issues facing Web Sockets.&lt;br /&gt;
&lt;br /&gt;
A few weeks ago, I blogged about how node.js would need to provide the things like I have described in this article to become mature.  Java EE  has exactly the same challenges if it is to remain mature in the future, as new technologies are integrated into it.&lt;br /&gt;
&lt;br /&gt;
Well, that&#039;s pretty much it.  What do you think?&lt;br /&gt;
&lt;br /&gt;
Patches for Tomcat 7.0.14 are available &lt;a href=&#034;/pebble/files/tomcat-7.0.14-src-patchesForWebSockets.zip&#034;&gt;here&lt;/a&gt;.&lt;br /&gt;
The webapp containing the servlet shown above can be downloaded &lt;a href=&#034;/pebble/files/nio-websockets_20110621_2219.zip&#034;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Other useful links:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://blogs.webtide.com/gregw/entry/jetty_websocket_server&#034;&gt;A blog article about Jetty websockets&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://download.java.net/maven/glassfish/org/glassfish/grizzly/grizzly-websockets/2.0/grizzly-websockets-2.0-sources.jar&#034;&gt;Source code for the Grizzly (Glassfish) web sockets solution&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://www.jcp.org/en/jsr/detail?id=340&#034;&gt;JSR-340&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://java.net/projects/servlet-spec/lists/jsr340-experts/archive/2011-05/message/16&#034;&gt;A discussion on whether Tomcat will have websockets soon&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://jwebsocket.org/&#034;&gt;jWebSockets - a standalone websocket server&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://xstream.codehaus.org/&#034;&gt;XStream - marshals/unmarshals XML &amp;amp; JSON&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://www.infoq.com/presentations/The-Future-of-Java-EE&#034;&gt;A video of the conference presentation about the future of Java EE&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://www.infoq.com/interviews/jerome-dochez-ee7&#034;&gt;A video interview with Glassfish&#039;s architect&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://tomcat.apache.org/tomcat-6.0-doc/aio.html&#034;&gt;Tomcat docs for Comet&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://caucho.com/resin-4.0/examples/websocket-java/index.xtp#WebSocketOverview&#034;&gt;Caucho&#039;s Resin Websockets&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://dev.w3.org/html5/websockets/&#034;&gt;HTML5 Web sockets spec&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target=&#034;_blank&#034; href=&#034;http://localhost:8080/nio-websockets/index.jsp&#034;&gt;The link to start the demo I created, once you install it locally - http://localhost:8080/nio-websockets/index.jsp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
Copyright &amp;copy; 2011 Ant Kutschera&lt;/p&gt;&lt;div class=&#034;tags&#034;&gt;&lt;span&gt;Social Bookmarks : &lt;/span&gt;&amp;nbsp;&lt;a href=&#034;http://slashdot.org/bookmark.pl?url=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;title=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Add this post to Slash Dot&#034;&gt;&lt;img src=&#034;common/images/slashdot.png&#034; alt=&#034;Add this post to Slashdot&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://digg.com/submit?url=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;title=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Digg this post&#034;&gt;&lt;img src=&#034;common/images/digg.png&#034; alt=&#034;Add this post to Digg&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://reddit.com/submit?url=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;title=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Add this post to Reddit&#034;&gt;&lt;img src=&#034;common/images/reddit.png&#034; alt=&#034;Add this post to Reddit&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://del.icio.us/post?url=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;title=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Save this post to Del.icio.us&#034;&gt;&lt;img src=&#034;common/images/delicious.png&#034; alt=&#034;Add this post to Delicious&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.stumbleupon.com/submit?url=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;title=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Stumble this post&#034;&gt;&lt;img src=&#034;common/images/stumbleupon.png&#034; alt=&#034;Add this post to Stumble it&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.google.com/bookmarks/mark?op=edit&amp;amp;bkmk=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;title=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Add this post to Google&#034;&gt;&lt;img src=&#034;common/images/google.png&#034; alt=&#034;Add this post to Google&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://technorati.com/faves?add=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Technorati&#034;&gt;&lt;img src=&#034;common/images/technorati.png&#034; alt=&#034;Add this post to Technorati&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.bloglines.com/sub/http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Bloglines&#034;&gt;&lt;img src=&#034;common/images/bloglines.png&#034; alt=&#034;Add this post to Bloglines&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.facebook.com/share.php?u=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Facebook&#034;&gt;&lt;img src=&#034;common/images/facebook.png&#034; alt=&#034;Add this post to Facebook&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.furl.net/storeIt.jsp?u=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;t=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Add this post to Furl&#034;&gt;&lt;img src=&#034;common/images/furl.png&#034; alt=&#034;Add this post to Furl&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;https://favorites.live.com/quickadd.aspx?mkt=en-us&amp;amp;url=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;title=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Add this post to Windows Live&#034;&gt;&lt;img src=&#034;common/images/windowslive.png&#034; alt=&#034;Add this post to Windows Live&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;amp;u=http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html&amp;amp;t=Tomcat%2C+WebSockets%2C+HTML5%2C+jWebSockets%2C+JSR-340%2C+JSON+and+more&#034; target=&#034;_blank&#034; title=&#034;Add this post to Yahoo!&#034;&gt;&lt;img src=&#034;common/images/yahoo.png&#034; alt=&#034;Add this post to Yahoo!&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&lt;/div&gt;
        </description>
      
      
    
    
    
    <comments>http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html#comments</comments>
    <guid isPermaLink="true">http://blog.maxant.co.uk:80/pebble/2011/06/21/1308690720000.html</guid>
    <pubDate>Tue, 21 Jun 2011 21:12:00 GMT</pubDate>
  </item>
  
  <item>
    <title>Transfer-Encoding: chunked</title>
    <link>http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html</link>
    
      
        <description>
          &lt;p&gt;The J2ME HTTPConnection which comes with MIDP lets you make HTTP requests to your server. It doesn&#039;t do much at a high level, for example the API doesn&#039;t have methods like addCookie() - you need to manually add them with a request header. But the implementation is clever enough to turn any request body which is greater than around 2Kb into a chunked request.&lt;br /&gt;
&lt;br /&gt;
With HTTP 1.0, the request had to contain a header called Content-Length which told the server how many bytes to read off the input stream when reading the body. HTTP 1.1 introduced the Transfer-Encoding header, which lets the client omit the Content-Length header, and instead create chunks of request body, which optimises the upload meaning that a) the server can start processing before it has everything, and b) more importantly for J2ME where memory might be a valuable resource, it lets the client send a bit of the request, free up that allocated memory and then send some more of the request.&lt;br /&gt;
&lt;br /&gt;
For a POST request, with no chunking, the headers and body might look like this:&lt;/p&gt;
&lt;pre&gt;
	POST /log.jsp HTTP/1.1
	User-Agent: Mozilla/4.0 (maxant J2ME Client) 
	Accept: text/html,application/xhtml+xml,application/xml
	Content-Type: application/x-www-form-urlencoded
	&lt;b&gt;Content-Length: 51&lt;/b&gt;
	Host: wwwchaseamatecom:8089

	problem=Failed%20to%20get%20installation%20response
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
Chunked, that becomes:&lt;/p&gt;
&lt;pre&gt;
	POST /ota/addInstallation.jsp HTTP/1.1
	User-Agent: Mozilla/4.0 (maxant J2ME Client) 
	Accept: text/html,application/xhtml+xml,application/xml
	Content-Type: application/x-www-form-urlencoded
	Host: wwwchaseamatecom:8089
	&lt;b&gt;Transfer-Encoding: chunked&lt;/b&gt;

	problem=Failed%20to%20get%20installation%20response
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
You&#039;ll notice that the body of the second example, &amp;quot;problem=...&amp;quot; doesn&#039;t contain chunk headers (search Wikipedia for chunking to see an example). The reason is that I copied that text out of the TCP/IP Monitor in Eclipse 3.5 and it seems kind enough to hide that information and simply show you the unchunked body. Not great if you aren&#039;t expecting that, somewhat useful none the less.&lt;br /&gt;
&lt;br /&gt;
Anyway, about time I got to the point of this blog article. Any version of Tomcat before 5.5.28 or 6.0.21 (ie. the latest versions at the time of writing!) had a nasty bug in them whereby POST requests did NOT get the body parsed and put into request.getParameter(String) or request.getQueryString(). Very nasty indeed for J2ME developers. I trawled the internet and found people were having problems from around 2002 when HTTP 1.1 became available in J2ME. Only with the following bug fix has this finally been corrected on Tomcat, some 8 years later. &lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&#034;https://issues.apache.org/bugzilla/show_bug.cgi?id=37794&#034;&gt;https://issues.apache.org/bugzilla/show_bug.cgi?id=37794&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Work arounds included using Apache to put together the chunks before sending the request on to Tomcat, or manually splitting the request on the device, into small chunks and upload each one and then joining them together at the end - what a load of work to have to do! &lt;br /&gt;
&lt;br /&gt;
I&#039;m working with an old 5.5.9 Tomcat installation and have just upgraded it to 5.5.28 to fix this problem. &lt;br /&gt;
&lt;br /&gt;
However before I found this bug report I did consider creating a filter and configuring it in my web.xml. The idea was that the filter would read the request body, URL decode it, unlock the requests parameter map (Catalina has a lockable map which is locked after parsing the request), and put the request bodies request parameters into the map. Something like this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr size=&#034;2&#034; width=&#034;100%&#034; /&gt;
&lt;div style=&#034;border: thin none ; overflow: auto; width: 525px; height: 300px; background-color: rgb(255, 255, 255);&#034;&gt;
&lt;pre&gt;
/*  
 * Copyright (c) 2010 Ant Kutschera, maxant
 * 
 * This file is part of Ant Kutschera&#039;s blog, http://blog.maxant.co.uk
 * 
 * This is free software: you can redistribute it and/or modify
 * it under the terms of the Lesser GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * It is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Lesser GNU General Public License for more details.
 * You should have received a copy of the Lesser GNU General Public License
 * along with Foobar.  If not, see .
 */
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

//nasty, but we are afterall fixing a bug in catalina!
import org.apache.catalina.util.ParameterMap;

public final class RequestHandler implements Filter {

	private static final String TRANSFER_ENCODING = &amp;quot;Transfer-Encoding&amp;quot;;
	private static final String CHUNKED = &amp;quot;chunked&amp;quot;;

	public void destroy() {
	}

	public void init(FilterConfig filterConfig) throws ServletException {
	}
	
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		String header = request.getHeader(TRANSFER_ENCODING);
		
		InputStream is = null;
		try{
			if(header != null &amp;amp;&amp;amp; header.equals(CHUNKED)){
				//time to work our magic

				((ParameterMap)request.getParameterMap()).setLocked(false);
				is = request.getInputStream();

				//read the body as a map
				Properties props = new Properties();
				props.load(is);
				
				//get the encoding to use for url-decoding
				String enc = request.getCharacterEncoding();
				if(enc == null){
					enc = &amp;quot;UTF-8&amp;quot;;
				}

				for(Entry e : props.entrySet()){
					
					String key = (String) e.getKey();

					//need to decode it!
					key = URLDecoder.decode(key, enc);

					if(!request.getParameterMap().containsKey(key)){
						String val = (String) e.getValue();

						//need to decode it!
						val = URLDecoder.decode(val, enc);

						request.getParameterMap().put(key, val);
					}
				}
			}				
				
			((ParameterMap)request.getParameterMap()).setLocked(true);
				
		}finally{
			if(is != null) is.close();
		}
	}
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
I wasted hours because of this rubbish bug. The problem is that its full of red herrings, making you think for example that because the monitor shows the request body unchunked, that the device isn&#039;t chunking the body properly. The web is also full of very old posts related to servers not being HTTP 1.1 compatible. And there are lots of work arounds which people went to the effort of because they had no other choice until most recently. So hopefully if you have had chunking problems with J2ME, you found this article without too much hassle!&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010 Ant Kutschera&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&#034;tags&#034;&gt;&lt;span&gt;Social Bookmarks : &lt;/span&gt;&amp;nbsp;&lt;a href=&#034;http://slashdot.org/bookmark.pl?url=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;title=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Add this post to Slash Dot&#034;&gt;&lt;img src=&#034;common/images/slashdot.png&#034; alt=&#034;Add this post to Slashdot&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://digg.com/submit?url=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;title=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Digg this post&#034;&gt;&lt;img src=&#034;common/images/digg.png&#034; alt=&#034;Add this post to Digg&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://reddit.com/submit?url=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;title=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Add this post to Reddit&#034;&gt;&lt;img src=&#034;common/images/reddit.png&#034; alt=&#034;Add this post to Reddit&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://del.icio.us/post?url=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;title=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Save this post to Del.icio.us&#034;&gt;&lt;img src=&#034;common/images/delicious.png&#034; alt=&#034;Add this post to Delicious&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.stumbleupon.com/submit?url=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;title=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Stumble this post&#034;&gt;&lt;img src=&#034;common/images/stumbleupon.png&#034; alt=&#034;Add this post to Stumble it&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.google.com/bookmarks/mark?op=edit&amp;amp;bkmk=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;title=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Add this post to Google&#034;&gt;&lt;img src=&#034;common/images/google.png&#034; alt=&#034;Add this post to Google&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://technorati.com/faves?add=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Technorati&#034;&gt;&lt;img src=&#034;common/images/technorati.png&#034; alt=&#034;Add this post to Technorati&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.bloglines.com/sub/http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Bloglines&#034;&gt;&lt;img src=&#034;common/images/bloglines.png&#034; alt=&#034;Add this post to Bloglines&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.facebook.com/share.php?u=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Facebook&#034;&gt;&lt;img src=&#034;common/images/facebook.png&#034; alt=&#034;Add this post to Facebook&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.furl.net/storeIt.jsp?u=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;t=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Add this post to Furl&#034;&gt;&lt;img src=&#034;common/images/furl.png&#034; alt=&#034;Add this post to Furl&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;https://favorites.live.com/quickadd.aspx?mkt=en-us&amp;amp;url=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;title=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Add this post to Windows Live&#034;&gt;&lt;img src=&#034;common/images/windowslive.png&#034; alt=&#034;Add this post to Windows Live&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;amp;u=http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html&amp;amp;t=Transfer-Encoding%3A+chunked&#034; target=&#034;_blank&#034; title=&#034;Add this post to Yahoo!&#034;&gt;&lt;img src=&#034;common/images/yahoo.png&#034; alt=&#034;Add this post to Yahoo!&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&lt;/div&gt;
        </description>
      
      
    
    
    
    <comments>http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html#comments</comments>
    <guid isPermaLink="true">http://blog.maxant.co.uk:80/pebble/2010/02/24/1266992820000.html</guid>
    <pubDate>Wed, 24 Feb 2010 06:27:00 GMT</pubDate>
  </item>
  
  </channel>
</rss>

