CS 596 Client-Server Programming
State Example
[To Lecture Notes Index]
San Diego State University -- This page last updated April 30, 1996

Contents of State Example Lecture
- Using States - SPOP Example
- The Big Picture
- The classes
- SPOPServer
- SPOPHandler
- SPOP_Command
- SPOP_Response
- SPOPOutputStream
- SPOPInputStream
- SPOPState
- NoAuth
- HaveUser
Simple Post Office Protocol (SPOP)
Command have the same functionality as POP but are limited to the following:
- USER <username>
- PASS <password>
- LIST
- RETR <message number>
- QUIT
Will assume that <username>, <password>, <message number> are
strings with no spaces.
All commands end with crlf
Responses are as in POP3
See notes Parsing and State machines for details on states and commands
Naming the states
We will use the following names for the states:
- NoAuth
- HaveUser
- Process
- Invalid
- Quit
Classes Used
SPOPState
- Parent for all state classes
NoAuth, HaveUser, Process, Invalid, Quit
- State classes
SPOPHandler
- Gets messages and sends them to current state
SPOP_Command, SPOP_Response
- Internal representation of client commands and server responses
SPOPServer
- Network interface
SPOPInputStream, SPOPOutputStream
Please note the following code is conceptual
import java.net.*;
import java.io.*;
import sdsu.io.ASCIIInputStream;
class SPOPServer
{
static int portNumber = 4444;
public static void main(String args[])
{
ServerSocket serverSocket;
serverSocket = serverSocketOn( portNumber );
Socket clientSocket = null;
InputStream fromClient;
OutputStream toClient;
while ( true )
{
clientSocket = acceptClientRequestOn( serverSocket );
fromClient = inputStreamFromClient( clientSocket );
toClient = outputStreamToClient( clientSocket );
processClientRequest( fromClient, toClient );
}
}
protected static ServerSocket serverSocketOn( int portNumber )
{
ServerSocket serverSocket = null;
try
{
serverSocket = new ServerSocket( portNumber );
}
catch (IOException e)
{
System.out.println("Could not listen on port: " + ", " + e);
System.exit(1);
}
return serverSocket;
}
protected static Socket acceptClientRequestOn( ServerSocket server)
{
Socket clientSocket = null;
try
{
clientSocket = server.accept();
}
catch (IOException e)
{
System.out.println("Accept failed: " + ", " + e);
System.exit(1);
}
return clientSocket;
}
protected static InputStream inputStreamFromClient( Socket client )
{
InputStream inputSocketStream;
BufferedInputStream bufferedInputSocketStream = null;
try
{
inputSocketStream = client.getInputStream();
bufferedInputSocketStream = new BufferedInputStream(
inputSocketStream );
}
catch ( IOException e)
{
// What to do here?
}
return bufferedInputSocketStream;
}
protected static OutputStream outputStreamToClient( Socket client )
{
OutputStream outputSocketStream;
BufferedOutputStream bufferedOutputSocketStream = null;
try
{
outputSocketStream = client.getOutputStream();
bufferedOutputSocketStream = new BufferedOutputStream(
outputSocketStream, 1024 );
}
catch ( IOException e)
{
// What to do here?
}
return bufferedOutputSocketStream;
}
protected static void processClientRequest( InputStream in,
OutputStream out )
{
SPOPHandler mail = new SPOPHandler( in, out);
Thread serverThread = new Thread( mail, "Mail Server" );
serverThread.start();
}
public class SPOPHandler
{
protected SPOPState currentState = new NoAuth( );
protected SPOPInputStream cin;
protected SPOPOutputStream cout;
public SPOPHandler( InputStream in, OutputStream out )
{
cin = new SPOPInputStream( cin );
cout = new SPOPOutputStream( cout );
}
public void run( )
{
while !( currentState instanceof Quit )
{
SPOP_Command clientRequest;
SPOP_Response serverResponse;
cin.read( clientRequest );
currentState = getServerResponse( clientRequest ,
serverResponse );
cout.write( serverResponse );
}
// In quit state, close connection
cin.close;
cout.close;
}
protected SPOPState getServerResponse(
SPOP_Command request,
SPOP_Response serverResponse)
{
SPOPState nextState;
String command = request.command();
if ( command.compareTo( "USER" ) == 0 )
nextState = currentState.USER( request, serverResponse );
else if ( command.compareTo( "PASS" ) == 0 )
nextState = currentState.PASS( request, serverResponse );
else if ( command.compareTo( "LIST" ) == 0 )
nextState = currentState.LIST( request, serverResponse );
else if ( command.compareTo( "QUIT" ) == 0 )
nextState = currentState.QUIT( request, serverResponse );
else
{
//create an error message here
serverResponse = error messsage
}
return nextState;
}
}
public class SPOP_Command
{
protected static final String EndOfCommand = "\r\n";
protected static final String Separator = " ";
protected String command = " "; // avoid null string
protected String argument = " "; // problems
public SPOP_Command( String aCommand )
{
command = aCommand ;
}
public setArgument( String SpopArgument)
{
argument = SpopArgument;
}
public String command()
{
return command;
}
public String argument()
{
return argument;
}
// Produce a string representation of command object
public String toString()
{
return command() + Separator +
argument() + EndOfCommand;
}
// return a command object from string represention of
// command
public static SPOP_Command fromString( String message )
{
StringTokenizer messageParser;
messageParser = new StringTokenizer( message, Separator );
String commandPart = messageParser.nextToken();
String argumentPart = messageParser.nextToken();
SPOP_Command commandFromString;
commandFromString = new SPOP_Command(
commandPart );
commandFromString.argument( argumentPart );
return commandFromString;
}
public class SPOP_Response
{
// See POP3 for these constants
protected static final String EndOfCommand = "\r\n.\r\n";
protected static final String Separator = "\r\n";
protected String statusMessage = " ";
protected String data = " ";
public SPOP_Response( String status )
{
statusMessage = status ;
}
public setData( String information)
{
data = information;
}
public String status()
{
return statusMessage ;
}
public String data()
{
return data;
}
// Produce a string representation of response object
public String toString()
{
return status() + Separator + data() + EndOfCommand;
}
// return a command object from string represention of
// command
public static SPOP_Command fromString( String message )
{
StringTokenizer messageParser;
messageParser = new StringTokenizer( message, Separator );
String statusPart = messageParser.nextToken();
String dataPart = messageParser.nextToken();
SPOP_Response responseFromString;
responseFromString = new SPOP_Response( statusPart );
responseFromString.argument( dataPart );
return responseFromString;
}
class SPOPOutputStream extends OutputStream
{
PrintStream cout;
public SPOPOutputStream( OutputStream out )
{
cout = new PrintStream( out );
}
public void print( SPOP_Command aCommand)
{
String message = aCommand.asString();
cout.print( message );
cout.flush();
}
public void print( SPOP_Response aResponse )
{
String message = aResponse.asString();
cout.print( message );
cout.flush();
}
}
class SPOPInputStream extends InputStream
{
ASCIIInputStream cin;
public SPOPInputStream( InputStream in )
{
cin = new ASCIIInputStream( in );
}
// Read a command from client, translate to command object
public SPOP_Command readSPOP_Command()
{
String fromClient = cin.readLine();
SPOP_Command commandFromClient;
commandFromClient = SPOP_Command.fromString(
fromClient );
return commandFromClient ;
}
// Read a response from server, translate to command object
public SPOP_Response readSPOP_Response()
{
// Like readSPOP_Command but harder
}
}
public class SPOPState {
public SPOPState USER( SPOP_Command clientRequest,
SPOP_Response serverResponse )
{
serverResponse = new SPOP_Response( "-ERR" );
return new Invalid();
}
public SPOPState PASS( SPOP_Command clientRequest,
SPOP_Response serverResponse )
{
serverResponse = new SPOP_Response( "-ERR" );
return new Invalid();
}
public SPOPState LIST( SPOP_Command clientRequest,
SPOP_Response serverResponse )
{
serverResponse = new SPOP_Response( "-ERR" );
return new Invalid();
}
public SPOPState RETR( SPOP_Command clientRequest,
SPOP_Response serverResponse )
{
serverResponse = new SPOP_Response( "-ERR" );
return new Invalid();
}
public SPOPState QUIT( SPOP_Command clientRequest,
SPOP_Response serverResponse ){
serverResponse = new SPOP_Response( "-ERR" );
return new Invalid();
}
}
public class NoAuth extends SPOPState
{
public SPOPState USER( SPOP_Command clientRequest,
SPOP_Response serverResponse )
{
serverResponse = new SPOP_Response( "+OK" );
String userName = clientRequest.getData();
return new HaveUser( userName );
}
}
public class HaveUser extends SPOPState
{
protected String userName;
public HaveUser( String name )
{
userName = name;
}
public SPOPState PASS( SPOP_Command clientRequest,
SPOP_Response serverResponse )
{
String password = clientRequest.getData();
put some code here that verifies that userName and password
form a valid login
if valid login then
{
serverResponse = new SPOP_Response( "+OK" );
return new Process( );
}
else {
serverResponse = new SPOP_Response( "+ERR" );
return new Invalid( );
}
}
}