Wednesday, October 31, 2007

Delicious - Just the Tip of the Iceberg

I had a long conversation with my long time friend James yesterday. We spent some time chatting about a link I sent to him via del.icio.us, which posited that social bookmarking is essentially broken. I like the kind of analysis the author provides - it's nice to see someone thinking about a problem, so I promptly commented on the blog, noted that for future reference, and sent it to James.

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.

I said: "noted that for future reference" and "sent it to James."

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.

Action 1: noted that for future reference


I actually stored a reminder for myself on del.iciou.us using a tag called "commented". This is an action tag, it's something I have done. I'll get to the difference between an action tag, and a classification 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.

Action 2: sent it to James


I sent the link to James using the built-in "for:" 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: http://del.icio.us/for/tgautier. 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 actionable tag. Now lets discuss what I'm talking about.

What's a Folksonomy, and why do I care?


First, we need to understand a little bit about what exactly is del.icio.us.

Everyone and their brother that uses del.icio.us today is familiar with using it as a classification system. Looking at the list of popular tags on del.iciou.us, they are primarily of the type that adds meta-data about the target link that relates to what the tagger thinks that link is. 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, folksonomy) 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. The del.iciou.us popular tags link shows you what people think of the web.

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.

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).

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:

What else can I do with link meta-data? The bigger picture


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:


+ Link Meta-Data Taxonomy
- Classification Folksonomy (e.g. tutorial, howto, tip, webdesign, etc.)
- Relational Folksonomy (e.g. authored, commented, etc.)
- Actional Folksonomy (e.g. forterracotta)


Classification Folksonomy


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 is. So if it's a tutorial on web design practices, you might tag the link as "tutorial webdesign".

Relational Folksonomy


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.

Actional Folksonomy


I've not seen much of these around. We use them for our buzz system on http://www.terracotta.org which I blogged about in detail several months back. 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 "my startpage". 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.

What next?


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.

Tuesday, October 30, 2007

Java 6, Leopard, Apple, Sun, who's really to blame?

Oh dear, I fear I may be jumping on the bandwagon. Nonetheless, here I go...

By my count, at DZone, there are at least 7 articles written specifically about the lack of Java 6 on Apple's new OS, Leopard. Which means there's probably at least 700 written so far, scaling up by a reasonable factor for all those posts I missed, forums and whatnot.

Now here's the thing - everyone seems up in arms about APPLE not putting out Java 6 on Leopard, but this seems quite odd to me. In what I think is the best analysis so far, [Time Code] posts some very relevant thoughts, the most interesting of which is Gosling's own admission that he has abandoned the Mac. I remember reading about this a few weeks ago, but I dismissed it quickly, since it didn't seem that there was anything here other than pure self interest at play - of course Gosling would switch from an Apple built machine running OS X to a no-name machine running Solaris - which one does Sun have a better interest in seeing Gosling champion? Hmmm you do the math.

In other opinions around the 'sphere, Michael Urban, from DZone itself, writes that he is so angry he's selling every Mac he owns - scary stuff -- I'm glad I don't have to work with someone like that, but that's beside the point. His ire isn't directed at SUN, it's pointed at APPLE. We get a counter point from Jeff Shell, calling the Java community Cry Babies. After reading Michael's post, I think I see where Jeff's coming from. My buddy Steve Harris, fortunately a little more reserved in his judgement, also makes a practical point - we at Terracotta write only Java Software, and most of us, including yours truly, have Mac Laptops so there's a real practical problem at stake here.

What I fail to understand in all of this, and hope to bring to light, is that for all the ire pointed at APPLE, where's the anger at the real company to blame for all of this - SUN. Yes, that's right, SUN. The most ironic thing I find in Michael Urban's post is this quote: "and will spend most of its time running Windows". So let me get this straight, Michael. You're going to sell all of your Mac machines, in extreme protest against APPLE, and run WINDOWS? Let's not forget that MICROSOFT out and out tried to destroy Java a few years ago, and no longer produces a JDK either (self interest again - .NET competes with it so I don't blame them). It's not as if the Linux community is producing JDKs either - in fact no one out there can due to SUN's licensing problems which only went open source as of last year.

My point is, SUN is to blame here, not APPLE. Those of us using Mac machines have been shielded from the glaring omission that is SUN's lack of support for the Apple platform, and it wasn't very nice of Apple to simply throw us into the cold swimming pool without warning, but let's not blame APPLE for the fact that SUN is the real bad guy here. The Java 6 Download page is as telling as anything you could want. (Note that I cannot link to it directly since it requires a "Sun Login" which is about as stupid a thing as I can imagine, but we have no other choice so we dutifully login to get our fix...). It lists the following operating systems: Windows, Linux, Solaris SPARC, Solaris x86, Solaris x64, Linux x64, and Windows x64. What is missing from that picture??

So before everyone starts flaming away (which you will anyway, I know you want to) -- I am aware of the rumor that APPLE insists on doing their own JDK. Until someone can substantiate it, I am inclined to believe that if SUN really believed in the Mac platform, they could probably have inked a deal by now so that they can ensure the livelihood of Java on the Mac Platform - in other words, I cannot believe that Jobs could really enforce Sun to NOT support Java on the Mac platform. It's not as if Gates wants Java on Windows either, but it's there.

As a last sidenote, the thing that amazes me is that I am writing this Tuesday morning, Oct 30. It's been a mere 4 days since Leopard's release. It seems to me that if you are complaining about broken things with a brand new Operating System 4 days old, and particularly if you are complaining that your production systems are impacted because of it, you might want to re-think your rollout strategy when it comes to new software. Patience is going to be the key here, I hope in the meantime APPLE does the right thing and lets people in on their plans (which they won't, which is why people are so angry with them, and I get that). In the meantime, I would like to switch to Leopard, because it looks really cool, but it seems I'll have to wait for the first -dot- release, not just because Java 6 isn't on OS 10.5, but because the guy that runs our IT department has some sense in his head and imposed a company wide lockdown on company owned Macs -- no Leopard for us until the -dot- release.

Until then, if you're angry about Java support on the Mac, tell Sun why don't ya?

Thursday, October 04, 2007

Reimplementing RMI

Today, on our forums, a user asked how to implement an RMI like solution:


My clustered app will be a client of an external service (via a socket connection) where only ONE node in the cluster will maintain the connection. All the other nodes will need to utilize the external service via the node connected to it.


An interesting puzzle. It's basically RMI. Should one reimplement RMI with Terracotta? That wasn't the point -- I can't resist a challenge like this, so I whipped up a solution. Ultimately, it ended up being a combination of a queue to send the method invocation, and some wait/notify to wait for the response.

As I was chatting about the solution with DSO Guy Steve Harris I remarked that I often come across questions of the sort "how do I do this in Terracotta?" I said that the answer was remarkably easy - though I think it just doesn't occur to people how easy it really is.

The great thing about Terracotta is that it really gives you just Java. By extending the Java Memory Model, Terracotta makes sure that memory and synchronization work exactly the same as in a single JVM. So the answer to the question "how do I do this in Terracotta?" is extremely easy: How do you do this in a single JVM with multiple threads? Whatever your answer is, that's the answer to doing it with Terracotta.

To illustrate this point, let's see how I solved the RMI question. Basically, I implemented a Dynamic Proxy (with some help from Hung on writing a Dynamic Proxy here which neatly wraps up the guts of the implementation so it can be wrapped around any implementation.

As a result of using Dynamic Proxy, we already get a Method and Arguments that we have to handle, so to execute this method on a specific node is the same as executing it on a separate thread. To do that, use a queue. And to signal the response, use wait and notify.

Here's the code:
import java.util.concurrent.*;
import java.lang.reflect.*;

public class RemoteInvoker implements InvocationHandler, Runnable
{
private BlockingQueue<MethodArguments> queue = new LinkedBlockingQueue<MethodArguments>();

private final Object instance;

public RemoteInvoker(Object instance)
{
this.instance = instance;
start();
}

private static class MethodArguments
{
public final Object proxy;
public final Method method;
public final Object[] args;
private MethodResult result;

public MethodArguments(Object proxy, Method method, Object[] args)
{
this.proxy = proxy;
this.method = method;
this.args = args;
}

public synchronized MethodResult getResult() throws InterruptedException
{
while (result == null) { wait(); }
return result;
}

public synchronized void setResult(MethodResult result)
{
this.result = result;
notify();
}
}

private static class MethodResult
{
public final Object object;
public final Exception exception;

public MethodResult(Object object, Exception exception)
{
this.object = object;
this.exception = exception;
}
}

private void start()
{
Thread t = new Thread(this);
// t.setDaemon(true);
t.start();
t.start();
}

public void run()
{
synchronized (instance) {
System.out.println("I am servicing requests...");

MethodArguments arguments;
while (true) {
try {
arguments = queue.take();
try {
Object value = arguments.method.invoke(instance, arguments.args);
arguments.setResult(new MethodResult(value, null));
} catch (Exception e) {
arguments.setResult(new MethodResult(null, e));
}
} catch (InterruptedException e) {
// do nothing
}
}
}
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
MethodArguments arguments = new MethodArguments(proxy, method, args);
queue.put(arguments);
MethodResult result;

result = arguments.getResult();
if (result.exception != null) {
throw result.exception;
}

return result.object;
}

And here's how to use it:
import java.lang.reflect.*;

public class Test implements TestInterface
{
int counter = 0;

public int count(int count)
{
System.out.println("Incrementing counter by: " + count);

counter += count;
return counter;
}

public static void main(String[] args)
{
Test t = new Test();
RemoteInvoker invoker = new RemoteInvoker(t);
TestInterface proxy = (TestInterface) Proxy.newProxyInstance(t.getClass().getClassLoader(), new Class[] { TestInterface.class } , invoker);
System.out.println("Proxy returns: " + proxy.count(3));
}
}

What I really like about this solution, and Terracotta in general, is that it works exactly the same in a single JVM as many JVMs. The key difference to many JVMs is that by clustering the Queue, the execution is transferred across physical JVMs, and the wait/notify sends the response back - no different than cross-thread communication in a single JVM.

For the complete instructions on running this with Terracotta, read the whole thread.

Btw, if you read the code, maybe you were wondering why run() method is synchronized against instance. Well, getting back to the request from the user, the original requirement was that only one instance can be "connected" - in other words servicing requests. The synchronized makes sure only one instance is servicing the queue - whether it's a single JVM or many JVMs.