Hi,
First of all, I'm new to this project and I'd like to
congratulate you on putting it together with your typical no-nonsense
approach to APIs. Particular praise is worthy for the IMessageConveyor
interface hiding the ugliness of ResourceBundle and MessageFormat
within a single method with varargs - inspired simplicity!
Secondly, I would like to suggest a use-case that your API does not
(yet?) cover. Maybe this is an idea you could consider incorporating.
Within
an enterprise application, especially a web-based application for
example, resources frequently need to be looked up and corresponding
strings returned to the user's display. But I have found that there are
times in such applications where I would prefer to defer the choice of
locale. For example, I may have some 'library' code not concerned with
the UI yet which produces messages that are fed back to the user.
These are status messages, error messages etc. The classic way to deal
with these is to return separate transfer objects and later construct
messages from them, but this can make the parameterisation awkward and
adds complexity. Maybe it would be simpler to return the message
directly.
The problem with the Cal10n API as it stands is that I need to know
the locale before I can construct a MessageConveyor. Only then can I
call the getMessage(E e, Object... args)
method to get the string, including its formatted parameters. The
problem with web applications is that only the UI tier knows the
locale. It is incorrect for other tiers to assume a different locale
and unwieldy to pass the correct locale through as a parameter. So it
would typically be wrong for the lower tiers to use MessageConveyor.
This is a shame and my suggestion is simply that an additional data
transfer object is required as part of the Cal10n API to fill the gap.
This is essentially a Message
class containing the enumeration and the args but without the resource
bundle/message format lookup having yet been performed. At a later
stage, a getLocalizedMessage(Locale locale) method will yield the required String for a given locale.
A desirable characteristic of Message
is that it be immutable because this would make it safe to hold within
Exceptions or to be shared between threads. In other words, it would
be better for it not to be a classic mutable JavaBean data transfer
object. Therefore it is arguable that a general interface is not needed
and a concrete and final Message class would be completely sufficient. So here is a possible implementation for Message:
public final class Message {
private final Enum<?> e;
private final Object[] args;
public Message(Enum<?> e, Object... args) {
this.e = e;
this.args = args;
}
public String getLocalizedMessage(Locale locale) {
final IMessageConveyor mc = new MessageConveyor(locale);
return mc.getMessage(e, args);
}
@Override
public String toString() {
final StringBuilder b = new StringBuilder("Message(");
b.append(e.name());
b.append(", [");
if (args != null) {
String comma = "";
for (Object o : args) {
b.append(comma).append(o);
comma = ", ";
}
}
b.append("])");
return b.toString();
}
}
In use, the 'library' (non-UI) code will have its own resource
bundle and corresponding enum. It will create instances of Message to
return to the UI tier, where the message string for the appropriate
locale can be looked up and then presented to the user.
It would be beneficial to override hashcode() and equals() methods
appropriately but I haven't included that here. There may also be some
performance value in holding transient caches of the toString() result
and the hashcode, although I omitted this also.
I wish the project success and I look forward to recommending it to my clients when it reaches a sufficient level of maturity.
Regards,
Rick Beton
--
Big Bee Consultants Limited : Registered in England & Wales No. 6397941
Registered Office: 71 The Hundred, Romsey, Hampshire, SO51 8BZ