Java Thinks There Are 13 Months

I was working on a component for credit card processing where I needed to get the months of the year. Trying to plan ahead, I decided to use the DateFormatSymbols so it could easily handle localization if it ever needed to be used in a different language.

It wasn’t doing what I expected and I finally found the problem with the following code:

1
2
3
4
DateFormatSymbols symbols = new DateFormatSymbols();
String[] months = symbols.getMonths();
int numOfMonths = months.length
System.out.println(numOfMonths);

The output is 13. If you list all of the strings in the months array, you’ll find the first 12 are what you’d expect, but there is a 13th blank month at the end.

It turns out that there are some lunar based calendars that have to add a “leap month” every so many years. This month is called Undecimber and comes after December. However, I’m not clear why Java is giving me a blank month. If the given locale only has 12 months, what is the value of giving back a 13 item array and just leaving one blank?

Adding Context to Links in Tapestry

Introduction

Tapestry looks at the URL and assumes that anything after the page name is the context that is being passed to the page. So a URL like:

http://www.site.com/MyPage/5

Is going to expect that the number 5 is the context needed on MyPage.  You can have multiple contexts passed to a page like this:

http://www.site.com/MyPage/5/foo

This will pass two contexts to the page.  Depending on what the page is expecting to receive in the context, these values may be uses as they are or they might be coerced into something else.  For example, the five might represent the ID of some object that will be retrieved from the Hibernate.

In the case of a single context value being passed, MyPage can get the value into a page property by doing something like this:

1
2
3
@PageActivationContext
@Property
private int myNumber;

The PageActivationContext annotation tells Tapestry to put the value on the URL that comes after the page into that variable. With Hibernate involved you can do something like this:

1
2
3
@PageActivationContext
@Property
private Person aPerson;

Tapestry will tell Hibernate to get the person object with an id of 5 and assign it to the variable aPerson.

If the page has multiple context values being passed, they are handled through the onActivate method:

1
2
3
public void onActivate(int myNumber, String myString) {
//set appropriate page properties
}

PageLink

Thats a little background. The main thing I wanted to look at in this post is how to get links that pass in these context values in the first place.

This snippet shows a pagelink that will give us something of the form:
http://www.site.com/MyPage/5
Assuming that the person.id is 5.

1
<t:pagelink page="MyPage" context="person.id">${person.name}</t:pagelink>

If we need to pass multiple context values it can be done like this.

1
<t:pagelink page="MyPage" context="[person.id,order.id]">view order</t:pagelink>

If person.id is 5 and order.id is 22 this link will produce:
http://www.site.com/MyPage/5/22

Returning Page and Context from a Method

Tapestry lets us return values in Java that specify the next page to load. This is commonly seen in the onSuccess method which can look like this:

1
2
3
4
public Object onSuccess() {
   //Do what needs to be done
   return "MyPage";
}

At first it looks like we can simply append the values like:

1
2
3
4
public Object onSuccess() {
   //Do what needs to be done
   return "MyPage/" + person.id + "/" + order.id;
}

But this does not work because Tapestry can’t find the page “MyPage/5/22”. It only knows about “MyPage”. To add a context you will need to inject the pageRenderLinkSource and use it to build the context.

1
2
3
4
5
6
7
@Inject
private PageRenderLinkSource pageRenderLS;
 
public Object onSuccess() {
   //Do what needs to be done
   return pageRenderLS.createPageRenderLinkWithContext("MyPage", person.id);
}

You can add additional context values to the parameters as well.

1
2
3
4
5
6
7
@Inject
private PageRenderLinkSource pageRenderLS;
 
public Object onSuccess() {
   //Do what needs to be done
   return pageRenderLS.createPageRenderLinkWithContext("MyPage", person.id, order.id);
}

Starcraft and Genetic Algorithms

I read an interesting article about using genetic algorithms to find the optimal first steps for Starcraft 2 gameplay. Starcraft is a bit like chess in that the first few minutes of play can usually be done in a prescribed order. In chess this is known as your opening moves. In Starcraft this is known as the build order.

You can find the code posted here. It uses JGAP which is something I’ve fiddled around with before as part of the genetic algorithms used in Robocode.

Eclipse Multi User Plugin Management

I am working on writing the curriculum for a class on Java Programming. I want it to scale and I want to be able to focus on writing code–not fiddling around with the tools. I don’t want it to turn into a big tech support nightmare to try to figure out why this student can’t seem to get the JUnit to run and why another can’t seem to see the GIT plugin in Eclipse.

To accomplish that I’m going to run Eclipse on a server and give students access through X2Go. They can run Eclipse on their local machine, but it is up to them to support their own setup if they aren’t working on the server. To make this work I needed a way to make sure everyone was using the same set of plugins in Eclipse. The “dropins” folder does what I need.

If you install Eclipse through apt-get on Ubuntu, it will create a folder of /usr/share/eclipse under that folder is the plugin folder, etc. However, there is no dropins folder. You have to create it manually at /usr/share/eclipse/dropins. This folder is checked by Eclipse when it starts up and the plugins put in that folder are loaded and installed into the users’s environment. This means you can easily manage what plugins each user has installed without touching each user’s home directory.

If a user installs a plugin from Eclipse, it gets installed in /home/[username]/.eclipse/[version]/plugins/. If you set things up with plugins in the /usr/share/eclipse/dropins folder, their personal plugins directory can be completely empty.

The best way I’ve found for setting this up is to create a fresh user that has nothing in their personal plugins directory. Have that user launch Eclipse and then use Eclipse to install any plugins you want to add for everyone. Once they are added, close eclipse and move everything that is in /home/[username]/.eclipse/[version]/plugins/ to /usr/share/eclipse/dropins. This will make sure you get all the dependencies you need to make things run.

If you need to troubleshoot how things are being loaded from /usr/share/eclipse/dropins, look in the workspace that is being launched. It will be in something like /home/[username]/workspace/.metadata/.log

RIM’s plans for the Blackberry

The the iPhone and Android as the platforms of choice for mobile developers.  Research in Motion is trying to make the Blackberry platform more attractive.  Apple didn’t originally allow developers to write code for their devices and pushed developers to create web apps instead.  Personally I think they were just trying to get the distribution part worked out for how apps would be purchased and didn’t want to roll out the hardware and the distribution infrastructure at the same time.

RIM’s response was to create their own “App World” where Blackberry apps can be featured, purchased and downloaded.  The purchase process is very convoluted and requires a Paypal account to pay for purchases.  Apple on the other hand integrates their purchases with the iTunes store so it is seamless and doesn’t require a third party payment service.

Research in Motion is trying to bring this type of capability to developers as well as in-app purchases for additional content or features–something the iPhone has.  While these may help attract developers, the Blackberry platform appears to be going through some big changes. The newest Blackberry, the Torch,  runs Blackberry 6 OS and it sounds like 6 will be compatible with some of the more modern Blackberry devices out there.

However, RIM also announced the new Playbook (an odd name considering the company’s focus on corporate sales) would be based on a new operating system from QNX.  Comments from several people from RIM make it sound as if this operating system will eventually be what is run on phones as well. It appears unlikely that the QNX operating system will be capable of running on any of the current phones.

OS X is turning into an even bigger asset for Apple because they have an OS that can scale up to run on a large server or down to run on a handheld device. RIM is going to have to work hard to stay relevant–particularly as Apple encroaches on the corporate market where Blackberrys have traditionally had a stronghold.