Skip to main content
 

Gopher on MTV

1 min read

I dug this little gem out of the archives.  Enjoy!

Gopher World Tour T-Shirt on MTV
 

Email Clients Full Circle

2 min read

In the beginning I used elm to read my mail.  This was somewhat radical, especially as I worked with the team that created POPMail for the mac and Minuet for the PC, and everyone else moved to pine.  Then came Mutt -- happy days -- I was able to slice and dice email with amazing speed.

A couple of years ago I converted over to Mail.app -- mostly because of the contacts and calendar integrations, and the fact that I could merge personal email and corp email accounts.  In the intervening time I had to move to comcast, which meant running my own imap server proved more difficult than it was worth, so I moved to Google Apps for Your Domain, all of a sudden my personal domain is running Gmail, and I discovered it has key bindings.
All of a sudden it's mutt deja-vu. navigation with vi j/k keys? yes.  Single window view (inbox/message)? yes again.  Tagging messages? yes.  Blazingly fast? you bet.  The only thing I miss is keystroke filtering of messages.
That's one reason why I see things like Google Wave working out so well, I might be late to the gmail party, but plenty of folks have been using this as their primary mode of communication for a long long time.
 

Tomcat and SSL Accelerators

3 min read

Using an SSL Accelerator like a Netscaler is really useful, you can offload a lot of work to a device that supports this in hardware and can use SSL session affinity to send requests to the same backend.  In the simplest setup the SSL Accelerator accepts the request and proxies it to your internal set of hosts running on port 80.

However, code that generates redirects and URLs works poorly because the servletRequest.getScheme(), getSecure() and getServerPort() will return http/false/80 for SSL and non-SSL connections.
One way to solve this is listen on multiple ports.  Create a Connection on 80 and 443, but do not run SSL on either port.  Then for the 443 port you configure it with secure="true" and scheme="https".  This is suboptimal however as then you have to manage yet another server pool in your load balancer and you end up sending twice the health checks.  Not so good.
You might try to solve this by using a ServletFilter.  You can use an HttpServletRequestWrapper instance to change the scheme/port/and secure flag.  Sadly this doesn't work, because of the way tomcat implements HttpServletResponse, it uses the original request object to ascertain the scheme/secure flag/port.  Overriding these will allow application logic to see the updated values.  You get into trouble when you call encodeRedirectURL() or sendRedirect() with non-absolute URLs.
Lucky for us Tomcat supports a way to inject code into the connection handling phase via Valves.  A valve can query and alter the Catalina and Coyote request objects before the first filter is run.  
To make your Valve work you'll need to configure your load balancer to send a special header when SSL is in use.  On the Netscaler this can be done by setting owa_support on.  With that enabled the http header Front-End-Https: On is sent for requests that use SSL.
Once we have these pieces in place the Valve is fairly straightforward:

import java.io.IOException;

import javax.servlet.ServletException;

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;

public class NetscalerSSLValve extends ValveBase {

        @Override
        public void invoke(Request req, Response resp) throws IOException, ServletException {
                if ("On".equals(req.getHeader("Front-End-Https"))) {
                    req.setSecure(true);
                    req.getCoyoteRequest().scheme().setString("https");
                    req.getCoyoteRequest().setServerPort(443);
                }
                if ( getNext() != null ) {
                        getNext().invoke(req, resp);
                }
        }
}

Compile this, stick it in the tomcat lib directory, add an entry in your server.xml and away you go.

 

Google I/O Today

1 min read

Speaking at "Meet the Containers", "Shindig 101" and "OpenSocial Fireside Chat".

All at Moscone West, check it out!

http://code.google.com/events/io/

 

The Mysteries of Java Character Set Performance

4 min read

"Two Characters Sets?  Seems like plenty!"

So I've been pushing Java to it's limits lately and finding some real nasty concurrency issues inside the JRE code itself.  Here's one particulary ugly one -- we had 700 threads stuck here:

       java.lang.Thread.State: BLOCKED (on object monitor)                                                                    
         at sun.nio.cs.FastCharsetProvider.charsetForName(FastCharsetProvider.java:118)
         - waiting to lock <0x00002aab4cdf91b8> (a sun.nio.cs.StandardCharsets)
         at java.nio.charset.Charset.lookup2(Charset.java:450) 
         at java.nio.charset.Charset.lookup(Charset.java:438)
         at java.nio.charset.Charset.isSupported(Charset.java:480) 
         at java.lang.StringCoding.lookupCharset(StringCoding.java:85) 
         at java.lang.StringCoding.decode(StringCoding.java:165)                                                                      
         at java.lang.String.(String.java:516) 
Digging deeper we find the lookupCharset is called all over the place.  The app in question is functions as a web proxy, so it's constantly reading and writing data from web pages in a variety of character sets.  The method charsetForName() uses a synchronized data structure to lookup defined character sets.  (Yay serialized access....)
But wait, lookup and lookup2 provide us with a cache so we can avoid the big bad synchronized method..  Sigh, here's the implementation:
     private static Charset lookup(String charsetName) {
         if (charsetName == null)
             throw new IllegalArgumentException("Null charset name");
 
         Object[] a;
         if ((a = cache1) != null && charsetName.equals(a[0]))
             return (Charset)a[1];
         // We expect most programs to use one Charset repeatedly.
         // We convey a hint to this effect to the VM by putting the
         // level 1 cache miss code in a separate method.
         return lookup2(charsetName);
     }
 
     private static Charset lookup2(String charsetName) {
         Object[] a;
         if ((a = cache2) != null && charsetName.equals(a[0])) {
             cache2 = cache1;
             cache1 = a;
             return (Charset)a[1];
         }
 
         Charset cs;
         if ((cs = standardProvider.charsetForName(charsetName)) != null ||
             (cs = lookupExtendedCharset(charsetName))           != null ||
             (cs = lookupViaProviders(charsetName))              != null)
         {
             cache(charsetName, cs);
             return cs;
         }
 
         /* Only need to check the name if we didn't find a charset for it */
         checkName(charsetName);
         return null;
     }
Yes, a whopping 2-entry cache!!
Also, the keys used are not canonical, so if my app asks for "UTF-8", "utf-8", and "ISO-8859-1" with regularity this 2 entry cache is worthless, every call ends up blocking in the evil thread-synchronized data structure.
Someone send them a copy of the ConcurrentHashMap doc.  please.
....
 

Social Graph Meat-up

1 min read

Dinner not for vegans at O'Reilly.

 
 

Tired

1 min read

Why am I so tired?

Been working hard to implement features decribed here..:

hi5 Launches New Music Applications By iLike and Qloud

No more music royalties for hi5.  Cost center is now a profit center...


 

Bugathon!

1 min read

'nuff said...

 

OpenSocial Roundup

3 min read

 At hi5 we've been busy busy busy getting OpenSocial up and running.  We released our developer sandbox, and are rapidly implementing features.  So check out the following URLs

Campfire One Highlights: Introducing OpenSocial


Also, here's a copy of my response to Tim O'Reilly's blog post:

OpenSocial: It's the data, stupid

Hi folks,

Good comments all around. However I'd like to posit that data access is _not_ the problem. We've had universal standards for years now with little uptake. Tribe.net, Typepad, LiveJournal and others have supported FOAF for many, many years, which encompasses the OpenSocial Person and Friends APIs. Not much has come of that -- there isn't a large enough base there to get people interested.

Now you have a broad industry consensus on a single way to provide all of the above plus activity stream data. You have a rich client platform that allows you to crack open that data and use it in interesting ways, and finally you have a common standard for social networks to interact with each other based on the REST api.

So Patrick's statement at the Web 2.0 Expo is correct, a app running inside a container only allows you to see what that container shows you. However that does not mean that a container could not contain friend references to external social networks via it's own federation mechanism. Movable Type 4.0 has shown that you can support any OpenID login in a single system, there's no reason to believe that social networks could not leverage OAuth to do the same.

And here's a final point to consider -- you have Myspace opening up to developers. That's huge. That alone is going to draw more developer attention to this problem than much of the oh-so academic discussions of the past few years.

I suggest people that _want_ OpenSocial to solve all the social graph ills get involved on the API mailing list and make sure that those elements are addressed as OpenSocial evolves.

There's a tremendous amount of momentum. Let's not waste this chance.