package com.lambdaworks.redis; import java.lang.reflect.Constructor; import java.net.SocketAddress; import java.util.concurrent.Callable; import java.util.concurrent.ThreadFactory; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.internal.LettuceClassUtils; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; /** * Wraps and provides Epoll classes. This is to protect the user from {@link ClassNotFoundException}'s caused by the absence of * the {@literal netty-transport-native-epoll} library during runtime. Internal API. * * @author Mark Paluch */ public class EpollProvider { protected static final InternalLogger logger = InternalLoggerFactory.getInstance(EpollProvider.class); public static final Class<EventLoopGroup> epollEventLoopGroupClass; public static final Class<Channel> epollDomainSocketChannelClass; public static final Class<SocketAddress> domainSocketAddressClass; static { epollEventLoopGroupClass = getClass("io.netty.channel.epoll.EpollEventLoopGroup"); epollDomainSocketChannelClass = getClass("io.netty.channel.epoll.EpollDomainSocketChannel"); domainSocketAddressClass = getClass("io.netty.channel.unix.DomainSocketAddress"); if (epollDomainSocketChannelClass == null || epollEventLoopGroupClass == null) { logger.debug("Starting without optional Epoll library"); } } /** * Try to load class {@literal className}. * * @param className * @param <T> Expected return type for casting. * @return instance of {@literal className} or null */ private static <T> Class<T> getClass(String className) { try { return (Class) LettuceClassUtils.forName(className); } catch (ClassNotFoundException e) { logger.debug("Cannot load class " + className, e); } return null; } /** * Check whether the Epoll library is available on the class path. * * @throws IllegalStateException if the {@literal netty-transport-native-epoll} library is not available * */ static void checkForEpollLibrary() { LettuceAssert.assertState(domainSocketAddressClass != null && epollDomainSocketChannelClass != null, "Cannot connect using sockets without the optional netty-transport-native-epoll library on the class path"); } static SocketAddress newSocketAddress(String socketPath) { return get(() -> { Constructor<SocketAddress> constructor = domainSocketAddressClass.getConstructor(String.class); return constructor.newInstance(socketPath); }); } public static EventLoopGroup newEventLoopGroup(int nThreads, ThreadFactory threadFactory) { try { Constructor<EventLoopGroup> constructor = epollEventLoopGroupClass .getConstructor(Integer.TYPE, ThreadFactory.class); return constructor.newInstance(nThreads, threadFactory); } catch (Exception e) { throw new IllegalStateException(e); } } private static <V> V get(Callable<V> supplier) { try { return supplier.call(); } catch (Exception e) { throw new IllegalStateException(e); } } }