/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.jacorb.orb.iiop;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Kevin Conner (Kevin.Conner@arjuna.com)
*/
class IIOPLoopbackInputStream extends InputStream
{
private static final int BUF_SIZE = 2048 ;
private final byte[] buf = new byte[BUF_SIZE] ;
private boolean connected ;
private boolean closed ;
private int writerIndex ;
private int readerIndex ;
public IIOPLoopbackInputStream()
{
super();
}
public IIOPLoopbackInputStream(final IIOPLoopbackOutputStream los)
throws IOException
{
this();
connect(los) ;
}
synchronized void connect(final IIOPLoopbackOutputStream los)
throws IOException
{
if (connected)
{
throw new IOException("Alread connected") ;
}
connected = true ;
los.connect(this) ;
}
public synchronized int read()
throws IOException
{
checkConnect() ;
return internalRead() ;
}
public synchronized int read(final byte[] b, final int off, final int len)
throws IOException
{
checkConnect() ;
checkBuffer(b, off, len) ;
int returnCount = 0 ;
while(returnCount < len)
{
final int val = internalRead() ;
if (val == -1)
{
break ;
}
b[off + returnCount] = (byte)val ;
returnCount++ ;
}
return (returnCount > 0 ? returnCount : -1) ;
}
public synchronized int available()
throws IOException
{
checkConnect() ;
if (writerIndex > readerIndex)
{
return (writerIndex - readerIndex) ;
}
else if (readerIndex > writerIndex)
{
return BUF_SIZE + writerIndex - readerIndex ;
}
else
{
checkClosed() ;
return 0 ;
}
}
public synchronized void close()
throws IOException
{
checkConnect() ;
closed = true ;
notifyAll() ;
}
synchronized void writerClose()
throws IOException
{
checkConnect() ;
closed = true ;
notifyAll() ;
}
synchronized void writeIntoBuffer(final int b)
throws IOException
{
checkConnect() ;
internalWrite((byte)b) ;
}
synchronized void writeIntoBuffer(final byte[] b, final int off, final int len)
throws IOException
{
checkConnect() ;
checkBuffer(b, off, len) ;
for(int count= 0 ; count < len ; count++)
{
internalWrite(b[off + count]) ;
}
}
private int internalRead()
{
while(bufferEmpty())
{
if (closed)
{
return -1 ;
}
try
{
wait() ;
}
catch (final InterruptedException ie) {} // Ignore
}
final boolean shouldNotify = bufferFull() ;
final int val = buf[readerIndex] & 0xff ;
readerIndex = nextIndex(readerIndex) ;
if (shouldNotify)
{
notifyAll() ;
}
return val ;
}
private void internalWrite(final byte b)
throws IOException
{
while(bufferFull())
{
checkClosed() ;
try
{
wait() ;
}
catch (final InterruptedException ie) {} // Ignore
}
checkClosed() ;
final boolean shouldNotify = bufferEmpty() ;
buf[writerIndex] = b ;
writerIndex = nextIndex(writerIndex) ;
if (shouldNotify)
{
notifyAll() ;
}
}
private void checkConnect()
throws IOException
{
if (!connected)
{
throw new IOException("IIOPLoopbackInputStream not connected") ;
}
}
private void checkClosed()
throws IOException
{
if (closed)
{
throw new IOException("IIOPLoopbackInputStream closed") ;
}
}
private void checkBuffer(final byte[] b, final int off, final int len)
{
if (b == null)
{
throw new NullPointerException("Null buffer") ;
}
final int bufLen = b.length ;
if ((off < 0) || (off >= bufLen) || (len < 0) || (len > bufLen) || (off + len > bufLen))
{
throw new IndexOutOfBoundsException("Invalid offset/length") ;
}
}
private boolean bufferEmpty()
{
return (readerIndex == writerIndex) ;
}
private boolean bufferFull()
{
return (readerIndex == nextIndex(writerIndex)) ;
}
private int nextIndex(final int index)
{
final int nextIndex = index+1 ;
return (nextIndex == BUF_SIZE ? 0 : nextIndex) ;
}
}