Skip to content

Commit 62b140b

Browse files
committed
Use custom Synchronizer class to manage ReentrantLock synchronization
1 parent eb77ea5 commit 62b140b

37 files changed

+816
-961
lines changed

jspwiki-event/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,11 @@
6262
<artifactId>junit-jupiter-engine</artifactId>
6363
<scope>test</scope>
6464
</dependency>
65+
66+
<dependency>
67+
<groupId>${project.groupId}</groupId>
68+
<artifactId>jspwiki-util</artifactId>
69+
<version>${project.version}</version>
70+
</dependency>
6571
</dependencies>
6672
</project>

jspwiki-event/src/main/java/org/apache/wiki/event/WikiEventManager.java

+68-93
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Licensed to the Apache Software Foundation (ASF) under one
2121

2222
import org.apache.logging.log4j.LogManager;
2323
import org.apache.logging.log4j.Logger;
24+
import org.apache.wiki.util.Synchronizer;
2425

2526
import java.lang.ref.WeakReference;
2627
import java.util.ArrayList;
@@ -33,6 +34,7 @@ Licensed to the Apache Software Foundation (ASF) under one
3334
import java.util.Set;
3435
import java.util.TreeSet;
3536
import java.util.Vector;
37+
import java.util.concurrent.atomic.AtomicBoolean;
3638
import java.util.concurrent.locks.ReentrantLock;
3739

3840
/**
@@ -150,7 +152,18 @@ public final class WikiEventManager {
150152
*
151153
* @see java.util.concurrent.locks.ReentrantLock
152154
*/
153-
private static final ReentrantLock lock = new ReentrantLock();
155+
private static final ReentrantLock instanceLock = new ReentrantLock();
156+
private static final ReentrantLock removeWikiEventListenerLock = new ReentrantLock();
157+
private static final ReentrantLock delegatesLockLock = new ReentrantLock();
158+
private static final ReentrantLock preloadCacheLock = new ReentrantLock();
159+
private static final ReentrantLock delegateForLock = new ReentrantLock();
160+
private static final ReentrantLock wikiEventListenersLock = new ReentrantLock();
161+
private static final ReentrantLock wikiEventListenerLock = new ReentrantLock();
162+
private static final ReentrantLock removeWikiEventListenerLock2 = new ReentrantLock();
163+
private static final ReentrantLock isListeningLock = new ReentrantLock();
164+
private static final ReentrantLock fireEventLock = new ReentrantLock();
165+
166+
154167

155168

156169
/** Constructor for a WikiEventManager. */
@@ -167,15 +180,12 @@ private WikiEventManager() {
167180
*/
168181
public static WikiEventManager getInstance() {
169182
if (c_instance == null) {
170-
lock.lock();
171-
try {
183+
Synchronizer.synchronize(instanceLock, () -> {
172184
if (c_instance == null) {
173185
c_instance = new WikiEventManager();
174186
// start up any post-instantiation services here
175187
}
176-
} finally {
177-
lock.unlock();
178-
}
188+
});
179189
}
180190
return c_instance;
181191
}
@@ -255,41 +265,28 @@ public static Set<WikiEventListener> getWikiEventListeners( final Object client
255265
* @return true if the listener was found and removed.
256266
*/
257267
public static boolean removeWikiEventListener( final WikiEventListener listener ) {
258-
boolean removed = false;
268+
final AtomicBoolean removed = new AtomicBoolean(false);
259269
// get the Map.entry object for the entire Map, then check match on entry (listener)
260270
final WikiEventManager mgr = getInstance();
261271
final Map< Object, WikiEventDelegate > sources = Collections.synchronizedMap( mgr.getDelegates() );
262-
lock.lock();
263-
try {
272+
Synchronizer.synchronize(removeWikiEventListenerLock, () -> {
264273
// get an iterator over the Map.Enty objects in the map
265274
for( final Map.Entry< Object, WikiEventDelegate > entry : sources.entrySet() ) {
266275
// the entry value is the delegate
267276
final WikiEventDelegate delegate = entry.getValue();
268277

269278
// now see if we can remove the listener from the delegate (delegate may be null because this is a weak reference)
270279
if( delegate != null && delegate.removeWikiEventListener( listener ) ) {
271-
removed = true; // was removed
280+
removed.set(true); // was removed
272281
}
273282
}
274-
} finally {
275-
lock.unlock();
276-
}
277-
return removed;
283+
});
284+
return removed.get();
278285
}
279286

280287
private void removeDelegates() {
281-
lock.lock();
282-
try {
283-
m_delegates.clear();
284-
} finally {
285-
lock.unlock();
286-
}
287-
lock.lock();
288-
try {
289-
m_preloadCache.clear();
290-
} finally {
291-
lock.unlock();
292-
}
288+
Synchronizer.synchronize(delegatesLockLock, m_delegates::clear);
289+
Synchronizer.synchronize(preloadCacheLock, m_preloadCache::clear);
293290
}
294291

295292
public static void shutdown() {
@@ -340,38 +337,35 @@ private Map< Object, WikiEventDelegate > getDelegates() {
340337
* @param client the client Object, or alternately a Class reference
341338
* @return the WikiEventDelegate.
342339
*/
343-
private WikiEventDelegate getDelegateFor( final Object client ) {
344-
lock.lock();
345-
try {
346-
if( client == null || client instanceof Class ) { // then preload the cache
347-
final WikiEventDelegate delegate = new WikiEventDelegate( client );
348-
m_preloadCache.add( delegate );
349-
m_delegates.put( client, delegate );
340+
private WikiEventDelegate getDelegateFor(final Object client) {
341+
return Synchronizer.synchronize(delegateForLock, () -> {
342+
if (client == null || client instanceof Class) { // then preload the cache
343+
final WikiEventDelegate delegate = new WikiEventDelegate(client);
344+
m_preloadCache.add(delegate);
345+
m_delegates.put(client, delegate);
350346
return delegate;
351-
} else if( !m_preloadCache.isEmpty() ) {
347+
} else if (!m_preloadCache.isEmpty()) {
352348
// then see if any of the cached delegates match the class of the incoming client
353-
for( int i = m_preloadCache.size()-1 ; i >= 0 ; i-- ) { // start with most-recently added
354-
final WikiEventDelegate delegate = m_preloadCache.elementAt( i );
355-
if( delegate.getClientClass() == null || delegate.getClientClass().equals( client.getClass() ) ) {
349+
for (int i = m_preloadCache.size() - 1; i >= 0; i--) { // start with most-recently added
350+
final WikiEventDelegate delegate = m_preloadCache.elementAt(i);
351+
if (delegate.getClientClass() == null || delegate.getClientClass().equals(client.getClass())) {
356352
// we have a hit, so use it, but only on a client we haven't seen before
357-
if( !m_delegates.containsKey( client ) ) {
358-
m_preloadCache.remove( delegate );
359-
m_delegates.put( client, delegate );
353+
if (!m_delegates.containsKey(client)) {
354+
m_preloadCache.remove(delegate);
355+
m_delegates.put(client, delegate);
360356
return delegate;
361357
}
362358
}
363359
}
364360
}
365361
// otherwise treat normally...
366-
WikiEventDelegate delegate = m_delegates.get( client );
367-
if( delegate == null ) {
368-
delegate = new WikiEventDelegate( client );
369-
m_delegates.put( client, delegate );
362+
WikiEventDelegate delegate = m_delegates.get(client);
363+
if (delegate == null) {
364+
delegate = new WikiEventDelegate(client);
365+
m_delegates.put(client, delegate);
370366
}
371367
return delegate;
372-
} finally {
373-
lock.unlock();
374-
}
368+
});
375369
}
376370

377371

@@ -415,8 +409,7 @@ private static final class WikiEventDelegate {
415409
* @throws java.lang.UnsupportedOperationException if any attempt is made to modify the Set
416410
*/
417411
public Set< WikiEventListener > getWikiEventListeners() {
418-
lock.lock();
419-
try {
412+
return Synchronizer.synchronize(wikiEventListenersLock, () -> {
420413
final TreeSet< WikiEventListener > set = new TreeSet<>( new WikiEventListenerComparator() );
421414
for( final WeakReference< WikiEventListener > wikiEventListenerWeakReference : m_listenerList ) {
422415
final WikiEventListener l = wikiEventListenerWeakReference.get();
@@ -426,9 +419,7 @@ public Set< WikiEventListener > getWikiEventListeners() {
426419
}
427420

428421
return Collections.unmodifiableSet( set );
429-
} finally {
430-
lock.unlock();
431-
}
422+
});
432423
}
433424

434425
/**
@@ -438,18 +429,15 @@ public Set< WikiEventListener > getWikiEventListeners() {
438429
* @return true if the listener was added (i.e., it was not already in the list and was added)
439430
*/
440431
public boolean addWikiEventListener( final WikiEventListener listener ) {
441-
lock.lock();
442-
try {
432+
return Synchronizer.synchronize(wikiEventListenerLock, () -> {
443433
final boolean listenerAlreadyContained = m_listenerList.stream()
444434
.map( WeakReference::get )
445435
.anyMatch( ref -> ref == listener );
446436
if( !listenerAlreadyContained ) {
447437
return m_listenerList.add( new WeakReference<>( listener ) );
448438
}
449-
} finally {
450-
lock.unlock();
451-
}
452-
return false;
439+
return false;
440+
});
453441
}
454442

455443
/**
@@ -459,67 +447,54 @@ public boolean addWikiEventListener( final WikiEventListener listener ) {
459447
* @return true if the listener was removed (i.e., it was actually in the list and was removed)
460448
*/
461449
public boolean removeWikiEventListener( final WikiEventListener listener ) {
462-
lock.lock();
463-
try {
464-
for( final Iterator< WeakReference< WikiEventListener > > i = m_listenerList.iterator(); i.hasNext(); ) {
450+
return Synchronizer.synchronize(removeWikiEventListenerLock2, () -> {
451+
for (final Iterator<WeakReference<WikiEventListener>> i = m_listenerList.iterator(); i.hasNext(); ) {
465452
final WikiEventListener l = i.next().get();
466-
if( l == listener ) {
453+
if (l == listener) {
467454
i.remove();
468455
return true;
469456
}
470457
}
471-
} finally {
472-
lock.unlock();
473-
}
474-
475-
return false;
458+
return false;
459+
});
476460
}
477461

478462
/**
479463
* Returns true if there are one or more listeners registered with this instance.
480464
*/
481465
public boolean isListening() {
482-
lock.lock();
483-
try {
484-
return !m_listenerList.isEmpty();
485-
} finally {
486-
lock.unlock();
487-
}
466+
return Synchronizer.synchronize(isListeningLock, () -> !m_listenerList.isEmpty());
488467
}
489468

490469
/**
491470
* Notify all listeners having a registered interest in change events of the supplied WikiEvent.
492471
*/
493-
public void fireEvent( final WikiEvent event ) {
494-
boolean needsCleanup = false;
472+
public void fireEvent(final WikiEvent event) {
473+
final AtomicBoolean needsCleanup = new AtomicBoolean(false);
495474
try {
496-
lock.lock();
497-
try {
498-
for( final WeakReference< WikiEventListener > wikiEventListenerWeakReference : m_listenerList ) {
475+
Synchronizer.synchronize(fireEventLock, () -> {
476+
for (final WeakReference<WikiEventListener> wikiEventListenerWeakReference : m_listenerList) {
499477
final WikiEventListener listener = wikiEventListenerWeakReference.get();
500-
if( listener != null ) {
501-
listener.actionPerformed( event );
478+
if (listener != null) {
479+
listener.actionPerformed(event);
502480
} else {
503-
needsCleanup = true;
481+
needsCleanup.set(true);
504482
}
505483
}
506484

507-
// Remove all such listeners which have expired
508-
if( needsCleanup ) {
509-
for( int i = 0; i < m_listenerList.size(); i++ ) {
510-
final WeakReference< WikiEventListener > w = m_listenerList.get( i );
511-
if( w.get() == null ) {
485+
// Remove all such listeners which have expired
486+
if (needsCleanup.get()) {
487+
for (int i = 0; i < m_listenerList.size(); i++) {
488+
final WeakReference<WikiEventListener> w = m_listenerList.get(i);
489+
if (w.get() == null) {
512490
m_listenerList.remove(i--);
513491
}
514492
}
515493
}
516-
517-
} finally {
518-
lock.unlock();
519-
}
520-
} catch( final ConcurrentModificationException e ) {
521-
// We don't die, we just don't do notifications in that case.
522-
LOG.info( "Concurrent modification of event list; please report this.", e );
494+
});
495+
} catch (final ConcurrentModificationException e) {
496+
// We don't die, we just don't do notifications in that case.
497+
LOG.info("Concurrent modification of event list; please report this.", e);
523498
}
524499
}
525500
}

jspwiki-kendra-searchprovider/src/main/java/org/apache/wiki/search/kendra/KendraSearchProvider.java

+8-9
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Licensed to the Apache Software Foundation (ASF) under one
4646
import org.apache.wiki.auth.permissions.PagePermission;
4747
import org.apache.wiki.pages.PageManager;
4848
import org.apache.wiki.search.SearchProvider;
49+
import org.apache.wiki.util.Synchronizer;
4950
import org.apache.wiki.util.TextUtil;
5051

5152
import java.io.IOException;
@@ -346,23 +347,21 @@ private void doFullReindex() throws IOException {
346347
* index pages that have been modified
347348
*/
348349
private void doPartialReindex() {
349-
if ( updates.isEmpty() ) {
350+
if (updates.isEmpty()) {
350351
return;
351352
}
352-
LOG.debug( "Indexing updated pages. Please wait ..." );
353+
LOG.debug("Indexing updated pages. Please wait ...");
353354
final String executionId = startExecution();
354-
lock.lock();
355-
try {
355+
356+
Synchronizer.synchronize(lock, () -> {
356357
try {
357-
while ( updates.size() > 0 ) {
358-
indexOnePage( updates.remove( 0 ), executionId );
358+
while (!updates.isEmpty()) {
359+
indexOnePage(updates.remove(0), executionId);
359360
}
360361
} finally {
361362
stopExecution();
362363
}
363-
} finally {
364-
lock.unlock();
365-
}
364+
});
366365
}
367366

368367
/**

0 commit comments

Comments
 (0)