Archive for the ‘Uncategorized’ Category

GemFire DTD

without comments

If you’re writing GemFire cache.xml files you’ll probably want to refer to the GemFire DTD files for valid syntax. These are hosted on gemstone.com but don’t seem to appear in Google searches so I’m putting this blog in place to facilitate finding them.

GemFire 6.6 DTD on gemstone.com (latest version)
Ye Olde GemFire 6.0 DTD (consider an upgrade)

Written by Carter Shanklin

March 23rd, 2012 at 11:14 pm

Posted in GemFire,Uncategorized,vfabric

Tagged with ,

vSphere 5 Licensing: A few things to consider.

with 30 comments

Disclaimer: These thoughts are my personal opinions. Since I work on vFabric these days and not vSphere I’m not very familiar with the specific reasons behind any choices made with respect to the new licensing scheme.

I missed the big launch yesterday because I’m hanging out in India with the GemFire and SQLFire teams, but I got up this morning and saw the discussion is completely dominated by talk of the licensing changes. That’s too bad because vSphere 5 has some pretty cool new features that aren’t getting the attention they deserve, for instance Storage DRS and SRM failback.

The new scheme is quite different from anything we’ve seen and any change is naturally met with skepticism. I think people who are worried about the new scheme should consider what would have happened if VMware maintained the status quo. vSphere 4 was not licensed per host, rather it’s “per CPU socket up to X cores” where X depends on the license level, 6 for Enterprise and 12 for Enterprise Plus if I recall correctly.

The big push in hardware is to increase core counts as fast as possible. Predictions are core counts will follow a Moore’s law-like trajectory of doubling about every 18 months. I know there are 10 core CPUs on the market today and much more dense CPUs are in the pipeline. So consider that in a few years you’re going to have computers with 32 or 48 or maybe even 64 cores per CPU. If you’ve got a computer with 4 CPU sockets  each with 64 cores you’d need 44 licenses of Enterprise or 24 licenses of Enterprise Plus to have the host in compliance. (The formula is ceiling(# cores / max cores at license level) * number of sockets. Get that??)

Now consider that each host in your inventory is going to have different hardware profiles and require the same kinds of calculations. What a mess!

The fundamental thing is that to deal with this mess VMware had to change to some sort of pooling mechanism. Other vendors are going to have to do similar things. These sorts of host-by-host calculations on discrete boundaries are just unsustainable as IT environments get more and more complex. Pooling is the only answer. The only other option that is tenable is per-host licensing, but you won’t see that from anyone because it can’t monetize big hosts and small hosts differently.

VMware could have chosen to do core-based pooling or memory-based pooling. As it happens they chose memory-based, I don’t know the specifics of why, these hardware assets seem to be on the same growth trajectory. But my understanding is the amounts of memory they chose (24/32/48 depending on license level) were chosen so that most common current hardware configurations would not be affected.

So if you’re worried about vSphere’s new licensing scheme, consider the mess you would be in without this change, and also bear in mind that you were going to need to buy a lot more vSphere 4 licenses to enable the next wave of hardware anyway, because of exploding core densities. With pooling the operational aspects get a whole lot easier.

Update: In case you missed it, the vRAM licensing scheme was changed with higher ratios and some other tweaks. Read about it on the official blog.

Written by Carter Shanklin

July 13th, 2011 at 2:25 am

Posted in Uncategorized

WANatronic 10001: An extremely simple WAN emulator

with 39 comments

A couple of products I work on, SQLFire is one of them, have WAN features for linking different datacenters together with asynchronous replication. Whenever I tell people about it the first thing they ask is what happens if the same data is updated in both datacenters at the same time. I don’t really know all that well, so I wanted to tool that would help me learn more about it, I needed a WAN emulator.

I looked at a couple of WAN simulators, specifically WANem and Dummy Cloud. WANem gave me a pretty bad impression, it’s text UI is extremely buggy and I didn’t even notice that it is supposed to be driven by its Web UI. Maybe the rest of the product is better but I’m looking for something as simple as possible. Dummy Cloud looks pretty good, and is loaded with features. Too many features actually, for what I want, and the free version doesn’t let you do really high latencies. So I decided to roll my own. I packaged the results as the WANatronic 10001 virtual appliance you can run on VMware Workstation, and probably ESX and Fusion as well.


  • Can work with nothing but a laptop (no actual network required).
  • As small and lightweight as possible.
  • Simple, as close to zero configuration as possible.
  • Really cool name.

I think things turned out fairly well. Namely:

  • Traffic sent directly to WANatronic 10001 is sent right back to whatever host it originated from. If  you ping WANatronic 10001 you’re actually pinging yourself. Same with SSH, etc.
  • Packaged as a VM needing 32MB and a download size of about 170MB, which unfortunately is small as far as virtual appliances go.
  • There are 4 things  you can configure. If you’re lazy and don’t configure anything, WANatronic 10001 will still work.
  • That’s pronounced WAN-a-tron-ic ten-thousand-one in case you were wondering. Just try to forget that name. See? You can’t do it.

Using WANatronic 10001

WANatronic 10001 Screenshot

Possibly the most interesting thing, and the thing I think I’ll use it most for, is simulating slow links on a single host. In this case there is nothing you need to do on your computer. In the screenshot above my WANatronic is at Any traffic I send to that IP is sent right back to me. So if I have two processes on my host that I want talking slowly, let’s say one is on port 8000 and one is on port 9000, all I do is tell the first application that its peer is on and tell the second one its peer is on Done.

WANatronic can also function as a router-on-a-stick, all you need to do is route traffic through WANatronic. For example Google’s free DNS is located at If you want to simulate being on a slow network between here and there run:

ip route add via

Your IP address will be different from mine, check the console to see what it is. You may need to adjust that command based on your OS. With that set up, ping to see the effect of latency and packet loss.

Last but not least, configuration is via the console since there is no way to remotely connect to WANatronic. Changes are automatically saved and applied.

Technical Mumbo Jumbo

WANatronic uses Ubuntu 8.04 JEOS as a base. I used this older distro to cut down on the size of the virtual appliance, which unfortunately is still huge. For the most part WANatronic is a very basic use of the iptables and tc utilities. The WANatronic source code is hosted on GitHub.

There is one exception that required a little bit of science. I really wanted any traffic sent to WANatronic to be NATted directly back to me. Without this I would need to use multiple network interfaces which I wanted to avoid. As far as I can tell there’s no way to do that with iptables, so I made a custom version of the iptables NETMAP target that would replace the packet’s destination address with its source address in PREROUTING. After that the packet is NATted so it appears to originate from WANatronic. This is the magic that lets you talk to yourself on what appears to be a very crappy link. Perfect for a demo that needs to reside completely on a single laptop.

Stuff It Doesn’t Do

Plenty of things really but things that come to my mind include:

  • Static IPs (seems useful)
  • Routing stuff like OSPF (not going to happen)
  • Remote management (not sure it’s worth it)
  • IPv6 (does anybody actually use that)
  • Really fancy stuff like packet reordering (not likely)

If you’ve got comments or would like to see something let me know.

In case you scrolled to the bottom for a download link here it is again: WANatronic 10001.

Written by Carter Shanklin

July 4th, 2011 at 7:12 am

Posted in Uncategorized

Find out which vCenter manages an ESX host.

with 2 comments

Ran into this problem today and didn’t see any info about it online. ESX stores the IP address of the vCenter that manages it in the HostConnectInfo object.

If you connect to ESX you can call QueryHostConnectionInfo on the HostSystem object to find out which vCenter manages it.

Here’s PowerCLI code that will do that.

Get-VMHost |
    Get-View -property Name |
    Foreach { $_.QueryHostConnectionInfo() } |
    Select ServerIp

Written by Carter Shanklin

May 24th, 2011 at 11:24 pm

Posted in Uncategorized

Tagged with , , ,

Vote For My Elastic Memory for Java VMworld Session Or Else!!

without comments

I tried not to get a swelled head when Stu Radnidge conferred divine status upon me some years ago. After all Stu grew up in the Australian wilderness and I suppose riding a kangaroo to school every day could lead to a warped sense of reality.

So it was refreshingly deflating to find that nobody even noticed my VMworld session (2917 vote for me). In fact permit me to helpfully reproduce what you would have seen if you had voted for me as you should.

Elastic Memory for Java is a project I’ve been helping out with for the past year or so that aims to let you run Java apps on ESX without having to give them all their memory all the time. Java apps run great on ESX, so long as they have all the memory they want. If they don’t, things can go south really quick.

This is a big problem because Java likes to be lazy about cleaning up after itself, and prefers to hold on to every piece of trash and dead memory in sight until it nearly collapses under its own weight. It’s sort of like the software world’s answer to the Collyer brothers.

This behavior also explains why traditional ballooning in ESX doesn’t work well with Java. EM4J is different because it’s designed to work within Java and has intimate understanding of what’s happening in the Java app. If you wanna find out more, you gotta come to the session.

Why is VMware doing this you ask?

  • Efficiency is in.
  • We’re on the precipice of an app explosion. We’ve already seen it in consumer space, more special purpose apps that individually do less than monolithic apps of the past. This is infiltrating enterprise and when it does we need an order-of-magnitude or two more consolidation to cope with it.
  • Oh yeah and cloud. Cloud cloud cloud cloud cloud. There I said it.

P.S. If you’re interested in trying Elastic Memory for Java out, we’re running a select beta. Message me on twitter or email me at cshanklin at vmware com and let me know you’re out there.

Otherwise see you in Vegas!

Written by Carter Shanklin

May 12th, 2011 at 12:03 am

Posted in Uncategorized

Tagged with , ,

ESX Performance Counter Secrets Revealed

with one comment

Top Secret

Successful Succession?

The future of ESX’s COS is still a contentious subject of speculation. And with its future in doubt, so is the future of the ESX administrator’s most beloved friend and constant companion, esxtop. Esxtop’s heir apparent, resxtop, remains plagued by platform restrictions and unclear compatibility. Can it really be a viable replacement?

Interestingly, the PowerCLI team introduced their own way of getting esxtop data, however the official documentation is a bit light on detail.

These both appear to use some form of secret, undocumented API. It’s not clear why such a vitally important data source needs to be shrouded in mystery. Thankfully, the following cable was intercepted by a brave and intrepid soul whose name I have sworn to anonymity. It sheds substantial light on the nature of this hidden API, and will hopefully prove an invaluable reference.

The aforementioned PowerCLI team provided some rudimentary discovery mechanisms, but they may not dig deep enough. For example, LucD notes on his blog that he found only 392 counters on his system, whereas the cable we obtained identifies 425 counters. Is there some dark conspiracy at work here? Worse, many of the counters appear to give misleading information, seeming to need adjustment before they can be used. Hopefully the information captured in this cable will resolve these questions once and for all.

Text of The Intercepted Cable

Thursday, 14 February 2008, 12:21
C O N F I D E N T I A L SECTION 01 OF 06 VMWARE 002012
EO 12958 DECL: 01/25/2018
Classified By: COM: Thomas Lindboe: For reasons 1.4 b/d


We must not let these values fall into the wrong hands. The fate
of the free world is in the balance. Full details attached.

What We Found

Our intercepted cable revealed a treasure trove of information. Not only did it give us a full readout of all statistics, but their names, the way they correspond to the names shown in esxtop, and possible clues for how to adjust misbehaving counters. We rely on all of  you to expose this data to the light and help us unravel this mystery.

Written by Carter Shanklin

December 19th, 2010 at 8:43 pm

Posted in Uncategorized

Tagged with , ,

vFabric GemFire — 20 demos in less than 5 minutes.

with 5 comments

vFabric GemFire is a Java-oriented in-memory distributed caching platform. To translate that into English, it’s a way of sharing and processing that’s extremely fast because the data is kept live in memory, and is also extremely scalable because GemFire applications can automatically discover and share data between peers over the network.

GemFire can run peer-to-peer or standalone. When you’re using it peer-to-peer you embed GemFire into your application. When the application launches, it discovers all its peers automatically via the network.

You run GemFire standalone through something called cacheserver. In the standalone case you launch one or a few cacheservers and then a large number of clients can connect to it. This mode resembles what you’d see if you used something like memcache or redis. This mode is good if you need to centralize data, write data to disk or if you want to perform continuous queries.

GemFire includes an extensive example set that gives you a good sense of what’s possible. Unfortunately I found the getting started guide a bit hard to follow. Part of it was just the usual Java BS: any time you’re asked to set environment variables to get software working you know you’re in for a rough ride. But beyond that there are  various different piece parts you have to collect and configure before you can really get started, and the way to run the examples themselves is not very clear, the directory structure of the sample files seems inconsistent with the way the instructions tell you to run the samples. Maybe that was my error but I bet a lot of people would make the same error.

To try to help things a bit I wrote a script that tries to completely automate the demo experience. The script downloads all the necessary code and then presents a menu where you can select any demo you want to run. Some of the examples require a cacheserver, and in those cases the demo script will automatically start and stop one for you. There’s nothing to think about, just run the script and it should work (leave me a note if it doesn’t!)

Download the script or just copy and paste it from the box below. After you download, just run it and you’re on your way (see below for a note on system requirements).

import string
import time
import urllib
import os.path
# If you want to see the commands as they execute, set this to 1.
verbose = 0
files = {
  "gemfire" : {
    "name" : "GemFire JAR",
    "file" : "gemfire-6.5.1.jar",
    "url"  : "http://dist.gemstone.com/maven/release/com/gemstone/gemfire/gemfire/6.5.1/",
    "sum"  : "f9b633da145a2afb27d2015ab76010818c0c2ee2"
  "antlr" : {
    "name" : "ANTLR JAR",
    "file" : "antlr-3.1.3.jar",
    "url"  : "http://www.antlr.org/download/",
    "sum"  : "acd5253cf1eba7bdb133f14cd77b0ba2fd219f98"
  "examples" : {
    "name" : "GemFire Examples",
    "file" : "GemFire_v6.5_SampleCode.zip",
    "url"  : "http://community.gemstone.com/download/attachments/6032137/",
    "sum"  : "6a1d6f5e4a9a4e1236caecac2935b5cb841bcb10"
demos = {
 'BenchmarkAckConsumer' : {},
 'BenchmarkAckProducer' : {},
 'BenchmarkClient' : { "cacheServerArgs" : "start cache-xml-file=xml/BenchmarkServer.xml" },
 'ClientConsumer'  : { "cacheServerArgs" : "start cache-xml-file=xml/Server.xml" },
 'ClientWorker' : {},
 'CqClient'        : { "cacheServerArgs" : "start cache-xml-file=xml/CqServer.xml" },
 'DataEviction' : {},
 'DataExpiration' : {},
 'DataOverflow' : {},
 'DataPersistence' : {},
 'DeltaPropagationClientFeeder' :
        { "cacheServerArgs" : "start cache-xml-file=xml/DeltaServer.xml" },
 'DeltaPropagationClientReceiver' : {},
 'DeltaPropagationServer' : {},
 'DistributedLocking' : {},
 'DurableClient' : {},
 'DurableServer' : {},
 'FunctionExecutionPeer1' : {},
 'FunctionExecutionPeer2' : {},
 'I18nClient' : {},
 'MultiuserSecurityClient' : {},
 'MultiuserSecurityServer' : {},
 'MyArrayListResultCollector' : {},
 'PartitionedRegionVM1' : {},
 'PartitionedRegionVM2' : {},
 'PushConsumer' : {},
 'PushProducer' : {},
 'Querying' : {},
 'SecurityClient' : {},
 'SecurityServer' : {},
 'Transactions' : {},
def download(url, file):
        urllib.urlretrieve(url, file)
def downloadFile(fileInfo):
        # Check to see if the file exists.
        if os.path.isfile(fileInfo["file"]):
        # Otherwise download it.
        url = fileInfo["url"] + fileInfo["file"]
        print "Downloading " + fileInfo["name"]
        download(url, fileInfo["file"])
def runDemo(demoName, args=""):
        baseCommand = "java -classpath classes:../gemfire-6.5.1.jar:../antlr-3.1.3.jar"
        fullCommand = baseCommand + " quickstart." + demoName + " " + args
        # Some demos require a cache server. Start one up.
        cacheServerNeeded = 0
        if "cacheServerArgs" in demos[demoName]:
                cacheServerNeeded = 1
                print "Starting a cache server for this demo."
                cacheServerCommand = baseCommand + \
                    " com.gemstone.gemfire.internal.cache.CacheServerLauncher " + \
                if verbose:
                        print "Starting cache server using: ", cacheServerCommand
        # Start the demo.
        if verbose:
                print "Starting demo using: ", fullCommand
        # Stop the cache server if we started one.
        if cacheServerNeeded:
                print "Stopping cache server."
                cacheServerCommand = baseCommand + \
                    " com.gemstone.gemfire.internal.cache.CacheServerLauncher stop"
                if verbose:
                        print "Stopping cache server using: ", cacheServerCommand
        demoName = raw_input("Press enter to return to the menu.")
def doMenu():
        while 1:
                print "Ready to run a demo."
                # Present choices.
                after = ""
                demoNames = demos.keys()
                for demo in demoNames:
                        formattedDemo = "%-33s" % demo
                        print formattedDemo, after,
                        if after == "": after = "\n"
                        else: after = ""
                input = raw_input("Enter your choice: ")
                tokens = input.split(" ")
                demoName = tokens[0]
                arguments = string.join(tokens[1:], " ")
                        runDemo(demoName, arguments)
                except KeyError, ValueError:
                        print "Unknown demo, try again."
def main():
        # Ensure we have all the files we need.
        for file in files.keys():
        # Extract the samples if they don't already exist.
        if not os.path.isdir("quickstart"):
                os.system("unzip -n -q GemFire_v6.5_SampleCode.zip")
        # Disable verbose output.
        fd = open("quickstart/classes/gemfire.properties", "w")

You need a system with Python, Java and unzip all in your path (no environment variables, please!). Other than that it should work anywhere. Leave me a comment if it you try it and it doesn’t work. Otherwise have fun checking out what GemFire has to offer, don’t forget to check out the continuous query and function execution examples!

Written by Carter Shanklin

December 19th, 2010 at 8:09 am

Posted in Uncategorized

Tagged with , ,

An open letter to linkedin about their new CAPTCHAs.

with 15 comments

Why do I have to pass a CAPTCHA test after I log in to my account with my exceptionally strong password? This is bullshit. I don’t feel like squinting to figure this crap out. Nobody else on planet earth is insane enough to do this nonsense and you guys need to cut it out. Not even my bank, you know the thing that controls, like, all my money and stuff, makes me do stupid shit like this. You guys are a 2nd rate social networking platform. Do you really think the junk in my linkedin account is more important than my finances??? Reality check time, people.

Not to mention that I use keypass and never use the same password on two different sites. The risk is extremely low without your unwanted roadblocks. In fact if you can figure out my password, go ahead and knock yourself out. Update my profile to say I’m a professor of scatology at UC Berkeley and that my hobbies include raping kittens. I don’t care because there is nothing of value within my linkedin account. Keep going the way you’re going and there will be nothing of value in any linkedin account.

Written by Carter Shanklin

August 25th, 2010 at 4:56 am

Posted in Uncategorized

Spring into lame puns with Roo.

without comments

Roo LogoI’ve never been much of a Java developer, back in my developing days I spent my time in just about anything but Java, whether scripting or compiled languages. But with the recent pairing of VMware and Salesforce, and then the announcement that VMware and Google are BFFs, Java suddenly seems a lot more relevant than ever.

So I decided I needed to be a bit more Java savvy. One of the most common technologies you’ll encounter when developing is so-called Object Relational Mapping or ORM. The concept here is really simple, ORM lets you treat rows in a database like they were real live language objects, so if you fetch objects you’re really fetching database rows and if you update objects you’re really updating database rows. The concept is pretty simple. Somehow, though, the implementation is really nasty. And I mean really, REALLY nasty.

I set out to learn probably the most popular Java ORM, hibernate, using a hibernate tutorial. The tutorial is pretty decent if you overlook the fact that it doesn’t actually work and you need to search the jboss forums for fixes to the Maven POM file (what is that anyway?). Well then there was the fact that I couldn’t actually get it working. In truth it was probably my fault, I probably got one of the 17 steps wrong in the 30 page tutorial, or maybe I did them out of sequence or something. But I got close enough that I decided that if I absolutely, positively had to get it working I probably could.

After this experience I can’s say I’ve become much more of a Java fan. I started to take a look at some of the other technologies involved in building Java apps and my head began to spin. Do I use hibernate or should I use JPA? Do those things even do the same thing? Do I need to use JTA with either of them? Is struts a part of tiles? Other way around? Or are they competing technologies? There are at least 3 logging frameworks in Java that seem to have good traction, which one should I use? Is TestNG better than JUnit? Does it really matter? A funny note in the Hibernate tutorial is that Hibernate supports *BOTH* c3p0 and proxool as JDBC connection pools (What?), but you should positively under no circumstances use the default JDBC connector that ships with Hibernate because it’s a piece of crap.

I’m ready to fly the white flag, this stuff is just too much for me. Call me a bad developer but I just don’t have the patience for all this nonsense. They have a term for this, “yak shaving”. Reminds me of the bad old days of UNIX, when you were thrilled if “configure; make; make install” didn’t require you to edit source code.

On day 2 of my Java adventure I decided to figure out Roo, mostly because I couldn’t figure out what it was or why anyone would use it. And I guess somebody must think it’s pretty important because it’s what Ben Alex showed off at Google IO. (Ben has a love for expense reports that borders on unnatural but it’s still a pretty good demo.)

Roo is a “convention over configuration” tool, which is just a fancy way of saying that it makes a bunch of decisions you really shouldn’t care about and it makes them automatically. No more scratching your head figuring out if you should use JMX or JPA or JINI or JPMC or JWTF. As someone who doesn’t know or care what’s going on under the covers this is really attractive.

So I gave it a shot, not trying to follow Ben’s IO demo, but rather the online Pizza Shop demo. (I have it on good authority that Ben once tried to expense over $13,000 worth of pizzas, probably where he got the idea for the expense report app.)

project --topLevelPackage com.springsource.roo.pizzashop
persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
entity --class ~.domain.Topping --testAutomatically
field string --fieldName name --notNull --sizeMin 2
entity --class ~.domain.Base --testAutomatically
field string --fieldName name --notNull --sizeMin 2
entity --class ~.domain.Pizza --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field number --fieldName price --type java.lang.Float
field set --fieldName toppings --element ~.domain.Topping
field reference --fieldName base --type ~.domain.Base
entity --class ~.domain.PizzaOrder --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float
field date --fieldName deliveryDate --type java.util.Date
field set --fieldName pizzas --element ~.domain.Pizza
controller all --package ~.web

With this file in hand, all you’ve got to do is pipe it into Roo and after a few minutes you’ve got a working application. If we break the script down, there are 5 major things:

  1. Create the application using “project”
  2. Instruct it to use Hibernate and the Hypersonic in-memory database.
  3. Create entities (these correspond to database tables).
  4. Create the fields within the entities, and associations between the entities.
  5. Add a web layer using “controller”.

It’s easy to feed this to Roo automatically by just putting it into a file called, say, pizza.roo and running:

$ /path/to/roo/roo.sh < pizza.roo

Roo does all the grunt work of dealing with Maven, which in turn downloads all your dependencies (this can take a while the first time you do it), and creates lots of stub code for you. After this I ended up with 458 files which I could compile into a web app. This included a fairly complex Maven pom.xml file which I could use to do other things, such as launch the application. To do that, just type this in the root of your project directory:

$ mvn tomcat:run

You should note that this wants to launch its own Tomcat and HSQLDB. If you have local copies of either of these apps, there will be conflicts. Since I did, I decided the path of least resistance was just to shut down my system services and let Maven handle it all. After that launches you can navigate to localhost with your web browser as follows:

Working Pizza Shop App

The working pizza shop application.

Success! A working (sample) app without a line of code! True I didn’t write code, but more importantly this approach seems to make data the primary concern, which I find very attractive since combining, processing and displaying data is the real value of any application.

In this example everything, including the database, runs in memory, you don’t need anything installed except Roo, Maven and your JDK. To make things a bit more interesting I decided to link this application to a MySQL database that I have running on my host. This proved to be surprisingly easy, with only one gotcha. I went back into my Roo shell and typed in:

persistence setup --provider HIBERNATE --database MYSQL --username carter

This almost worked, but I had to manually edit a field in a file called database.properties to read like:


Here “hibernate” is the name of my database in MySQL. Ordinarily you’d probably want to use things like usernames and passwords but I like to live dangerously. With that in place I launched my application again by typing “mvn tomcat:run”. I was pleasantly surprised to find that everything worked! I took a peek in MySQL and couldn’t believe my eyes, all the right tables had been created automatically! Working with Roo is a real pleasure compared to slugging it out by hand with tools like Hibernate.

Showing the schema in MySQL

Shockingly, things "just worked".

I’m really impressed with Roo and think it’s one of the most interesting things going on in the SpringSource portfolio right now.

Written by Carter Shanklin

May 22nd, 2010 at 3:07 am

Posted in Uncategorized

Tagged with , ,