package com.softwaremill.common.faces.messages; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.softwaremill.common.cdi.el.ELEvaluator; import com.softwaremill.common.faces.i18n.CurrentLocale; import javax.enterprise.context.SessionScoped; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.inject.Inject; import java.io.Serializable; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.MissingResourceException; import java.util.ResourceBundle; /** * @author Seam2 authors (http://seamframework.org) * @author Adam Warski (adam at warski dot org) */ @SessionScoped // TODO: make @FlashScoped after flash is fixed public class FacesMessages implements Serializable { private final static Logger LOG = LoggerFactory.getLogger(FacesMessages.class); @Inject private ELEvaluator elEvaluator; @Inject private CurrentLocale currentLocale; private static class MessageData { private final String controlId; private final FacesMessage fm; private MessageData(String controlId, FacesMessage fm) { this.controlId = controlId; this.fm = fm; } public String getControlId() { return controlId; } public FacesMessage getFm() { return fm; } } private List<MessageData> messages = new ArrayList<MessageData>(); /** * Adds a raw message (without looking into Resource Bundle) for a given UI control base on controlId * * @param controlId UI control ID * @param message a raw message to add * @param severity FacesMessage's severity level */ public void addMesageToControl(String controlId, String message, FacesMessage.Severity severity) { messages.add(new MessageData(controlId, new FacesMessage(severity, message, message))); } /** * Adds a raw message (without looking into Resource Bundle) as a global message * * @param message a raw message to add * @param severity FacesMessage's severity level */ public void addMesageToControl(String message, FacesMessage.Severity severity) { addMesageToControl(null, message, severity); } public void addEL(String elExpression, FacesMessage.Severity severity) { addELToControl(null, elExpression, severity); } public void addELToControl(String controlId, String elExpression, FacesMessage.Severity severity) { String message = elEvaluator.evaluate(elExpression, String.class); messages.add(new MessageData(controlId, new FacesMessage(severity, message, message))); } public void addInfoFromBundle(String key, Object... params) { addInfoFromBundleToControl(null, key, params); } public void addFromBundle(String key, FacesMessage.Severity severity, Object... params) { addFromBundleToControl(null, key, severity, params); } public void addInfoFromBundleToControl(String controlId, String key, Object... params) { addFromBundleToControl(controlId, key, FacesMessage.SEVERITY_INFO, params); } public void addFromBundleToControl(String controlId, String key, FacesMessage.Severity severity, Object... params) { String message = formatMessage(key, params); FacesMessage fm = new FacesMessage(severity, message, message); messages.add(new MessageData(controlId, fm)); } public void beforeRenderResponse() { for (MessageData message : messages) { FacesContext.getCurrentInstance().addMessage(getClientId(message.getControlId()), message.getFm()); } messages.clear(); } public String formatMessage(String key, Object... params) { // TODO: multiple bundles? try { return tryFormatMessage(key, params); } catch (MissingResourceException e) { LOG.warn("Missing resource key: [" + key + "]", e); return "???" + key + "???"; } } private String tryFormatMessage(String key, Object[] params) { ResourceBundle rb = ResourceBundle.getBundle("messages", currentLocale.getCurrentLocale()); String value = rb.getString(key); return new MessageFormat(value).format(params); } private String getClientId(String id) { if (id == null) { return null; } FacesContext facesContext = FacesContext.getCurrentInstance(); return getClientId(facesContext.getViewRoot(), id, facesContext); } private static String getClientId(UIComponent component, String id, FacesContext facesContext) { String componentId = component.getId(); if (componentId != null && componentId.equals(id)) { return component.getClientId(facesContext); } else { Iterator iter = component.getFacetsAndChildren(); while (iter.hasNext()) { UIComponent child = (UIComponent) iter.next(); String clientId = getClientId(child, id, facesContext); if (clientId != null) return clientId; } return null; } } }