📄 servicereader.java
字号:
/*
* @<#> ServiceReader.java, version 0.0.1, 1/1/2001
*
* THIS PROGRAM IS FREE SOFTWARE; YOU CAN DISTRIBUTE IT AND/OR
* MODIFY IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE
* AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION.
*
* THIS PROGRAM 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 GENERAL PUBLIC LICENSE FOR MORE DETAILS.
*
* Copyright (c) 2000 Wayne State University. All Rights Reserved.
*/
package naplet.serviceChannel;
import java.io.Reader;
import java.io.IOException;
import naplet.*;
import naplet.serviceChannel.*;
/**
* Piped character-input streams between naplets and priviledged services.
* The pipe is non-symmetric in the sense that a ServiceReader may exist
* alone and can be connected by NapletWriters at different instances.
* By contrast, Java's built-in <code>PipedReader</code> and <code>PipedWriter
* </code> are symmetric and they are dependent on each other.
*
* @version 0.0.1, 1/1/2001
* @author C. Xu (czxu@yahoo.com)
*/
public class ServiceReader extends Reader
{
boolean closedByServer = false;
boolean closedByNaplet = false;
boolean connected = false;
/**
* Non-symmetric piped reader/writer. The ServiceReader is a primary
* party which can exist alone and be connected to secondary parties
* at different time.
*/
NapletWriter source = null;
static final int PIPE_SIZE = 1024;
char buffer[] = new char[PIPE_SIZE];
/**
* The position index pair in the circular buffer at which the
* next character of data will be stored by NapletWriter and read
* by ServiceReader. <code>in<0</code> implies the buffer is empty,
* <code>in==out</code> implies the buffer is full
*/
int in = -1;
int out = 0;
/**
* Creates a <code>ServiceReader</code> with an open input channel.
* A <code>NapletWriter<code> must be connected to it before it
* being used.
*
* @see naplet.ServiceReader#connect(naplet.NapletWriter)
*/
public ServiceReader( )
{
}
/**
* Connect a NapletWriter to the ServiceReader.
* If the sink is already connected, throws an IOException
*/
protected void connect( NapletWriter src )
throws IOException
{
if ( src == null )
{
throw new NullPointerException( );
}
synchronized ( lock )
{
while ( connected )
{
if ( source == null )
{
throw new NapletInternalError(
"Null source in a connected pipe" );
}
if ( source.equals( src ) )
{
closedByNaplet = false;
in = -1;
out = 0;
} // Already connected by itself
else
{
System.out.println( "Already connected by other source" );
try
{
lock.wait( );
}
catch ( InterruptedException ie )
{
throw new java.io.InterruptedIOException( );
}
}
}
source = src;
src.sink = this;
in = -1;
out = 0;
connected = true;
// To release any waiting ServiceReader
lock.notifyAll();
}
}
/**
* Close this piped stream and releases any system resources
* associated with the stream. A question is how to safely close
* the pipe.
*
* @exception IOException if an I/O error occurs.
*/
public void close( )
throws IOException
{
synchronized ( lock )
{
in = -1;
closedByServer = true;
connected = false;
}
}
/**
* Write a char of data to the pipe stream. If the pipe is unconnected,
* an IOException is thrown. This method will block if the pipe is full.
*/
void receive( int c )
throws IOException
{
synchronized ( lock )
{
if ( !connected )
{
if ( closedByServer )
{
throw new IOException( "Service is discontinued" );
}
else
{
throw new IOException( "Pipe not connected" );
}
}
while ( in == out )
{
// Pipe is full, wake up readers and wait for it.
lock.notifyAll( );
try
{
lock.wait( );
}
catch ( InterruptedException ex )
{
throw new java.io.InterruptedIOException( );
}
if ( closedByServer )
{
throw new IOException( "Pipe closed by Server" );
}
}
if ( in < 0 )
{
in = 0;
} // If pipe is empty
buffer[in++] = ( char ) c;
if ( in >= buffer.length )
{
in = 0;
}
lock.notifyAll();
}
}
/**
* Receives data into an array of characters. This method will
* block until some input is available.
*/
void receive( char c[], int off, int len )
throws IOException
{
synchronized ( lock )
{
if ( !connected )
{
if ( closedByServer )
{
throw new IOException( "Service is discontinued" );
}
else
{
throw new IOException( "Pipe not connected" );
}
}
while ( --len >= 0 )
{
while ( in == out )
{
// Pipe is full, wake up readers and wait for it.
lock.notifyAll( );
try
{
lock.wait( );
}
catch ( InterruptedException ex )
{
throw new java.io.InterruptedIOException( );
}
if ( closedByServer )
{
throw new IOException( "Pipe closed by Server" );
}
}
if ( in < 0 )
{
in = 0;
} // If pipe is empty
buffer[in++] = c[off++];
if ( in >= buffer.length )
{
in = 0;
}
}
lock.notifyAll( );
}
}
/**
* Reads the next character of data from this piped stream.
* If no character is available because the end of the stream
* has been reached, the value <code>-1</code> is returned.
*
* This method blocks until input data is available, the end of
* the stream is detected, or an exception is thrown.
*
* If a thread was providing data characters
* to the connected piped writer, but
* the thread is no longer alive, then an
* <code>IOException</code> is thrown.
*
* @return the next character of data, or <code>-1</code>
* if the end of the stream is reached.
* @exception IOException if the pipe is broken.
*/
public int read( )
throws IOException
{
synchronized ( lock )
{
while ( !connected && !closedByNaplet )
{
// If pipe is initially disconnected
try
{
lock.wait( );
}
catch ( InterruptedException ie )
{
throw new java.io.InterruptedIOException( );
}
}
// If pipe is connected, or recently disconnected by Naplet
// Since a recently disconnected pipe may not be empty, it must
// be flushed before it is reset to the initial condition.
try
{
while ( in < 0 )
{
if ( !connected && closedByNaplet )
{
// reset to initial state
closedByNaplet = false;
return -1;
}
lock.notifyAll( );
lock.wait();
} // The pipe is empty
}
catch ( InterruptedException ie )
{
close( );
throw new java.io.InterruptedIOException(
"Service is discontinued" );
}
int ret = buffer[out++];
if ( out >= buffer.length )
{
out = 0;
}
if ( in == out )
{
in = -1;
out = 0;
} // Pipe is now empty
lock.notifyAll( );
return ret;
}
}
/**
* Reads up to <code>len</code> characters of data from this piped
* stream into an array of characters. Less than <code>len</code>
* characters will be read if the end of the data stream is reached.
* This method blocks until at least one character of input is
* available. If a thread was providing data characters to the
* connected piped output, but the thread is no longer alive, then
* an <code>IOException</code> is thrown.
*
* @param cbuf the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of characters read.
* @return the total number of characters read into the buffer, or
* <code>-1</code> if there is no more data because the end
* of the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
public int read( char cbuf[], int off, int len )
throws IOException
{
if ( ( off < 0 ) || ( off >= cbuf.length ) || ( len < 0 )
|| ( ( off + len ) > cbuf.length ) || ( ( off + len ) < 0 ) )
{
throw new IndexOutOfBoundsException( "Index out of boundary" );
}
/* possibly wait on the first character */
int c = read( );
if ( c < 0 )
{
return -1;
}
else if ( len == 0 )
{
return 0;
}
cbuf[off] = ( char ) c;
int rlen = 1;
synchronized ( lock )
{
while ( ( in >= 0 ) && ( --len > 0 ) )
{
cbuf[off + rlen] = buffer[out++];
rlen++;
if ( out >= buffer.length )
{
out = 0;
}
if ( in == out )
{
in = -1;
out = 0;
} // Empty buffer
}
lock.notifyAll( );
}
return rlen;
}
public synchronized boolean ready( )
throws IOException
{
if ( closedByServer )
{
throw new IOException( "Pipe closed" );
}
if ( in < 0 )
{
return false;
}
int count;
if ( out < in )
{
count = in - out;
}
else
{
count = buffer.length - out - in;
}
return ( count > 0 );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -