Tropical Software Observations

20 March 2009

Posted by Teo Choong Ping

at 9:40 AM

0 comments

Labels: ,

Grails and Rails: Domain Classes and Web Services

Let's take a brief look at the differences between Grails and Rails in term of persisting domain classes and creating web services. Both Grails and Rails are MVC frameworks and are very similar in terms of code syntax.

1. Domain Class Persistence

In Grails:



class Person {
String firstName
String lastName
String email
Date birthDate
Address address

static constraint = {
firstName(blank:false)
lastName(blank:false)
email(blank:false, email:true) // check if it's really e-mail
}
}

class Address {
String street
String city
String country
Person person

static belongsTo = Person
}



In Rails, attributes can be inferred from the database table's structure:

class Person <>
# Expects database schema to have a table "person"
# with columns first_name, last_name, email, birth_date

validates_presence_of :first_name, :last_name, :email
end

class Address <> has_one :address
belongs_to :person
end


2. Making a service class available as a web service

In Grails, inside a controller closure:


def listAllPeople = {
def pplList = Person.list() // or by query Person.findByLastName("Hewitts")
render pplList as XML
// render pplList as JSON
}



In Rails, inside a controller block:


def listAllPeople
@pplList = Person.all # or by query Person.find_by_last_name("Hewitts")
render :xml => @pplList
# render :json => pplList
end


Note:
1. Grails will auto-generate the database schema and update the schema when more domain fields are added to the class. It's also possible to go in the reverse direction if you prefer starting with an existing schema.
2. Rails expects the database schema to be pre-created and to conform to camel case naming conventions.
3. Grails has the notion of service classes which are commonly used for business logic and can be use in a controller as a web service end point.

18 March 2009

Posted by Bacchus D

at 4:26 PM

3 comments

Labels:

VMware ESXi For Cheapskates

I've finally had it with Xen. We've been using it for QA and infrastructure hosts for a couple of years now (after a brief, bizarre detour with Solaris containers) with pretty good results. But after discovering Xen support had been dropped from the latest version of Ubuntu, I tried out KVM only to discover that its client tools are currently dribbly pieces of poo. I'm sure there's a clever way to compile your own kernel with the Xen patches to create some sort of frankenstein hypervisor, but really all I want is just the thinnest layer possible on top of bare metal in order to run some Linux VMs. Not really all that much to ask for.


Most of the software we use at Favorite Medium is open source so I, too, was surprised when my search led me to VMware. They recently made ESXi, the smaller and somewhat crippled cousin of ESX, free so I decided to try installing it on a $600 machine that formerly ran Xen in another life. This host is known around our office as 'pike' and is named after Rob Pike for no particular reason.

After burning the ISO image to a disk and booting up pike, I immediately ran into problems. First it was the ethernet card. Apparently ESXi has a fairly limited HCL and our crappy D-Link NIC was not on it. A quick trip to the local IT graveyard and I was back in the office with two replacements: an Intel PRO/100, and a Broadcom gigabit something or other. $12 each.

The Broadcom NIC worked perfectly but then the installer complained about the disk controller. Our super cheap Gigabyte motherboard (G31M-SL2, if you must know) uses a cruddy SATA controller that, again, isn't on the ESXi HCL. Note that if you're trying this on consumer-grade hardware you'll likely run into the same problem as well. Now the installer probably ought to handle the condition more gracefully but instead it just stops cold with an ominous "The installation has encountered a fatal error" message. Not to worry, a quick one line edit of a Python script fixed the problem. Check out the detailed procedure here.

Never thought I'd say this but...VMware, lovin' it!


17 March 2009

Posted by Irregular Zero

at 6:38 PM

1 comments

Labels:

Delegation for iphone-google-maps-component

The iphone-google-maps-component is a way for you to use Google Maps on the iPhone through the use of an extended UIWebView and an html file on a server somewhere that does the map loading.

The present code overrides the default delegate UIWebViewDelegate with its own, MapWebViewDelegate. You cannot use the setCenterWithLatLng to establish the starting location until the view has finished loading. With the override, the webViewDidFinishLoad delegate method is unavailable.

Going by this post, the following code changes will allow the use of both delegates.

MapWebView.h
1) Change protocol definition.
@protocol MapWebViewDelegate < UIWebViewDelegate >

MapWebView.m
2) Remove the synthesize line.
//@synthesize delegate;

3) Replace with own methods, to hook into super.delegate.

- (id ) delegate {
return (id )super.delegate;
}

- (void) setDelegate :(id ) delegate {
super.delegate = delegate;
}


webViewDidFinishLoad should be accessible, as well as the other methods in the UIWebViewDelegate.

Another way of setting the starting location is through the loadMap method in MapWebView.h. The URL string can accept two more variables, latitude and longitude.

Change this:
NSString *urlStr = [NSString stringWithFormat:
@"http://www.wenear.com/iphone-test?width=%d&height=%d&zoom=%d",
width, height, DEFAULT_ZOOM_LEVEL];


To this:

NSString *urlStr = [NSString stringWithFormat:
@"http://www.wenear.com/iphone-test?width=%d&height=%d&latitude=%f&longitude=%f&zoom=%d",
width, height, location.coordinate.latitude, location.coordinate.longitude, DEFAULT_ZOOM_LEVEL];


Here, location is a CLLocation, part of the CoreLocation framework. The loadMap method is publicly defined in the interface and it accepts location as its variable. The call in didMoveToSuperview should be properly handled.

The latitude and longitude are doubles and can be hardcoded instead.