added synchronization in RaceStateChangedListeners with a working copy of listeners to avoid ConcurrentModificationException

Change-Id: I8875826f61f76cd55831e57a55afc043017a1d7c
This commit is contained in:
Axel Uhl committed 2017-06-23 12:08:54 +02:00
1 parent 405348cf6d
commit 66b5a093df
1 file changed
+37 -11
@@ -9,79 +9,105 @@ public class RaceStateChangedListeners extends HashSet<RaceStateChangedListener>
private static final long serialVersionUID = 2028183211903975659L;
@Override
public boolean add(RaceStateChangedListener listener) {
synchronized (this) {
return super.add(listener);
}
}
@Override
public boolean remove(Object o) {
synchronized (this) {
return super.remove(o);
}
}
/**
* Produces a working copy that can safely be iterated over. While producing, holds this objects
* monitor using {@code synchronized(this)} which teams with {@link #add(RaceStateChangedListener)} and
* {@link #remove} which
* also synchronized on {@code this} object.
*/
private Iterable<RaceStateChangedListener> getWorkingCopyOfListeners() {
synchronized (this) {
return new HashSet<>(this);
}
}
@Override
public void onRacingProcedureChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onRacingProcedureChanged(state);
}
}
@Override
public void onStatusChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onStatusChanged(state);
}
}
@Override
public void onStartTimeChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onStartTimeChanged(state);
}
}
@Override
public void onFinishingTimeChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onFinishingTimeChanged(state);
}
}
@Override
public void onFinishedTimeChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onFinishedTimeChanged(state);
}
}
@Override
public void onProtestTimeChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onProtestTimeChanged(state);
}
}
@Override
public void onAdvancePass(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onAdvancePass(state);
}
}
@Override
public void onFinishingPositioningsChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onFinishingPositioningsChanged(state);
}
}
@Override
public void onFinishingPositionsConfirmed(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onFinishingPositionsConfirmed(state);
}
}
@Override
public void onCourseDesignChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onCourseDesignChanged(state);
}
}
@Override
public void onWindFixChanged(ReadonlyRaceState state) {
for (RaceStateChangedListener listener : this) {
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
listener.onWindFixChanged(state);
}
}