This is an automated email from the ASF dual-hosted git repository. juanpablo pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/jspwiki.git
commit 9f27a1ce4cce3820d907b3dfe5286bb52498bcea Author: juanpablo <[email protected]> AuthorDate: Sat Apr 11 17:57:52 2020 +0200 avoid registering several times the same listener on the same client --- .../org/apache/wiki/event/WikiEventManager.java | 22 ++++--- .../apache/wiki/event/TestWikiEventListener.java | 35 +++++++++++ .../apache/wiki/event/WikiEventManagerTest.java | 71 ++++++++++++++++++++++ 3 files changed, 121 insertions(+), 7 deletions(-) diff --git a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java index dc069e9..95728fd 100644 --- a/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java +++ b/jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java @@ -29,6 +29,7 @@ import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.Vector; @@ -230,16 +231,17 @@ public final class WikiEventManager { } /** - * Un-registers a WikiEventListener from any WikiEventDelegate client managed by this WikiEventManager. Since this is a one-to-one - * relation, the first match will be returned upon removal; a true return value indicates the WikiEventListener was found and removed. + * Un-registers a WikiEventListener from any WikiEventDelegate client managed by this WikiEventManager. A true return value indicates + * the WikiEventListener was found and removed. * * @param listener the event listener * @return true if the listener was found and removed. */ public static boolean removeWikiEventListener( final WikiEventListener listener ) { + boolean removed = false; // get the Map.entry object for the entire Map, then check match on entry (listener) final WikiEventManager mgr = getInstance(); - final Map< Object, WikiEventDelegate > sources = mgr.getDelegates(); + final Map< Object, WikiEventDelegate > sources = Collections.synchronizedMap( mgr.getDelegates() ); synchronized( sources ) { // get an iterator over the Map.Enty objects in the map for( final Map.Entry< Object, WikiEventDelegate > entry : sources.entrySet() ) { @@ -248,11 +250,11 @@ public final class WikiEventManager { // now see if we can remove the listener from the delegate (delegate may be null because this is a weak reference) if( delegate != null && delegate.removeWikiEventListener( listener ) ) { - return true; // was removed + removed = true; // was removed } } } - return false; + return removed; } /** @@ -387,13 +389,19 @@ public final class WikiEventManager { /** * Adds <tt>listener</tt> as a listener for events fired by the WikiEventDelegate. * - * @param listener the WikiEventListener to be added + * @param listener the WikiEventListener to be added * @return true if the listener was added (i.e., it was not already in the list and was added) */ public boolean addWikiEventListener( final WikiEventListener listener ) { synchronized( m_listenerList ) { - return m_listenerList.add( new WeakReference<>(listener) ); + final boolean listenerAlreadyContained = m_listenerList.stream() + .map( WeakReference::get ) + .anyMatch( ref -> Objects.equals( ref, listener ) ); + if( !listenerAlreadyContained ) { + return m_listenerList.add( new WeakReference<>( listener ) ); + } } + return false; } /** diff --git a/jspwiki-event/src/test/java/org/apache/wiki/event/TestWikiEventListener.java b/jspwiki-event/src/test/java/org/apache/wiki/event/TestWikiEventListener.java new file mode 100644 index 0000000..8372e0a --- /dev/null +++ b/jspwiki-event/src/test/java/org/apache/wiki/event/TestWikiEventListener.java @@ -0,0 +1,35 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.event; + +public class TestWikiEventListener implements WikiEventListener { + + int invoked = 0; + + /** {@inheritDoc} */ + @Override + public void actionPerformed( final WikiEvent event ) { + invoked++; + } + + public int getInvoked() { + return invoked; + } + +} diff --git a/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventManagerTest.java b/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventManagerTest.java new file mode 100644 index 0000000..8902201 --- /dev/null +++ b/jspwiki-event/src/test/java/org/apache/wiki/event/WikiEventManagerTest.java @@ -0,0 +1,71 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.event; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + + +public class WikiEventManagerTest { + + @Test + public void shouldCheckRegisterUnregister() { + final String client1 = "test1"; + final String client2 = "test2"; + final TestWikiEventListener listener = new TestWikiEventListener(); + WikiEventManager.addWikiEventListener( client1, listener ); + Assertions.assertEquals( 1, WikiEventManager.getWikiEventListeners( client1 ).size() ); + Assertions.assertTrue( WikiEventManager.isListening( client1 ) ); + + WikiEventManager.removeWikiEventListener( client1, listener ); + Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client1 ).size() ); + Assertions.assertFalse( WikiEventManager.isListening( client1 ) ); + + WikiEventManager.addWikiEventListener( client1, listener ); + WikiEventManager.addWikiEventListener( client2, listener ); + WikiEventManager.removeWikiEventListener( listener ); + Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client1 ).size() ); + Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client2 ).size() ); + } + + @Test + public void shouldCheckAddingSameWikiEventListenerSeveralTimesOnlyGetsRegisteredOnce() { + final String client = "test3"; + final TestWikiEventListener listener = new TestWikiEventListener(); + WikiEventManager.addWikiEventListener( client, listener ); + WikiEventManager.addWikiEventListener( client, listener ); + + Assertions.assertEquals( 1, WikiEventManager.getWikiEventListeners( client ).size() ); + + WikiEventManager.removeWikiEventListener( client, listener ); + Assertions.assertEquals( 0, WikiEventManager.getWikiEventListeners( client ).size() ); + } + + @Test + public void shouldCheckEventsFiring() { + final String client = "test4"; + final TestWikiEventListener listener = new TestWikiEventListener(); + WikiEventManager.addWikiEventListener( client, listener ); + WikiEventManager.fireEvent( client, new WikiPageEvent( "object which fires the event", WikiPageEvent.PAGE_REQUESTED, "page" ) ); + + Assertions.assertEquals( 1, listener.getInvoked() ); + WikiEventManager.removeWikiEventListener( listener ); // dispose listener; if not done, listener would still be attached to test4 on other tests + } + +}
