org.eclipse.jetty.io.ChannelEndPoint Maven / Gradle / Ivy
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.io;
import java.io.EOFException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.SocketChannel;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler;
/**
* Channel End Point.
* Holds the channel and socket for an NIO endpoint.
*/
public class ChannelEndPoint extends AbstractEndPoint implements SocketBased
{
private static final Logger LOG = Log.getLogger(ChannelEndPoint.class);
private final ByteChannel _channel;
private final Socket _socket;
private volatile boolean _ishut;
private volatile boolean _oshut;
public ChannelEndPoint(Scheduler scheduler,SocketChannel channel)
{
super(scheduler,
(InetSocketAddress)channel.socket().getLocalSocketAddress(),
(InetSocketAddress)channel.socket().getRemoteSocketAddress());
_channel = channel;
_socket=channel.socket();
}
@Override
public boolean isOpen()
{
return _channel.isOpen();
}
protected void shutdownInput()
{
LOG.debug("ishut {}", this);
_ishut=true;
if (_oshut)
close();
}
@Override
public void shutdownOutput()
{
LOG.debug("oshut {}", this);
_oshut = true;
if (_channel.isOpen())
{
try
{
if (!_socket.isOutputShutdown())
_socket.shutdownOutput();
}
catch (IOException e)
{
LOG.debug(e);
}
finally
{
if (_ishut)
{
close();
}
}
}
}
@Override
public boolean isOutputShutdown()
{
return _oshut || !_channel.isOpen() || _socket.isOutputShutdown();
}
@Override
public boolean isInputShutdown()
{
return _ishut || !_channel.isOpen() || _socket.isInputShutdown();
}
@Override
public void close()
{
LOG.debug("close {}", this);
try
{
_channel.close();
}
catch (IOException e)
{
LOG.debug(e);
}
finally
{
_ishut=true;
_oshut=true;
}
}
@Override
public int fill(ByteBuffer buffer) throws IOException
{
if (_ishut)
return -1;
int pos=BufferUtil.flipToFill(buffer);
try
{
int filled = _channel.read(buffer);
LOG.debug("filled {} {}", filled, this);
if (filled>0)
notIdle();
else if (filled==-1)
shutdownInput();
return filled;
}
catch(IOException e)
{
LOG.debug(e);
shutdownInput();
return -1;
}
finally
{
BufferUtil.flipToFlush(buffer,pos);
}
}
@Override
public boolean flush(ByteBuffer... buffers) throws IOException
{
int flushed=0;
try
{
if (buffers.length==1)
flushed=_channel.write(buffers[0]);
else if (buffers.length>1 && _channel instanceof GatheringByteChannel)
flushed= (int)((GatheringByteChannel)_channel).write(buffers,0,buffers.length);
else
{
for (ByteBuffer b : buffers)
{
if (b.hasRemaining())
{
int l=_channel.write(b);
if (l>0)
flushed+=l;
if (b.hasRemaining())
break;
}
}
}
LOG.debug("flushed {} {}", flushed, this);
}
catch (IOException e)
{
throw new EofException(e);
}
boolean all_flushed=true;
if (flushed>0)
{
notIdle();
// clear empty buffers to prevent position creeping up the buffer
for (ByteBuffer b : buffers)
{
if (BufferUtil.isEmpty(b))
BufferUtil.clear(b);
else
all_flushed=false;
}
}
return all_flushed;
}
public ByteChannel getChannel()
{
return _channel;
}
@Override
public Object getTransport()
{
return _channel;
}
@Override
public Socket getSocket()
{
return _socket;
}
@Override
protected void onIncompleteFlush()
{
throw new UnsupportedOperationException();
}
@Override
protected boolean needsFill() throws IOException
{
throw new UnsupportedOperationException();
}
}