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     &lt;c:if test="${not empty web4j_key_for_messages}"&gt; 
019      Message(s) :
020      &lt;w:messages name="web4j_key_for_messages"&gt;
021       &lt;span class="message"&gt;placeholder&lt;/span&gt;&lt;br&gt;
022      &lt;/w:messages&gt;
023      &lt;c:remove var="web4j_key_for_messages" scope="session"/&gt;
024     &lt;/c:if&gt;
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    }