/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty_voltpatches;
import java.lang.reflect.Field;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.AbstractSet;
import java.util.Iterator;
/*
* A set implementation optimized for use in an NIO selector
* which doesn't actually need a set. Taken from netty
* and munged for use in Volt where we don't need to flip.
* Also has the boilerplate code for instrumenting a selector with the key set
*/
public final class NinjaKeySet extends AbstractSet<SelectionKey> {
private SelectionKey[] keys;
private int numKeys;
public NinjaKeySet() {
keys = new SelectionKey[1024];
}
@Override
public boolean add(SelectionKey o) {
if (o == null) {
return false;
}
int size = numKeys;
keys[size ++] = o;
numKeys = size;
if (size == keys.length) {
doubleCapacity();
}
return true;
}
public SelectionKey[] keys() {
return keys;
}
private void doubleCapacity() {
SelectionKey[] newKeys = new SelectionKey[keys.length << 1];
System.arraycopy(keys, 0, newKeys, 0, numKeys);
keys = newKeys;
}
@Override
public void clear() {
//Don't packrat references to keys
for (int ii = 0; ii < numKeys; ii++) {
keys[ii] = null;
}
numKeys = 0;
}
@Override
public boolean remove(Object o) {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<SelectionKey> iterator() {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return numKeys;
}
public static NinjaKeySet instrumentSelector(Selector selector) {
try {
NinjaKeySet selectedKeySet = new NinjaKeySet();
if (!supported) return selectedKeySet;
Class<?> selectorImplClass =
Class.forName("sun.nio.ch.SelectorImpl", false, ClassLoader.getSystemClassLoader());
// Ensure the current selector implementation is what we can instrument.
if (!selectorImplClass.isAssignableFrom(selector.getClass())) {
return selectedKeySet;
}
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
selectedKeysField.setAccessible(true);
publicSelectedKeysField.setAccessible(true);
selectedKeysField.set(selector, selectedKeySet);
publicSelectedKeysField.set(selector, selectedKeySet);
return selectedKeySet;
} catch (Throwable t) {
return null;
}
}
public static final boolean supported;
static {
boolean supportedTemp = false;
try {
Selector s = Selector.open();
try {
Class<?> selectorImplClass =
Class.forName("sun.nio.ch.SelectorImpl", false, ClassLoader.getSystemClassLoader());
// Ensure the current selector implementation is what we can instrument.
if (selectorImplClass.isAssignableFrom(s.getClass())) {
supportedTemp = true;
}
} finally {
s.close();
}
} catch (Throwable t){}
supported = supportedTemp;
}
}