States and Classes | slide # 1 |
...The Basic Idea | slide # 2 |
...Strawman | slide # 3 |
...CardboardMan Driver Program | slide # 5 |
...Issue - The State of the States | slide # 7 |
...SoggyCardboardMan NoAuth | slide # 7 |
...TinMan NoAuth | slide # 9 |
...Issue - How to create Just One Object | slide # 11 |
The Picture | slide # 12 |
Example protocol: Simple Post Office Protocol (SPOP)
Command have the same functionality as POP but are limited to the following:
SPopState is abstract state with the default behavior for each method
Server is done with client when we reach the Quit state, so I did not add methods to that state
class SPopServer implements ServerEngine { DataInputStream input; PrintStream output; // some stuff removed, see DateServer, Doc 10, slide 8 public void run() { try { SPopState currentState = new NoAuth(); do { String inputLine = input.readLine(); if ( inputLine.startsWith( "PASS" ) ) currentState = currentState.pass(); else if ( inputLine.startsWith( "USER" ) ) currentState = currentState.user(); etc. send response to client } while ( ! currentState instanceof Quit ); input.close(); output.close(); } } }
Let one argument be a response object, which state can modify by adding proper response
So create SPopResponse class!
What are the responsibilities of SPopResponse?
class SPopServer implements ServerEngine { public void run() { try { SPopState currentState = new NoAuth(); do { String inputLine = input.readLine(); SPopResponse answer = new SPopResponse(); if ( inputLine.startsWith( "PASS" ) ) currentState = currentState.pass( answer ); else if ( inputLine.startsWith( "USER" ) ) currentState = currentState.user( answer ); etc. output.println( answer ); } while ( ! currentState instanceof Quit ); input.close(); output.close(); } } }
public class SPOPState { public SPOPState USER( other arguments, SPopResponse serverResponse ) { return defaultAction( serverResponse ); } public SPOPState PASS( other arguments, SPopResponse serverResponse ) { return defaultAction( serverResponse ); } public SPOPState LIST( other arguments, SPopResponse serverResponse ) { return defaultAction( serverResponse ); } private SPOPState defaultAction( SPopResponse serverResponse ) { serverResponse.error(); return new Invalid(); } }
The HaveUser state gets the password
The HaveUser state needs the user name to verify password
But the PASS command from client does not contain user name
The Process state needs user name to get mail messages
public class NoAuth extends SPOPState { public SPOPState user( some other arguments, SPopResponse serverResponse ) { serverResponse = new SPopResponse.ok(); String userName = get userName from argument list; return new HaveUser( userName ); } }
If a large number of clients connect to a concurrent server at the same time, the creation of all the state objects can become a performance issue
Solution is to create one object per state class and reuse it
If the objects have data fields (data members) then two threads can not use the same object
Solution is to not allow the state classes to have any data fields
So where do we store the user name so other state objects can access it?
Solution is to create a class to store the data needed by all states
Call this class SPopData
What are the responsibilities of SPopData?
public class NoAuth extends SPOPState { public SPOPState user( some other arguments,SPopData data, SPopResponse serverResponse ) { serverResponse = new SPopResponse.ok(); String userName = get userName from argument list; data.setUserName( userName ); return new HaveUser( ); } }
class SPopServer implements ServerEngine { public void run() { try { SPopState currentState = new NoAuth(); SPopData clientData, do { String inputLine = input.readLine(); SPopResponse answer = new SPopResponse(); if ( inputLine.startsWith( "PASS" ) ) currentState = currentState.pass( clientData, answer ); else if ( inputLine.startsWith( "USER" ) ) currentState = currentState.user( clientData, answer ); etc. output.println( answer ); } while ( ! currentState instanceof Quit ); input.close(); output.close(); } } }
// Only one object of this class can be created public class NoAuth extends SPOPState { private static NoAuth _instance = null; private NoAuth() { } public static NoAuth getInstance() { if ( _instance == null ) _instance = new NoAuth(); return _instance; } public SPOPState user( some other arguments,SPopData data, SPopResponse serverResponse ) { serverResponse = new SPopResponse.ok(); String userName = get userName from argument list; data.setUserName( userName ); return new HaveUser( ); } }
Who does the mapping from strings to functions?
How does all this fit together?
Does anyone understand this?