/*
* Copyright (C) 2012-2016 Facebook, Inc.
*
* 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 com.facebook.nifty.server;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.net.ProtocolFamily;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
import java.util.Collections;
import java.util.Set;
/**
* An implementation of {@link SelectorProvider}, which is nifty's way to get sockets
* for the clients that totally ignores all bind and connect requests. Therefore any
* attempt to connect to a server will run into the connection timeout.
*
* This is useful to test the timeout logic in the nifty client.
*/
public class DeafSelectorProvider extends SelectorProvider
{
@Override
public DatagramChannel openDatagramChannel() throws IOException
{
throw new UnsupportedOperationException("openDatagramChannel");
}
@Override
public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException
{
throw new UnsupportedOperationException("openDatagramChannel");
}
@Override
public Pipe openPipe() throws IOException
{
throw new UnsupportedOperationException("openPipe");
}
@Override
public AbstractSelector openSelector() throws IOException
{
return new AbstractSelector(this) {
private final Object lock = new Object();
private final Set<SelectionKey> keys = Sets.newHashSet();
@Override
protected void implCloseSelector() throws IOException
{
}
@Override
protected SelectionKey register(final AbstractSelectableChannel ch, final int ops, final Object att)
{
final AbstractSelector selector = this;
final SelectionKey key = new SelectionKey() {
@Override
public Selector selector()
{
return selector;
}
@Override
public int readyOps()
{
return 0;
}
@Override
public boolean isValid()
{
return true;
}
@Override
public SelectionKey interestOps(int ops)
{
return this;
}
@Override
public int interestOps()
{
return 0;
}
@Override
public SelectableChannel channel()
{
return ch;
}
@Override
public void cancel()
{
keys.remove(this);
}
};
key.interestOps(ops);
key.attach(att);
keys.add(key);
return key;
}
@Override
public Set<SelectionKey> keys()
{
return keys;
}
@Override
public Set<SelectionKey> selectedKeys()
{
return Collections.emptySet();
}
@Override
public int selectNow() throws IOException
{
return 0;
}
@Override
public int select(long timeout) throws IOException
{
synchronized (lock) {
try {
lock.wait(timeout);
return 0;
} catch (InterruptedException e) {
throw new IOException(e);
}
}
}
@Override
public int select() throws IOException
{
synchronized (lock) {
try {
lock.wait();
return 0;
} catch (InterruptedException e) {
throw new IOException(e);
}
}
}
@Override
public Selector wakeup()
{
synchronized (lock) {
lock.notify();
return this;
}
}
};
}
@Override
public ServerSocketChannel openServerSocketChannel() throws IOException
{
return null;
}
@Override
public SocketChannel openSocketChannel() throws IOException
{
return new SocketChannel(this) {
final Socket socket = new Socket();
@Override
public SocketAddress getLocalAddress() throws IOException
{
return null;
}
@Override
public <T> T getOption(SocketOption<T> name) throws IOException
{
return null;
}
@Override
public Set<SocketOption<?>> supportedOptions()
{
return Collections.emptySet();
}
@Override
public SocketChannel bind(SocketAddress local) throws IOException
{
return this;
}
@Override
public <T> SocketChannel setOption(SocketOption<T> name, T value) throws IOException
{
return this;
}
@Override
public SocketChannel shutdownInput() throws IOException
{
return this;
}
@Override
public SocketChannel shutdownOutput() throws IOException
{
return this;
}
@Override
public Socket socket()
{
return socket;
}
@Override
public boolean isConnected()
{
return false;
}
@Override
public boolean isConnectionPending()
{
return false;
}
@Override
public boolean connect(SocketAddress remote) throws IOException
{
return false;
}
@Override
public boolean finishConnect() throws IOException
{
return false;
}
@Override
public SocketAddress getRemoteAddress() throws IOException
{
return null;
}
@Override
public int read(ByteBuffer dst) throws IOException
{
return 0;
}
@Override
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException
{
return 0;
}
@Override
public int write(ByteBuffer src) throws IOException
{
return 0;
}
@Override
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException
{
return 0;
}
@Override
protected void implCloseSelectableChannel() throws IOException
{
}
@Override
protected void implConfigureBlocking(boolean block) throws IOException
{
}
};
}
}