[ http://issues.apache.org/jira/browse/JS2-219?page=history ]
Ate Douma closed JS2-219:
-------------------------
Resolution: Fixed
> A new message definition and automatic translation facility: KeyedMessage.
> --------------------------------------------------------------------------
>
> Key: JS2-219
> URL: http://issues.apache.org/jira/browse/JS2-219
> Project: Jetspeed 2
> Type: Improvement
> Components: i18n and l10n
> Versions: 2.0-dev/cvs
> Reporter: Ate Douma
> Assignee: Ate Douma
> Fix For: 2.0-dev/cvs, 2.0-M2
>
> I've been working on enhancements of the Login Portlet to provide better
> feedback to the user about login errors.
> Because the exceptions thrown by the Security layer currently use statically
> defined Exception messages to distinguish the different conditions, checking
> which type of error occurred is very cumbersome to do. Furthermore, in some
> situations the statically defined messages
> are only used as templates (.e.g. a specific User/Role/Group name is
> postfixed) making it even harder to compare the exceptions.
> I've come up with a generic, transparent and very easy to use, i18n
> supporting, message definition and automatic translation facility which also
> provides named constant definitions (phew, heavy definition).
> For this I created a new class org.apache.jetspeed.i18n.KeyedMessage.
> As I've provided extensive documentation through javadoc I'll provide the
> class level description below to explain its purpose and usage including a
> real ;-) example.
> I've used this KeyedMessage to replace all SecurityException constant String
> messages with a KeyedMessage variant.
> Furthermore, I've enhanced JetspeedException (and JetspeedRuntimeException)
> to recognize Exceptions constructed using a KeyMessage, and provided a
> org.apache.jetspeed.exception.JetspeedExceptionMessages.properties resource
> bundle (as well as a Dutch variant) containing SecurityException translations.
> After I've committed these changes, the benefit of this new facility can be
> easily tested as follows:
> - login as admin
> - switch the locale to Dutch using the Locale Portlet
> - go to the UserBrowserPortlet
> - select the guest user
> - try to delete the guest user
> - You will see a Dutch error message saying: "De gebruiker guest is
> beveiligd."
> (Previously, you would have been presented with: "The anonymous user is
> protected.")
> I didn't have to change anything in the UserBrowserPorlet or UserDetailPorlet
> for this to work.
> A copy of the class level documentation of
> org.apache.jetspeed.i18n.KeyedMessage follows:
> =========================================================================================
> public class KeyedMessage extends java.lang.Object implements
> java.io.Serializable
> KeyedMessage provides an automatically derived i18n message key based on its
> static instance definition and can be used as comparable constant too.
> Purpose
> -------
> With a KeyedMessage a named constant message (format) can be statically
> defined which automatically translate themselves for a specific locale using
> an automatically derived ResourceBundle or even a specified one.
> Key derivation
> --------------
> Because KeyedMessages are created with a default message (format), even if no
> ResourceBundle or its key is defined or can't be found, message translation
> is still possible.
> A KeyedMessage automatically derives the ResourceBundle lookup key from its
> (statically defined) instance field name using the following format:
> <containingClass.name>.<staticInstanceField.name>
> The containingClass is derived at construction time by analyzing the
> StackTraceElements of a thrown exception. This requires the instance to be
> defined as a public static field!
> At first access, the key is resolved by inspecting the derived
> containingClass for the declared field defining this instance.
> If the KeyedMessage instance wasn't defined as public static field, the key
> can't be resolved and message translation using a ResourceBundle won't be
> possible. Translation using the default message will still work though.
> Furthermore, this instance can't be used as comparable named constant as the
> equals(Object)method will always return false in this case.
> Default ResourceBundle name derivation
> --------------------------------------
> When the key of a KeyedMessage is resolved, the default ResourceBundle name
> for message translation is retrieved from the defined public static String
> field named "KEYED_MESSAGE_BUNDLE"defined in its containingClass or one of
> its superClasses or interfaces.
> If this field cannot be found, the fully qualified name of the
> containingClass is used.
> ResourceBundle names are cached in a Map for each containingClass and only
> derived for the first KeyedMessage defined in a containingClass.
> Again: only resolved instances can use a ResourceBundle for message
> translation.
> Default Locale lookup
> ---------------------
> When a message is translated without a specified Locale,
> CurrentLocale.get()is used to determine the default Locale for the current
> Thread.
> In Jetspeed, the LocalizationValve initializes the CurrentLocale on each
> request. KeyedMessages accessed within the context of an Jetspeed request
> therefore will always be translated using the current user Locale with the
> getMessage()or toString()methods.
> Default ResourceBundle lookup
> If a message translation is done using the default ResourceBundle name the
> ResourceBundle is retrieved using the ClassLoader of the containingClass.
> This means the bundle(s) must be provided in the same context as from where
> the containingClass is loaded. Usually (and preferably), this will be from
> the shared classpath of the webserver.
> MessageFormat parameters
> ------------------------
> MessageFormat patterns can also be used for a KeyedMessage.
> With the create(Object[])method a specialized copy of a KeyedMessage instance
> can be created containing the arguments to be used during message translation.
> This new copy remains equals(Object)to its source and can still be used for
> named constant comparison.
> For simplified usage, three create(Object),create(Object, Object)and
> create(Object, Object, Object)methods are provided which delegate to
> create(Object[])with their argument(s) transformed into an Object array.
> Extending KeyedMessage
> ----------------------
> An statically defined KeyedMessage can be used as a "simple" named constant.
> If additional metadata is required like some kind of status, level or type
> indication, the KeyedMessage class can easily be extended by providing a
> specialized version of the create(KeyedMessage, Object[])copy factory.
> Usage
> -----
> KeyedMessage has been used to replace the hardcoded SecurityException String
> constants.
> The ResourceBundle name used is defined by
> JetspeedException.KEYED_MESSAGE_BUNDLE which is the superClass of
> SecurityException.
> For a different ResourceBundle to be used for SecurityException messages a
> KEYED_MESSAGE_BUNDLE field can be defined in SecurityException too,
> overriding the one in JetspeedException.
> Example:
> public class JetspeedException extends Exception {
> public static final String KEYED_MESSAGE_BUNDLE =
> "org.apache.jetspeed.exception.JetspeedExceptionMessages";
> ...
>
> public String getMessage() {
> if ( keyedMessage != null ) {
> return keyedMessage.getMessage(); // translated using
> current Locale and default ResourceBundle
> }
> return super.getMessage();
> }
> }
>
> public class SecurityException extends JetspeedException {
> public static final KeyedMessage USER_DOES_NOT_EXIST = new
> KeyedMessage("The user {0} does not exist.");
> ...
> }
>
> // resource file:
> org.apache.jetspeed.exception.JetspeedExceptionMessages_nl.properties
> org.apache.jetspeed.security.SecurityException.USER_DOES_NOT_EXIST =
> De gebruiker {0} bestaat niet.
> ...
>
> public class UserManagerImpl implements UserManager {
> public User getUser(String username) throws SecurityException {
> ...
> if (null == userPrincipal) {
> throw new
> SecurityException(SecurityException.USER_DOES_NOT_EXIST.create(username));
> }
> ...
> }
> ...
> }
>
> // example get User
> try {
> User user = userManager.getUser(userName);
> } catch (SecurityException sex) {
> if (
> SecurityException.USER_DOES_NOT_EXISTS.equals(sex.getKeyedMessage()) {
> // handle USER_DOES_NOT_EXISTS error
> }
> }
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://issues.apache.org/jira/secure/Administrators.jspa
-
If you want more information on JIRA, or have a bug to report see:
http://www.atlassian.com/software/jira
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]