JSF session based queued flash messages

Standard

This article is intended to expand on the first article “JSF Bootstrap Style Validation” by adding sessions to store messages between views.

Other examples use getFlash() or phase listeners to intercept the messages:

context.getExternalContext().getFlash().setKeepMessages(true);

This solution uses session map instead to store the messages in between views. Using this class will allow for messages to sit in the queue until they are rendered out, this could happen 1,2,3…. pages later.

These two methods when added to the existing getMessages and queueMessage methods add session based messaging. Saving messages is handled by storing all queued messages into the existing faces session map. Then when we restore all messages it grabs the messages from the session map and adds them back to the current facesContext for rendering.

    /**
     * This is our session name
     */
    private static final String sessionToken = "MULTIPAGE-MESSAGES";

    /**
     * Saves all messages queued to the sessionToken
     *
     * @param facesContext
     */
    private static void saveMessages(final FacesContext facesContext) {

        // get existing messages map from session
        Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
        HashMap<String, List<FacesMessage>> messagesByIDMap = (HashMap<String, List<FacesMessage>>) sessionMap.get(sessionToken);

        // If it doesn't exist make one
        if (messagesByIDMap == null) {
            messagesByIDMap = new HashMap<>();
            sessionMap.put(sessionToken, messagesByIDMap);
        }

        // Iterate through all messages that are waiting in queue
        for (Iterator<String> iter = facesContext.getClientIdsWithMessages(); iter.hasNext();) {

            String clientId = iter.next();
            List<FacesMessage> messageList = messagesByIDMap.get(clientId);

            // If no messages for client ID yet create empty arrayList
            if (messageList == null) {
                messageList = new ArrayList<>();
                messagesByIDMap.put(clientId, messageList);
            }

            Iterator<FacesMessage> facesIterator = facesContext.getMessages(clientId);

            // Add all the messages for that client ID to the session
            while (facesIterator.hasNext()) {
                messageList.add(facesIterator.next());
            }
        }
    }

    /**
     * Finds all the messages in the sessionToken and adds them
     *
     * @param facesContext
     */
    private static void restoreMessages(final FacesContext facesContext) {

        Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
        HashMap<String, List<FacesMessage>> messagesByIDMap = (HashMap<String, List<FacesMessage>>) sessionMap.remove(sessionToken);

        if (messagesByIDMap == null) {
            return;
        }

        // Add all messages by client ID back to the facesContext
        for (String clientID : messagesByIDMap.keySet()) {
            List<FacesMessage> messages = messagesByIDMap.get(clientID);
            for (FacesMessage facesMessage : messages) {
                facesContext.addMessage(clientID, facesMessage);
            }
        }
    }

Looking for the rest of the code? View the first article “JSF Bootstrap Style Validation” or checkout the code on found on Github.

Leave a Reply

Your email address will not be published.