The best solution to dealing with user messages is the humble ResourceBundle. But even that is a pain. ATG provided a class called ResourceUtils, but it wasn't very Util. I lost count of the number of MY_BUNDLE_NAME and sResourceBundle fields I had to stick into classes to make everything work.
I wrote about this earlier, but I didn't think I had a good solution. Now I think I do.
public class UserMessages {
protected UserMessages(String pBundleName) {
mBundleName = pBundleName;
mResourceBundle = ResourceUtils.getBundle(mBundleName);
}
public static UserMessages getUserMessages(Class pClass) {
Package classPackage = pClass.getPackage();
String name = classPackage.getName() + ".UserMessages";
return getUserMessages(name);
}
public static UserMessages getUserMessages(String pBundleName) {
return new UserMessages(pBundleName);
}
public String getUserMessage(String pCode) {
String message = ResourceUtils.getUserMsgResource(pCode, getBundleName(), getResourceBundle());
return message;
}
}Admittedly this is ATG-specific, but it's easy enough to generalize this.
Using this one class, you can do the following:
private static final UserMessages sMessages = UserMessages.getUserMessage(MyClass.class);
And from there you can get user messages for the package.
There's a number of optimizations possible with this class. I could make ResourceBundles hierarchical -- start at the class's package, and then go to each ancestor class and query for a valid messageCode. It should be possible to validate user messages through this class as well. I could do this by looking through the class and picking out any private String fields starting with "MSG_".
What I find interesting is that my instinct says that message code constants should be private to a class. I'm still not exactly sure why, but it just feels better to me if a class can't pick up parent message codes from a different package.