Saturday, 21 November 2009

Ajax in Tapestry (Pt 2)

In my last blog entry, I outlined how to take control of Ajax in Tapestry and pass data into our event handler as a request parameter - useful perhaps, but not very exciting!

In this entry I'm going to build on this knowledge to create an insert zone. By default Tapestry will entirely replace the content of a Zone when we update it - what if we want to add more content to it, eg. add more items to a list? Although this feature is supported by Prototype's insert method, Tapestry doesn't expose it - what we need is an insert zone! Let's start with the following TML:

  • ${item}



more items


Here we've bound a unordered list to a Tapestry zone and inside that we're looping through a collection of items. The component class (not shown) is extremely similar to the class described in the previous blog entry - the only real difference is that we're now dealing with a list of items.

Next we need an event handler that looks like this:
@Inject
private Request request;

Object onMoreItemsEvent() {
int pageNumber = Integer.parseInt(request.getParameter("page"));
setCurrentPage(pageNumber); // this pulls in the next page of items
return listZone.getBody();
}

And now we get to the JavaScript. First of all we need an initMoreItems function:
Tapestry.Initializer.initMoreItems = function(element, zoneId, url) {
element = $(element);
$T(element).zoneId = zoneId;
// add a property to the element - we increment this each time the user clicks 'more items'
element.nextPage = 1;
element.observe("click", function(event) {
Event.stop(event);
var zoneObject = Tapestry.findZoneManager(element);
if (!zoneObject) return;
new Ajax.Request(url, {
method: 'get',
parameters: { "page" : element.nextPage },
onException: Tapestry.ajaxFailureHandler,
onFailure: Tapestry.ajaxFailureHandler,
onSuccess : function (transport) {
zoneObject.processReply(transport.responseJSON, true);
element.nextPage++;
}
});
});
}

Again, extremely similar to the previous blog entry, but here we're using a nextPage property to store our page numbers and we're also passing an insert parameter to the processReply function.

At this point we have a working component ... sort of! Problem is, it doesn't actually do what we set out to do, ie. add further content to the div. To get round this, we need to override the Tapestry functions that actually do the update - processReply + show in Tapestry.ZoneManager. We do this by using JavaScript's prototype keyword:
Tapestry.ZoneManager.prototype.processReply = function(reply, insert) {
Tapestry.loadScriptsInReply(reply, function() {
// In a multi-zone update, the reply.content may be blank or missing.
reply.content && this.show(reply.content, insert);
// zones is an object of zone ids and zone content that will be present
// in a multi-zone update response.
Object.keys(reply.zones).each(function (zoneId) {
var manager = Tapestry.findZoneManagerForZone(zoneId);
if (manager) {
var zoneContent = reply.zones[zoneId];
manager.show(zoneContent, insert);
}
});
}.bind(this));
}

Tapestry.ZoneManager.prototype.show = function(content, insert) {
if (insert) {
this.updateElement.insert(content);
}
else {
this.updateElement.update(content);
}
var func = this.element.visible() ? this.updateFunc : this.showFunc;
func.call(this, this.element);
this.element.fire(Tapestry.ZONE_UPDATED_EVENT);
}

Both these functions have been copied from tapestry.js and then had an insert parameter added to them. They've been modified in a way that means they'll continue to work if called without the parameter but will add more content (by calling insert on the Prototype Element) if the insert parameter is supplied. Of course, it's the show function that we're really interested in, but we need to override processReply because that's what we're calling from our onSuccess handler.

Monday, 9 November 2009

Controlling Ajax in Tapestry

The standard way to do Ajax in Tapestry is with Zones, EventLinks and occasionally Blocks. This can result in a very simple TML file:



Hello ${name}!

Hello World!




Hello Sam


And an equally simple Java class:
@InjectComponent
private Zone helloZone;

@Property
private String name;

Object onHelloEvent(String name) {
this.name = name;
return helloZone.getBody();
}

public boolean isNamePopulated() {
return (name != null) && (name.length() > 0);
}

If that's all you need then job done (and not a line of JavaScript in sight!)

However, I'm finding that real world requirements often require greater control over the implementation details - typically this means we need to write our own JavaScript. Here's how we do it ...

First of all we modify the TML file to use a standard anchor in place of the EventLink:

Hello Sam


Now we need to tell JavaScript what to do with that link. But before we can start writing our JavaScript, we add the following to our Java class:
@Environmental
private RenderSupport renderSupport;

@Inject
private ComponentResources resources;

@Property
private String clientId;

void setupRender() {
clientId = renderSupport.allocateClientId(resources);
}

void afterRender() {
Link helloLink = resources.createEventLink("helloEvent", "Sam");
JSONArray parameters = new JSONArray();
parameters.put(clientId);
parameters.put(helloZone.getClientId());
parameters.put(helloLink.toAbsoluteURI());
renderSupport.addInit("initHello", parameters);
}

This makes use of two methods in Tapestry's rendering lifecycle - setupRender + afterRender. In setupRender we're getting unique client ID for this component. In afterRender we're passing some information to a JavaScript function via Tapestry's JSONArray object - note that one of these parameters is the URI of an EventLink we've created. For this to work, we also need to annotate the class:
@IncludeJavaScriptLibrary("myZone.js")

Finally we get to the JavaScript. What we need is a function that gets called when the page loads and accepts the three parameters we're passing in from the Java class. Here's what it looks like:
Tapestry.Initializer.initHello = function(element, zoneId, url) {
element = $(element);
$T(element).zoneId = zoneId;
element.observe("click", function(event) {
Event.stop(event);
var zoneObject = Tapestry.findZoneManager(element);
if (!zoneObject) return;
zoneObject.updateFromURL(url);
});
}

In fact, all that JavaScript was copied from the linkZone function in tapestry.js - we're doing exactly what Tapestry was doing, but now the JavaScript is under our control. :-)

So now we're in control of the JavaScript, what can we do with it? Pretty much anything we like as it turns out, but for now, let's pass the name in as a standard request parameter. First of all we modify our event handler to look like this:
@Inject
private Request request;

Object onHelloEvent() {
this.name = request.getParameter("name");
return helloZone.getBody();
}

And then we replace zoneObject.updateFromURL with a standard Prototype Ajax request:
// zoneObject.updateFromURL(url);
new Ajax.Request(url, {
method: 'get',
parameters: { "name" : "Sam" },
onException: Tapestry.ajaxFailureHandler,
onFailure: Tapestry.ajaxFailureHandler,
onSuccess : function (transport) {
zoneObject.processReply(transport.responseJSON);
}
});

Note that we are now using GET instead of POST and we have also exposed the onSuccess handler. This can prove very useful when we start implementing more advanced requirements.

Saturday, 24 October 2009

Tapestry Revisited

I've been doing a bit of Tapestry 5 at work recently. Have to say, I haven't been much of a fan in the past, but I am starting to see its merits. Yes, it's sometimes quite hard to do relatively simple things, but this is usually down to a lack of documentation more than anything. Once you've arrived at a solution, the end result is often clean and concise - it's getting there that's the issue!

It's very different to working with an MVC framework and requires you to look at server-side development in an entirely different way. For example, developing a functional component nearly always requires some knowledge of JavaScript / Prototype and I seem to frequently find myself looking through the source code for the Tapestry JavaScript library. Although I was uncomfortable with this at first (why would a Java developer need to understand JavaScript?) I'm now finding that I enjoy the challenge. In fact, the weird and wonderful world of JavaScript is turning out to be a more friendly place than I'd feared!

Friday, 25 September 2009

New Mac

Work have kindly given me a brand new MacBook Pro! It features the new 'Unibody Enclosure' and looks absolutely gorgeous - there's a video of it being made here.

Naturally, I spent some of last night making sure my Pygame efforts still worked on it. This pretty much forced me to try Python 2.6 + Pygame 1.9 (I had previously only tried Python 2.5 + Pygame 1.7) so I was quite pleased when it worked first time. Here's what it looks like:


This also hints at a couple of new features - coins + keys! Unfortunately, although you can now collect these items, you can't actually do anything with them yet.

Tuesday, 25 August 2009

Paying The Bills

A distinct lack of activity on the blogging front lately. This is because I've been (a) moving house and (b) actually enjoying myself at work! ;-)

As Tech Lead on a brand new project, I've been writing a web app using Spring MVC, Freemarker + Hibernate and I thought I would share a few thoughts. I should start by saying that it's been nowhere near as easy as Grails, GSP + GORM, but nonetheless, it's a big improvement on the 'bad old days' of Java web app development.

To be honest, although Spring MVC is both powerful and flexible, I've always found it a little fiddly in the past. However, this time I decided to use annotation-driven controllers and these were way easier to work with than the MultiActionController I've used before. All you need is something like this in your context:
<context:component-scan package="com.royale.sam.web.controller">
And then you can annotate your controller class like this:
@Controller
@RequestMapping(method = RequestMethod.GET)
public class PageController {

...

@RequestMapping(value={"/page.html", "/item.html"})
public ModelAndView pageHandler(HttpServletRequest request, HttpServletResponse response) {
...
}
}
And that's it! Using this technique you can group handler methods in one controller (much like you can in Grails) which makes it easier to reuse domain logic and leads to a well organised application. We found this was particularly useful when implementing handlers for our AJAX functionality.

Freemarker was also pretty good, although - possibly because it's application agnostic - we found that it didn't support a number of features that you take for granted when using JSP. (In fact, I would've used JSP, but requirements dictated that we used a templating language.) For example, we couldn't find an easy + reliable way to get the context path, so we ended up introducing a servlet filter that made this information (and more) available to every page in our app. We also steered clear of using taglibs in our Freemarker templates, preferring to write our own directives.

And Hibernate was Hibernate. Always trickier than you expect to set it up, but once it's done, you generally don't have to worry about it anymore.

Monday, 20 April 2009

Pixel Art

Something I am starting to realise is that pixel art is hard and animated pixel art is even harder. Not just hard, but extremely time consuming too. To give you an idea of how much work goes into these things, take a close look at the forward-facing frames for our protagonist ...

I'm telling you, the guys who did Metal Slug should get some kind of medal.

Pygame Update

I recently realised that I haven't blogged about my Python/Pygame efforts in quite a while, so I figured it was time for an update. The good news is, my lack of blogging is not reflected by a lack of development, so there's quite a few new features - so many, in fact, that it's probably best if I just post a video ...



So here we can see a couple of maps designed with my very own level editor, an animated main character, a scrolling background, the ability to seamlessly walk off one map and onto another, animated features (eg. flames), pickups (eg. coins) and movement correction (ie. note the way the little fella 'slides' off obstacles that are blocking his way).

If anyone's interested, I created this video by running gtk-recordMyDesktop against the Pygame window and converting the resulting .ogg with mencoder:
mencoder out.ogg -oac lavc -ovc lavc -lavcopts abitrate=160 -o rpg-world.avi
I have no idea what most of that means, but the quality has turned out okay!

Wednesday, 8 April 2009

Groovy comes to Google App Engine

It would seem that my reservations about Google App Engine may soon be no more. I haven't had chance to try it yet, but Google App Engine now supports Java!

Better still (for fans of Groovy like myself) work has been going on behind the scenes to ensure that Groovy is also supported - see here and here. In fact, Guillaume Laforge (creator/inventor of Groovy) has already written a Google Maps / Flickr mashup with it.

:-D

Monday, 30 March 2009

Being Groovy

Nothing spectacular here, but it's interesting to see just how nice and simple Groovy can be. I have a page in my app where the user can tick a checkbox for each of their networks to say which networks should receive a status update. The request looks something like this:
newStatus=hello%20world!&network1=on&network2=on&network3=on

Grails supplies this as a map called params, but what I really want is a simple list of network ID's. Here's how I do it:
def networkIds = params.findAll({ key, val ->
key.startsWith("network")
}).collect({ key, val ->
Integer.parseInt(key[7..-1])
})

Basically, I'm chaining two calls together - findAll + collect - that both accept a closure. I'm using findAll to filter out any entries that don't start with 'network' and then collect to convert the resulting map into a list of ints. And not an iterator in sight!

Tuesday, 24 March 2009

Why Grails Is Good

Obviously I can't say that Grails is the best thing since sliced bread and then not present some evidence to support my claim, so here's a specific example.

In my application I have a Network domain class and some other domain classes that extend it - TwitterNetwork, FacebookNetwork, etc. I wanted to handle the CRUD functionality for these classes in a single controller, but keep the forms separate. Having auto-generated the controller + views and then deleted the stuff I didn't want, here's the structure I ended up with:
- grails-app
- domain
- Network.groovy
- FacebookNetwork.groovy
- TwitterNetwork.groovy
- controllers
- NetworkController.groovy
- views
- network
- list.gsp
- facebookNetwork
- create.gsp
- edit.gsp
- twitterNetwork
- create.gsp
- edit.gsp
Out of the box, the default list action just works:
def list = {
if (!params.max) params.max = 10
[ networkInstanceList: Network.list(params) ]
}

As do the delete, save and update actions.

All I have to do now is get the edit and create actions to use the correct view, depending on the network type. To do this I use the class name to determine which view to use. For example, here's my edit action:
def edit = {
def networkInstance = Network.get(params.id)
renderEditForm(networkInstance)
}

def renderEditForm(network) {
def map = [ networkInstance : network ]
def viewPath = getViewPath(network)
render(view:"/${viewPath}/edit", model:map)
}

// derive the view path from the given network instance
def getViewPath(network) {
def networkName = getName(network)
networkName[0].toLowerCase() + networkName[1..-1]
}

The great thing is, I know that will work because by convention Grails will put the views for TwitterNetwork in the twitterNetwork folder and the views for FacebookNetwork in the facebookNetwork folder. It then becomes a simple case of taking the class name and making the first character lower case.

I use the same principle for my create action:
static networks = [ "twitter" : TwitterNetwork,
"facebook" : FacebookNetwork ]

def create = {
def networkInstance = createNetwork(params.type)
networkInstance.properties = params
renderCreateForm(networkInstance, params.type)
}

// create a new network instance of the given type
def createNetwork(networkType) {
if (networkType in networks.keySet()) {
def clazz = networks[networkType]
return clazz.newInstance()
}
}

... etc

And that's it! Full CRUD functionality for a set of polymorphic domain classes in a few lines of code - most of which were auto-generated by the framework. :-)

Wednesday, 11 March 2009

Is Grails The Answer?

I certainly think so. Over the last few years, I've used a variety of Java web frameworks such as Struts, Spring MVC + Tapestry and various combinations of Spring, Hibernate, JPA + EJB. Before all those things came along, I even tried my hand at JSP's, vanilla servlets + JDBC. I got some decent results out of most of those frameworks, but at the same time, it was hard work and productivity wasn't very high on the agenda. However, once things like Rails + Django appeared on the scene, I started to wonder if I should be using Java in the first place? These new frameworks made use of more dynamic languages - Ruby and Python - and promised short development cycles and extremely high productivity.

But, having spent the best part of ten years becoming a Java expert, moving to an entirely new platform seemed like a very big jump - particularly in the case of Ruby/Rails. After all, the JVM is (in my opinion) one of Java's biggest strengths - if only there was an easier way to tap that potential. Enter Groovy + Grails! I'd been following Groovy pretty closely for a while and really liked the look of it, eg. its extensive use of closures. I was also aware of Grails, but the name put me off slightly - it just seemed to be shouting "me too!" a little too loudly for my liking. But following my disappointment with Google App Engine, I decided it was finally time to take the plunge.

I needn't have worried. Quite simply, Groovy + Grails is the best web framework I have ever used in any language. After just one day (which included frequently referring to the documentation) I had full CRUD functionality for a set of polymorphic domain classes. Following that, adding an Authentication Filter was a breeze, creating a Custom Tag Library was incredibly easy and even Ajax Integration (so often where complexity starts to creep in) wasn't too unpleasant. And here's the best part ... all these features build on my existing knowledge of Servlets, Spring, Hibernate, etc, so I'm not learning a whole new technology stack from scratch.

After three days I had an application that was every bit as functional as its Google App Engine equivalent, which took a similar amount of time. I'll admit that I haven't strayed too far from the golden path, but so far, all the signs are extremely encouraging. There's plenty of support out there and the user community is extremely active. I've also read reports of companies using Grails for real-world sites, which is more than some of the latest frameworks can boast. I'll keep you posted ...

RSS Feeds - A Confession

Shocking I know, but I have never really made use of RSS feeds. I gave Google Reader a try, but I just couldn't see the point. Having added various sites like guardian.co.uk, bbc.co.uk and Slashdot, I just never bothered to check it. Why? Because these were sites I visited pretty much every day anyway - I didn't need another application telling me what articles were on there.

However, having been on a mission to immerse myself in the Groovy + Grails community of late, I suddenly get it! Sites like Graeme Rocher's Blog and Grails Podcast are not sites I look at every day, but I want to be notified whenever they publish new articles. And that's exactly what RSS / Google Reader does for me. A quick glance at my overview page, and I can see if any of the feeds I've subscribed to contain any new articles. :-)

Friday, 6 March 2009

Google App Engine - Final Thoughts

I was a little disappointed with Google App Engine. While I concede that it allows you to get some VERY quick results, what started out as niggling doubts at the start of the project soon became genuine concerns:

1) The whole thing seems to be a bit muddled. They're kind of half-supporting an old version of Django, meaning that some Django features are available but some are not. For example, if you try to do a server-side password field as suggested in the Django docs, it doesn't work.

2) No guidance on project structure, unit testing, etc. The approach adopted by most people seems to be 'lump everything in one folder' which leads to a very disorganised project. By contrast, Groovy + Grails has clearly defined areas for domain models, controllers, views and tests.

3) You're tied to Google's technology. Running a GAE app outside the App Engine environment is not simply a case of flicking a switch. Similarly, you would need to do a significant amount of work to get a Django app to run on app engine.

4) Out of the box, you don't even have access to the session! Everything has to be done with the datastore, which feels very restrictive.

5) Your request handlers implement get, post, etc which map directly to HTTP methods. For me, this level of abstraction is too low - in the last few years the Java community have progressed onto controllers + actions which seems to be a better fit for implementing complex behaviour.

6) Persistent entities must extend a database Model class. Worse still, if you intend to create multiple sub-classes of that class, you should extend PolyModel. Again, this kind of thing has been frowned upon by the Java community for some time. By contrast, a model in Groovy + Grails looks like this:
class User {

String email
String password

static hasMany = [networks: Network]

static constraints = {
...
}
}
Note that it does not need to extend anything (ie. the domain model is decoupled from the persistence strategy) and is given the ability to get, save and delete itself at runtime.

That said, I don't suppose that I'm the target market for GAE. Just the fact that hosting is provided will be a massive draw for a lot of people and I doubt there's anything better if you're wanting to create a quick and dirty mashup of some 3rd party services.

Thursday, 26 February 2009

Battling the Facebook API

One of the things I've been trying to do with Google App Engine is get my app to talk to Facebook. As it turns out, this is a reasonably straightforward task made incredibly complicated by the appalling Facebook Developers documentation. Just trying to work out what it is you need to do (never mind how you actually go about doing it) is a real trial.

Undeterred (I was getting paid for this, after all) I persevered and eventually worked out that before my app could talk to Facebook, users would have to add it to their profile and grant it permission to do stuff - for this I would need a 'Callback URL'. Unfortunately, all the examples in the docs are PHP, but here's what I came up with in Google App Engine:
class FacebookPage(webapp.RequestHandler):

def get(self):
self.post()

def post(self):
self.response.out.write("<fb:prompt-permission perms=\"status_update\">\
Grant permission for status updates\
</fb:prompt-permission>")
Yes, it's not pretty and yes, I've got markup in the source code, but it works. Those three lines of FBML (Facebook Markup Language) request that the user gives my app the necessary permissions. Once added, my app can then use the PyFacebook utility to make calls to the API:
fb = facebook.Facebook(FACEBOOK_API_KEY, FACEBOOK_SECRET_KEY)
result = fb.users.setStatus(new_status, False, uid=facebook_user_id)
Easy when you know how!

More Google ...

Seems like I'm going Google crazy these days, but as part of my day job I've been looking at Google App Engine this week. It's certainly a very rapid development tool and I wouldn't hesitate to use it for personal projects ... but at the same time it feels a bit lashed together to me. It uses Python 2.5.2, so no complaints there, but why use Django 0.96.1 when Django 1.0 was released in September last year? Anyway, I'm just nit-picking to be honest - it's another great tool from Google and the benefits far outweigh the drawbacks.

Saturday, 21 February 2009

Google Code

I've written a fair amount of code now and I've been looking for somewhere to store it for a while. Up until now this has meant a combination of a friend's SVN repo, a couple of laptops and an external hard drive. However, I recently decided to take the plunge and try Google Code.

For some reason, I'd previously thought that Google Code was only used for Google App Engine. However, this turned out to be totally wrong (you can put pretty much anything on there as far as I can tell) and I now have a high availability SVN repo at my disposal. Once I'd created my top-level project I quickly added two sub-projects - one for the level editor (Java) and one for the game itself (Python).

First impressions are extremely good. Integration with Eclipse (via the Subversive plugin) was seamless and so far, the repo has been available every time I've used it. It's occasionally a little sluggish, but that's a small price to pay as far as I'm concerned.

Monday, 2 February 2009

Lessons Learned

In contrast to my day-job as an Enterprise Java Developer, working on my level editor was generally pleasant experience. It was nice to do some proper OO on a self-contained project with no external dependencies for a change!

I didn't do any up-front design for it and developed each component in isolation, providing functional mocks for inter-component dependencies. Somewhat surprisingly, a domain model ended up simply 'falling out' of this approach as the code evolved - I guess that's what's supposed to happen with Agile methodologies.

That said, I'm not sure how well this would translate to a large project / team environment. This was a small project where I was able to mentally keep everything in the air at once, ie. whenever I changed something I had a very clear idea of how it would affect everything else. If I'd been working on a vertical slice of a much larger application, would this approach still work?

Level Editors

As we all know, every good game needs a level editor and mine is no exception. Here's what it looks like:


I knocked this up in Java / SWT in a few weeks and it already covers all the basic use cases. In fact, drawing the tiles was more time-consuming.

I was quite impressed by SWT. It's about a million times easier/quicker than Swing and I like the way it just looks like a native app. I did give the Eclipse Rich Client Platform a try to start with but that seemed to be one of the most impenetrably hard things I've ever looked at so I settled on SWT in the end. I also toyed with the idea of doing it in Python, but the sheer range of Windows Toolkits that are available for it put me off slightly.

Wednesday, 21 January 2009

Python Gotcha

Spent ages last night trying to track down a bug in Python. I wanted to do something you don’t often need to do in Python – initialise a two-dimensional list – which I did like this ...
>>> a = [[None] * 4] * 2
>>> a
[[None, None, None, None], [None, None, None, None]]
Turns out I should have used a list comprehension to do it ...
>>> a = [[None] * 4 for i in range(2)]
>>> a
[[None, None, None, None], [None, None, None, None]]
They both look the same, but they are not! It’s fairly obvious when you think about it, but trying to track this down in a reasonably complex piece of code wasn’t easy ...