Overview
Other MyFaces Extensions
- ExtVal
- Ext-Script
- [Orchestra]
- [Portlet Bridge]
Community
Development
Sponsorship
Your browser does not support iframes
The MessageContext
allows using a fluent API for
Furthermore, the context provides the current locale.
The default implementation provides
The Message
interface extends Localizable
. Therefore it's possible to use a MessageContext
to create the final message text based on the message and the current configuration of the MessageContext
.
Instead of instantiating messages manually, the fluent API allows to create messages with (named-)arguments and message payload.
Message message = messageContext.message().text("Hello MyFaces").create();
... creates a message with the hardcoded text 'Hello MyFaces' as message descriptor.
Message message = messageContext.message().text("msgKey").create();
... creates a message with the key 'msgKey' as message descriptor.
(The concrete syntax of a key depends on the used MessageResolver. Further details are available in the DevDoc.)
Message message = messageContext.message().text("Hello {0}").argument("MyFaces").create();
... creates a message with 'Hello {0}' as message descriptor and 'MyFaces' as argument.
An argument has to be Serializable
.
(By default numbered arguments are formatted by MessageFormat
based on the current locale.)
Message message = messageContext.message().text("Hello {name}").namedArgument("name", "MyFaces").create();
... creates a message with 'Hello {name}' as message descriptor and 'MyFaces' as argument.
Values of named arguments are formatted by Formatter
s created by the FormatterFactory
Message message = messageContext.message().text("Hello CODI").payload(MessageSeverity.ERROR).create();
... creates a message with 'Hello CODI' as message descriptor and error as message-severity.
Payload is similar to the validation payload of Bean-Validation. Via payload it's possible to provide additional information via a typesafe mechanism. It's possible to use the provided types of payload ( MessageSeverity
or InternalMessage
) or to create custom payload like Label
or to create something like serializable attatchments. It's possible to handle messages depending on the payload of the message. By default a message is created with MessageSeverity.INFO
.
String messageText = messageContext.message().text("msgKey").toText();
... creates the message-text based on the constructed message.
To avoid side-effects with other libs as well as IDEs there is no #toString().
//Message message = messageContext.message().text("Hello {name}").namedArgument("name", "MyFaces").create(); String messageText = message.toString(messageContext);
... creates the message-text based on the given message and MessageContext
. That's essential if you would like to create the final text with a different/new MessageContext
e.g. with a different configuration or with the current MessageContext
if you receive a de-serialized message instance.
It's possible to register MessageHandler
s which process or forward messages added to the MessageContext
.
E.g. a MessageHandler
for JSF would convert messages to FacesMessage
s and add them to the current FacesContext
.
messageContext.message().text("Hello MyFaces").add();
... adds the constructed message to the MessageHandler
(s) of the current MessageContext
.
//Message message = messageContext.message().text("Hello {name}").namedArgument("name", "MyFaces").create(); messageContext.addMessage(message);
... adds the given message to the MessageHandler
(s) of the current MessageContext
.
The MessageContext
uses a (default) MessageBuilder
to create Message s via a fluent API.
If you don't have access to the MessageContext
it's possible to use a stand-alone MessageBuilder
(SimpleMessageBuilder
).
Attention!
Keep in mind that a stand-alone MessageBuilder
is able to create Message
objects, but it needs a MessageContext
to create the final text or to add the message to the context.
Without direct access to the MessageContext
you can use a MessageBuilder
to create a message via:
Message message = SimpleMessageBuilder.message().text("msgKey").create();
As soon as you have a MessageContext you have access to the final message-text via:
message.toString(messageContext);
And/or you can add it to the context via:
messageContext.addMessage(message);
A custom MessageBuilder
also allows to introduce custom message types easily:
Message label = CustomMessageBuilder.label().text("myMsgKey").create(); Message technicalMessage = CustomMessageBuilder.technicalMessage().text("myMsgKey").create(); //the context needs a message-resolver which knows how to handle the different message types. label.toString(messageContext); technicalMessage.toString(messageContext);
public class CustomMessageBuilder extends SimpleMessageBuilder { private CustomMessageBuilder () { } public static MessageBuilder message() { return new CustomMessageBuilder(); } public static MessageBuilder technicalMessage() { return new CustomMessageBuilder().payload(TechnicalMessage.PAYLOAD); } public static MessageBuilder label() { return new CustomMessageBuilder().payload(Label.PAYLOAD); } }
A custom MessageResolver
has to know how to handle the different message types. If a payload type just allows one possible value (as marker), we can use the class of the payload to check if the payload-map contains such a marker entry.
public class TestMessageResolver implements MessageResolver { public String getMessage(String key, Locale locale, Map<Class, MessagePayload> messagePayload) { if (!isKey(key)) { return key; } try { key = extractKey(key); if(messagePayload.containsKey(Label.class)) { return ResourceBundle.getBundle(TEST_LABELS, locale, getClassLoader()).getString(key); } else if(messagePayload.containsKey(TechnicalMessage.class)) { return ResourceBundle.getBundle(TEST_TECHNICAL_MESSAGES, locale, getClassLoader()).getString(key); } return ResourceBundle.getBundle(TEST_MESSAGES, locale, getClassLoader()).getString(key); } catch (MissingResourceException e) { return key; } } //The full example is available in the code-base (see: TestMessageResolver) }
As soon as an application has to support different business clients, it's required to display messages which are specific to each business client. The message module allows to use one MessageResolver
per client. So it's possible to use the same message-keys for all clients and the concrete MessageResolver
provides the correct message.
In combination with CDI a possible implementation is illustrated in the following listings.
@Produces @RequestScoped public Client getCurrentClient(ClientService clientService) { return clientService.loadClient(this.currentClientId); }
@Produces @RequestScoped @ClientQualifier public MessageContext createClientAwareContext(@Jsf MessageContext messageContext, Client client) { MessageResolver clientAwareMessageResolver = createMessageResolverForClient(client.getId()); return messageContext.config().use().messageResolver(clientAwareMessageResolver).create(); } private MessageResolver createMessageResolverForClient(final String currentClientId) { return new MessageResolver() { public String getMessage(String messageDescriptor, Locale locale, Map<Class, MessagePayload> messagePayload) { FacesContext facesContext = FacesContext.getCurrentInstance(); try { return facesContext.getApplication() .getResourceBundle(facesContext, currentClientId).getString(messageDescriptor); } catch (MissingResourceException e) { return "???" + messageDescriptor + "???"; } } }; }
This example uses the existing message-context as template and creates a new context with a different message resolver.
In this example the client-id is used as resource-bundle name.
@Inject @ClientQualifier private MessageContext clientAwareMessageContext;
To use such messages in a XHTML page, it's required to provide a bean which in-/directly implements the Map interface.
@Named("clientMessages") @Singleton public class ClientAwareMessages extends MapHelper<String, String> { @Inject @ClientQualifier private MessageContext clientAwareMessageContext; protected String getValue(String key) { return this.clientAwareMessageContext.message().text(key).toText(); } }
#{clientMessages.sample_message}
The full example is available in the current MyFaces CODI example application.
If you don't like the fluent API you can create your own message (e.g. based on DefaultMessage
) or you can just instantiate DefaultMessage
.
Message message = new DefaultMessage("inline message");