You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mm...@apache.org on 2007/08/29 16:51:49 UTC

svn commit: r570827 - /myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java

Author: mmarinschek
Date: Wed Aug 29 07:51:48 2007
New Revision: 570827

URL: http://svn.apache.org/viewvc?rev=570827&view=rev
Log:
NPE if label null

Modified:
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java

Modified: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java?rev=570827&r1=570826&r2=570827&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java (original)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java Wed Aug 29 07:51:48 2007
@@ -1,548 +1,539 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- * 
- *  http://www.apache.org/licenses/LICENSE-2.0
- * 
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.myfaces.trinidadinternal.renderkit.core.xhtml;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import javax.faces.application.FacesMessage;
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-import javax.faces.context.ResponseWriter;
-
-import org.apache.myfaces.trinidad.bean.FacesBean;
-import org.apache.myfaces.trinidad.bean.PropertyKey;
-import org.apache.myfaces.trinidad.component.core.output.CoreMessages;
-
-import org.apache.myfaces.trinidad.context.RenderingContext;
-import org.apache.myfaces.trinidad.context.RequestContext;
-import org.apache.myfaces.trinidad.skin.Icon;
-import org.apache.myfaces.trinidad.util.LabeledFacesMessage;
-import org.apache.myfaces.trinidadinternal.util.MessageUtils;
-
-/**
- * Renderer for org.apache.myfaces.trinidad.Messages, family org.apache.myfaces.trinidad.Messages.
- * 
- */
-public class MessageBoxRenderer extends XhtmlRenderer
-{
-  public MessageBoxRenderer()
-  {
-    this(CoreMessages.TYPE);
-  }
-
-  protected MessageBoxRenderer(FacesBean.Type type)
-  {
-    super(type);
-  }
-
-  @Override
-  protected void findTypeConstants(FacesBean.Type type)
-  {
-    super.findTypeConstants(type);
-    _textKey     = type.findKey("text");
-    _messageKey     = type.findKey("message");
-    _globalOnlyKey  = type.findKey("globalOnly");
-
-    _headerRenderer = new HeaderRenderer(type);
-    _boxRenderer = new BoxRenderer(type);
-  }
-
-  @Override
-  public boolean getRendersChildren()
-  {
-    return true;
-  }
-  
-  @SuppressWarnings("unchecked")
-  @Override
-  protected void encodeAll(FacesContext context, RenderingContext arc,
-      UIComponent component, FacesBean bean) throws IOException
-  {
-    // Force MessageBox to be re-rendered via PPR, since the set
-    // of messages may have changed.
-    RequestContext afContext = RequestContext.getCurrentInstance();
-    if (afContext != null)
-      afContext.addPartialTarget(component);
-
-    ResponseWriter writer = context.getResponseWriter();
-    
-    Map<String, String> origSkinResourceMap = arc.getSkinResourceKeyMap();
-
-    // Setup the rendering context, so that default skin selectors of
-    // delegate renderers are mapped to those of this renderer
-    arc.setSkinResourceKeyMap(_RESOURCE_KEY_MAP);
-    
-    // Check if INLINE validation mode is enabled
-    boolean inlineValidation = 
-        RequestContext.ClientValidation.INLINE.equals(
-            RequestContext.getCurrentInstance().getClientValidation());
-    
-    // Only when there's at least one message queued
-    if (inlineValidation || context.getMessages().hasNext())
-    {
-      
-      if (inlineValidation)
-      {
-        writer.startElement(XhtmlConstants.SCRIPT_ELEMENT, null);
-        renderScriptDeferAttribute(context, arc);
-        renderScriptTypeAttribute(context, arc);
-        
-        // Output the styles required for client-side manipulation of the MessageBox
-        
-        // Output style for list of messages
-        writer.writeText("TrPage.getInstance().addStyleClassMap( {'", null);
-        writer.writeText(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS + "':'", null);
-        writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
-
-        // Single entry list uses two styles
-        writer.writeText("','" + SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS + "':'", null);
-        writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
-        writer.writeText(" " + arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS), null);
-
-        // Output Style for MessageBox Anchors
-        writer.writeText("','" + SkinSelectors.LINK_STYLE_CLASS + "':'", null);
-        writer.writeText(arc.getStyleClass(SkinSelectors.LINK_STYLE_CLASS), null);
-        writer.writeText("'} ); ", null);
-
-        // Output the script that will register the MessageBox with
-        // the TrMessageBox javascript class that handles client-side
-        // add/remove of messages.
-        writer.writeText("TrMessageBox._registerMessageBox(\"", null);
-        writer.writeText(getClientId(context, component), null);
-        writer.writeText("\");", null);
-        writer.endElement("script");
-      }
-      
-      // Delegate rendering of the outer shell to the BoxRenderer class
-      // which will call back to this renderer to output the messages
-      _boxRenderer.encodeAll(context, arc, component, bean);
-    }
-    else
-    {
-      // Always render an element, for update at PPR-time
-      writer.startElement(XhtmlConstants.SPAN_ELEMENT, component);
-      renderId(context, component);
-      writer.endElement(XhtmlConstants.SPAN_ELEMENT);
-    }
-    
-    // Reset the skin resource map
-    arc.setSkinResourceKeyMap(origSkinResourceMap);
-  }
-  
-  protected void _renderContent(
-      FacesContext context,
-      RenderingContext arc,
-      UIComponent component,
-      FacesBean bean) 
-      throws IOException
-  {
-    ResponseWriter writer = context.getResponseWriter();
-    
-    boolean globalOnly = isGlobalOnly(bean);
-    
-    // TODO - Merge styles into AF_MESSAGES_STYLE_CLASS
-    writer.startElement(XhtmlConstants.DIV_ELEMENT, component);
-    renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_BODY_STYLE_CLASS);
-
-    _renderHeader(context, arc, component, bean);
-    
-    // Render the 'message' attribute if specified
-    String message = getMessage(bean);
-    if (message != null)
-    {
-      writer.startElement(XhtmlConstants.DIV_ELEMENT, null);
-      renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_MESSAGE_TEXT_STYLE_CLASS);
-      writer.write(message);
-      writer.endElement(XhtmlConstants.DIV_ELEMENT);
-    }
-
-    // Render messages as a list
-    writer.startElement("ol", null);
-    
-    // Output an id for the list so client-side validation can 
-    // easily access the element
-    String listId = getClientId(context, component) + "__LIST__";
-    writer.writeAttribute(XhtmlConstants.ID_ATTRIBUTE, listId, null);
-    
-    // Switch list style depending if no. of messages is 1 or >1
-    String[] styleClasses = null;
-    if (MessageUtils.multipleMessagesQueued(context, globalOnly))
-      styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS};
-    else
-      styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS};
-
-    renderStyleClasses(context, arc, styleClasses);
-    
-    _renderGlobalMessages(context, arc, component, bean);
-    
-    if (!globalOnly)
-      _renderComponentMessages(context, arc, component, bean);
-    
-    // End of list
-    writer.endElement("ol");
-    
-    writer.endElement(XhtmlConstants.DIV_ELEMENT);
-  }  
-  
-  @SuppressWarnings("unchecked")
-  protected void _renderGlobalMessages(
-      FacesContext context,
-      RenderingContext arc,
-      UIComponent component,
-      FacesBean bean) 
-      throws IOException
-  {
-    ResponseWriter writer = context.getResponseWriter();
-
-    // Get all messages without and id
-    Iterator<FacesMessage> msgIter = context.getMessages(null);
-    while (msgIter.hasNext())
-    {
-      FacesMessage msg = msgIter.next();
-
-      writer.startElement("li", null);
-
-      String text = MessageUtils.getGlobalMessage(arc, msg.getSummary(), msg.getDetail());
-      renderPossiblyFormattedText(context, text);
-      
-      writer.endElement("li");
-    }
-  }
-  
-  @SuppressWarnings("unchecked")
-  protected void _renderComponentMessages(
-      FacesContext context,
-      RenderingContext arc,
-      UIComponent component,
-      FacesBean bean) 
-      throws IOException
-  {
-    ResponseWriter writer = context.getResponseWriter();
-    
-    Iterator<String> idIter = context.getClientIdsWithMessages();
-    while (idIter.hasNext())
-    {
-      String id = idIter.next();
-      
-      // Skip global messages
-      if (id == null)
-        continue;
-
-      Iterator<FacesMessage> msgIter = context.getMessages(id);
-      while (msgIter.hasNext())
-      {
-        FacesMessage msg = msgIter.next();
-
-        writer.startElement("li", null);
-        
-        _renderMessageAnchor(context, arc, msg, id);
-        
-        String text = MessageUtils.getClientMessage(arc, msg.getSummary(), msg.getDetail());
-
-        renderPossiblyFormattedText(context, text);
-        
-        writer.endElement("li");
-      }
-    }
-  }
-  
-  protected void _renderHeader(
-      FacesContext        context,
-      RenderingContext arc,
-      UIComponent         component,
-      FacesBean           bean) throws IOException
-  {
-    delegateRenderer(context, arc, component, bean, _headerRenderer);
-  }
-
-  protected void _renderMessageAnchor(
-      FacesContext        context,
-      RenderingContext arc,
-      FacesMessage msg,
-      String componentId) throws IOException
-  {
-    ResponseWriter writer = context.getResponseWriter();
-    
-    if (componentId == null)
-      return;
-
-    // Anchor rendering currently only possible for messages that 
-    // contain a label, but we could use summary text in future
-    if (msg instanceof LabeledFacesMessage)
-    {
-      LabeledFacesMessage labeledMsg = (LabeledFacesMessage)msg;
-      String anchor = MessageUtils.getAnchor(componentId);
-      if (anchor != null)
-      {
-        writer.startElement(XhtmlConstants.LINK_ELEMENT, null);
-        renderStyleClass(context, arc, SkinSelectors.LINK_STYLE_CLASS);
-        writer.writeAttribute(XhtmlConstants.HREF_ATTRIBUTE, "#" + anchor, null);
-        writer.write(labeledMsg.getLabel().toString());
-        writer.endElement(XhtmlConstants.LINK_ELEMENT);
-      } 
-    }
-  }
-
-  // Rendering delegate to handle output of the header for the message box
-  private class HeaderRenderer extends PanelHeaderRenderer
-  {
-    public HeaderRenderer(FacesBean.Type type)
-    {
-      super(type);
-    }
-    
-    @Override
-    protected boolean shouldRenderId(FacesContext context, UIComponent component)
-    {
-      // Header will always be refreshed as sub-element of parent
-      return false;
-    }
-    
-    @Override
-    protected void renderEventHandlers(FacesContext context, FacesBean bean)
-        throws IOException
-    {
-      // Prevent HeaderRenderer from re-rendering event handlers
-    }    
-
-    @Override
-    protected String getMessageType(FacesBean bean)
-    {
-      String messageType = null;
-      
-      FacesMessage.Severity maxSeverity = 
-        FacesContext.getCurrentInstance().getMaximumSeverity();
-      
-      // Map FacesMessage severity to levels expected by panelHeaderRenderer
-      if (maxSeverity == null)
-        messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
-      else if (FacesMessage.SEVERITY_FATAL.equals(maxSeverity))
-        messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
-      else if (FacesMessage.SEVERITY_ERROR.equals(maxSeverity))
-        messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
-      else if (FacesMessage.SEVERITY_WARN.equals(maxSeverity))
-        messageType = XhtmlConstants.MESSAGE_TYPE_WARNING;
-      else if (FacesMessage.SEVERITY_INFO.equals(maxSeverity))
-        messageType = XhtmlConstants.MESSAGE_TYPE_INFO;
-
-      return messageType;
-    }
-    
-    @Override
-    protected String getText(RenderingContext arc, FacesBean bean,
-        String messageType)
-    {
-      String text = MessageBoxRenderer.this.getText(bean);
-      if (text != null)
-        // Use Text attribute of this component for header text
-        return text;
-      
-      // Otherwise parent will decide text & style based on messageType
-      return super.getText(arc, bean, messageType);
-    }
-    
-    @Override
-    protected String getMessageIconName(String messageType)
-    {
-      String iconName = null;
-
-      // Use the af|messages skin selectors instead of those
-      // used by panelHeader
-      if (XhtmlConstants.MESSAGE_TYPE_ERROR.equals(messageType))
-        iconName = SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME;
-      else if (XhtmlConstants.MESSAGE_TYPE_WARNING.equals(messageType))
-        iconName = SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME;
-      else if (XhtmlConstants.MESSAGE_TYPE_INFO.equals(messageType))
-        iconName = SkinSelectors.AF_MESSAGES_INFO_ICON_NAME;
-      else if (XhtmlConstants.MESSAGE_TYPE_CONFIRMATION.equals(messageType))
-        iconName = SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME;
-
-      assert ((iconName != null) ||
-              XhtmlConstants.MESSAGE_TYPE_NONE.equals(messageType));
-
-      return iconName;
-    }
-
-  }
-  
-  // Delegate renderer, handles the outer element rendering and
-  // provides option to wrap message box using rounded borders etc.
-  private class BoxRenderer extends PanelBoxRenderer
-  {
-   
-    public BoxRenderer(FacesBean.Type type)
-    {
-      super(type);
-    }
-    
-    @Override
-    protected boolean shouldRenderId(FacesContext context, UIComponent component)
-    {
-      // As panelBox is handling the outer rendering, then it should render
-      // the id of the MessageBox component
-      return true;
-    }
-   
-    @Override
-    protected String getBackground(FacesBean bean)
-    {
-      // Force use of 'light' style, so we know which style
-      // to re-map in _RESOURCE_KEY_MAP
-      return "light";
-    }
-    
-    @Override
-    protected String getInlineStyle(FacesBean bean)
-    {
-      String inlineStyle = super.getInlineStyle(bean);
-      
-      boolean inlineValidation = 
-        RequestContext.ClientValidation.INLINE.equals(
-            RequestContext.getCurrentInstance().getClientValidation());
-      
-      if (!inlineValidation)
-        return inlineStyle;
-      
-      boolean hasMessages = FacesContext.getCurrentInstance().getMessages().hasNext();
-      
-      if (hasMessages)
-        return inlineStyle;
-      
-      // Ensure the MessageBox is hidden for inline mode when
-      // there are no messages
-      if (inlineStyle == null)
-        return "display:none";
-      else
-        return inlineStyle + ";display:none";
-    }
-    
-    @Override
-    protected boolean hasChildren(UIComponent component)
-    {
-      // Required to force panelBox to call render properly
-      return true;
-    }
-    
-    @Override
-    protected void renderBody(FacesContext context, RenderingContext arc,
-        UIComponent component, FacesBean bean, Object icon, Object text) throws IOException
-    {
-      // Pass control back to MessageBoxRenderer to continue rendering
-      // the content of the message box.
-      MessageBoxRenderer.this._renderContent(context, arc, component, bean);
-    }
-  }
-    
-  @Override
-  protected boolean shouldRenderId(FacesContext context, UIComponent component)
-  {
-    // Normally BoxRenderer will output the id for this component, but
-    // if we're just outputting an empty element for PPR purposes, then
-    // this renderer should output the id.
-    return true;
-  }
-
-  protected String getText(FacesBean bean)
-  {
-    if (_textKey == null)
-      return null;
-    return toString(bean.getProperty(_textKey));
-  }
-
-  protected String getMessage(FacesBean bean)
-  {
-    if (_messageKey == null)
-      return null;
-    return toString(bean.getProperty(_messageKey));
-  }
-
-  protected boolean isGlobalOnly(FacesBean bean)
-  {
-    Object o = bean.getProperty(_globalOnlyKey);
-    if (o == null)
-      o = _globalOnlyKey.getDefault();
-    return Boolean.TRUE.equals(o);
-  }
-
-  private PropertyKey _textKey;
-  private PropertyKey _messageKey;
-  private PropertyKey _globalOnlyKey;
-  private XhtmlRenderer _headerRenderer;
-  private PanelBoxRenderer _boxRenderer;
-
-  // Map panelHeader & panelBox Styles/Icons etc. to this renderer's selectors.
-  private static final Map<String, String> _RESOURCE_KEY_MAP;
-
-  static
-  {
-    _RESOURCE_KEY_MAP = new HashMap<String, String>();
-    
-    // translation keys
-    _RESOURCE_KEY_MAP.put("af_panelHeader.INFORMATION",
-                              "af_messages.INFORMATION");
-    _RESOURCE_KEY_MAP.put("af_panelHeader.WARNING",
-                              "af_messages.WARNING");
-    _RESOURCE_KEY_MAP.put("af_panelHeader.ERROR",
-                              "af_messages.ERROR");
-    _RESOURCE_KEY_MAP.put("af_panelHeader.CONFIRMATION",
-                              "af_messages.CONFIRMATION");
-    // icons
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_ICON_NAME,
-        SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_WARNING_ICON_NAME,
-        SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_INFO_ICON_NAME,
-        SkinSelectors.AF_MESSAGES_INFO_ICON_NAME);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_CONFIRMATION_ICON_NAME,
-        SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME);
-
-    // styles
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_STYLE_CLASS,
-        SkinSelectors.AF_MESSAGES_ERROR_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_STYLE_CLASS,
-        SkinSelectors.AF_MESSAGES_HEADER_STYLE_CLASS);
-    
-    // We forced the use of 'light' style above, so now map it
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_LIGHT_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_STYLE_CLASS);
-
-    // frame styles
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_START_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_TOP_START_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_TOP_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_END_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_TOP_END_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_START_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_START_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_END_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_END_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_START_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_BOTTOM_START_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_BOTTOM_STYLE_CLASS);
-    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_END_STYLE_CLASS, 
-        SkinSelectors.AF_MESSAGES_BOTTOM_END_STYLE_CLASS);
-  } 
-  
-}
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidadinternal.renderkit.core.xhtml;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.apache.myfaces.trinidad.bean.FacesBean;
+import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.core.output.CoreMessages;
+
+import org.apache.myfaces.trinidad.context.RenderingContext;
+import org.apache.myfaces.trinidad.context.RequestContext;
+import org.apache.myfaces.trinidad.skin.Icon;
+import org.apache.myfaces.trinidad.util.LabeledFacesMessage;
+import org.apache.myfaces.trinidadinternal.util.MessageUtils;
+
+/**
+ * Renderer for org.apache.myfaces.trinidad.Messages, family org.apache.myfaces.trinidad.Messages.
+ *
+ */
+public class MessageBoxRenderer extends XhtmlRenderer
+{
+  public MessageBoxRenderer()
+  {
+    this(CoreMessages.TYPE);
+  }
+
+  protected MessageBoxRenderer(FacesBean.Type type)
+  {
+    super(type);
+  }
+
+  @Override
+  protected void findTypeConstants(FacesBean.Type type)
+  {
+    super.findTypeConstants(type);
+    _textKey     = type.findKey("text");
+    _messageKey     = type.findKey("message");
+    _globalOnlyKey  = type.findKey("globalOnly");
+
+    _headerRenderer = new HeaderRenderer(type);
+    _boxRenderer = new BoxRenderer(type);
+  }
+
+  @Override
+  public boolean getRendersChildren()
+  {
+    return true;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  protected void encodeAll(FacesContext context, RenderingContext arc,
+      UIComponent component, FacesBean bean) throws IOException
+  {
+    // Force MessageBox to be re-rendered via PPR, since the set
+    // of messages may have changed.
+    RequestContext afContext = RequestContext.getCurrentInstance();
+    if (afContext != null)
+      afContext.addPartialTarget(component);
+
+    ResponseWriter writer = context.getResponseWriter();
+
+    // Check if INLINE validation mode is enabled
+    boolean inlineValidation =
+        RequestContext.ClientValidation.INLINE.equals(
+            RequestContext.getCurrentInstance().getClientValidation());
+
+    // Only when there's at least one message queued
+    if (inlineValidation || context.getMessages().hasNext())
+    {
+
+      if (inlineValidation)
+      {
+        writer.startElement(XhtmlConstants.SCRIPT_ELEMENT, null);
+        renderScriptDeferAttribute(context, arc);
+        renderScriptTypeAttribute(context, arc);
+
+        // Output the styles required for client-side manipulation of the MessageBox
+
+        // Output style for list of messages
+        writer.writeText("TrPage.getInstance().addStyleClassMap( {'", null);
+        writer.writeText(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS + "':'", null);
+        writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
+
+        // Single entry list uses two styles
+        writer.writeText("','" + SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS + "':'", null);
+        writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
+        writer.writeText(" " + arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS), null);
+
+        // Output Style for MessageBox Anchors
+        writer.writeText("','" + SkinSelectors.LINK_STYLE_CLASS + "':'", null);
+        writer.writeText(arc.getStyleClass(SkinSelectors.LINK_STYLE_CLASS), null);
+        writer.writeText("'} ); ", null);
+
+        // Output the script that will register the MessageBox with
+        // the TrMessageBox javascript class that handles client-side
+        // add/remove of messages.
+        writer.writeText("TrMessageBox._registerMessageBox(\"", null);
+        writer.writeText(getClientId(context, component), null);
+        writer.writeText("\");", null);
+        writer.endElement("script");
+      }
+
+      // Setup the rendering context, so that default skin selectors of
+      // delegate renderers are mapped to those of this renderer
+      arc.setSkinResourceKeyMap(_RESOURCE_KEY_MAP);
+
+      // Delegate rendering of the outer shell to the BoxRenderer class
+      // which will call back to this renderer to output the messages
+      _boxRenderer.encodeAll(context, arc, component, bean);
+    }
+    else
+    {
+      // Always render an element, for update at PPR-time
+      writer.startElement(XhtmlConstants.SPAN_ELEMENT, component);
+      renderId(context, component);
+      writer.endElement(XhtmlConstants.SPAN_ELEMENT);
+    }
+  }
+
+  protected void _renderContent(
+      FacesContext context,
+      RenderingContext arc,
+      UIComponent component,
+      FacesBean bean)
+      throws IOException
+  {
+    ResponseWriter writer = context.getResponseWriter();
+
+    boolean globalOnly = isGlobalOnly(bean);
+
+    // TODO - Merge styles into AF_MESSAGES_STYLE_CLASS
+    writer.startElement(XhtmlConstants.DIV_ELEMENT, component);
+    renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_BODY_STYLE_CLASS);
+
+    _renderHeader(context, arc, component, bean);
+
+    // Render the 'message' attribute if specified
+    String message = getMessage(bean);
+    if (message != null)
+    {
+      writer.startElement(XhtmlConstants.DIV_ELEMENT, null);
+      renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_MESSAGE_TEXT_STYLE_CLASS);
+      writer.write(message);
+      writer.endElement(XhtmlConstants.DIV_ELEMENT);
+    }
+
+    // Render messages as a list
+    writer.startElement("ol", null);
+
+    // Output an id for the list so client-side validation can
+    // easily access the element
+    String listId = getClientId(context, component) + "__LIST__";
+    writer.writeAttribute(XhtmlConstants.ID_ATTRIBUTE, listId, null);
+
+    // Switch list style depending if no. of messages is 1 or >1
+    String[] styleClasses = null;
+    if (MessageUtils.multipleMessagesQueued(context, globalOnly))
+      styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS};
+    else
+      styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS};
+
+    renderStyleClasses(context, arc, styleClasses);
+
+    _renderGlobalMessages(context, arc, component, bean);
+
+    if (!globalOnly)
+      _renderComponentMessages(context, arc, component, bean);
+
+    // End of list
+    writer.endElement("ol");
+
+    writer.endElement(XhtmlConstants.DIV_ELEMENT);
+  }
+
+  @SuppressWarnings("unchecked")
+  protected void _renderGlobalMessages(
+      FacesContext context,
+      RenderingContext arc,
+      UIComponent component,
+      FacesBean bean)
+      throws IOException
+  {
+    ResponseWriter writer = context.getResponseWriter();
+
+    // Get all messages without and id
+    Iterator<FacesMessage> msgIter = context.getMessages(null);
+    while (msgIter.hasNext())
+    {
+      FacesMessage msg = msgIter.next();
+
+      writer.startElement("li", null);
+
+      String text = MessageUtils.getGlobalMessage(arc, msg.getSummary(), msg.getDetail());
+      renderPossiblyFormattedText(context, text);
+
+      writer.endElement("li");
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  protected void _renderComponentMessages(
+      FacesContext context,
+      RenderingContext arc,
+      UIComponent component,
+      FacesBean bean)
+      throws IOException
+  {
+    ResponseWriter writer = context.getResponseWriter();
+
+    Iterator<String> idIter = context.getClientIdsWithMessages();
+    while (idIter.hasNext())
+    {
+      String id = idIter.next();
+
+      // Skip global messages
+      if (id == null)
+        continue;
+
+      Iterator<FacesMessage> msgIter = context.getMessages(id);
+      while (msgIter.hasNext())
+      {
+        FacesMessage msg = msgIter.next();
+
+        writer.startElement("li", null);
+
+        _renderMessageAnchor(context, arc, msg, id);
+
+        String text = MessageUtils.getClientMessage(arc, msg.getSummary(), msg.getDetail());
+
+        renderPossiblyFormattedText(context, text);
+
+        writer.endElement("li");
+      }
+    }
+  }
+
+  protected void _renderHeader(
+      FacesContext        context,
+      RenderingContext arc,
+      UIComponent         component,
+      FacesBean           bean) throws IOException
+  {
+    delegateRenderer(context, arc, component, bean, _headerRenderer);
+  }
+
+  protected void _renderMessageAnchor(
+      FacesContext        context,
+      RenderingContext arc,
+      FacesMessage msg,
+      String componentId) throws IOException
+  {
+    ResponseWriter writer = context.getResponseWriter();
+
+    if (componentId == null)
+      return;
+
+    // Anchor rendering currently only possible for messages that
+    // contain a label, but we could use summary text in future
+    if (msg instanceof LabeledFacesMessage)
+    {
+      LabeledFacesMessage labeledMsg = (LabeledFacesMessage)msg;
+      String anchor = MessageUtils.getAnchor(componentId);
+      if (anchor != null)
+      {
+        writer.startElement(XhtmlConstants.LINK_ELEMENT, null);
+        renderStyleClass(context, arc, SkinSelectors.LINK_STYLE_CLASS);
+        writer.writeAttribute(XhtmlConstants.HREF_ATTRIBUTE, "#" + anchor, null);
+        writer.write(labeledMsg.getLabel().toString());
+        writer.endElement(XhtmlConstants.LINK_ELEMENT);
+      }
+    }
+  }
+
+  // Rendering delegate to handle output of the header for the message box
+  private class HeaderRenderer extends PanelHeaderRenderer
+  {
+    public HeaderRenderer(FacesBean.Type type)
+    {
+      super(type);
+    }
+
+    @Override
+    protected boolean shouldRenderId(FacesContext context, UIComponent component)
+    {
+      // Header will always be refreshed as sub-element of parent
+      return false;
+    }
+
+    @Override
+    protected void renderEventHandlers(FacesContext context, FacesBean bean)
+        throws IOException
+    {
+      // Prevent HeaderRenderer from re-rendering event handlers
+    }
+
+    @Override
+    protected String getMessageType(FacesBean bean)
+    {
+      String messageType = null;
+
+      FacesMessage.Severity maxSeverity =
+        FacesContext.getCurrentInstance().getMaximumSeverity();
+
+      // Map FacesMessage severity to levels expected by panelHeaderRenderer
+      if (maxSeverity == null)
+        messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
+      else if (FacesMessage.SEVERITY_FATAL.equals(maxSeverity))
+        messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
+      else if (FacesMessage.SEVERITY_ERROR.equals(maxSeverity))
+        messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
+      else if (FacesMessage.SEVERITY_WARN.equals(maxSeverity))
+        messageType = XhtmlConstants.MESSAGE_TYPE_WARNING;
+      else if (FacesMessage.SEVERITY_INFO.equals(maxSeverity))
+        messageType = XhtmlConstants.MESSAGE_TYPE_INFO;
+
+      return messageType;
+    }
+
+    @Override
+    protected String getText(RenderingContext arc, FacesBean bean,
+        String messageType)
+    {
+      String text = MessageBoxRenderer.this.getText(bean);
+      if (text != null)
+        // Use Text attribute of this component for header text
+        return text;
+
+      // Otherwise parent will decide text & style based on messageType
+      return super.getText(arc, bean, messageType);
+    }
+
+    @Override
+    protected String getMessageIconName(String messageType)
+    {
+      String iconName = null;
+
+      // Use the af|messages skin selectors instead of those
+      // used by panelHeader
+      if (XhtmlConstants.MESSAGE_TYPE_ERROR.equals(messageType))
+        iconName = SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME;
+      else if (XhtmlConstants.MESSAGE_TYPE_WARNING.equals(messageType))
+        iconName = SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME;
+      else if (XhtmlConstants.MESSAGE_TYPE_INFO.equals(messageType))
+        iconName = SkinSelectors.AF_MESSAGES_INFO_ICON_NAME;
+      else if (XhtmlConstants.MESSAGE_TYPE_CONFIRMATION.equals(messageType))
+        iconName = SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME;
+
+      assert ((iconName != null) ||
+              XhtmlConstants.MESSAGE_TYPE_NONE.equals(messageType));
+
+      return iconName;
+    }
+
+  }
+
+  // Delegate renderer, handles the outer element rendering and
+  // provides option to wrap message box using rounded borders etc.
+  private class BoxRenderer extends PanelBoxRenderer
+  {
+
+    public BoxRenderer(FacesBean.Type type)
+    {
+      super(type);
+    }
+
+    @Override
+    protected boolean shouldRenderId(FacesContext context, UIComponent component)
+    {
+      // As panelBox is handling the outer rendering, then it should render
+      // the id of the MessageBox component
+      return true;
+    }
+
+    @Override
+    protected String getBackground(FacesBean bean)
+    {
+      // Force use of 'light' style, so we know which style
+      // to re-map in _RESOURCE_KEY_MAP
+      return "light";
+    }
+
+    @Override
+    protected String getInlineStyle(FacesBean bean)
+    {
+      String inlineStyle = super.getInlineStyle(bean);
+
+      boolean inlineValidation =
+        RequestContext.ClientValidation.INLINE.equals(
+            RequestContext.getCurrentInstance().getClientValidation());
+
+      if (!inlineValidation)
+        return inlineStyle;
+
+      boolean hasMessages = FacesContext.getCurrentInstance().getMessages().hasNext();
+
+      if (hasMessages)
+        return inlineStyle;
+
+      // Ensure the MessageBox is hidden for inline mode when there are no messages
+      return inlineStyle + ";display:none;";
+    }
+
+    @Override
+    protected boolean hasChildren(UIComponent component)
+    {
+      // Required to force panelBox to call render properly
+      return true;
+    }
+
+    @Override
+    protected void renderBody(FacesContext context, RenderingContext arc,
+        UIComponent component, FacesBean bean, Object icon, Object text) throws IOException
+    {
+      // Pass control back to MessageBoxRenderer to continue rendering
+      // the content of the message box.
+      MessageBoxRenderer.this._renderContent(context, arc, component, bean);
+    }
+  }
+
+  @Override
+  protected boolean shouldRenderId(FacesContext context, UIComponent component)
+  {
+    // Normally BoxRenderer will output the id for this component, but
+    // if we're just outputting an empty element for PPR purposes, then
+    // this renderer should output the id.
+    return true;
+  }
+
+  protected String getText(FacesBean bean)
+  {
+    if (_textKey == null)
+      return null;
+    return toString(bean.getProperty(_textKey));
+  }
+
+  protected String getMessage(FacesBean bean)
+  {
+    if (_messageKey == null)
+      return null;
+    return toString(bean.getProperty(_messageKey));
+  }
+
+  protected boolean isGlobalOnly(FacesBean bean)
+  {
+    Object o = bean.getProperty(_globalOnlyKey);
+    if (o == null)
+      o = _globalOnlyKey.getDefault();
+    return Boolean.TRUE.equals(o);
+  }
+
+  private PropertyKey _textKey;
+  private PropertyKey _messageKey;
+  private PropertyKey _globalOnlyKey;
+  private XhtmlRenderer _headerRenderer;
+  private PanelBoxRenderer _boxRenderer;
+
+  // Map panelHeader & panelBox Styles/Icons etc. to this renderer's selectors.
+  private static final Map<String, String> _RESOURCE_KEY_MAP;
+
+  static
+  {
+    _RESOURCE_KEY_MAP = new HashMap<String, String>();
+
+    // translation keys
+    _RESOURCE_KEY_MAP.put("af_panelHeader.INFORMATION",
+                              "af_messages.INFORMATION");
+    _RESOURCE_KEY_MAP.put("af_panelHeader.WARNING",
+                              "af_messages.WARNING");
+    _RESOURCE_KEY_MAP.put("af_panelHeader.ERROR",
+                              "af_messages.ERROR");
+    _RESOURCE_KEY_MAP.put("af_panelHeader.CONFIRMATION",
+                              "af_messages.CONFIRMATION");
+    // icons
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_ICON_NAME,
+        SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_WARNING_ICON_NAME,
+        SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_INFO_ICON_NAME,
+        SkinSelectors.AF_MESSAGES_INFO_ICON_NAME);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_CONFIRMATION_ICON_NAME,
+        SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME);
+
+    // styles
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_ERROR_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_HEADER_STYLE_CLASS);
+
+    // We forced the use of 'light' style above, so now map it
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_LIGHT_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_STYLE_CLASS);
+
+    // frame styles
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_START_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_TOP_START_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_TOP_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_END_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_TOP_END_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_START_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_START_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_END_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_END_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_START_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_BOTTOM_START_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_BOTTOM_STYLE_CLASS);
+    _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_END_STYLE_CLASS,
+        SkinSelectors.AF_MESSAGES_BOTTOM_END_STYLE_CLASS);
+  }
+
+}