mirror of
				https://github.com/IntellectualSites/PlotSquared.git
				synced 2025-11-04 11:13:45 +01:00 
			
		
		
		
	Don't keep PlotFlagUpdateHandlers forever
This allows Plots, FlagContainers and its PlotFlagUpdateHandlers being cleaned up by the GC correctly
This commit is contained in:
		@@ -85,6 +85,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 | 
				
			|||||||
import org.apache.logging.log4j.LogManager;
 | 
					import org.apache.logging.log4j.LogManager;
 | 
				
			||||||
import org.apache.logging.log4j.Logger;
 | 
					import org.apache.logging.log4j.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.lang.ref.Cleaner;
 | 
				
			||||||
import java.text.DecimalFormat;
 | 
					import java.text.DecimalFormat;
 | 
				
			||||||
import java.text.SimpleDateFormat;
 | 
					import java.text.SimpleDateFormat;
 | 
				
			||||||
import java.util.ArrayDeque;
 | 
					import java.util.ArrayDeque;
 | 
				
			||||||
@@ -127,6 +128,7 @@ public class Plot {
 | 
				
			|||||||
    private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + Plot.class.getSimpleName());
 | 
					    private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + Plot.class.getSimpleName());
 | 
				
			||||||
    private static final DecimalFormat FLAG_DECIMAL_FORMAT = new DecimalFormat("0");
 | 
					    private static final DecimalFormat FLAG_DECIMAL_FORMAT = new DecimalFormat("0");
 | 
				
			||||||
    private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build();
 | 
					    private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build();
 | 
				
			||||||
 | 
					    private static final Cleaner CLEANER = Cleaner.create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static Set<Plot> connected_cache;
 | 
					    static Set<Plot> connected_cache;
 | 
				
			||||||
    static Set<CuboidRegion> regions_cache;
 | 
					    static Set<CuboidRegion> regions_cache;
 | 
				
			||||||
@@ -256,6 +258,9 @@ public class Plot {
 | 
				
			|||||||
        this.temp = temp;
 | 
					        this.temp = temp;
 | 
				
			||||||
        this.flagContainer.setParentContainer(area.getFlagContainer());
 | 
					        this.flagContainer.setParentContainer(area.getFlagContainer());
 | 
				
			||||||
        PlotSquared.platform().injector().injectMembers(this);
 | 
					        PlotSquared.platform().injector().injectMembers(this);
 | 
				
			||||||
 | 
					        // This is needed, because otherwise the Plot, the FlagContainer and its
 | 
				
			||||||
 | 
					        // `this::handleUnknown` PlotFlagUpdateHandler won't get cleaned up ever
 | 
				
			||||||
 | 
					        CLEANER.register(this, this.flagContainer.createCleanupHook());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,14 +27,15 @@ package com.plotsquared.core.plot.flag;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.google.common.base.Preconditions;
 | 
					import com.google.common.base.Preconditions;
 | 
				
			||||||
import com.google.common.collect.ImmutableMap;
 | 
					import com.google.common.collect.ImmutableMap;
 | 
				
			||||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
					 | 
				
			||||||
import org.checkerframework.checker.nullness.qual.Nullable;
 | 
					 | 
				
			||||||
import org.apache.logging.log4j.LogManager;
 | 
					import org.apache.logging.log4j.LogManager;
 | 
				
			||||||
import org.apache.logging.log4j.Logger;
 | 
					import org.apache.logging.log4j.Logger;
 | 
				
			||||||
 | 
					import org.checkerframework.checker.nullness.qual.NonNull;
 | 
				
			||||||
 | 
					import org.checkerframework.checker.nullness.qual.Nullable;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					import java.util.HashSet;
 | 
				
			||||||
import java.util.Locale;
 | 
					import java.util.Locale;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
@@ -49,8 +50,9 @@ public class FlagContainer {
 | 
				
			|||||||
    private final Map<String, String> unknownFlags = new HashMap<>();
 | 
					    private final Map<String, String> unknownFlags = new HashMap<>();
 | 
				
			||||||
    private final Map<Class<?>, PlotFlag<?, ?>> flagMap = new HashMap<>();
 | 
					    private final Map<Class<?>, PlotFlag<?, ?>> flagMap = new HashMap<>();
 | 
				
			||||||
    private final PlotFlagUpdateHandler plotFlagUpdateHandler;
 | 
					    private final PlotFlagUpdateHandler plotFlagUpdateHandler;
 | 
				
			||||||
    private final Collection<PlotFlagUpdateHandler> updateSubscribers = new ArrayList<>();
 | 
					    private final Collection<PlotFlagUpdateHandler> updateSubscribers = new HashSet<>();
 | 
				
			||||||
    private FlagContainer parentContainer;
 | 
					    private FlagContainer parentContainer;
 | 
				
			||||||
 | 
					    private final PlotFlagUpdateHandler unknownsRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Construct a new flag container with an optional parent container and update handler.
 | 
					     * Construct a new flag container with an optional parent container and update handler.
 | 
				
			||||||
@@ -71,7 +73,10 @@ public class FlagContainer {
 | 
				
			|||||||
        this.parentContainer = parentContainer;
 | 
					        this.parentContainer = parentContainer;
 | 
				
			||||||
        this.plotFlagUpdateHandler = plotFlagUpdateHandler;
 | 
					        this.plotFlagUpdateHandler = plotFlagUpdateHandler;
 | 
				
			||||||
        if (!(this instanceof GlobalFlagContainer)) {
 | 
					        if (!(this instanceof GlobalFlagContainer)) {
 | 
				
			||||||
            GlobalFlagContainer.getInstance().subscribe(this::handleUnknowns);
 | 
					            this.unknownsRef = this::handleUnknowns;
 | 
				
			||||||
 | 
					            GlobalFlagContainer.getInstance().subscribe(this.unknownsRef);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this.unknownsRef = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -336,6 +341,23 @@ public class FlagContainer {
 | 
				
			|||||||
        this.unknownFlags.put(flagName.toLowerCase(Locale.ENGLISH), value);
 | 
					        this.unknownFlags.put(flagName.toLowerCase(Locale.ENGLISH), value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates a cleanup hook that is meant to run once this FlagContainer isn't needed anymore.
 | 
				
			||||||
 | 
					     * This is to prevent memory leaks. This method is not part of the API.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return a new Runnable that cleans up once the FlagContainer isn't needed anymore.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @ApiStatus.Internal
 | 
				
			||||||
 | 
					    public Runnable createCleanupHook() {
 | 
				
			||||||
 | 
					        return () -> GlobalFlagContainer.getInstance().unsubscribe(unknownsRef);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void unsubscribe(final @Nullable PlotFlagUpdateHandler updateHandler) {
 | 
				
			||||||
 | 
					        if (updateHandler != null) {
 | 
				
			||||||
 | 
					            this.updateSubscribers.remove(updateHandler);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean equals(final Object o) {
 | 
					    public boolean equals(final Object o) {
 | 
				
			||||||
        if (o == this) {
 | 
					        if (o == this) {
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user