package org.sef4j.core.util; import java.util.HashSet; import java.util.Set; import java.util.function.Supplier; import org.sef4j.core.util.IStartableSupport.StartStopMethods; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * basic helper for Handle Generator + Set<> * this class can optionnally delegate to IStartableSupport start() on first handle creation, and stop() on last handle deletion */ public class HandleSet { private static final Logger LOG = LoggerFactory.getLogger(HandleSet.class); private HandleGenerator handleGenerator = new HandleGenerator(); private Set<Handle> handles = new HashSet<Handle>(); private IStartableSupport startableCallback; // ------------------------------------------------------------------------ public HandleSet(IStartableSupport startableCallback) { this.startableCallback = startableCallback; } public HandleSet(Supplier<Boolean> isStarted, Runnable startCallback, Runnable stopCallback) { this(new StartStopMethods(isStarted, startCallback, stopCallback)); } // ------------------------------------------------------------------------ public Handle addGenerated() { Handle res = handleGenerator.generate(); boolean needStart; synchronized(handles) { needStart = handles.isEmpty(); handles.add(res); } if (needStart) { doStart(); } return res; } /** @return remaining handle count */ public void remove(Handle handle) { boolean needStop; synchronized(handles) { boolean removed = handles.remove(handle); needStop = removed && handles.isEmpty(); } if (needStop) { doStop(); } } public void clear() { boolean needStop; synchronized(handles) { needStop = ! handles.isEmpty(); handles.clear(); } if (needStop) { doStop(); } } protected void doStart() { if (startableCallback != null) { try { startableCallback.start(); } catch(Exception ex) { // should not occur... if start() is unsafe => should manage retryal by underlying object + use async thread // => remove handle + rethrow?! .. or catch exception LOG.error("Failed to start() on first handle acqquired: " + startableCallback + " ... ignore, no rethrow?!", ex); } } } protected void doStop() { if (startableCallback != null) { try { startableCallback.stop(); } catch(Exception ex) { // should not occur... if start() is unsafe => should manage retryal by underlying object + use async thread // => remove handle + rethrow?! .. or catch exception LOG.error("Failed to stop() on last handle release: " + startableCallback + " ... ignore, no rethrow?!", ex); } } } }