package EDU.gac.max.flip; import java.io.*; import java.net.*; import java.awt.*; /** This class is the main class for an application program called NetFlip * that is an multi-user networked variant of the Flip program (a * single-user puzzle program implemented by the Flip class). * The idea is that all the users anywhere on the network are working * together on a common puzzle -- they all see the same board, and each * can manipulate it. This presumes that a FlipServer is running somewhere * on the network to tie the various NetFlips together. * The hostname of the machine running the FlipServer must be provided * as a command-line argument to this program. * *

Warning: this NetFlip class may be missing some "synchronized" * keywords on some methods -- either it or NetInterface is. This is * intentional as part of a lab assignment on race conditions and monitors * for the MC78 course. The students are supposed to find the race * conditions and predict the buggy behavior that can result, then verify * by inserting appropriate sleeps, then fix the problem by adding the * needed synchronized keywords. So, either this class or the other class * in this source file (NetInterface) is known to be buggy. * *

Written 17 Aug 1996 by * Max Hailperin * <max@gac.edu> * * @see EDU.gac.max.flipserver.FlipServer * @see NetInterface */ public class NetFlip extends Flip { public NetFlip(String server){ setTitle("NetFlip"); netInterface = new NetInterface(server, this); netInterface.start(); } protected void flip(int key){ netInterface.sendFlip(key); } /** The localFlip method causes the user interface to flip the state/color * of a particular key without any network communication. */ protected void localFlip(int key){ super.flip(key); } public static void main(String[] args){ if(args.length != 1){ System.err.println("Usage: java NetFlip serverhost"); } else { new NetFlip(args[0]); } } NetInterface netInterface; } /** This NetInteface class is used by NetFlip to provide the client-side * network interface for communication with the FlipServer. It runs as * a separate thread so that it can await network messages from the * FlipServer concurrently with the user interface handling events like * mouse clicks. (However the class boundaries do not correspond 100% * with the thread boundaries: the user interface thread invokes this class's * sendFlip method and the NetInteface thread invokes the main NetFlip * class's localFlip method -- that's how a user interface action can * trigger a network message or a network message can trigger a user * interface display.) * *

Warning: this NetInterface class may be missing some * synchronized keywords on some methods -- either it or NetFlip is. This is * intentional as part of a lab assignment on race conditions and monitors * for the MC78 course. The students are supposed to find the race * conditions and predict the buggy behavior that can result, then verify * by inserting appropriate sleeps, then fix the problem by adding the * needed synchronized keywords. So, either this class or the other class * in this source file (NetFlip) is known to be buggy. * *

Written 17 Aug 1996 by * Max Hailperin * <max@gac.edu> * * @see EDU.gac.max.flipserver.FlipServer * @see NetFlip */ class NetInterface extends Thread { NetInterface(String server, NetFlip nf){ nFlip = nf; try{ sock = new Socket(server, port); in = new DataInputStream(sock.getInputStream()); out = new PrintStream(sock.getOutputStream()); } catch(Exception e){ System.err.println(e); System.err.println("Trouble connecting to server; running standalone."); } } public void run(){ if(out == null) // no server connection return; try{ while(true){ String line = in.readLine(); if(line == null) break; nFlip.localFlip(Integer.parseInt(line)); } closeDown(); } catch(Exception e){ System.err.println(e); System.exit(1); } } /** The sendFlip method is used in response to a user click to cause * the flipping of a specific key (the clicked-on one or a neighbor) * to be sent to the FlipServer, from whence it will be forwarded * back to all the NetInterfaces, this one included. In the case that * there is no server connection, the round-trip communication that * would have occured is simulated by simply locally doing the flip. */ void sendFlip(int key){ if(out == null) // no server connection nFlip.localFlip(key); else out.println(key); } void closeDown() throws IOException{ out.close(); in.close(); sock.close(); System.err.println("Server shut down; reverting to standalone operation."); out = null; } static final int port = 8198; // agreed upon with FlipServer, unassigned NetFlip nFlip; Socket sock; DataInputStream in; PrintStream out; }