001: package org.contineo.web;
002:
003: import java.util.ArrayList;
004: import java.util.Iterator;
005: import java.util.List;
006: import java.util.Map;
007:
008: import javax.faces.application.FacesMessage;
009: import javax.faces.context.FacesContext;
010: import javax.faces.event.PhaseEvent;
011: import javax.faces.event.PhaseId;
012: import javax.faces.event.PhaseListener;
013:
014: /**
015: * Enables messages to be rendered on different pages from which they were set.
016: * To produce this behaviour, this class acts as a <code>PhaseListener</code>.
017: *
018: * This is performed by moving the FacesMessage objects:
019: * <li>After each phase where messages may be added, this moves the messages
020: * from the page-scoped FacesContext to the session-scoped session map.
021: * <li>Before messages are rendered, this moves the messages from the
022: * session-scoped session map back to the page-scoped FacesContext.
023: *
024: * Only messages that are not associated with a particular component are ever
025: * moved. These are the only messages that can be rendered on a page that is
026: * different from where they originated. * To enable this behaviour, add a
027: * <code>lifecycle</code> block to your faces-config.xml file. That block
028: * should contain a single <code>phase-listener</code> block containing the
029: * fully-qualified classname of this file.
030: *
031: * @author <a href="mailto:jesse@odel.on.ca">Jesse Wilson</a>
032: */
033: public class MultiPageMessagesSupport implements PhaseListener {
034: private static final long serialVersionUID = 1L;
035:
036: /** a name to save messages in the session under */
037: private static final String sessionToken = "MULTI_PAGE_MESSAGES_SUPPORT";
038:
039: /**
040: * Return the identifier of the request processing phase during which this
041: * listener is interested in processing PhaseEvent events.
042: */
043: public PhaseId getPhaseId() {
044: return PhaseId.ANY_PHASE;
045: }
046:
047: /**
048: * Handle a notification that the processing for a particular phase of the
049: * request processing lifecycle is about to begin.
050: */
051: public void beforePhase(PhaseEvent event) {
052: if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
053: FacesContext facesContext = event.getFacesContext();
054: restoreMessages(facesContext);
055: }
056: }
057:
058: /**
059: * Handle a notification that the processing for a particular phase has just
060: * been completed.
061: */
062: public void afterPhase(PhaseEvent event) {
063: if ((event.getPhaseId() == PhaseId.APPLY_REQUEST_VALUES)
064: || (event.getPhaseId() == PhaseId.PROCESS_VALIDATIONS)
065: || (event.getPhaseId() == PhaseId.INVOKE_APPLICATION)) {
066: FacesContext facesContext = event.getFacesContext();
067: saveMessages(facesContext);
068: }
069: }
070:
071: /**
072: * Remove the messages that are not associated with any particular component
073: * from the faces context and store them to the user's session.
074: *
075: * @return the number of removed messages.
076: */
077: private int saveMessages(FacesContext facesContext) {
078: // remove messages from the context
079: List messages = new ArrayList();
080:
081: for (Iterator i = facesContext.getMessages(null); i.hasNext();) {
082: messages.add(i.next());
083: i.remove();
084: }
085:
086: // store them in the session
087: if (messages.size() == 0) {
088: return 0;
089: }
090:
091: Map sessionMap = facesContext.getExternalContext()
092: .getSessionMap();
093:
094: // if there already are messages
095: List existingMessages = (List) sessionMap.get(sessionToken);
096:
097: if (existingMessages != null) {
098: existingMessages.addAll(messages);
099:
100: // if these are the first messages
101: } else {
102: sessionMap.put(sessionToken, messages);
103: }
104:
105: return messages.size();
106: }
107:
108: /**
109: * Remove the messages that are not associated with any particular component
110: * from the user's session and add them to the faces context.
111: *
112: * @return the number of removed messages.
113: */
114: private int restoreMessages(FacesContext facesContext) {
115: // remove messages from the session
116: Map sessionMap = facesContext.getExternalContext()
117: .getSessionMap();
118: List messages = (List) sessionMap.remove(sessionToken);
119:
120: // store them in the context
121: if (messages == null) {
122: return 0;
123: }
124:
125: int restoredCount = messages.size();
126:
127: for (Iterator i = messages.iterator(); i.hasNext();) {
128: facesContext.addMessage(null, (FacesMessage) i.next());
129: }
130:
131: return restoredCount;
132: }
133: }
|