[ 
https://issues.apache.org/jira/browse/WICKET-5619?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14185265#comment-14185265
 ] 

Daniel Kernebeck commented on WICKET-5619:
------------------------------------------

This issue still occurs in our webapplication. 
The exception is easy reproducable on the following way:

You have multiple users surfing a page (Page A) which has subscribes for an 
event (Event A). Now a user (User A) does an action which triggers the Event A 
to get posted to the Eventbus. While the eventbus posts the event to the 
registered listeners, a User B leaves the page and unregisters for the event, 
f.e because he now want's surfs another page, which does not subscribe to the 
event. Now the ConcurrentModificationException occurs because the unregistering 
of User B changed the list of listeners while the eventbus is still posting the 
event to the different listeners. This happen because the unregistin

In my opinion this issue can be solved if the line: 
{code} Collection<EventSubscription> eventSubscriptions = 
subscriptions.get(key);
subscriptionsForPage = Iterables.filter(eventSubscriptions, new 
EventFilter(event)); {code}
makes an copy of the EventSubscriptions an works on this copy instead on the 
original list. When the eventbus now trys to post the event on a component 
which does not exists anymore he could try to unregister the component from the 
original subscribers list. 

Also:
{code}
Iterable<EventSubscription> subscriptionsForPage;
                synchronized (this)
                {
                        key = trackedPages.get(resource.uuid());
                        Collection<EventSubscription> eventSubscriptions = 
subscriptions.get(key);
                        subscriptionsForPage = 
Iterables.filter(eventSubscriptions, new EventFilter(event));
                }
{code}
creates a lazy iterator on the the {{eventSubscriptions}}, and will be iterated 
outside the synchronized block.
You need to create a copy of the eventSubscriptions, because this might be 
changed during the unregistering process:

{code}
public synchronized void unregister(Component component)
        {
                ...     
                Collection<EventSubscription> subscriptionsForPage = 
subscriptions.get(pageKey);
                Iterator<EventSubscription> it = 
subscriptionsForPage.iterator();
                while (it.hasNext())
                {
                        if (it.next().getComponentPath().equals(componentPath))
                                it.remove();
                }
        }
{code}
{{it.remove()}} changes the iterator within the lazy Iterator!

> ConcurrentModificationException may occur when calling EventBus.post()
> ----------------------------------------------------------------------
>
>                 Key: WICKET-5619
>                 URL: https://issues.apache.org/jira/browse/WICKET-5619
>             Project: Wicket
>          Issue Type: Bug
>          Components: wicket-atmosphere
>    Affects Versions: 6.15.0
>            Reporter: Daniel Stoch
>            Assignee: Martin Grigorov
>              Labels: atmosphere
>             Fix For: 7.0.0-M3, 6.17.0
>
>
> ConcurrentModificationException may occur when calling EventBus.post() 
> because subscriptionsForPage collection can be modified by another thread 
> during a loop inside AtmosphereRequestHandler.executeHandlers:
> {code}
> java.util.ConcurrentModificationException
>       at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
>       at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
>       at 
> com.google.common.collect.AbstractMultimap$WrappedCollection$WrappedIterator.next(AbstractMultimap.java:540)
>       at 
> java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1102)
>       at com.google.common.collect.Iterators$8.computeNext(Iterators.java:735)
>       at 
> com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:143)
>       at 
> com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:138)
>       at 
> org.apache.wicket.atmosphere.AtmosphereRequestHandler.executeHandlers(AtmosphereRequestHandler.java:79)
>       at 
> org.apache.wicket.atmosphere.AtmosphereRequestHandler.respond(AtmosphereRequestHandler.java:74)
>       at 
> org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:862)
>       at 
> org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)
>       at 
> org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:261)
>       at 
> org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:218)
>       at 
> org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:289)
>       at org.apache.wicket.atmosphere.EventBus.post(EventBus.java:417)
>       at 
> org.apache.wicket.atmosphere.EventBus.postToSingleResource(EventBus.java:393)
>       at org.apache.wicket.atmosphere.EventBus.post(EventBus.java:346)
>       at org.apache.wicket.atmosphere.EventBus.post(EventBus.java:329)
> {code}
> I think the problem is inside in EventBus.postToSingleResource() method:
> {code}
> subscriptionsForPage = Collections2.filter(                   
> Collections.unmodifiableCollection(subscriptions.get(key)), new 
> EventFilter(event));
> {code}
> I think collection get from "subscriptions.get(key)" should be copied first 
> and then assigned to subscriptionsForPage variable. Now it is a pass as a 
> reference (not directly but it is) and it can lead to 
> ConcurrentModificationException.
> It is not easy to reproduce this problem (more that one thread must call post 
> at the same time), but sometimes it happen.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to