TargettedMessageList is a simple container of targetted message objects, which is held under the standard location targettedMessageList in RSF's request context. "Targetted" in this context indicates that the messages may be considered bound to either an EL path at which they originated, or else at a corresponding location (RSF full id) in the component tree/user interface field. The TargettedMessageList, especially the instance for the current request, is often referred to as TML for short.
Messages may enter the TML by a number of routes. The most obvious is through direct injection, which is the approach to be used when complex formatting of messages is required. Naturally the penalty of this approach is the dependence on the TML class itself. TML is defined at the PonderUtilCore level which represents a very low/light level of dependency, but is still an intrusion on what should properly be considered the pure business logic of the app - these TML entries will typically arise from validation rules etc. some of which may operate extremely close to the logical core. Some discussion of the seriousness of this dependency is on the BeanLine page - in general the point is that each dependency needs to "pay for itself" in terms of trading off the costs of introduced dependency against the benefits of reduced/cleaner coding.
For example a logic bean might in outline work as the following:
<bean class="uk.ac.cam.caret.messages.actions.ReplyMessageAction"> <property name="targettedMessageList" ref="targettedMessageListProxy" /> </bean>
with implementation
public class ReplyMessageAction extends BasicMessageAction { private TargettedMessageList targettedMessageList; public void setTargettedMessageList(TargettedMessageList targettedMessageList) { this.targettedMessageList = targettedMessageList; } ... public String init(RawMessageData messagedata) { ... if (!haspermission) { targettedMessageList.addMessage(new TargettedMessage(CoreMessages.NO_REPLY_PERMISSION)) } else { ... core logic if (message.getTitle() == null || message.getTitle().length() == 0) { targettedMessageList.addMessage(new TargettedMessage("error.blank.title", "title")); } }
RSF actually features a straightforward scheme of expressing the first of these two usages of TargettedMessage without introducting a dependence on TML. Part of RSF's standard action handling semantics is that any exception thrown out from evaluation an action binding will have its message text (accessed through Throwable.getMessage()) looked up as a message key, and if found, will be contributed automatically to the TML as a message with no target. E.g. in the (!haspermission) branch above, we could have an equivalent effect by simply writing it as
if (!haspermission) { throw new PermissionException(CoreMessages.NO_REPLY_PERMISSION); }
For cases where either the target id was required to be set, or a more complex constructor was required for the TargettedMessage, direct use would be needed of the TML. However, in many of these situations, the intrusion could be neatly contained by using some of RSF's interception facilities, for example BeanGuards as used in the LogonTest sample. These could be applied to intercept outgoing validation exceptions and convert them into TML entries in a more finegrained way, without intruding directly on the generation site.