001 package hirondelle.web4j.ui.translate;
002
003 import java.util.logging.*;
004 import hirondelle.web4j.BuildImpl;
005 import hirondelle.web4j.request.LocaleSource;
006 import hirondelle.web4j.util.Util;
007 import hirondelle.web4j.model.AppResponseMessage;
008 import hirondelle.web4j.model.MessageList;
009 import hirondelle.web4j.ui.tag.TagHelper;
010
011 import java.util.*;
012
013 /**
014 Custom tag for rendering a {@link hirondelle.web4j.model.MessageList}.
015
016 <P>Example use case :
017 <PRE>
018 <c:if test="${not empty web4j_key_for_messages}">
019 Message(s) :
020 <w:messages name="web4j_key_for_messages">
021 <span class="message">placeholder</span><br>
022 </w:messages>
023 <c:remove var="web4j_key_for_messages" scope="session"/>
024 </c:if>
025 </PRE>
026
027 <P>The body of this tag is a simple template for emitting each element of the named
028 {@link MessageList}. The special <tt>placeholder</tt> text is the location where
029 each item returned by {@link MessageList#getMessages()} is displayed.
030 */
031 public final class Messages extends TagHelper {
032
033 /**
034 Key for a {@link MessageList} (in any scope).
035
036 <P>Required attribute. The {@link hirondelle.web4j.action.ActionImpl} class creates two such items, identified
037 with {@link hirondelle.web4j.action.ActionImpl#ERRORS} and {@link hirondelle.web4j.action.ActionImpl#MESSAGES}.
038 */
039 public void setName(String aMessageListName){
040 Object object = getPageContext().findAttribute(aMessageListName);
041 if ( object == null ) {
042 String message = "No object named " + Util.quote(aMessageListName) + " found in any scope.";
043 fLogger.severe(message);
044 throw new IllegalArgumentException(message);
045 }
046 fMessageList = (MessageList)object;
047 }
048
049 /**
050 Emit given template text for each item in the {@link MessageList}.
051
052 <P>Emit the text in this tag's body (which acts as a template), by replacing the
053 special {@link #PLACEHOLDER} text with the content of each message. The configured
054 implementations of both {@link LocaleSource} and {@link Translator} are used to render
055 each item. (This performs "last-second localization".)
056 */
057 @Override protected String getEmittedText(String aOriginalBody){
058 StringBuilder result = new StringBuilder();
059 Locale locale = BuildImpl.forLocaleSource().get(getRequest());
060 TimeZone timeZone = BuildImpl.forTimeZoneSource().get(getRequest());
061 List<AppResponseMessage> messages = fMessageList.getMessages();
062 for(AppResponseMessage message: messages){
063 String messageText = message.getMessage(locale, timeZone);
064 String fullText = replacePlaceholder(aOriginalBody, messageText);
065 result.append(fullText);
066 }
067 return result.toString();
068 }
069
070 /**
071 Special text used by this class to conveniently identify where message text
072 is placed.
073 */
074 public static final String PLACEHOLDER = "placeholder";
075
076 // PRIVATE
077 private MessageList fMessageList;
078 private static final Logger fLogger = Util.getLogger(Messages.class);
079
080 private String replacePlaceholder(String aOriginalBody, String aMessageText){
081 return Util.replace(aOriginalBody, PLACEHOLDER, aMessageText);
082 }
083 }