fix exceptions when reloading the server (#1689)

This commit is contained in:
Pasqual Koschmieder 2022-06-30 01:08:14 +02:00 committed by GitHub
parent a2bf242097
commit 4f18d37832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 130 additions and 46 deletions

View File

@ -4,10 +4,14 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
@SuppressWarnings("NullableProblems")
final class ListeningList implements List<Object> {
@ -25,17 +29,23 @@ final class ListeningList implements List<Object> {
@Override
public int size() {
return this.original.size();
synchronized (this) {
return this.original.size();
}
}
@Override
public boolean isEmpty() {
return this.original.isEmpty();
synchronized (this) {
return this.original.isEmpty();
}
}
@Override
public boolean contains(Object o) {
return this.original.contains(o);
synchronized (this) {
return this.original.contains(o);
}
}
@Override
@ -43,81 +53,113 @@ final class ListeningList implements List<Object> {
return this.original.iterator();
}
@Override
public void forEach(Consumer<? super Object> action) {
synchronized (this) {
this.original.forEach(action);
}
}
@Override
public Object[] toArray() {
return this.original.toArray();
synchronized (this) {
return this.original.toArray();
}
}
@Override
public <T> T[] toArray(T[] a) {
//noinspection SuspiciousToArrayCall
return this.original.toArray(a);
synchronized (this) {
//noinspection SuspiciousToArrayCall
return this.original.toArray(a);
}
}
@Override
public boolean add(Object o) {
this.processInsert(o);
return this.original.add(o);
synchronized (this) {
this.processInsert(o);
return this.original.add(o);
}
}
@Override
public void add(int index, Object element) {
this.processInsert(element);
this.original.add(index, element);
synchronized (this) {
this.processInsert(element);
this.original.add(index, element);
}
}
@Override
public boolean addAll(Collection<?> c) {
c.forEach(this::processInsert);
return this.original.addAll(c);
synchronized (this) {
c.forEach(this::processInsert);
return this.original.addAll(c);
}
}
@Override
public boolean addAll(int index, Collection<?> c) {
c.forEach(this::processInsert);
return this.original.addAll(index, c);
synchronized (this) {
c.forEach(this::processInsert);
return this.original.addAll(index, c);
}
}
@Override
public Object set(int index, Object element) {
this.processInsert(element);
synchronized (this) {
this.processInsert(element);
Object prev = this.original.set(index, element);
this.processRemove(prev);
Object prev = this.original.set(index, element);
this.processRemove(prev);
return prev;
return prev;
}
}
@Override
public boolean remove(Object o) {
if (this.original.remove(o)) {
this.processRemove(o);
return true;
}
synchronized (this) {
if (this.original.remove(o)) {
this.processRemove(o);
return true;
}
return false;
return false;
}
}
@Override
public boolean containsAll(Collection<?> c) {
return this.original.containsAll(c);
synchronized (this) {
//noinspection SlowListContainsAll
return this.original.containsAll(c);
}
}
@Override
public Object remove(int index) {
Object removed = this.original.remove(index);
this.processRemove(removed);
return removed;
synchronized (this) {
Object removed = this.original.remove(index);
this.processRemove(removed);
return removed;
}
}
@Override
public int indexOf(Object o) {
return this.original.indexOf(o);
synchronized (this) {
return this.original.indexOf(o);
}
}
@Override
public int lastIndexOf(Object o) {
return this.original.lastIndexOf(o);
synchronized (this) {
return this.original.lastIndexOf(o);
}
}
@Override
@ -132,33 +174,77 @@ final class ListeningList implements List<Object> {
@Override
public List<Object> subList(int fromIndex, int toIndex) {
return this.original.subList(fromIndex, toIndex);
synchronized (this) {
return this.original.subList(fromIndex, toIndex);
}
}
@Override
public boolean removeAll(Collection<?> c) {
c.forEach(element -> {
if (this.original.contains(element)) {
this.processRemove(element);
}
});
return this.original.removeAll(c);
synchronized (this) {
c.forEach(element -> {
if (this.original.contains(element)) {
this.processRemove(element);
}
});
return this.original.removeAll(c);
}
}
@Override
public boolean removeIf(Predicate<? super Object> filter) {
synchronized (this) {
return this.original.removeIf(object -> {
boolean shouldRemove = filter.test(object);
if (shouldRemove) {
this.processRemove(object);
}
return shouldRemove;
});
}
}
@Override
public boolean retainAll(Collection<?> c) {
return this.original.retainAll(c);
synchronized (this) {
return this.original.retainAll(c);
}
}
@Override
public void replaceAll(UnaryOperator<Object> operator) {
synchronized (this) {
this.original.replaceAll(value -> {
Object newValue = operator.apply(value);
if (newValue != value) {
this.processRemove(value);
this.processInsert(newValue);
}
return newValue;
});
}
}
@Override
public void sort(Comparator<? super Object> c) {
synchronized (this) {
this.original.sort(c);
}
}
@Override
public void clear() {
this.original.forEach(this::processRemove);
this.original.clear();
synchronized (this) {
this.original.forEach(this::processRemove);
this.original.clear();
}
}
@Override
public Object get(int index) {
return this.original.get(index);
synchronized (this) {
return this.original.get(index);
}
}
private void processInsert(Object element) {

View File

@ -26,7 +26,6 @@ import io.netty.channel.ChannelFuture;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -205,7 +204,7 @@ public class NetworkManagerInjector implements ChannelListener {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (value) {
// override the list field with our list
List<Object> newList = Collections.synchronizedList(new ListeningList(value, this.pipelineInjectorHandler));
List<Object> newList = new ListeningList(value, this.pipelineInjectorHandler);
accessor.set(serverConnection, newList);
}
}
@ -215,7 +214,6 @@ public class NetworkManagerInjector implements ChannelListener {
this.injected = true;
}
@SuppressWarnings("unchecked")
public void close() {
if (this.closed || !this.injected) {
return;
@ -229,10 +227,10 @@ public class NetworkManagerInjector implements ChannelListener {
for (Pair<Object, FieldAccessor> list : this.overriddenLists) {
// get the value of the field we've overridden, if it is no longer a ListeningList someone probably jumped in
// and replaced the field himself - we are out safely as the other person needs to clean the mess...
List<Object> value = (List<Object>) list.getSecond().get(list.getFirst());
if (value instanceof ListeningList) {
Object currentFieldValue = list.getSecond().get(list.getFirst());
if (currentFieldValue instanceof ListeningList) {
// just reset to the list we wrapped originally
ListeningList ourList = (ListeningList) value;
ListeningList ourList = (ListeningList) currentFieldValue;
List<Object> original = ourList.getOriginal();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (original) {