26 September 2008

GWT: Generators HowTo (BuildStamp)

If you're curious what generators are, or have never used them with GWT, this simple generator will give you a quick introduction to get your hamster wheels turning.

I do a lot of prototyping in GWT before I build the backend and I've recently had the need to generate a "build version" for my GWT interface. While there are about fiftybazillionmillion different ways to do this, I've chosen a GWT generator to create a buildstamp. This
lets me tar up the www results of clicking on "Compile/Browse" and fire them off for others to play.

In your Java code, you just add:

...
BuildStamp buildStamp = GWT.create(BuildStamp.class);
yourLogo.setTitle(buildStamp.getBuildStamp());
...

This will add a tooltip to yourLogo which looks like: "Built on kikai.linuxstuff.org at Tue Jul 29 19:07:05 PDT 2008".

When you compile your GWT application the generator is compiled and run. It generates Java code which is converted to JavaScript along with the rest of your application. When this happens the timestamp is "frozen".

Code and wiring follows. Imports omitted, use your favourite IDE to fill them in. This makes a pretty simple Hello World example.

Comments are more than welcome.
package org.example.rebind;

public class BuildStampGenerator extends Generator {

private String className;
private String packageName;

@Override
public String generate(TreeLogger logger, GeneratorContext context, String typeName)
throws UnableToCompleteException {

try {

TypeOracle typeOracle = context.getTypeOracle();
JClassType classType = typeOracle.getType(typeName);
packageName = classType.getPackage().getName();
className = classType.getSimpleSourceName() + "Impl";

generateClass(logger, context);

} catch (Exception e) {
logger.log(TreeLogger.ERROR, "Exception during BuildStamp creation.", e);
}

return packageName + "." + className;

}

private void generateClass(TreeLogger logger, GeneratorContext context) {

PrintWriter printWriter = context.tryCreate(logger, packageName, className);

/* Returns null if the package has already been generated. */
if (printWriter == null) {
return;
}

ClassSourceFileComposerFactory composer =
new ClassSourceFileComposerFactory(packageName, className);

// shouldn't magic just happen here?
composer.addImplementedInterface(BuildStamp.class.getCanonicalName());

SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter);

writeGetBuildStamp(sourceWriter);

sourceWriter.outdent();
sourceWriter.println("}");

context.commit(logger, printWriter);

}

/**
* Write the source code for {@code BuildStamp#getBuildStamp()}.
*/
private void writeGetBuildStamp(SourceWriter sourceWriter) {
sourceWriter.println("public String getBuildStamp() {");
sourceWriter.println(" return \"" + Generator.escape(getBuildStamp()) + "\";");
sourceWriter.println("}");
}

/**
* Executed at *compile* time, this generates a string that is embedded in the
* generated class. In hosted mode, this code is rebuilt each Refresh.
*
* @return A user-friendly build string, good for hiding in tooltips.
*/
String getBuildStamp() {
StringBuilder msg = new StringBuilder();
msg.append("Built on ");
try {
String hostname = InetAddress.getLocalHost().getCanonicalHostName();
msg.append(hostname);
} catch (UnknownHostException e) {
msg.append("(hostname not available)");
}
msg.append(" at ");
msg.append(new Date());
return msg.toString();
}

}

You will need a BuildStamp interface:


package org.example.client;
public interface BuildStamp { public String getBuildStamp(); }

And wire it up in your .gwt.xml:
<generate-with class="org.example.rebind.BuildStampGenerator">
<when-type-assignable class="org.example.client.BuildStamp" />
</generate-with>


What do you think?

15 September 2008

Spore on Linux

If you're a Linux user wondering if Spore works, the answer is: Sorta.

I bought the download version from the EA Store. Nothing mentioned until after my purchase was complete that I needed a Windows-only downloader. I didn't test this under Wine.

Aside: The EA Store website allows + in email addresses, but the Spore online login does not.

I'm using Ubuntu 8.04 with a custom build of Wine 1.1.4 (includes a patch needed to make Spore run). The installer runs fine in Wine. Skip the DirectX install. While the game works, piracy prevention code doesn't. You'll need to find a cracked SporeApp.exe floating around to work around the issue. I believe a similar workaround is needed if you purchase the boxed game.

I'm still on the creature level, I've found a few graphical glitches:

  • Minor: Turn "Shadows" to "Low" to reduce some of the bizarre sploches of blackness.
  • Minor: The icon by the mouse pointer seems to not be transparent properly
  • Minor: Text describing your goals overlaps the text describing items you've picked up.
  • Medium: The water isn't rendered.


Check the the WineHQ page about Spore.

03 September 2008

Chromium and Bees

Watching what Google does feels like watching X-Files. I want to believe there's some grand master plan, but I'm pretty sure they're just making things up as they go.

Hank Williams over at Why Does Everything Suck pretty much covers my thoughts on Google's new web browser in his Huh? and Huh! posts.