[ http://issues.apache.org/jira/browse/MYFACES-750?page=all ]
     
Manfred Geiler resolved MYFACES-750:
------------------------------------

    Fix Version: Nightly
     Resolution: Fixed

Actually implemented a slightly different solution than was suggested. But 
synchronized is the right solution here, Thanks!

> Need synchronization in LifecycleImpl
> -------------------------------------
>
>          Key: MYFACES-750
>          URL: http://issues.apache.org/jira/browse/MYFACES-750
>      Project: MyFaces Core
>         Type: Bug
>   Components: Implementation
>     Versions: 1.1.0
>  Environment: Weblogic 8.1, AIX
>     Reporter: Sam Schneider
>     Assignee: Manfred Geiler
>      Fix For: Nightly

>
> Getting this exception when removing a bean as a listener:
> java.util.ConcurrentModificationException
>  at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:462)
>  at java.util.AbstractList$Itr.next(AbstractList.java:433)
>  at java.util.AbstractCollection.remove(AbstractCollection.java:268)
>  at 
> org.apache.myfaces.lifecycle.LifecycleImpl.removePhaseListener(LifecycleImpl.java:411)
>  at 
> com.erac.riskmgmt.ice.web.AbstractPageBean.afterPhase(AbstractPageBean.java:128)
> The method call at AbstractPageBean:128 is 
> getLifecycle().removePhaseListener(this);
>   protected Lifecycle getLifecycle() {
>     String lifecycleId = 
> getExternalContext().getInitParameter("javax.faces.LIFECYCLE_ID");
>     if ((lifecycleId == null) || (lifecycleId.length() == 0)) {
>       lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
>     }
>     LifecycleFactory lifecycleFactory = (LifecycleFactory) 
> FactoryFinder.getFactory(
>         FactoryFinder.LIFECYCLE_FACTORY);
>     return lifecycleFactory.getLifecycle(lifecycleId);
>   }
> Basically what's happening from a request perspective is that we have a 
> custom ViewHandler that creates the backing bean that's registered for a 
> given view id (custom registry using a HashMap that's created as a managed 
> bean and maintained manually in faces-config).  When the backing bean is 
> created it adds itself as a listener and when the AFTER RENDER_RESPONSE is 
> executed the bean removes itself as a listener (as above at line 128 in 
> AbstractPageBean).  No problems are observed in low-load situations, but when 
> we sent the application to benchmarking simulating ~200 "concurrent" users we 
> noticed this problem.  It looks like easiest fix is to synchronize the array 
> list on adding and removing listeners (currently we've worked around this by 
> using an external lock to synchronize add/remove calls from our 
> AbstractPageBean).
> However, It looks like there is also a potential problem with the call to 
> getPhaseListeners() in that it creates a cached array that's later copied 
> back into a *new* ArrayList in addPhaseListener(...) and 
> removePhaseListener(...).  Since there is no synchronization if someone 
> called getPhaseListeners() and then two/N different threads tried to add 
> listeners 1..N listeners could be lost (all would check for a null 
> _phaseListenerList and multiple threads could potentially attempt to create a 
> new _phaseListenerList and add/remove the PhaseListener) -- of course the 
> converse problem would be that two/N different threads tried to remove phase 
> listeners and the 1..N listeners would not be removed (they would be recopied 
> in on another thread).
> What would simplify this whole business greatly would be to remove the cached 
> list and simply synchronize on the ArrayList on the add/remove/getListeners:
>     public void addPhaseListener(PhaseListener phaseListener)
>     {
>         if(phaseListener == null)
>         {
>             throw new NullPointerException("PhaseListener must not be null.");
>         }
>        
> // create _phaseListenerList at class scope -- so no more null-checks for it
>         synchronized(_phaseListenerList) {
>         _phaseListenerList.add(phaseListener);
>         }
>     }
>     public void removePhaseListener(PhaseListener phaseListener)
>     {
>         synchronized(_phaseListenerList) {
>         _phaseListenerList.remove(phaseListener);
>         }
>     }
>     public PhaseListener[] getPhaseListeners()
>     {
>         synchronized(_phaseListenerList) {
>                 return  (PhaseListener[])_phaseListenerList.toArray(new 
> PhaseListener[_phaseListenerList.size()]);
>          }
>     }

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira

Reply via email to