ICEfaces
  1. ICEfaces
  2. ICE-3668

ice:message not displayed when using Spring Web Flow

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.7.2
    • Fix Version/s: 1.8DR#2, 1.8
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      ICEfaces 1.7.2, SWF 2.0.3

      Description

      After some more debugging on the problem I have noticed that the BridgeFacesContext never hold any messages because they are added to the FlowFacesContext which is the Spring Web Flow version of the FacesContext. All phases of the JSF lifecycle except for RENDER_RESPONSE is handled by the FlowFacesContext.

      When entering the RENDER_RESPONCE phase the FlowFacesContext is unwrapped to a BridgeFacesContext by the following code:

      Code:
        public static FacesContext unwrap(FacesContext facesContext) {
               if (facesContext instanceof BridgeFacesContext) {
                   return facesContext;
               }
               FacesContext result = facesContext;
               try {
                   Method delegateMethod = facesContext.getClass()
                           .getDeclaredMethod("getDelegate", new Class[]{});
                   delegateMethod.setAccessible(true);
                   Object delegate = delegateMethod
                           .invoke(facesContext, (Object[]) null);
                   if (delegate instanceof BridgeFacesContext) {
                       result = (FacesContext) delegate;
                       if (log.isDebugEnabled()) {
                           log.debug("BridgeFacesContext delegate of " + facesContext);
                       }
                   }
               } catch (Exception e) {
               }
       
               return result;
           }
       


      The FacesMessages that were added to the FlowFacesContext are never passed on to the BridgeFacesContext.

      I therefore made a small change to the unwrap method:
      Code:
         public static FacesContext unwrap(FacesContext facesContext) {
               if (facesContext instanceof BridgeFacesContext) {
                   return facesContext;
               }
               FacesContext result = facesContext;
               try {
                   Method delegateMethod = facesContext.getClass()
                           .getDeclaredMethod("getDelegate", new Class[]{});
                   delegateMethod.setAccessible(true);
                   Object delegate = delegateMethod
                           .invoke(facesContext, (Object[]) null);
                   if (delegate instanceof BridgeFacesContext) {
                       result = (FacesContext) delegate;
                        //patch start : getting the faces messages from the FlowFacesContext
                       Iterator clientIdIterator = facesContext.getClientIdsWithMessages();
                       while(clientIdIterator.hasNext()){
                        String clientId = (String)clientIdIterator.next();
                        Iterator facesMessagesForClientId = facesContext.getMessages(clientId);
                        while(facesMessagesForClientId.hasNext()){
                        FacesMessage message = (FacesMessage)facesMessagesForClientId.next();
                        result.addMessage(clientId, message);
                        }
                       }
                       // patch end.
                       if (log.isDebugEnabled()) {
                           log.debug("BridgeFacesContext delegate of " + facesContext);
                       }
                   }
               } catch (Exception e) {
               }
       
               return result;
           }
       

        Activity

        Hide
        Ted Goddard added a comment -

        Deryk, please assign the suggested patch for code review; on the surface it looks like a good fix.

        Show
        Ted Goddard added a comment - Deryk, please assign the suggested patch for code review; on the surface it looks like a good fix.
        Hide
        Deryk Sinotte added a comment -

        Assigning to Greg for code review.

        Show
        Deryk Sinotte added a comment - Assigning to Greg for code review.
        Hide
        Per Cilius Jakobsen added a comment -

        I don't think that the patch i complete as it does not handle messages with no id. You should therefore add another iterator for messages without id's.

        Like this:

        public static FacesContext unwrap(FacesContext facesContext) {
        if (facesContext instanceof BridgeFacesContext)

        { return facesContext; }

        FacesContext result = facesContext;
        try {
        Method delegateMethod = facesContext.getClass()
        .getDeclaredMethod("getDelegate", new Class[]{});
        delegateMethod.setAccessible(true);
        Object delegate = delegateMethod
        .invoke(facesContext, (Object[]) null);
        if (delegate instanceof BridgeFacesContext) {
        result = (FacesContext) delegate;
        Iterator clientIdIterator = facesContext.getClientIdsWithMessages();
        while(clientIdIterator.hasNext()){
        String clientId = (String)clientIdIterator.next();
        Iterator facesMessagesForClientId = facesContext.getMessages(clientId);
        while(facesMessagesForClientId.hasNext())

        { FacesMessage message = (FacesMessage)facesMessagesForClientId.next(); result.addMessage(clientId, message); }

        }
        Iterator facesMessagesWithNoId = facesContext.getMessages(null);
        while(facesMessagesWithNoId.hasNext())

        { FacesMessage message = (FacesMessage)facesMessagesWithNoId.next(); result.addMessage("", message); }

        RequestContextHolder.getRequestContext().getConversationScope().put("INTUIMESSAGES", intuiMessages);
        if (log.isDebugEnabled())

        { log.debug("BridgeFacesContext delegate of " + facesContext); }

        }
        } catch (Exception e) {
        }

        return result;
        }

        Show
        Per Cilius Jakobsen added a comment - I don't think that the patch i complete as it does not handle messages with no id. You should therefore add another iterator for messages without id's. Like this: public static FacesContext unwrap(FacesContext facesContext) { if (facesContext instanceof BridgeFacesContext) { return facesContext; } FacesContext result = facesContext; try { Method delegateMethod = facesContext.getClass() .getDeclaredMethod("getDelegate", new Class[]{}); delegateMethod.setAccessible(true); Object delegate = delegateMethod .invoke(facesContext, (Object[]) null); if (delegate instanceof BridgeFacesContext) { result = (FacesContext) delegate; Iterator clientIdIterator = facesContext.getClientIdsWithMessages(); while(clientIdIterator.hasNext()){ String clientId = (String)clientIdIterator.next(); Iterator facesMessagesForClientId = facesContext.getMessages(clientId); while(facesMessagesForClientId.hasNext()) { FacesMessage message = (FacesMessage)facesMessagesForClientId.next(); result.addMessage(clientId, message); } } Iterator facesMessagesWithNoId = facesContext.getMessages(null); while(facesMessagesWithNoId.hasNext()) { FacesMessage message = (FacesMessage)facesMessagesWithNoId.next(); result.addMessage("", message); } RequestContextHolder.getRequestContext().getConversationScope().put("INTUIMESSAGES", intuiMessages); if (log.isDebugEnabled()) { log.debug("BridgeFacesContext delegate of " + facesContext); } } } catch (Exception e) { } return result; }
        Hide
        Per Cilius Jakobsen added a comment -

        forget this line of code: RequestContextHolder.getRequestContext().getConversationScope().put("INTUIMESSAGES", intuiMessages); :-D

        Show
        Per Cilius Jakobsen added a comment - forget this line of code: RequestContextHolder.getRequestContext().getConversationScope().put("INTUIMESSAGES", intuiMessages); :-D
        Hide
        Greg Dick added a comment -

        Code works and appears to be correct. FacesMessages definitely don't appear before the change!

        Show
        Greg Dick added a comment - Code works and appears to be correct. FacesMessages definitely don't appear before the change!
        Hide
        Per Cilius Jakobsen added a comment -

        The suggested code which has been added to ICEfaces 1.8 does not work as intended.

        When I suggested the code I had missed that the spec on the getClientIdWithMessages() method on FacesContext says that it will return the value "null" in the Iterator if a global message was added.

        This means that the suggested code adds any global message on the FlowFacesContext twice on the BridgeFacesContext.

        Fix:

         /**
             * Check the delegation chain for a BridgeFacesContext wrapped by another
             *
             * @param facesContext return BridgeFacesContext (if found) or input FacesContext
             */
            public static FacesContext unwrap(FacesContext facesContext) {
                if (facesContext instanceof BridgeFacesContext) {
                    return facesContext;
                }
                FacesContext result = facesContext;
                try {
                    Method delegateMethod = facesContext.getClass()
                            .getDeclaredMethod("getDelegate", new Class[]{});
                    delegateMethod.setAccessible(true);
                    Object delegate = delegateMethod
                            .invoke(facesContext, (Object[]) null);
                    if (delegate instanceof BridgeFacesContext) {
                        result = (FacesContext) delegate;
                        // #3668 fetch messages from Spring
                        Iterator clientIdIterator = facesContext.getClientIdsWithMessages();
                        FacesMessage message;
                        String clientId;
                        while(clientIdIterator.hasNext()){
                        	clientId = (String)clientIdIterator.next();
                            Iterator facesMessagesForClientId = facesContext.getMessages(clientId);
                            while(facesMessagesForClientId.hasNext()){
                                message = (FacesMessage)facesMessagesForClientId.next();
                                if(isGlobalMessage(clientId)){
                                	result.addMessage(null, message);	
                                }else{
                                	result.addMessage(clientId, message);
                                }
                            }
                        }
                        if (log.isDebugEnabled()) {
                            log.debug("BridgeFacesContext delegate of " + facesContext);
                        }
                    }
                } catch (Exception e) {
                }
        
                return result;
            }
        
            private static boolean isGlobalMessage(String clientId) {
        		return clientId == null || clientId.equals("null");
        	}
        
        
        
        Show
        Per Cilius Jakobsen added a comment - The suggested code which has been added to ICEfaces 1.8 does not work as intended. When I suggested the code I had missed that the spec on the getClientIdWithMessages() method on FacesContext says that it will return the value "null" in the Iterator if a global message was added. This means that the suggested code adds any global message on the FlowFacesContext twice on the BridgeFacesContext. Fix: /** * Check the delegation chain for a BridgeFacesContext wrapped by another * * @param facesContext return BridgeFacesContext ( if found) or input FacesContext */ public static FacesContext unwrap(FacesContext facesContext) { if (facesContext instanceof BridgeFacesContext) { return facesContext; } FacesContext result = facesContext; try { Method delegateMethod = facesContext.getClass() .getDeclaredMethod( "getDelegate" , new Class []{}); delegateMethod.setAccessible( true ); Object delegate = delegateMethod .invoke(facesContext, ( Object []) null ); if (delegate instanceof BridgeFacesContext) { result = (FacesContext) delegate; // #3668 fetch messages from Spring Iterator clientIdIterator = facesContext.getClientIdsWithMessages(); FacesMessage message; String clientId; while (clientIdIterator.hasNext()){ clientId = ( String )clientIdIterator.next(); Iterator facesMessagesForClientId = facesContext.getMessages(clientId); while (facesMessagesForClientId.hasNext()){ message = (FacesMessage)facesMessagesForClientId.next(); if (isGlobalMessage(clientId)){ result.addMessage( null , message); } else { result.addMessage(clientId, message); } } } if (log.isDebugEnabled()) { log.debug( "BridgeFacesContext delegate of " + facesContext); } } } catch (Exception e) { } return result; } private static boolean isGlobalMessage( String clientId) { return clientId == null || clientId.equals( " null " ); }
        Hide
        Tyler Johnson added a comment -

        The committed fix does not handle the case of global messages. The following line:

        result.addMessage("", message);

        when changed to null resolves the issue which is similar to Per´s suggestion above.

        Show
        Tyler Johnson added a comment - The committed fix does not handle the case of global messages. The following line: result.addMessage("", message); when changed to null resolves the issue which is similar to Per´s suggestion above.
        Hide
        Tyler Johnson added a comment -

        I have created ICE-6853 for ice:messages not being displayed when using Spring.

        Show
        Tyler Johnson added a comment - I have created ICE-6853 for ice:messages not being displayed when using Spring.

          People

          • Assignee:
            Greg Dick
            Reporter:
            Ted Goddard
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: