voyent
no message is displayed by the ice:message tag when using ICEfaces with Spring Webflow  XML
Forum Index -> General Help
Author Message
cilius

Joined: 08/Jul/2008 00:00:00
Messages: 11
Offline


Hi

I am having some trouble getting my FacesMessages displayed by the <ice:message> and <ice:messages> tag when using ICEfaces together with Spring Webflow.

My very simple facelet page:

Code:
<ice:form id="myForm">
   <ice:outputText id="count" value="count: #{testBean.count}" />
   <ice:inputText id="emailAddress" value="#{testBean.emailAddress}" partialSubmit="true" />
    <ice:message for="emailAddress" />
    <ice:inputText id="someText" value="#{testBean.someText}" />
    <ice:commandButton id="submitIndex" value="Forward" action="toPage2" />
 </ice:form>
 


I don’t get any exception… and my page is just reloaded without the wanted message.

My application runs on webSphere 6.0 has the following setup:
JSF 1.1
Icefaces 1.7.2
Spring webflow 2.0.3
Facelets

Are any of you having the same problem?

Thanks in advance

-cilius
cilius

Joined: 08/Jul/2008 00:00:00
Messages: 11
Offline


Hi

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;
     }
 


I am now able to present messages created in my Controller class on the page with the ICEfaces message tag.

Unfortunately this did not solve the problem completely!. If the FacesMessage is added to the FlowFacesContext due to a conversion error I run in to a new problem. When the message is not created in a bean class the FacesMessage apparently needs to be serialized and because I am on JSF 1.1 the FacesMessage contains an inner Severity class that does not implement Serializable and therefore I end up with a NotSerializableException.

I am not sure how to fix this problem. Any suggestions will be appreciated :-)

-cilius
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline



Is it possible to create a test case without ICEfaces for the spring forum?

http://forum.springframework.org/showthread.php?t=62445

(For instance, the serialization exception may be a SWF 2.0.3 / JSF 1.1 integration problem, and that may cause them to fix it without being able to blame ICEfaces.)

We've created the following JIRA to track the problem:

http://jira.icefaces.org/browse/ICE-3668

Thanks for your suggested fix (please use the JIRA to provide any comments on the fix).
[Email]
cilius

Joined: 08/Jul/2008 00:00:00
Messages: 11
Offline


Hi Ted

Thanks for your answer. I am working on a testcase for SWF without ICEfaces to see if I can isolate the problem in SWF alone.

-cilius
cilius

Joined: 08/Jul/2008 00:00:00
Messages: 11
Offline


Hi

I have created a testcase on our setup with SWF and without ICEfaces. The testcase shows my messages just fine, so I am thinking it must be something in the integration between SWF and ICEfaces that causes the error.

in the D2DViewHandler:

Code:
	// Render the components
 	public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException {
 		initializeParameters(context);
 		if (SeamUtilities.isSpringEnvironment()) {
 			context = BridgeFacesContext.unwrap(context);
 			if (context instanceof BridgeFacesContext) {
 				((BridgeFacesContext) context).setCurrentInstance();
 			}
 		}
 		if (delegateView(context)) {
 			delegate.renderView(context, viewToRender);
 			return;
 		}
 		if (log.isTraceEnabled()) {
 			log.trace("renderView(FC,UIVR)  BEFORE  renderResponse  " + "viewToRender.getViewId(): " + viewToRender.getViewId());
 		}
 		renderResponse(context);
 		if (jsfStateManagement) {
 			StateManager stateMgr = context.getApplication().getStateManager();
 			// Serialization test- start
 			try {
 				new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(context);
 //				is able to serialize
 			} catch (NotSerializableException e) {
 //				can't serialize
 			}
 //			Serialization test - end
 			stateMgr.saveSerializedView(context);
 		}
 	}


This small test shows that the BridgeFacesContext can't serialize but the stateMgr still tries to...

-cilius
cilius

Joined: 08/Jul/2008 00:00:00
Messages: 11
Offline


Hi Obi-Ted-Kenobi ;-)

I have done some more debugging and I have done the following observations:

1)
The D2DViewHandler tries to create a serialized view by calling the StateManager. When used in conjunction with Spring Web Flow, the stateManager is a FlowViewStateManager.
The FlowViewStateManager tries to serialize the view. And that view is put into SWF’s viewScope which requires objects to be Serializable. So that’s the error I end up with – putting an object into viewScope that’s not Serializable.
I have looked at the serialized view returned from the FlowViewStateManager, and it seems that the problem is with the view.getState().
This is what I have tried in the D2DViewHandler to:
Code:
 			String object = "";
 			try {
 				object = context.getViewRoot().getClass().toString();
 				new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(context.getViewRoot());
 				System.out.println("viewRoot is serializable.");
 			
 				SerializedView view = stateMgr.saveSerializedView(context);
 				object = view.getStructure().getClass().toString();
 				new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(view.getStructure());
 
 				object = view.getState().getClass().toString();
 				new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(view.getState());
 
 				
 				System.out.println("I am able to serialize :-) YYEEEEHHAAAAAAAA!");
 			} catch (NotSerializableException e) {
 				System.out.println("can't serialize..."+object);
 				System.err.println("NO SERIALIZATION!");
 			}
 


And I get the NotSerializableException after the writeObject(view.getState()).


2)
The problem does not occur if the message is added to the FacesContext by a bean.
Code:
 FacesContext context = FacesContext.getCurrentInstance();
 context.addMessage("myForm:someText", new FacesMessage(FacesMessage.SEVERITY_ERROR,"error", "errror -  detail"));
 


It only happens when the message is added by a converter or validator. For example having an input field hooked up to an int property will cause an standard JSF-conversion error when typing in letters.

So I think that ICEfaces must add something to the state (that I cannot seem to find) that causes the NotSerializableException.

Is ICEfaces adding some information to the view state about which components in the page that are associated with a FacesMessage?

3)
Another thing regarding messages is that I can’t load my page at all when I add <ice:messages /> . Then it fails due to a serialization error when the page is requested the first time. I’m not really sure if the two errors are related.

-cilius
cilius

Joined: 08/Jul/2008 00:00:00
Messages: 11
Offline


Hi

I have solved my problem by building a new version of the jsf-api 1.1.02 jar with a Severity object that implements serializable.

I no longer get at NotSerializableException and my messages is rendered to the page.

-cilius
 
Forum Index -> General Help
Go to:   
Powered by JForum 2.1.7ice © JForum Team