package edu.uw.zookeeper.netty; import static com.google.common.base.Preconditions.*; import java.util.concurrent.Executor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import io.netty.channel.EventLoopGroup; import com.google.common.base.Optional; import com.google.common.util.concurrent.AbstractIdleService; import edu.uw.zookeeper.common.Factory; import edu.uw.zookeeper.common.ParameterizedFactory; import edu.uw.zookeeper.common.Reference; import edu.uw.zookeeper.common.ServiceMonitor; import edu.uw.zookeeper.common.TimeValue; public class EventLoopGroupService<T extends EventLoopGroup> extends AbstractIdleService implements Reference<T> { public static MonitoredEventLoopGroupFactory factory( ParameterizedFactory<ThreadFactory, EventLoopGroup> eventLoopGroupFactory, ServiceMonitor serviceMonitor) { return MonitoredEventLoopGroupFactory.newInstance(eventLoopGroupFactory, serviceMonitor); } public static class MonitoredEventLoopGroupFactory implements ParameterizedFactory<ThreadFactory, Factory<? extends EventLoopGroup>> { public static MonitoredEventLoopGroupFactory newInstance( ParameterizedFactory<ThreadFactory, EventLoopGroup> eventLoopGroupFactory, ServiceMonitor serviceMonitor) { return new MonitoredEventLoopGroupFactory(eventLoopGroupFactory, serviceMonitor); } protected final ParameterizedFactory<ThreadFactory, EventLoopGroup> eventLoopGroupFactory; protected final ServiceMonitor serviceMonitor; protected MonitoredEventLoopGroupFactory( ParameterizedFactory<ThreadFactory, EventLoopGroup> eventLoopGroupFactory, ServiceMonitor serviceMonitor) { this.eventLoopGroupFactory = eventLoopGroupFactory; this.serviceMonitor = serviceMonitor; } @Override public Reference<? extends EventLoopGroup> get(ThreadFactory threadFactory) { EventLoopGroup group = eventLoopGroupFactory.get(threadFactory); EventLoopGroupService<?> groupService = EventLoopGroupService.newInstance(group); serviceMonitor.add(groupService); return groupService; } } public static <T extends EventLoopGroup> EventLoopGroupService<T> newInstance(T group) { return new EventLoopGroupService<T>(group, Optional.<Executor>absent()); } public static <T extends EventLoopGroup> EventLoopGroupService<T> newInstance(T group, Executor thisExecutor) { return new EventLoopGroupService<T>(group, Optional.<Executor>of(thisExecutor)); } private static final TimeValue DEFAULT_WAIT_INTERVAL = TimeValue.create(30L, TimeUnit.SECONDS); private final Logger logger = LogManager .getLogger(EventLoopGroupService.class); private final Optional<Executor> thisExecutor; private final T group; protected EventLoopGroupService(T group, Optional<Executor> thisExecutor) { this.thisExecutor = thisExecutor; this.group = checkNotNull(group); } @Override protected Executor executor() { if (thisExecutor.isPresent()) { return thisExecutor.get(); } else { return super.executor(); } } public T get() { return group; } @Override protected void startUp() throws Exception { } @Override protected void shutDown() throws Exception { if (! get().isShuttingDown()) { get().shutdownGracefully(); // take the defaults } if (! get().isTerminated()) { if (! get().awaitTermination(DEFAULT_WAIT_INTERVAL.value(), DEFAULT_WAIT_INTERVAL.unit())) { logger.warn("Failed to gracefully terminate EventLoopGroup {}", get()); } } } }