diff --git a/src/main/java/org/xbib/event/loop/nio/NioEventLoop.java b/src/main/java/org/xbib/event/loop/nio/NioEventLoop.java index e40792c..f0750ae 100644 --- a/src/main/java/org/xbib/event/loop/nio/NioEventLoop.java +++ b/src/main/java/org/xbib/event/loop/nio/NioEventLoop.java @@ -8,6 +8,7 @@ import org.xbib.event.loop.SingleThreadEventLoop; import org.xbib.event.util.IntSupplier; import java.io.IOException; +import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectableChannel; @@ -15,14 +16,8 @@ import java.nio.channels.Selector; import java.nio.channels.SelectionKey; import java.nio.channels.spi.SelectorProvider; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; import java.util.Objects; import java.util.Queue; -import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; @@ -155,8 +150,7 @@ public final class NioEventLoop extends SingleThreadEventLoop { } // ensure the current selector implementation is what we can instrument. - if (maybeSelectorImplClass == null || - !maybeSelectorImplClass.isAssignableFrom(unwrappedSelector.getClass())) { + if (maybeSelectorImplClass == null || !maybeSelectorImplClass.isAssignableFrom(unwrappedSelector.getClass())) { return new SelectorTuple(unwrappedSelector); } @@ -167,40 +161,19 @@ public final class NioEventLoop extends SingleThreadEventLoop { try { Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); - - if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) { - // Let us try to use sun.misc.Unsafe to replace the SelectionKeySet. - // This allows us to also do this in Java9+ without any extra flags. - long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField); - long publicSelectedKeysFieldOffset = - PlatformDependent.objectFieldOffset(publicSelectedKeysField); - - if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) { - PlatformDependent.putObject( - unwrappedSelector, selectedKeysFieldOffset, selectedKeySet); - PlatformDependent.putObject( - unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet); - return null; - } - // We could not retrieve the offset, lets try reflection as last-resort. - } - - Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true); + Throwable cause = trySetAccessible(selectedKeysField, true); if (cause != null) { - return cause; + maybeException = cause; } - cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true); + cause = trySetAccessible(publicSelectedKeysField, true); if (cause != null) { - return cause; + maybeException = cause; } - selectedKeysField.set(unwrappedSelector, selectedKeySet); publicSelectedKeysField.set(unwrappedSelector, selectedKeySet); - return null; } catch (NoSuchFieldException | IllegalAccessException e) { maybeException = e; } - if (maybeException instanceof Exception) { selectedKeys = null; Exception e = (Exception) maybeException; @@ -763,4 +736,40 @@ public final class NioEventLoop extends SingleThreadEventLoop { logger.log(Level.WARNING, "Failed to update SelectionKeys.", t); } } + + private static Throwable trySetAccessible(AccessibleObject object, boolean checkAccessible) { + if (checkAccessible && !isExplicitTryReflectionSetAccessible()) { + return new UnsupportedOperationException("Reflective setAccessible(true) disabled"); + } + try { + object.setAccessible(true); + return null; + } catch (SecurityException e) { + return e; + } + } + private static boolean isExplicitTryReflectionSetAccessible() { + // we disable reflective access + boolean defaultValue = javaVersion() < 9 || System.getProperties().containsKey("org.graalvm.nativeimage.imagecode"); + return Boolean.parseBoolean(System.getProperties().getProperty("io.netty.tryReflectionSetAccessible", + Boolean.toString(defaultValue))); + } + + private static int javaVersion() { + return majorVersion(System.getProperties().getProperty("java.specification.version", "1.6")); + } + + private static int majorVersion(String javaSpecVersion) { + final String[] components = javaSpecVersion.split("\\."); + final int[] version = new int[components.length]; + for (int i = 0; i < components.length; i++) { + version[i] = Integer.parseInt(components[i]); + } + if (version[0] == 1) { + assert version[1] >= 6; + return version[1]; + } else { + return version[0]; + } + } }