All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minestom.server.event.EventNodeLazyImpl Maven / Gradle / Ivy

There is a newer version: 7320437640
Show newest version
package net.minestom.server.event;

import org.jetbrains.annotations.NotNull;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.function.Consumer;

final class EventNodeLazyImpl extends EventNodeImpl {
    private static final VarHandle MAPPED;

    static {
        try {
            MAPPED = MethodHandles.lookup().findVarHandle(EventNodeLazyImpl.class, "mapped", boolean.class);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

    private final EventNodeImpl holder;
    private final WeakReference owner;
    @SuppressWarnings("unused")
    private boolean mapped;

    EventNodeLazyImpl(@NotNull EventNodeImpl holder,
                      @NotNull Object owner, @NotNull EventFilter filter) {
        super(owner.toString(), filter, null);
        this.holder = holder;
        this.owner = new WeakReference<>(owner);
    }

    @Override
    public @NotNull EventNode addChild(@NotNull EventNode child) {
        ensureMap();
        return super.addChild(child);
    }

    @Override
    public @NotNull EventNode addListener(@NotNull EventListener listener) {
        ensureMap();
        return super.addListener(listener);
    }

    @Override
    public @NotNull  EventNode addListener(@NotNull Class eventType, @NotNull Consumer<@NotNull E1> listener) {
        ensureMap();
        return super.addListener(eventType, listener);
    }

    @Override
    public @NotNull  EventNode map(@NotNull H value, @NotNull EventFilter filter) {
        final Object owner = retrieveOwner();
        if (owner != value) {
            throw new IllegalArgumentException("Cannot map an object to an already mapped node.");
        }
        return (EventNode) this;
    }

    @Override
    public void register(@NotNull EventBinding binding) {
        ensureMap();
        super.register(binding);
    }

    private void ensureMap() {
        if (MAPPED.compareAndSet(this, false, true)) {
            synchronized (GLOBAL_CHILD_LOCK) {
                Map registered = new WeakHashMap<>(this.holder.registeredMappedNode);
                var previous = registered.putIfAbsent(retrieveOwner(),
                        new WeakReference<>(EventNodeLazyImpl.class.cast(this)));
                this.holder.registeredMappedNode = registered;
                if (previous == null) invalidateEventsFor(holder);
            }
        }
    }

    private Object retrieveOwner() {
        final Object owner = this.owner.get();
        if (owner == null) {
            throw new IllegalStateException("Node handle is null. Be sure to never cache a local node.");
        }
        return owner;
    }
}