Table of Contents
Table of Contents |
---|
indent | 10px |
---|
style | disc |
---|
printable | false |
---|
|
MessageContext
The MessageContext
allows using a fluent API for
- Creating messages
- Creating message text
- Processing messages
- Changing the configuration of the current context
- Using the current context as template for a new context
Furthermore, the context provides the current locale.
Message
The default implementation provides
- Descriptor (Key or inline-message)
- Arguments
- Numbered arguments
- Named arguments
- Payload
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
.
Creating messages
Instead of instantiating messages manually, the fluent API allows to create messages with (named-)arguments and message payload.
Example 1
Code Block |
---|
title | Creating messages with inline-text |
---|
borderStyle | solid |
---|
|
Message message = messageContext.message().text("Hello MyFaces").create();
|
... creates a message with the hardcoded text 'Hello MyFaces' as message descriptor.
Example 2
Code Block |
---|
title | Creating messages with a key |
---|
borderStyle | solid |
---|
|
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.)
Example 3
Code Block |
---|
title | Creating messages with arguments |
---|
borderStyle | solid |
---|
|
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.)
Example 4
Code Block |
---|
title | Creating messages with named arguments |
---|
borderStyle | solid |
---|
|
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
Example 5
Code Block |
---|
title | Creating messages with payload |
---|
borderStyle | solid |
---|
|
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
.
Creating message text
Example 1
Code Block |
---|
title | Creating the message-text (immediately) |
---|
borderStyle | solid |
---|
|
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().
Example 2
Code Block |
---|
title | Creating the message-text of a given message |
---|
borderStyle | solid |
---|
|
//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.
Processing messages
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
.
Example 1
Code Block |
---|
title | Creating the message-text (immediately) |
---|
borderStyle | solid |
---|
|
messageContext.message().text("Hello MyFaces").add();
|
... adds the constructed message to the MessageHandler
(s) of the current MessageContext
.
Example 2
Code Block |
---|
title | Creating the message-text of a given message |
---|
borderStyle | solid |
---|
|
//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
.
Message Builder
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
).
Note |
---|
|
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); |
Advanced Use-Cases
Custom Message Types
A custom MessageBuilder
also allows to introduce custom message types easily:
Code Block |
---|
title | Creating custom message types via a custom message-builder |
---|
borderStyle | solid |
---|
|
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);
|
Code Block |
---|
title | Implementation of a custom message-builder |
---|
borderStyle | solid |
---|
|
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.
Code Block |
---|
title | Handling different message types |
---|
borderStyle | solid |
---|
|
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)
}
|
Business client specific messages
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.
Code Block |
---|
title | Provider of the current business client |
---|
borderStyle | solid |
---|
|
@Produces
@RequestScoped
public Client getCurrentClient(ClientService clientService)
{
return clientService.loadClient(this.currentClientId);
}
|
Code Block |
---|
title | Business client specific messages |
---|
borderStyle | solid |
---|
|
@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.
Code Block |
---|
title | Injecting the business client aware MessageContext |
---|
borderStyle | solid |
---|
|
@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.
Code Block |
---|
title | Expose business client aware messages to XHTML pages |
---|
borderStyle | solid |
---|
|
@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();
}
}
|
Code Block |
---|
title | Usage in XHTML pages |
---|
borderStyle | solid |
---|
|
#{clientMessages.sample_message}
|
The full example is available in the current MyFaces CODI example application.
Manual Usage
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
.
Code Block |
---|
title | Creating a message manually |
---|
borderStyle | solid |
---|
|
Message message = new DefaultMessage("inline message");
|