X-plane

I’ve been looking for a decent flight simulator for years & finally have found one that fits the bill: X-plane. I’ve taken some screenshots of a few Sunday online fly-ins for your viewing pleasure.

Blog migration & a new ‘retro’ theme

I’ve finally upgraded the version of WordPress which runs this blog. In doing so, sadly I managed to trash all the comments that people had contributed. One of the reasons for the upgrade was that I’d had to disable comments due to the sheer deluge of comment-spam (1000+ messages a day). Comments are now enabled again.

I’ve chosen this retro theme because I like it and it’s clear and easy to read – but it still needs a few tweaks.

NextDesk

Nearly three years after I first started the project, the first public beta of NextDesk is now online.

Put simply, NextDesk lets you easily drag and drop files from your computer to another computer. If you paste text to it from the clipboard, the pasted text will appear on the clipboard of the other computer.

Have fun!

Blogging on a train

National Express On-Train WiFi

I was on an intercity train this evening, journeying up the East Coast main line from London to Edinburgh; it was my first trip on the new National Express service since they took over from GNER some months ago. They offer free wifi to all passengers, which I was keen to try out with my new Eee 900 PC.

Upon firing up the ‘Wireless Networks’ window, I was heartened to see five hotspots with names like BN06DE, BN06EF and BN06FH. Selecting the one with the strongest signal yielded a WEP key prompt, which I eventually discovered could be bypassed simply by pressing OK. The window then displayed more hotspots named ‘nxecwifi’ and one called ‘Jet Blue hot spot’.

After several futile attempts at connecting to the more-enticing ‘Jet Blue hot spot’, I tried ‘nxecwifi’ … and Bingo! It took 15 seconds or so to acquire an IP address via DHCP, but after that I could ping www.google.com. Upon opening firefox I was immediately redirected to www.nationalexpresswifi.train – hosted on the train’s LAN. The page presents a login box asking for your email address (the password is supplied). After logging in you’re finally online at this point and can type any website address into your browser’s address bar.

Being a geek I now felt compelled to poke around and measure a few things. The network latency was pretty variable – between 500 and 6000 milliseconds, but this still seems remarkable considering you’re hurtling along backwards – in my case – at 150mph through the countryside. Tunnels tend to cause temporary blackouts, however TCP keepalive handles this nicely. www.speedtest.net recorded my ping time as 1 second, my download rate as 714kbps and my upload rate as 34kbps. There didn’t appear to be any direct correlation between latency and train speed.

Actual browsing seemed fairly slow, but definitely usable. My surfing was at one point redirected back to the train login page, whereupon I had to log back in using my email address, but this only happened once.

So all in all, an impressive service, especially so given that it’s free. One last gem to finish with – the onboard train website has a map showing where you are. And I’ve just passed Berwick-upon-Tweed.

BT Broadband

My BT Broadband failed at 16.30 last Thursday. As it turned out, all I needed to do was change the part of my broadband username which read ‘hg4.btinternet.com’ to ‘btinternet.com’. A quick reboot of the router, and I’m connected again. I’m writing this up in the hope it might help someone else – because I’d been through the fault reporting process, line check etc, but nobody from BT Broadband was able to either diagnose the fault or suggest that the username might have changed.

XFire Custom Types

XFire Custom Types – 25th February 2008 – XFire 1.2.6

  • Custom Types are types registered with XFire that perform their own mapping to/from XML.
  • "complex types" are your own beans/objects which don’t have a custom type mapping, therefore XFire will attempt to map to/from XML on its own.
  • They *do* work, but you have to be careful that you set everything up right, otherwise you’ll see a StackOverflowError and many other exceptions.
  • XFire sometimes gets terribly confused if one of your own (complex) types is put inside a map (e.g. of <String,Object>) – unless you create a custom type mapping as described below. (see bug XFIRE-831)
  • I couldn’t find a proper example of this on the web & spent several days discovering the correct way to do this.

Example: java.util.Date
Date objects are automatically converted to XMLGregorianCalendar by XFire. This behaviour may not be appropriate since converting back from an XMLGregorianCalendar to a Date is very slow. This example overrides the normal mapping for java.util.Date so that only a long value is passed across the wire, then reparsed back into a java.util.Date again.

  1. Define your type mapping class. The below defines a mapping for java.util.Date, so that it will be read and written as a String containing a long value (the number of milliseconds from the Date object). Note that this class must be available on the classpath for both client and server.
    import java.util.Date;
     
    import javax.xml.namespace.QName;
     
    import org.codehaus.xfire.MessageContext;
    import org.codehaus.xfire.aegis.MessageReader;
    import org.codehaus.xfire.aegis.MessageWriter;
    import org.codehaus.xfire.aegis.type.basic.ObjectType;
    import org.codehaus.xfire.aegis.type.java5.Java5TypeCreator;
    import org.codehaus.xfire.fault.XFireFault;
     
    public class DateType extends ObjectType {
    	private static final Class&lt;java.util.Date&gt; componentClass = java.util.Date.class;
    	protected QName qname = new Java5TypeCreator().createQName(componentClass);
     
    	public DateType()
    	{
    		setNillable(true);
    		setTypeClass(java.util.Date.class);
    		setSchemaType(qname);
    		System.out.println(&quot;Created DateType&quot;);
    	}
     
    	public Object readObject(MessageReader reader, MessageContext context) throws XFireFault
    	{	
    		String value = reader.getValue();
    		System.out.println(&quot;Reading DateType from '&quot;+value+&quot;'&quot;);
     
    		if (value == null)
    			return null;
     
    		try {
        		Long l = Long.parseLong(value);
        		return new Date(l.longValue());
    		} catch( NumberFormatException e ) {
    			throw new XFireFault(&quot;Could not parse Date: &quot; + e.getMessage(), e, XFireFault.SENDER);
    		}
    	}
     
    	public void writeObject(Object object, MessageWriter writer, MessageContext context)
    	{
    		System.out.println(&quot;Writing DateType..&quot;);
     
    		assert( object instanceof Date );
     
    		Date d = (Date) object;
    		writer.writeValue(&quot;&quot;+d.getTime());
    	}
    }
  2. Register the type mapping with both the client and the server

    Registering with the client is easy. I dare say you already have a convenience method that allows you to get hold of a Service. The important parts from mine look something like this:

    	String serviceURL = ... // replace with your service URL
    	Class serviceClass = ... // replace with the class object for your service (e.g. MyService.class)
    	Service service = new ObjectServiceFactory().create(serviceClass);
     
    	// register our new type mapping class
    	TypeMapping tm = ((AegisBindingProvider)service.getBindingProvider()).getTypeMapping(serviceModel);
    	tm.register(new DateType());	
     
    	serviceObject = new XFireProxyFactory().create(service, serviceURL);
    	System.out.println(&quot;Created service object.&quot;);
     
    	// then cast your serviceObject to the correct type (e.g. MyService) and use it.

    Registering with the server is somewhat more confusing. I tried several things and ended up extending XFireConfigurableServlet so that the type mappings were registered inside the init() method:

    public class MyXFireServlet extends XFireConfigurableServlet {
    	public MyXFireServlet() {
    		super();
    		System.out.println(&quot;Creating MyXFireServlet.&quot;);
    	}
     
    	public void init() throws ServletException {
    		super.init();
     
    		System.out.println(&quot;Initializing My XFire Servlet..&quot;);
     
    		ServiceRegistry serviceRegistry = getXFire().getServiceRegistry();
    		for( Service service : (Collection&lt;Service&gt;) serviceRegistry.getServices() ) {
    			TypeMapping tm = ((AegisBindingProvider) service.getBindingProvider()).getTypeMapping(service);
    			tm.register(new DateType());
    			System.out.println(&quot;Registering DateType for service &quot;+service.getName());
    		}
     
    		System.out.println(&quot;Initialization complete.&quot;);
    	}
    }

    If you do this, you should also update your web.xml file so that your servlet definition for XFire uses your customized servlet, like this:

    	&lt;!-- XFire --&gt;
    	&lt;servlet&gt;
    		&lt;servlet-name&gt;XFireServlet&lt;/servlet-name&gt;
    		&lt;display-name&gt;XFire Servlet&lt;/display-name&gt;
    		&lt;servlet-class&gt;my.package.name.MyXFireServlet&lt;/servlet-class&gt;
    	&lt;/servlet&gt;

    Now your type mapping will be used whenever XFire encounters an object of the type registered by setTypeClass().

Note: if sending Date objects created by Hibernate, they may be of type java.sql.Date – in which case XFire will still convert them to XMLGregorianCalendar unless you add a type mapping (as above) for java.sql.Date. Depending on your database vendor, you may also have to register mappings for vendor-specific types (e.g. com.sybase.jdbc2.tds.SybTimestamp).

You can define type mappings for any of your own objects – just substitute your fully-qualified class name where java.util.Date is used in the example above, and customize the readObject() and writeObject() methods to read and write a representation of your object.

For this example, I used the 3.2.4 version of the woodstox library. If you don’t specify woodstox as a dependency, you may get a cryptic com.bea.xml.stream.MXParserFactory not found error.

Hints:

If you see the following then your client is almost certainly not aware of a custom type mapping that it needs in order to parse a type that it has encountered (possibly in a Map or List). Check that you’ve registered it with the appropriate code that creates your service object.

java.lang.StackOverflowError
	at com.ctc.wstx.util.StringVector.findLastNonInterned(StringVector.java:194)
	at com.ctc.wstx.sr.NsInputElementStack.getNamespaceURI(NsInputElementStack.java:503)
	at com.ctc.wstx.sr.BasicStreamReader.getNamespaceURI(BasicStreamReader.java:775)
	at org.codehaus.xfire.util.stax.DepthXMLStreamReader.getNamespaceURI(DepthXMLStreamReader.java:142)
	at org.codehaus.xfire.util.stax.DepthXMLStreamReader.getNamespaceURI(DepthXMLStreamReader.java:142)
	at org.codehaus.xfire.aegis.stax.ElementReader.getNamespaceForPrefix(ElementReader.java:271)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.extractQName(ObjectType.java:146)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.readObject(ObjectType.java:97)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.readObject(ObjectType.java:133)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.readObject(ObjectType.java:133)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.readObject(ObjectType.java:133)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.readObject(ObjectType.java:133)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.readObject(ObjectType.java:133)
	at org.codehaus.xfire.aegis.type.basic.ObjectType.readObject(ObjectType.java:133)

JDarkRoom 12

JDarkRoom version 12 is now available including the following new features:

  • Auto-save backups
  • Adjustable screen margins for smaller displays
  • Text search

As I write this, JDarkRoom has now been downloaded over 20,000 times.

JDarkRoom 11

JDarkRoom 11 is now available, with mouse-wheel scrolling and a few more bug-fixes.

Interest in JDarkRoom continues, with over 48,000 hits to the website and nearly 16,000 downloads so far. Last month, JDarkRoom was featured on the cover DVD of Computer Idee magazine in the Netherlands and continues to feature in blog posts from time to time.

Java font metrics

I’m always having to remind myself how Java’s font metrics work. As an aide-memoire (mainly for my own use, but someone may find it useful), I’ve created this diagram:

Java Font Metrics

JDarkRoom sightings

Ok, please allow me to indulge in a little ego-trip. :-) My pet application, JDarkRoom, has been downloaded rather a lot & I’ve discovered a few people writing good things about it on their blogs:

I am writing this post from pretty much the coolest Java app I’ve ever seen. …

(from http://frem.wordpress.com/2007/01/05/jdarkroom/)

Thanks James! Donald also has some nice things to say..

I find it very useful. The fact that there’s nothing else displayed on the screen allows me to focus entirely on the task in front of me. No disruption, no eye candy, nothing. Just me and the task. Just me… and the task. Such situation gives me a peace of mind, a “mind like water”. It is a good condition for me to enter the “flow” state, a condition where I lose track of time and have my creative juice flows freely.

(from http://www.lifeoptimizer.org/2007/02/15/creative-thinking-cool-tool-jdarkroom/)

.. and my personal favourite ..

JDarkRoom is a sanity saver

Over the last month or two, there have been a lot of distractions in my life. Distractions that have piled on the stress and which have made writing very difficult at times. So, I’ve let a few assignments slip. Not to the point of missing deadlines, mind you, but enough so that I have to scramble to meet those deadlines. Which adds to my stress.

In those cases, JDarkRoom really helped me get work done. My writing process has been to find a (relatively) quiet corner, turn off my notebook’s wireless card, fire up JDarkRoom, and start writing. Pretty soon, I have a completed draft of an article. With about 70% of articles that I’ve used JDarkRoom to write, the first draft has been pretty close to the final draft. And I’ve been able to bang out articles in record time.

Sure, JDarkRoom doesn’t have a built-in spelling checker, but I have other tools for that. And I can usually spot spelling errors during my first read-through of an article. The only feature that I’d like added to it is scrolling with the mouse wheel. As with a spelling checker, that’s not a make-or-break feature with me. JDarkRoom lets me write. That’s the only feature I really need.

(from http://www.scottnesbitt.net/weblog/archive/2007_02_25_archive.html)

Thanks for the good review, Scott. JDarkRoom even features on a photo that Bryan Villarin has posted to flickr. Nice to see it in action.

It’s good to know that JDarkRoom is useful to people. If you have any more sightings, please send them in. :-)

Comment Spam

It seems that I’ve finally got rid of all the comment spam that was clogging up this blog and its moderation queue. My apologies if your comment was delayed and has only now made it to the blog.

Thank you again for all the comments about JDarkRoom. I read every one and good suggestions make it into the JDarkRoom TODO list.

Summary: JDarkRoom

January 2007 has been a good month for JDarkRoom. What started out as a toy proof-of-concept Java implementation of WriteRoom (well, the main idea anyway) suddenly got some attention on LifeHacker (#1, #2) in podcasts (#1, #2) and was discussed on several blogs (#1, #2 and #3). There were also some generally negative comments that resulted in some interesting discussion and an O’Reilly blog post. This resulted in 14,776 hits on the website (11,613 of which were unique visitors) and 5,147 downloads. Not bad for one month in the life of a toy computer program.

Since the first release in early July 2006, I’ve received many emails requesting new features for JDarkRoom. From reading most of the comments on blogs and in the podcasts, I should take the time to point out that JDarkRoom is first and foremost intended as a creative writer’s tool – to get ideas down and to focus on the words themselves, rather than font style, font size, paragraph formatting etc. That said, it is a text editor and people have therefore requested features such as spellcheck, page formatting, syntax highlighting and editing of documents held on the internet. However, other editors already do these things well, so I won’t be adding these features to JDarkRoom any time soon. (I’d rather that it set out towards a relatively simple goal and succeeded than tried to do too much.)

So thank you to everybody that has downloaded and commented on JDarkRoom. It’s been fun reading your comments and adding a few new features whenever I had a “why didn’t I think of that?” moment. I will continue to develop JDarkRoom, but with a tight focus on what it sets out to achieve.

JDarkRoom 8

Yesterday afternoon saw the release of JDarkRoom 8, now with undo/redo support, ability to toggle a more visible cursor and a text-only colour choice mode (to fix problems some users were experiencing on Apple macs).

It’s been a good month for JDarkRoom so far, with over 10,000 hits to the website and nearly 4,000 downloads. We’ve even been featured on a podcast!

JobTrawler 1.0 released

After a lot of beta testing, I have finally released JobTrawler 1.0 to the CodeAlchemists website.

JobTrawler is a job-search program that takes some of the pain away from searching online recruitment websites and helps you to track the progress of multiple job applications.

Many thanks to the following for their invaluable input:

  • Victoria Jauncey
  • Steve Batty
  • John Montgomery
  • Ian Ozsvald

Licences for JobTrawler 1.0 are currently free.

JDarkRoom featured on Lifehacker, Digg

Last Friday (5th Jan), JDarkRoom was featured in articles and comments from
Digg and Lifehacker. This resulted in over a thousand hits on that day alone and some very useful user feedback. I have just released JDarkRoom 7 with a couple of new features and will be working on the other suggestions over the next week.

Dansette