...Parsing, States, and Servers | slide # 1 |
......First Idea - Use If statements | slide # 3 |
......Second Idea - Map Strings to Functions | slide # 4 |
.........Use function pointers | slide # 4 |
.........Java 1.1 Solution - Class.getMethod | slide # 6 |
.........Java/C++ Solution - Commands | slide # 11 |
......Complex Case - States | slide # 13 |
......Finite Automata | slide # 17 |
.........Implementing a State Machine: switch | slide # 18 |
.........Implementing a State Machine: Table | slide # 20 |
class AirlineServer implements ServerEngine { DataInputStream input; PrintStream output; // some stuff removed, see DateServer, Doc 10, slide 8 public void run() { try { String inputLine = input.readLine();
input.close(); output.close(); } catch ( IOException howToHandleThis ) { // A topic to be covered later } } }
public void run() { try { String inputLine = input.readLine().trim(); String answer; if ( inputLine.startsWith( "Cities" ) ) answer = getCitiesList(); else if ( inputLine.startsWith( "LunchMenu" ) ) answer = getLunchMenu(); else if ( inputLine.startsWith( "Manifest" ) ) answer = getFlightManifest( inputLine); output.println( answer ); input.close(); output.close(); } catch ( IOException howToHandleThis ) { // A topic to be covered later } } }
void quickSort( int* array, int LowBound, int HighBound) { // source code to sort array from LowBound to HighBound // using quicksort has been removed to save room on page } void mergeSort(int* array, int LowBound, int HighBound) { // same here} void insertionSort(int* array, int LowBound, int HighBound) { // ditto } void main() { void (*sort) (int*, int, int); int Size; int Data[100]; // pretend data and Size are initialized if (Size < 25) sort = insertionSort; else if (Size > 100) sort = quickSort; else sort = mergeSort; sort(Data, 0, 99); }
typedef struct { char *command; int (*function)( char*); } vector; vector commandTable[] = { {"Cities", getCitiesList}, {"LunchMenu", getLunchMenu}, {"Manifest", getFlightManifest} }; void executeCommand( char* inputLine, vector commandTable) { char* command = getCommand( inputLine ); for ( int k = 0, k < TABLESIZE; k++ ) if ( strcmp( command, commandTable[k].command ) == 0 ) commandTable[k].function( inputLine ); }
Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object. The name parameter is a String specifying the simple name the desired method, and the parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order.
The method to reflect is located by searching all the member methods
of the class or interface represented by this Class object for a public
method with the specified name and exactly the same formal
parameter types.
Throws: NoSuchMethodException
class Example { public void getLunch() { System.out.println( "Lunch Time!"); } public void getLunch( String day) { System.out.println( "Lunch Time for " + day); } public void eatOut( String where) { System.out.println( "MacDonalds? "); } public void eatOut( int where) { System.out.println( "PizzaHut? " + where ); } }
import java.lang.reflect.Method; class Test { public static void main( String args[] ) throws Exception { Example a = new Example(); Class[] stringType = { Class.forName( "java.lang.String" ) }; Object[] stringParameter = { "Monday" }; Method tryMe; tryMe = a.getClass().getMethod( "getLunch", stringType ); tryMe.invoke( a, stringParameter ); } }
import java.lang.reflect.Method; class Test { public static void main( String args[] ) throws Exception { Example a = new Example(); Class[] stringType = { Class.forName( "java.lang.String" ) }; Class[] intType = { java.lang.Integer.TYPE }; Class[] noType = { }; Object[] stringParameter = { "Monday" }; Object[] intParameter = { new Integer(6) }; Object[] noParameter = { }; Method tryMe; tryMe = a.getClass().getMethod( "getLunch", stringType ); tryMe.invoke( a, stringParameter ); tryMe = a.getClass().getMethod( "getLunch", noType); tryMe.invoke( a, noParameter ); tryMe = a.getClass().getMethod( "eatOut", intType ); tryMe.invoke( a, intParameter ); } }
class AirlineServer implements ServerEngine { // More some stuff removed, see slide 3? public String getCitiesList( ) { blah }
public String getLunchMenu( ) { blah }
public String getFlightManifest( String usedHere ) { blah }
public String invoke( String methodName, String argument ) { Class[] argType = { }; Object[] parameter = { }; if ( argument != null ) { argType = { Class.forName( "java.lang.String" ) }; parameter = { argument }; } Method toInvoke; toInvoke = this.getClass().getMethod( methodName, argType); return toInvoke.invoke( this, parameter ); }
interface AirlineCommand { public String execute( AirlineServer executer, String argument ); } class GetCitiesList implements AirlineCommand { public String execute( AirlineServer executer, String argument ) { return executer.getCitiesList(); } } class GetLunchMenu implements AirlineCommand { public String execute( AirlineServer executer, String argument ) { return executer.getLunchMenu(); } } class getFlightManifest implements AirlineCommand { public String execute( AirlineServer executer, String argument ) { return executer.getFlightManifest( argument ); } }
Java Parser
class AirlineServer implements ServerEngine { public String getCitiesList( ) { blah } public String getLunchMenu( ) { blah } public String getFlightManifest( String usedHere ) { blah } private Hashtable commands= new Hashtable(); public AirlineServer(){ commands.put("Cities", new GetCitiesList() ); commands.put("LunchMenu", new GetLunchMenu() ); commands.put("Manifest", new GetFlightManifest() ); } String invoke( String method, String argument ){ AirlineCommand toInvoke; toInvoke = (AirlineCommand ) commands.get( method ); return toInvoke.execute( this, argument ); } public void run() { try { String inputLine = input.readLine().trim(); // get command and argument from inputLine String answer = invoke( command, argument ); output.println( answer ); input.close(); output.close(); } catch ( IOException howToHandleThis ) {} }
Example protocol: Simple Post Office Protocol (SPOP)
Command have the same functionality as POP but are limited to the following:
What does this mean for the client and server?
The first step in parsing a protocol is to extract the commands from the input stream.
Since POP (and therefore SPOP) is a line oriented protocol, the logical steps to get commands is:
In Java we can use readLine() to get a line of text and a
StringTokenizer to break the line into tokens.
Why not use ASCIIInputStream.readWord()?
Simple approach:
start: get command if command is "USER" then username = argument get command if command is "PASS" then password = argument if valid(username,password) then while true get command if command is "LIST" then performLIST elsif command is "RETR" then performRETR(argument) elsif command is "QUIT" then return end if end while end if end if end if
Major problems with this algorithm:
Naming the states
We will use the following names for the states:
0 | NoAuth |
1 | HaveUser |
2 | Process |
3 | Invalid |
4 | Quit |
int state = 0; while (true) { command = next command; switch (state) { case 0: if (command.equals("USER")) { username = argument; state = 1; } else if (command.equals("QUIT")) state = 4; else error("Unknown: " + command); break; case 1: if (command.equals("PASS")) { if (valid(username, argument)) state = 2; else { error("Unauthorized"); state = 3; } } else error("Unknown: " + command); break; ...
Major problems with this algorithm:
Advantages:
Commands | States | ||||
NoAuth | HaveUser | Process | Invalid | Quit | |
USER | |||||
PASS | |||||
LIST | |||||
RETR | |||||
QUIT |
Each cell needs:
Commands | States | ||||
NoAuth | HaveUser | Process | Invalid | Quit | |
USER | actionUser | actionNull | actionNull | ||
HaveUser | Invalid | Invalid | Quit | Quit | |
Invalid | Invalid | Invalid | Quit | Quit | |
PASS | actionNull | actionPass | actionNull | ||
Invalid | Process | Invalid | Quit | Quit | |
Invalid | Invalid | Invalid | Quit | Quit | |
LIST | actionNull | actionNull | actionList | ||
Invalid | Invalid | Process | Quit | Quit | |
Invalid | Invalid | Invalid | Quit | Quit | |
RETR | actionNull | actionNull | actionRetr | ||
Invalid | Invalid | Process | Quit | Quit | |
Invalid | Invalid | Invalid | Quit | Quit | |
QUIT | actionQuit | actionQuit | actionQuit | ||
Quit | Quit | Quit | Quit | Quit | |
Quit | Quit | Quit | Quit | Quit |
struct { int currentState; char *command; int stateIfSucceed; int stateIfFailed; int (*action)(char **); } actionTable[] = { {0, "USER", 1, 3, actionUser}, {0, "QUIT", 4, 4, actionQuit}, {1, "PASS", 2, 3, actionPass}, {1, "QUIT", 4, 4, actionQuit}, {2, "LIST", 2, 2, actionList}, {2, "RETR", 2, 2, actionList}, {2, "QUIT", 4, 4, actionList}, {0, 0, 0, 0, 0} };