/* * Copyright 2015 Odnoklassniki Ltd, Mail.Ru Group * * Licensed 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 one.nio.net; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.util.Collections; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; final class JavaSelector extends Selector { private final java.nio.channels.Selector impl; private final ConcurrentLinkedQueue<Session> pendingSessions; JavaSelector() throws IOException { this.impl = java.nio.channels.Selector.open(); this.pendingSessions = new ConcurrentLinkedQueue<Session>(); } @Override public final int size() { return impl.keys().size(); } @Override public boolean isOpen() { return impl.isOpen(); } @Override public final void close() { try { impl.close(); } catch (IOException e) { // Ignore } } @Override public final void register(Session session) { session.selector = this; pendingSessions.add(session); impl.wakeup(); } @Override public final void unregister(Session session) { ((JavaSocket) session.socket).ch.keyFor(impl).cancel(); } @Override public final void listen(Session session, int events) { ((JavaSocket) session.socket).ch.keyFor(impl).interestOps(events); impl.wakeup(); } @Override public final Iterator<Session> iterator() { return iteratorFor(impl.keys()); } @Override public final Iterator<Session> select() { try { do { registerPendingSessions(); } while (impl.select() == 0); } catch (Exception e) { return iteratorFor(Collections.<SelectionKey>emptySet()); } Set<SelectionKey> selectedKeys = impl.selectedKeys(); Iterator<Session> result = iteratorFor(selectedKeys); selectedKeys.clear(); return result; } private void registerPendingSessions() throws ClosedChannelException { for (Session session; (session = pendingSessions.poll()) != null; ) { ((JavaSocket) session.socket).ch.register(impl, session.eventsToListen, session); } } private static Iterator<Session> iteratorFor(Set<SelectionKey> keys) { final Session[] sessions = new Session[keys.size() + 1]; int i = 0; for (SelectionKey key : keys) { if (key.isValid()) { Session session = (Session) key.attachment(); session.events = key.readyOps(); sessions[i++] = session; } } return new Iterator<Session>() { private int next = 0; @Override public final boolean hasNext() { return sessions[next] != null; } @Override public final Session next() { return sessions[next++]; } @Override public final void remove() { throw new UnsupportedOperationException(); } }; } }