I am experiencing exceptions with my ICEfaces 1.6.0#DR5 / Seam 1.2 application.
I have a page with an expandable table. It's very similar to the sample in the ICEfaces distribution. Sometimes when one clicks the expand / contract nodes, there is an exception telling that the Seam conversation cannot be found. This happens particularly when I make the nodes very quickly expand, contract, expand, contract, ...
This is the exception:
Code:
13:33:50,218 ERROR [D2DFaceletViewHandler] Problem in renderResponse:
/pricing/viewAdjustPremium.jspx @39,80 itemValue="${layer.value}":
/pricing/viewAdjustPremium.jspx @38,110 items="#{ctrl.pricingConversation.x}":
Exception getting value of property pricingConversation of base of type :
com.agcs.pricing.web.controller.ViewAdjustPremiumController_$$_javassist_39
javax.faces.el.EvaluationException: /pricing/viewAdjustPremium.jspx @39,80 itemValue="${x.value}":
/pricing/viewAdjustPremium.jspx @38,110 items="#{viewadjustpremiumcontroller.pricingConversation.x}":
Exception getting value of property pricingConversation of base of type :
com.agcs.pricing.web.controller.ViewAdjustPremiumController_$$_javassist_39
at com.sun.facelets.el.LegacyValueBinding.getValue(LegacyValueBinding.java:60)
....
("pricingConversation" is a Seam bean in the conversation scope)
Looking into the ICEfaces source code I saw that the ViewBoundAdaptingServlet that is executed for handling the Ajax request manipulates the view information stored in ServletView. However there is no (or very little) synchronization.
In order to see what's going on I have added a few code statements to the class which looks like this
Code:
public class ViewBoundAdaptingServlet extends BasicAdaptingServlet {
private int concurrentCalls = 0;
...
public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (++concurrentCalls > 1) {
System.err.println("***************************************");
System.err.println("** Concurrent calls: " + concurrentCalls);
System.err.println("***************************************");
...
finally {
view.release();
concurrentCalls--;
}
}
}
}
And indeed - the exception occurs exactly when the number of concurrent calls is 2: everytime the "*****...." appears the exception is thrown. In every request where it does not appear there is no exception. So it looks like there is some systematical logic preventing the Seam conversation from being found when the request is executed in parallel with another.
You have to click a few times in order to produce this situation but you can have it also in the official component-showcase example (without Seam). The component-showcase however does not show an exception (may be due to the lack of a dependency to a running Seam conversation).
So obviously it's possible to execute two concurrent Ajax requests (/pricing/block/send-receive-updates) for the same view simply by clicking repeatedly in the user interface. Why is that? And does it make sense to have them processed concurrently?
I changed the source code of the ViewBoundAdaptingServlet and made the service() method synchronized:
Code:
public class ViewBoundAdaptingServlet extends BasicAdaptingServlet {
synchronized public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
}
}
This modification obviously prevents concurrent execution for the user session effectively. And this works great. I cannot produce the exception however fast and often I click on the expand / contract nodes.
What does this mean? Is this an ICEfaces bug? Or could there be any setting I have not done incorrectly?