package org.jboss.seam.faces;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.international.StatusMessage;
import org.jboss.seam.international.StatusMessages;
import org.jboss.seam.util.Strings;
/**
* A Seam component that propagates FacesMessages across redirects
* and interpolates EL expressions in the message string.
*
* @author Gavin King
* @author Pete Muir
*/
@Scope(ScopeType.CONVERSATION)
@Name(StatusMessages.COMPONENT_NAME)
@Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
@BypassInterceptors
public class FacesMessages extends StatusMessages
{
/**
* Called by Seam to transfer messages from FacesMessages to JSF
*/
public void beforeRenderResponse()
{
for (StatusMessage statusMessage: getMessages())
{
FacesContext.getCurrentInstance().addMessage( null, toFacesMessage(statusMessage) );
}
for ( Map.Entry<String, List<StatusMessage>> entry: getKeyedMessages().entrySet() )
{
for ( StatusMessage statusMessage: entry.getValue() )
{
String clientId = getClientId(entry.getKey());
FacesContext.getCurrentInstance().addMessage( clientId, toFacesMessage(statusMessage) );
}
}
clear();
}
/**
* Called by Seam to transfer any messages added in the phase just processed
* to the FacesMessages component.
*
* A task runner is used to allow the messages access to outjected values.
*/
public static void afterPhase()
{
runTasks();
}
/**
* Convert a StatusMessage to a FacesMessage
*/
private static FacesMessage toFacesMessage(StatusMessage statusMessage)
{
if (!Strings.isEmpty(statusMessage.getSummary()))
{
return new FacesMessage(toSeverity(statusMessage.getSeverity()), statusMessage.getSummary(), statusMessage.getDetail() );
}
else
{
return null;
}
}
/**
* Convert a StatusMessage.Severity to a FacesMessage.Severity
*/
private static javax.faces.application.FacesMessage.Severity toSeverity(org.jboss.seam.international.StatusMessage.Severity severity)
{
switch (severity)
{
case ERROR:
return FacesMessage.SEVERITY_ERROR;
case FATAL:
return FacesMessage.SEVERITY_FATAL;
case INFO:
return FacesMessage.SEVERITY_INFO;
case WARN:
return FacesMessage.SEVERITY_WARN;
default:
return null;
}
}
/**
* Convert a FacesMessage.Severity to a StatusMessage.Severity
*/
private static org.jboss.seam.international.StatusMessage.Severity toSeverity(javax.faces.application.FacesMessage.Severity severity)
{
if (FacesMessage.SEVERITY_ERROR.equals(severity))
{
return org.jboss.seam.international.StatusMessage.Severity.ERROR;
}
else if (FacesMessage.SEVERITY_FATAL.equals(severity))
{
return org.jboss.seam.international.StatusMessage.Severity.FATAL;
}
else if (FacesMessage.SEVERITY_INFO.equals(severity))
{
return org.jboss.seam.international.StatusMessage.Severity.INFO;
}
else if (FacesMessage.SEVERITY_WARN.equals(severity))
{
return org.jboss.seam.international.StatusMessage.Severity.WARN;
}
else
{
return null;
}
}
/**
* Calculate the JSF client ID from the provided widget ID
*/
private String getClientId(String id)
{
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;
}
}
/**
* Get all faces messages that have already been added
* to the context.
*
*/
public List<FacesMessage> getCurrentMessages()
{
List<FacesMessage> result = new ArrayList<FacesMessage>();
Iterator<FacesMessage> iter = FacesContext.getCurrentInstance().getMessages();
while ( iter.hasNext() )
{
result.add( iter.next() );
}
return result;
}
/**
* Get all faces global messages that have already been added
* to the context.
*
*/
public List<FacesMessage> getCurrentGlobalMessages()
{
List<FacesMessage> result = new ArrayList<FacesMessage>();
Iterator<FacesMessage> iter = FacesContext.getCurrentInstance().getMessages(null);
while ( iter.hasNext() )
{
result.add( iter.next() );
}
return result;
}
/**
* Get all faces messages that have already been added
* to the control.
*
*/
public List<FacesMessage> getCurrentMessagesForControl(String id)
{
String clientId = getClientId(id);
List<FacesMessage> result = new ArrayList<FacesMessage>();
Iterator<FacesMessage> iter = FacesContext.getCurrentInstance().getMessages(clientId);
while ( iter.hasNext() )
{
result.add( iter.next() );
}
return result;
}
/**
* Utility method to create a FacesMessage from a Severity, messageTemplate
* and params.
*
* This method interpolates the parameters provided
*/
public static FacesMessage createFacesMessage(javax.faces.application.FacesMessage.Severity severity, String messageTemplate, Object... params)
{
return createFacesMessage(severity, null, messageTemplate, params);
}
/**
* Utility method to create a FacesMessage from a Severity, key,
* defaultMessageTemplate and params.
*
* This method interpolates the parameters provided
*/
public static FacesMessage createFacesMessage(javax.faces.application.FacesMessage.Severity severity, String key, String defaultMessageTemplate, Object... params)
{
StatusMessage message = new StatusMessage(toSeverity(severity), key, null, defaultMessageTemplate, null);
message.interpolate(params);
return toFacesMessage(message);
}
/**
* Add a FacesMessage that will be used
* the next time a page is rendered.
*
* Deprecated, use a method in {@link StatusMessages} instead
*/
@Deprecated
public void add(FacesMessage facesMessage)
{
if (facesMessage!=null)
{
add(toSeverity(facesMessage.getSeverity()), null, null, facesMessage.getSummary(), facesMessage.getDetail());
}
}
/**
* Create a new status message, with the messageTemplate is as the message.
*
* You can also specify the severity, and parameters to be interpolated
*
* Deprecated, use {@link #add(org.jboss.seam.international.StatusMessage.Severity, String, Object...)}
* instead
*/
@Deprecated
public void add(javax.faces.application.FacesMessage.Severity severity, String messageTemplate, Object... params)
{
add(toSeverity(severity), messageTemplate, params);
}
/**
* Create a new status message, with the messageTemplate is as the message.
*
* A severity of INFO will be used, and you can specify paramters to be
* interpolated
*
* Deprecated, use {@link #addToControl(String, org.jboss.seam.international.StatusMessage.Severity, String, Object...)}
* instead
*/
@Deprecated
public void addToControl(String id, javax.faces.application.FacesMessage.Severity severity, String messageTemplate, Object... params)
{
addToControl(id, toSeverity(severity), messageTemplate, params);
}
/**
* Add a status message, looking up the message in the resource bundle
* using the provided key.
*
* You can also specify the severity, and parameters to be interpolated
*
* Deprecated, use {@link #addFromResourceBundle(org.jboss.seam.international.StatusMessage.Severity, String, Object...)}
* instead
*/
@Deprecated
public void addFromResourceBundle(javax.faces.application.FacesMessage.Severity severity, String key, Object... params)
{
addFromResourceBundle(toSeverity(severity), key, params);
}
/**
* Add a status message, looking up the message in the resource bundle
* using the provided key.
*
* You can also specify the severity, and parameters to be interpolated
*
* Deprecated, use {@link #addFromResourceBundleOrDefault(javax.faces.application.FacesMessage.Severity, String, String, Object...)}
* instead
*/
@Deprecated
public void addFromResourceBundleOrDefault(javax.faces.application.FacesMessage.Severity severity, String key, String defaultMessageTemplate, Object... params)
{
addFromResourceBundleOrDefault(toSeverity(severity), key, defaultMessageTemplate, params);
}
/**
* Create a new status message, looking up the message in the resource bundle
* using the provided key.
*
* The message will be added to the widget specified by the ID. The algorithm
* used determine which widget the id refers to is determined by the view
* layer implementation in use.
*
* You can also specify the severity, and parameters to be interpolated
*
* Deprecated, use {@link #addToControlFromResourceBundle(String, org.jboss.seam.international.StatusMessage.Severity, String, Object...)}
* instead
*/
@Deprecated
public void addToControlFromResourceBundle(String id, javax.faces.application.FacesMessage.Severity severity, String key, Object... params)
{
addToControlFromResourceBundle(id, toSeverity(severity), key, params);
}
/**
* Add a status message, looking up the message in the resource bundle
* using the provided key. If the message is found, it is used, otherwise,
* the defaultMessageTemplate will be used.
*
* The message will be added to the widget specified by the ID. The algorithm
* used determine which widget the id refers to is determined by the view
* layer implementation in use.
*
* You can also specify the severity, and parameters to be interpolated
*
* Deprecated, use {@link #addToControlFromResourceBundleOrDefault(String, org.jboss.seam.international.StatusMessage.Severity, String, String, Object...)}
* instead
*/
@Deprecated
public void addToControlFromResourceBundleOrDefault(String id, javax.faces.application.FacesMessage.Severity severity, String key, String defaultMessageTemplate, Object... params)
{
addToControlFromResourceBundleOrDefault(id, toSeverity(severity), key, defaultMessageTemplate, params);
}
public static FacesMessages instance()
{
Component component = Component.forName(StatusMessages.COMPONENT_NAME);
if(component != null && !component.getScope().isContextActive())
{
throw new IllegalStateException("No active "+component.getScope().name()+" context");
}
//Attempting to get the instance anyway for backwards compatibility with some potential hack situations.
return (FacesMessages) Component.getInstance(StatusMessages.COMPONENT_NAME);
}
}