package xapi.event.impl; import xapi.annotation.inject.SingletonDefault; import xapi.event.api.EventHandler; import xapi.event.api.EventHandlerWithIdentity; import xapi.event.api.EventService; import xapi.event.api.IsEvent; import xapi.except.NotImplemented; import xapi.fu.X_Fu; import xapi.log.X_Log; import xapi.util.X_Debug; import xapi.util.X_Util; import java.io.IOException; import java.io.Serializable; /** * Created by James X. Nelson (james @wetheinter.net) on 7/16/16. */ @SingletonDefault(implFor = EventService.class) public class AbstractEventService implements EventService { private boolean warn = true; @Override public <Source, Event extends IsEvent<Source>> EventHandler<Source, Event> normalizeHandler(EventHandler<Source, Event> handler) { try { // in case our handler is a lambda, we want to create an equals-safe implementation... if (isLambda(handler)) { Serializable lambdaBytes = extractIdentifier(handler); return new EventHandlerWithIdentity<>(lambdaBytes, handler); } } catch (Exception e) { warnOnce(handler); if (shouldDebug()) { X_Debug.maybeRethrow(e); } else { X_Util.maybeRethrow(e); } } // no luck... just return the handler unmodified return handler; } private <Source, Event extends IsEvent<Source>> void warnOnce(EventHandler<Source, Event> handler) { if (warn) { warn = false; X_Log.warn(getClass(), "Unable to serialize lambda-typed event handler", handler, ".\nMost likely this lambda is attached to a non-serializable instance, or closes over non-serializable " + "values.\nAs such, identity-semantics cannot be ensured, and you will be unable to remove this handler " + "by calling EventManager.removeHandler\n(instead, you MUST retain the RemovalHandler returned by " + "EventManager.addHandler, or else your application may leak memory).\nAlternatively, use an EventHandler " + "which provides equality semantics (EventHandlerWithIdentity)."); } } protected boolean shouldDebug() { return false; } protected <Source, Event extends IsEvent<Source>> Serializable extractIdentifier(EventHandler<Source, Event> handler) throws IOException { String name = X_Fu.getLambdaMethodName(handler); if (name != null) { return name; } return backupExtractIdentifier(handler); } protected <Source, Event extends IsEvent<Source>> Serializable backupExtractIdentifier(EventHandler<Source, Event> handler) throws IOException { throw new NotImplemented(getClass() + " must implement backupExtractIdentifier; could not get id for "+ handler); } public boolean isLambda(EventHandler<?, ?> handler) { return X_Fu.isLambda(handler); } }