SDSU CS 596: Client-Server Programming
Spring Semester, 1997
Doc 15, Parsing, States, and Servers

To Lecture Notes Index
San Diego State University -- This page last updated Mar 10, 1997
----------

Contents of Doc 15, Parsing, States, and Servers

...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

Doc 15, Parsing, States, and Servers Slide # 1

Parsing, States, and Servers

Simple Case

server Overview


Assume there are three possible commands from client to server:



Doc 15, Parsing, States, and Servers Slide # 2
Sample Code

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();

Now What?
               input.close();
               output.close();
               }
          catch ( IOException howToHandleThis )
               {
               // A topic to be covered later
               }
          }     
     }


Doc 15, Parsing, States, and Servers Slide # 3

First Idea - Use If statements


     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
               }
          }     
     }


Doc 15, Parsing, States, and Servers Slide # 4

Second Idea - Map Strings to Functions

C/C++ Implementation

Use function pointers


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);
}

Doc 15, Parsing, States, and Servers Slide # 5
C/C++ Parser

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 );
     }

Notes:

Java 1.1 Solution - Class.getMethod


Class.getMethod maps strings to methods

public Method getMethod(String name,Class parameterTypes[])
throws NoSuchMethodException, SecurityException

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

if a matching method is not found.

Throws: SecurityException
if access to the information is denied.

Doc 15, Parsing, States, and Servers Slide # 7
Simple Class for Example

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 );
          }
     }


Doc 15, Parsing, States, and Servers Slide # 8
Using Class.getMethod
Simple Example


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 );

          }
     }

Output
Lunch Time for Monday


Doc 15, Parsing, States, and Servers Slide # 9
Using Class.getMethod - Some Details

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 );
          }
     }

Output
Lunch Time for Monday
Lunch Time
PizzaHut? 6


Doc 15, Parsing, States, and Servers Slide # 10
Java 1.1 Parser

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 );
     }


Doc 15, Parsing, States, and Servers Slide # 11
Map Strings to Functions

Java/C++ Solution - Commands


Simulate function pointers with objects!

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 );
          }
     }


Doc 15, Parsing, States, and Servers Slide # 12
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 ) {}
          }


Doc 15, Parsing, States, and Servers Slide # 13
Parsing, States, and Servers

Complex Case - States

An Example

SPOP

Example protocol: Simple Post Office Protocol (SPOP)

Command have the same functionality as POP but are limited to the following:

SPOP features

The authentication consists of two commands which have to come in sequence:


The other commands (except for QUIT) cannot be executed before the user has been authenticated.

What does this mean for the client and server?


Doc 15, Parsing, States, and Servers Slide # 14
Lexical Analysis

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()?


Doc 15, Parsing, States, and Servers Slide # 15
Parsing

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


Doc 15, Parsing, States, and Servers Slide # 16
Simple Parsing Problems

Major problems with this algorithm:


Doc 15, Parsing, States, and Servers Slide # 17

Finite Automata



A better way of looking at all of this is using a picture.



Naming the states


We will use the following names for the states:

0NoAuth
1HaveUser
2Process
3Invalid
4Quit


Doc 15, Parsing, States, and Servers Slide # 18

Implementing a State Machine: switch


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;
...

Doc 15, Parsing, States, and Servers Slide # 19

Switch Method Analysis

Major problems with this algorithm:



Advantages:



Doc 15, Parsing, States, and Servers Slide # 20

Implementing a State Machine: Table

CommandsStates
NoAuthHaveUserProcessInvalidQuit
USER
PASS
LIST
RETR
QUIT

Each cell needs:



Doc 15, Parsing, States, and Servers Slide # 21
The State Table

CommandsStates
NoAuthHaveUserProcessInvalidQuit
USER
actionUser
actionNullactionNull
HaveUserInvalidInvalidQuitQuit
InvalidInvalidInvalidQuitQuit
PASSactionNullactionPassactionNull
InvalidProcessInvalidQuitQuit
InvalidInvalidInvalidQuitQuit
LISTactionNullactionNullactionList
InvalidInvalidProcessQuitQuit
InvalidInvalidInvalidQuitQuit
RETRactionNullactionNullactionRetr
InvalidInvalidProcessQuitQuit
InvalidInvalidInvalidQuitQuit
QUITactionQuitactionQuitactionQuit
QuitQuitQuitQuitQuit
QuitQuitQuitQuitQuit


Doc 15, Parsing, States, and Servers Slide # 22
State table: C/C++


In C/C++ we can define the following:
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}
};

Advantages:


----------