May 8, 2009

Slow, Very Slow, Coding Through Treacle, And Then There's IntelliJ...

Slower all the time
Hey! Perhaps an EAP release will fix it?!


Update: 8.1 is slow. I hadn't tried upgrade to 8.1.2, but I hear:

"Don’t do it. Performance is abysmal.

Enter key -> beach ball of waiting
Ctrl-space -> beach ball of waiting

I’m going back to 8.1"


Update: I'm still hanging in there. Things have not improved. I've disabled most all inspections, as many plugins as I can without disabling refactoring support. I semi-regularly delete the IDEA cache. I've followed some OS X specific advice and set the IDE font to Monospaced. Along the way I upgraded to 8.1.3 (because things can't get any worse, right?). All these tweaks make it more usable, but still a very sorry state for premium software.

Apr 27, 2009

Getting Started With Cometd, Jetty, and jQuery

I had difficulty getting started with these tools, so I thought I'd blog my minimal setup. This is all derived from the cometd demo who's war you can find inside the Jetty 6 webapp directory, and who's code you can find inside the contrib/cometd directory of the Jetty 6 source download.

First of all you need to be able to run Jetty (and debug it). I recommend the Run Jetty Run plugin for Eclipse.

Next you need to populate your web.xml for your webapp: (it's quite possible that you don't need all these init params)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>comet2</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

<context-param>
<param-name>org.mortbay.jetty.servlet.ManagedAttributes</param-name>
<param-value>org.cometd.bayeux,dojox.cometd.bayeux</param-value>
</context-param>

<servlet>
<servlet-name>game</servlet-name>
<servlet-class>
org.mortbay.cometd.continuation.ContinuationCometdServlet</servlet-class>
<init-param>
<param-name>timeout</param-name>
<param-value>120000</param-value>
</init-param>
<init-param>
<param-name>interval</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>maxInterval</param-name>
<param-value>10000</param-value>
</init-param>
<init-param>
<param-name>multiFrameInterval</param-name>
<param-value>2000</param-value>
</init-param>
<init-param>
<param-name>logLevel</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>directDeliver</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>refsThreshold</param-name>
<param-value>10</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>game</servlet-name>
<url-pattern>/game/*</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>gameServlet</servlet-name>
<servlet-class>server.GameServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>

</web-app>
The GameServlet is pretty much boiler plate:
package server;

import java.io.IOException;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import org.cometd.Bayeux;
import org.mortbay.cometd.ext.AcknowledgedMessagesExtension;
import org.mortbay.cometd.ext.TimesyncExtension;

public class GameServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
((HttpServletResponse)res).sendError(503);
}

@Override
public void init() throws ServletException {
super.init();
Bayeux bayeux=(Bayeux)getServletContext().getAttribute(Bayeux.DOJOX_COMETD_BAYEUX);
new GameService(bayeux);
bayeux.addExtension(new TimesyncExtension());
bayeux.addExtension(new AcknowledgedMessagesExtension());
}
}
The GameService pairs paths to method names. You can call the send() method to send messages to clients. Mine looks like this:
package server;

import java.util.Map;

import org.cometd.Bayeux;
import org.cometd.Client;
import org.mortbay.cometd.BayeuxService;

public class GameService extends BayeuxService {
private GameState state = new GameState();

public GameService(Bayeux bayeux) {
super(bayeux, "game");
subscribe("/game/join", "join");
subscribe("/game/event", "event");
}

public void join(final Client joiner, final String channelName, Map<String, Object> data, final String messageId) {
send(joiner, "/game/state", state.getData(), null)
}

public void event(final Client joiner, final String channelName, Map<String, Object> data, final String messageId) {
// TODO
}
}
Finally, and perhaps most importantly (as this was the part that confused me the most), here's the JavaScript to talk to the comet service:
var _connected = false;

function _metaConnect(message)
{
var wasConnected = _connected;
_connected = message.successful;
if (_connected && !wasConnected)
{
$.cometd.startBatch();
$.cometd.subscribe('/game/state', this, receive);
$.cometd.publish('/game/join', {});
$.cometd.endBatch();
}
}

function join()
{
$.cometd.addListener('/meta/connect', this, _metaConnect);

var cometURL = document.location.protocol + '//' + document.location.hostname + ':' + document.location.port + '/c2/game';
$.cometd.init(cometURL);
}

function send(data) {
$.cometd.publish('/game/event', data);
}

function receive(message)
{
// handle message.data content
}

join();
Note that /c2 is the context name of my webapp in Jetty.

One last point, I used the same includes in my index.html as the cometd chat example did:
<script type="text/javascript" src="jquery/json2.js"></script>
<script type="text/javascript" src="jquery/jquery.js"></script>
<script type="text/javascript" src="jquery/jquery.cometd.js"></script>
Let me know if you get up to something with comet.

Apr 25, 2009

Jetty and Cometd Documentation Woes

I've been trying to get going with Comet using Jetty and cometd-jquery. It's been an uphill battle. First off there's practically zero documentation for Cometd. I've been reverse engineering the chat example - a very poor source of documentation. I've finally gotten to a point where my JavaScript initiates a Bayeux connection. Great.

Now I want to debug my app that Jetty is hosting. That's been a very frustrating experience. Jetty 6 forks a JVM for each webapp, so none my standard approaches to debugging are working for me. Jetty documentation is again very weak and it's hard to differentiate which versions of Jetty documentation refers to.

Can anyone help me out?

Update: IntelliJ debugs Jetty 6 out of the box (with the Jetty Integration plugin). The IntelliJ run configuration uses -Xdebug -Xrunjdwp:transport... to start in debug. I guess these settings may work for Eclipse: -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=y.

Update: Run Jetty Run for Eclipse works out of the box too.

Apr 24, 2009

Leadership Philosophy

McKnight quoted in Leading Lean Software Development:

"Mistakes will be made. But if a person is essentially right, the mistakes he or she makes are not as serious in the long run as the mistakes management will make it if undertakes to tell those in authority exactly how they must do their jobs"

Mar 30, 2009

Managing Ivy Dependencies In Gant

Maven and IntelliJ are far from best friends. I really really don't enjoy using them together. This post is born out of that frustration. I want good, transparent dependency management, and a very very easy time integrating with my IDE.

What I wanted was to actually download the jar files to inside a project's folder and have them all in one directory to make updating from the IDE a simple process.

No, I don't want to use maven. Gradle is still to other for me - I also couldn't find out from the documentation how to explicitly download the jars to a location. So, Gant is my logical choice.

Right. Gant integrates well with Ivy - there's just not a lot of documentation. I wanted adding a new dependency to be as readable as this:
dependency( jar:'commons-lang:commons-lang:2.3').

Here's a gant build file to do just that:

libDirectory = 'lib'

includeTool << gant.tools.Ivy

def patternForScope(scope) {
"$libDirectory/$scope/[artifact]-[revision].[ext]"
}

def dependency( map ) {
def elements = map.jar.split(':')
def opts = [ organisation: elements[0],
module: elements[1],
revision: elements[2],
inline:true
]
ivy.retrieve( opts + [ pattern:patternForScope(map.scope ?: 'main') ] )
ivy.retrieve( opts + [ pattern:patternForScope('all') ] )
}

target ( retrieveDependencies : 'Downloads jars for lib/main, lib/test, and lib/all.' ) {
delete ( dir : libDirectory )
mkdir ( dir : libDirectory )
dependency ( jar:'commons-lang:commons-lang:2.3' )
dependency ( jar:'junit:junit:4.5', scope:'test')
}

setDefaultTarget ( retrieveDependencies )
Once you've run gant this is what the resulting structure looks like:
$ find lib
lib
lib/all
lib/all/commons-lang-2.3.jar
lib/all/junit-4.5.jar
lib/main
lib/main/commons-lang-2.3.jar
lib/test
lib/test/junit-4.5.jar
The build file here is derivative of this.

Mar 25, 2009

Building Test Data

If your experience with building test data is anything like mine then you've tried a lot of different ways of creating test data - each with their own subtle flaws:

Setup all the data in the test method: going this route you quickly cluttered your tests with data that didn't help the reader understand the test.

Setup all the data in a file (or a database): it made your tests more concise, but you ended up with "magic" numbers that depended on what was in the file or database. This made tests brittle and hard to interpret.

You pulled all of the setup out into setUp (or helper methods or helper classes): much better. You were able to show the significant details, hide the mechanics of setting up test data, and gave helper methods readable names. Well, at first at least. The helper methods were hard to generalize so pretty quickly you ended up with an explosion of helper methods that became hard to manage.

Hmm. This is as far as I'd gotten and I've not been very happy about it.

At this point perhap you'd dumped Java anyway and run off to the Ruby space. If you didn't then did you arrive at something like this?

  Order order1 = anOrder()
.withLine("Deerstalker Hat", 1) // detail important to the test
.withLine("Tweed Cape", 1) // detail important to the test
.withCustomersReference(1234) // detail important to the test
.build();

So this approach appeals to me (read the "Removing Duplication At Point of Use" section to see why). I took the time to code up what this might look like. It feels like a ton of boiler plate:

public class BuilderFactory {
public static OrderBuilder anOrder() {
return new OrderBuilder();
}
// factory methods for each builder...
}

public class OrderBuilder implements Cloneable {
private Customer customer = new CustomerBuilder().build();
private List<OrderLine> lines = new ArrayList<OrderLine>();
private BigDecimal discountRate = BigDecimal.ZERO;
private String voucher = null;

public OrderBuilder withCustomer(Customer customer) {
this.customer = customer;
return this;
}

public OrderBuilder withCustomer(CustomerBuilder customerBuilder) {
this.customer = customerBuilder.build();
return this;
}

public OrderBuilder withOrderLines(List<OrderLine> lines) {
this.lines = lines;
return this;
}

public OrderBuilder withOrderLine(String name, int quantity) {
lines.add(new OrderLineBuilder().withName(name).withQuantity(quantity).build());
return this;
}

public OrderBuilder withDiscount(BigDecimal discountRate) {
this.discountRate = discountRate;
return this;
}

public OrderBuilder withGiftVoucher(String voucher) {
this.voucher = voucher;
return this;
}

public Order build() {
Order order = new Order(customer);
for (OrderLine line : lines) order.addLine(line);
order.setDiscountRate(discountRate);
order.setVoucher(voucher);
return order;
}

public OrderBuilder but() {
try {
return (OrderBuilder) clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}

}

// plus all the other builders too...
What's your reaction? Do you have a more elegant solution? [the code]

I like the readability of the code that uses the builders. The real disappointment is that the essence of all of the builder code is in the 6% of the code that defines the sensible defaults for test data, namely:
  private Customer customer = new CustomerBuilder().build();
private List<OrderLine> lines = new ArrayList<OrderLine>();
private BigDecimal discountRate = BigDecimal.ZERO;
private String voucher = null;
The rest is all ceremony. Are there better solutions out there?

Mar 23, 2009

Raphael, SpriteLib GPL, And Timers In JavaScript

I tried to hack together a much simplified Arkanoid clone using Raphael in JavaScript. All was well until I tried to set up a fine grained timer to move the ball sprite around the screen. I think it has to be to do with the timeout facility, as updated based on mouse movement are very smooth. Using setTimeout is looked like I was getting max three frames per second. Shame.

Kudos to SpriteLib GPL for making the Arkanoid graphics available. I used this Groovy script to split the images up (copied and pasted from somewhere):

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;

BufferedImage bigImg = ImageIO.read(new File("arkanoid.png"));

final int width = 32;
final int height = 32;
final int rows = 19;
final int cols = 13;
BufferedImage[] sprites = new BufferedImage[rows * cols];

for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
def sprite = bigImg.getSubimage(
i * width + 1,
j * height + 1,
width - 1,
height - 1);
ImageIO.write(sprite, "PNG", new File("sprites/$i-$j.png"));
}
}

Mar 22, 2009

Exploring Safari 4

I'm quite liking Safari 4. It feels fast and has a rather elegant interface and I don't have to give up FireBug*. Navigating browser histories is something that Safari does especially well. Nice touch, Apple:


* defaults write com.apple.Safari WebKitDeveloperExtras -bool true from the command line will install a FireBug-like tool [more].

Finding Source Code

Velocity has an annoying bug in it's MathTool.pow method. It can't handle anything higher than 2^63. Finding the source code can be a real pain. My checklist goes like this:

* Can I get the source code via maven?
* Can I find it by searching for something like: fisheye "public class MathTool" pow?
* Find the project home page and download the source distribution for my version, etc. etc.

If I have to go through all three of these steps then it takes me rather too long to find the code. Enter Google Code Search:

* My search term is: class:MathTool function:pow

Which is quick! I can now browse the class, and if I want to the rest of the code in that distribution. It does suffer from now showing me all versions of velocity however. I'd also by nice if there was some xref-style navigation on offer.

Ditching Twitter

After trying twitter for a month I'm giving it up. I did get some useful ideas and links to interesting material. What it cost me was a lot of my time and attention. I also stopped blogging and stopped reading more substantive material. Twitter wasn't being a good influence.