Package org.omnifaces.renderer

Source Code of org.omnifaces.renderer.MessagesRenderer

/*
* Copyright 2013 OmniFaces.
*
* Licensed 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.omnifaces.renderer;

import static org.omnifaces.util.Components.findComponentsInChildren;
import static org.omnifaces.util.Messages.createInfo;
import static org.omnifaces.util.Renderers.writeAttribute;
import static org.omnifaces.util.Renderers.writeAttributes;
import static org.omnifaces.util.Renderers.writeText;
import static org.omnifaces.util.Utils.coalesce;
import static org.omnifaces.util.Utils.isEmpty;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.component.UIMessages;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.faces.render.Renderer;

import org.omnifaces.component.messages.OmniMessages;

/**
* This renderer is the default renderer of {@link OmniMessages}. It's basically copypasted from Mojarra 2.2,
* including the fix of tooltip rendering as described in <a href="http://java.net/jira/browse/JAVASERVERFACES-2160">
* issue 2160</a>, and afterwards slightly rewritten, refactored and enhanced to take the new features into account.
*
* @author Bauke Scholtz
* @since 1.5
*/
@FacesRenderer(componentFamily=UIMessages.COMPONENT_FAMILY, rendererType=MessagesRenderer.RENDERER_TYPE)
public class MessagesRenderer extends Renderer {

  // Public constants -----------------------------------------------------------------------------------------------

  /** The standard renderer type. */
  public static final String RENDERER_TYPE = "org.omnifaces.Messages";

  // Private constants ----------------------------------------------------------------------------------------------

  private static final Map<Severity, String> SEVERITY_NAMES = createSeverityNames();

  private static final Map<Severity, String> createSeverityNames() {
    Map<Severity, String> severityNames = new HashMap<>();
    severityNames.put(FacesMessage.SEVERITY_INFO, "info");
    severityNames.put(FacesMessage.SEVERITY_WARN, "warn");
    severityNames.put(FacesMessage.SEVERITY_ERROR, "error");
    severityNames.put(FacesMessage.SEVERITY_FATAL, "fatal");
    return Collections.unmodifiableMap(severityNames);
  }

  // Actions --------------------------------------------------------------------------------------------------------

  /**
   * Returns <code>true</code>.
   */
  @Override
  public boolean getRendersChildren() {
    return true;
  }

  @Override
  public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
    if (!component.isRendered()) {
      return;
    }

    OmniMessages omniMessages = (OmniMessages) component;
    List<FacesMessage> messages = getMessages(context, omniMessages);

    if (!isEmpty(omniMessages.getVar()) && omniMessages.getChildCount() > 0) {
      encodeMessagesRepeater(context, omniMessages, messages);
    }
    else if (messages.isEmpty()) {
      encodeEmptyMessages(context, omniMessages);
    }
    else {
      String message = omniMessages.getMessage();

      if (!isEmpty(message)) {
        messages = Arrays.asList(createInfo(message));
      }

      encodeMessages(context, omniMessages, messages, "table".equals(omniMessages.getLayout()));
    }
  }

  /**
   * Collect all messages associated with components identified by <code>for</code> attribute and return it. An empty
   * list will be returned when there are no messages.
   * @param context The involved faces context.
   * @param component The messages component.
   * @return All messages associated with components identified by <code>for</code> attribute.
   */
  protected List<FacesMessage> getMessages(FacesContext context, OmniMessages component) {
    String forClientIds = component.getFor();

    if (forClientIds == null) {
      return component.isGlobalOnly() ? context.getMessageList(null) : context.getMessageList();
    }

    List<FacesMessage> messages = new ArrayList<>();

    for (String forClientId : forClientIds.split("\\s+")) {
      UIComponent forComponent = component.findComponent(forClientId);

      if (forComponent == null) {
        continue;
      }

      messages.addAll(context.getMessageList(forComponent.getClientId(context)));

      if (!(forComponent instanceof UIInput)) {
        for (UIInput child : findComponentsInChildren(forComponent, UIInput.class)) {
          messages.addAll(context.getMessageList(child.getClientId(context)));
        }
      }
    }

    return messages;
  }

  /**
   * Encode the case when the <code>var</code> attribute is specified. This will render without any HTML markup and
   * put the current message in the request scope as identified by the <code>var</code> attribute.
   * Note: the iteration is by design completely stateless.
   * @param context The involved faces context.
   * @param component The messages component.
   * @param messages The queued faces messages.
   * @throws IOException When an I/O error occurs.
   */
  protected void encodeMessagesRepeater(FacesContext context, OmniMessages component, List<FacesMessage> messages)
    throws IOException
  {
    String var = component.getVar();
    Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
    Object originalVar = requestMap.get(var);

    try {
      for (FacesMessage message : messages) {
        if (message.isRendered() && !component.isRedisplay()) {
          continue;
        }

        requestMap.put(var, message);

        for (UIComponent child : component.getChildren()) {
          child.encodeAll(context);
        }

        message.rendered();
      }
    }
    finally {
      if (originalVar != null) {
        requestMap.put(var, originalVar);
      }
      else {
        requestMap.remove(var);
      }
    }
  }

  /**
   * Encode the case when there are no messages. This will render a div when the ID is specified.
   * @param context The involved faces context.
   * @param component The messages component.
   * @throws IOException When an I/O error occurs.
   */
  protected void encodeEmptyMessages(FacesContext context, OmniMessages component) throws IOException {
    String id = component.getId();

    if (id != null && !id.equals("javax_faces_developmentstage_messages")) {
      ResponseWriter writer = context.getResponseWriter();
      writer.startElement("div", component);
      writeAttribute(writer, "id", component.getClientId(context));
      writer.endElement("div");
    }
  }

  /**
   * Encode the case when the faces messages are to be rendered as either a HTML table or a HTML list.
   * @param context The involved faces context.
   * @param component The messages component.
   * @param messages The queued faces messages.
   * @param table Whether to render the messages as a HTML table or a HTML list.
   * @throws IOException When an I/O error occurs.
   */
  protected void encodeMessages
    (FacesContext context, OmniMessages component, List<FacesMessage> messages, boolean table)
      throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    writer.startElement(table ? "table" : "ul", component);
    writeAttribute(writer, "id", component.getClientId(context));
    writeAttribute(writer, component, "styleClass", "class");
    writeAttributes(writer, component, "style", "title", "lang", "dir");

    boolean showSummary = component.isShowSummary();
    boolean showDetail = component.isShowDetail();
    boolean escape = component.isEscape();
    boolean tooltip = component.isTooltip() && isEmpty(component.getTitle());

    for (FacesMessage message : messages) {
      if (message.isRendered() && !component.isRedisplay()) {
        continue;
      }

      writer.startElement(table ? "tr" : "li", component);
      String severityName = SEVERITY_NAMES.get(message.getSeverity());
      writeAttribute(writer, component, severityName + "Style", "style");
      writeAttribute(writer, component, severityName + "Class", "class", "styleClass");

      if (table) {
        writer.startElement("td", component);
      }

      String summary = coalesce(message.getSummary(), "");
      String detail = coalesce(message.getDetail(), summary);

      if (tooltip) {
        writeAttribute(writer, "title", detail);
      }

      if (showSummary) {
        writeText(writer, component, summary, escape);

        if (showDetail) {
          writer.write(" ");
        }
      }

      if (showDetail) {
        writeText(writer, component, detail, escape);
      }

      message.rendered();

      if (table) {
        writer.endElement("td");
      }

      writer.endElement(table ? "tr" : "li");
    }

    writer.endElement(table ? "table" : "ul");
  }

}
TOP

Related Classes of org.omnifaces.renderer.MessagesRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.