WTF from the Past

The missing image

I was remembering a strange problem from a few years ago and thought I would share the issue.

We had a simple web page around the year 2002 which contained either a plus or a minus image, not unlike these: plus minus

The problem we had was that regardless of the code we used, we could only ever see the minus image. Checking the page source and viewing the image on its own told us that we should be seeing the plus image where appropriate, and yet on the page itself we only ever saw the minus image.

How does your browser scale images?

It turns out that actual images were 11 pixels wide and 11 pixels high, but the image tag was telling the page to display as 10 pixels wide. I’ll show you what that looks like in today’s browsers, but your mileage may vary: plus minus

Hopefully you saw something like this: plus minus

If you’re unlucky you’ll see something like this: plus minus

Depending on the scaling algorithm used by your browser, scaling from width 11 to width 10 may just remove the middle line, making a plus look like a minus. Problem solved. I didn’t pick it and I’m sad to say that it took too long to pick up the issue.

Java Enums can implement Interfaces

Something which came as a surprise to me but ended up quite useful, was that enums in Java can also implement interfaces.

A typical enumeration in Java, introduced in Java 5, looks like a String value, but also introduces other features which make them a particularly useful language feature. Besides looking like an typical enumeration with a finite ordered list of values, it is also possible to attach additional information to each enumeration value.

A basic enumeration, which defines the four suits in a typical set of cards looks like this:

public enum Suit 
{ CLUBS, DIAMONDS, HEARTS, SPADES }

To attach additional information to the enumerated type, add a private constructor, add a private field, and get each enumeration value to call the new constructor.

public enum Numbers {
	One(1), Two(2), Three(3);

	private Numbers(int value)
	{
		this.value = value;
	}
	
	public int getValue()
	{
		return this.value;
	}
	
	private int value;
}

In the example above, we also introduced the getValue() method. This introduces the concept of behaviour to our enumeration; not something we would normally consider. It also lends itself to the idea of common behaviour between enumerated types.

To show how this works, consider an interface which defines the mapping between a class and a table.

public interface DatabaseMapping {
	public String getType();
	public boolean isKey();
	public boolean isNullable();
	//public String name();
}

The method name() is commented for now, we’ll get back to that in a minute.

To use this, we can now create a new Java class and then define the mapping of that class to a database.

public class Person {
	public String getFirstname() {
		return firstname;
	}
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	public String getLastname() {
		return lastname;
	}
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	private String firstname;
	private String lastname;
	private int age;
}

(I realise there are better ways to map a class to a database table, this example is contrived) When we define the mapping from our class to our table, we can define a separate mapping class. We create this class, we will make it an enumeration and allow each class/database field to be a member in an enumeration.

public enum PersonMapping {
	personId, firstname, lastname, age;
}

Using the trick where we are able to attach additional information to enumerated types, we define some of the database mapping details:

public enum PersonMapping {
	personId("INTEGER", true, false), 
	firstname("TEXT", false, false), 
	lastname("TEXT", false, false),
	age("INTEGER", false, false);
	private PersonMapping(String type, boolean key, boolean nullable )
	{
		this.type = type;
		this.key = key;
		this.nullable = nullable;
	}
	public String getType() {
		return type;
	}
	public boolean isKey() {
		return key;
	}
	public boolean isNullable() {
		return nullable;
	}
	private final String type;
	private final boolean key;
	private final boolean nullable;
}

So now we are able to use the enumeration to iterate the fields and do some database stuff. For the moment we’ll hold off including the interface.

public String dbTableCreate(String tableName) {
	StringBuilder builder = new StringBuilder("Create table ");
	builder.append(tableName);
	builder.append("(");
	for (PersonMapping column : PersonMapping.values()) {
		builder.append(column.name());
		builder.append(" ");
		builder.append(column.getType());
		builder.append(column.isKey() ? " primary key" : "");
		builder.append(", ");
	}
	builder = new StringBuilder(builder.substring(0, builder.length() - 2));
	builder.append(");");
	return builder.toString();
}

Which looks fine for our PersonMapping enumerated type, but doesn’t allow us to plug in different class-to-database mappings. Time to introduce the interface. Looking closely at the code above, we need to use two of the additional methods available to all enumerations, name() and values(). The first returns the text name of the current enumerated value, and the second allows us to access the values that make up this enumerated type.

First add the interface to the enumeration:

public enum PersonMapping implements MappingEnum{

Uncomment the name() method so that it can be accessed from the interface.

public interface MappingEnum {
	public String getType();
	public boolean isKey();
	public boolean isNullable();
	public String name();
}

Final piece of the puzzle is to write the dbTableCreate() above to allow it to be reused with other enumerated types. The problem we need to work around is that the values() method is static, making it difficult to pass the enumerated type to the method. The simple solution is to call the method explicitly and pass the values:

dbTableCreate("tableName", PersonMapping.values()));

… and realise that we can now receive the values using the interface …

public String dbTableCreate(String tableName, MappingEnum[] values) {
	StringBuilder builder = new StringBuilder("Create table ");
	builder.append(tableName);
	builder.append("(");
	for (MappingEnum column : values) {
		builder.append(column.name());
		builder.append(" ");
		builder.append(column.getType());
		builder.append(column.isKey() ? " primary key" : "");
		builder.append(", ");
	}
	builder = new StringBuilder(builder.substring(0, builder.length() - 2));
	builder.append(");");
	return builder.toString();
}

Conclusion

* Enumerations can store additional data and have additional methods,
* Enumerations can use interfaces to define behaviour,
* Enumerated item behaviour can be accessed via an interface, the same as regular Java classes,
* The values() method from enumerations can be used to return an array of a interface.

Combined, it allows us to treat enumerated types as both regular Java classes and enumerated types and interact using common behaviour rather than being tied to a single implementation.

first weekend with my new mac

I got my first Mac in 12 years a few days ago.  On Friday, I was able to surf the net.  Now I’ve advanced to doing almost everything I need except for development tools.

What I liked a lot:

  1. It still feels like home
  2. The trackpad lets you scroll so easily.
  3. iChat – thanks Scott! – only important setup was to check the box to automatically save transcripts on the messages part of preferences.
  4. My laser printer worked out of the box. I didn’t need to configure anything!
  5. Ejecting a CD/DVD is a lot more intuitive now than ejecting a disk was on the old Macs. Hmm, is dragging the disk to the trash can going to eject it or wipe it clean. The current icon to eject matches DVD players and is something most people are used to. There’s even a physical button on the keyboard. I also notice that dragging a disk to trash is still an option. This is actually nice in that it doesn’t change the behavior users who have been around a long time are used to. I was upset at how Windows moved everything in Office 2007 as I now waste time finding features. Apple moved things, but not in a way that makes them hard to find.
  6. Having a real UNIX command line and real UNIX system under the hood.

What I found unintuitive: (none of this is terrible, but it takes a little getting used to)

  1. When I wasn’t in stretch resolution, the browser didn’t extend to use the full screen real estate. I get that this is a “feature”, but if all I am using is the browser, I want to use the whole screen!
  2. To look at the site stats for this blog, one needs Flash. The first time I went to that page in Safari it said “missing plugin.” Fair enough. I click on it and get a message that the type is unspecified. This is probably WordPress’s fault and not Apple’s, but still unintuitive.
  3. I keep forgetting that there isn’t isn’t a pop-up when a download has started and then I start it twice. I have to remember to check the downloads list to see it is in progress. Some visual feedback on .dmg files would be nice. (It looks like if I already have the download window open, it does come to the front.)
  4. I understand why secondary clicking is off by default on the trackpad – whether you want bottom right or two finger touch is a personal preference. The default of neither is a surprise though. “right clicking” to choose a command is pretty common.
  5. How to find Mac Help – go to finder and choose help/mac help
  6. I blame Google or Adobe for this since other sites work just fine, but I have the problem where the cursor disappears in plain text mode when using the arrow keys.  The solution will be to get used to using rich text mode.  This was reported over a year ago and I can’t believe nobody fixed.
  7. How to run something as root/admin: “sudo command”.  This *should* be non-intuitive so people don’t do it by accident!
  8. Closing an app via the red x doesn’t release resources. This is actually easier to remember now as it shows up in the Doc. You actually need to quit the app.  This I did remember from last time, but it isn’t obvious.

Interesting configuration:

  1. I understand why secondary clicking is off by default on the trackpad – whether you want bottom right or two finger touch is a personal preference.  The default of neither is a surprise though.  “right clicking” to choose a command is pretty common.
  2. Need to enter your admin password when installing Flash but not Chrome.
  3. Turn on status bar in Safari so can see URLs before click on them.

Some maintenance tasks:

  1. Let battery run down to zero
  2. Checked all hardware works
  3. Print Safari keyboard shortcuts and Mac OS X keyboard shortcuts to start learning them.
  4. Buy a Mac wired keyboard.  I wanted the number pad and navigation options.  I also prefer not to have to replace batteries in as many things.
  5. Buy external hard drive.  Time machine is very easy to use.  Plug it in and go.
  6. Copied files in My Documents folder to Mac via a flash drive.

Installed after first day:

  1. Flash
  2. ClamXAV – Consensus says you don’t need anti-virus. I feel better having it though and know at least one person who does on a Mac. I think it’s cool they include in the feature list that you can use regular expressions!  Not that I’ll need to, but it’s nice someone thinks it is important.
  3. Open Office – The editing I do on my home computer is pretty light.  Except for the time I was preparing for The Server Side Java Symposium and needed PowerPoint.  I’ll cross that bridge when I come to it.
  4. Skype
  5. Dropbox
  6. Postgres and pgadmin – I got a message “Your system seems to be set up with less than 32MB shared memory”.  The postgres readme clearly explained what to do about it.
  7. Tomcat – this was the first thing I downloaded that assumes you know Mac is a UNIX system.  Granted postgres required that knowledge to install, but not to download.  Not a bad assumption since it is a developer tool of course.  I didn’t untar it/install since I’m not up to testing an application locally yet.
  8. Assorted Safari plugins.  (this seems like a good blog post in itself).  I will say at this time that I like how fast the plugins install.  The first two I tried didn’t work until I restarted Safari.  Would have been nice to a prompt to this effect.
  9. Regular readers of this blog may note that Eclipse is not on the list.  Since Indigo comes out in about a week, I’m going to wait for that to install Eclipse.  I can do any development on my old machine until then.