|
JMeetUp
An Example Using TCP and UDP |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
package jmeetup;
import java.util.*;
/**
* A Proposal in JMeetUp
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public class Proposal
{
private Hashtable<String,String> proponents; // Thread safe
private int id;
private String description;
/**
* Default Constructor
*/
public Proposal()
{
this(-1, "Default Proposal");
}
/**
* Explicit Value Constructor
*/
public Proposal(int id, String description)
{
this.id = id;
this.description = description;
proponents = new Hashtable<String,String>();
}
/**
* Add a new proponent
*
* @param proponent The new proponent
*/
public void addProponent(String proponent)
{
proponents.put(proponent, proponent);
}
/**
* Get the ID of this Proposal
*
* @return The ID
*/
public int getID()
{
return id;
}
/**
* Get all of the proponents for this Proposal
*
* @return The proponents
*/
public Enumeration<String> getProponents()
{
return proponents.elements();
}
/**
* Remove a proponent
*
* @param proponent The proponent to remove
*/
public void removeProponent(String proponent)
{
proponents.remove(proponent);
}
/**
* Return a String representation of this Proposal
*
* @return The String
*/
public String toString()
{
Enumeration<String> e;
String s;
s = "("+id+") "+description+"\t\t";
s += "Proponents: ";
e = proponents.elements();
while (e.hasMoreElements())
{
s += e.nextElement() + " ";
}
return s;
}
}
package jmeetup;
import java.awt.*;
import java.io.*;
import java.net.*;
import gui.*;
import internet.*;
/**
* A JMeetUp Client
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public class Client
{
private BufferedReader in;
private UDPMessageReceiver messageReceiver;
private PrintWriter out;
private Socket s;
private String username;
/**
* Constructor
*/
public Client(String username, String host,
int tcpPort, int udpPort) throws IOException,
SocketException
{
MessageWindow messageWindow;
this.username = username;
s = new Socket(host, tcpPort);
out = new PrintWriter(s.getOutputStream());
in = new BufferedReader(
new InputStreamReader(s.getInputStream()));
// Send the login information
send("login:"+username);
send("port:"+udpPort);
// Create the GUI components
messageWindow = new MessageWindow();
// Start the pieces
messageReceiver = new UDPMessageReceiver(udpPort);
messageReceiver.addMessageListener(messageWindow);
messageReceiver.start();
processCommands();
// Stop the pieces
System.out.print("Bye, ");
messageReceiver.stop();
messageWindow.setVisible(false);
messageWindow.dispose();
System.out.print("bye...");
}
/**
* Read commands from the console, send them to the server, and
* print the responses
*/
private void processCommands()
{
BufferedReader cin;
String line;
cin = new BufferedReader(
new InputStreamReader(System.in));
try
{
while ((line=cin.readLine()) != null)
{
send(line);
line = receive();
System.out.println(line.replaceAll("<BR/>","\n")+"\n");
}
send("logout:"+username);
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
/**
* Receive a line of text
*
* @return The text
*/
private String receive()
{
String line;
line = null;
try
{
line = in.readLine();
}
catch (IOException ioe)
{
// Ignore it
}
return line;
}
/**
* Send a line of text
*
* @param text The text to send
*/
private void send(String text)
{
out.println(text);
out.flush();
}
}
package jmeetup;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import gui.*;
import internet.*;
/**
* The JMeetUp server
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public class Server implements Runnable
{
private volatile boolean keepRunning;
private Hashtable<ConnectionHandler,
ConnectionHandler> tcpHandlers; // Thread safe
private Hashtable<ConnectionHandler,
UDPMessageSender> udpHandlers; // Thread safe
private ServerSocket ss;
private Thread controlThread;
private Vector<Proposal> proposals; // Thread safe
/**
* Default Constructor
*/
public Server()
{
this(9000);
}
/**
* Explicit Value Constructor
*
* @param port The port the server should listen to
*/
public Server(int port)
{
try
{
ss = new ServerSocket(port);
// Make sure accept() will timeout so that we can stop
ss.setSoTimeout(5000);
tcpHandlers = new Hashtable<ConnectionHandler,ConnectionHandler>();
udpHandlers = new Hashtable<ConnectionHandler,UDPMessageSender>();
proposals = new Vector<Proposal>();
}
catch (Exception e)
{
System.err.println(e);
System.exit(1);
}
}
/**
* Add a proponent to a Proposal
*
* @param id The ID of the proposal
* @param username The proponent
*/
public synchronized void addProponent(int id,
String username)
{
Enumeration<Proposal> e;
Proposal p;
e = proposals.elements();
while (e.hasMoreElements())
{
p = e.nextElement();
if (p.getID() != id) p.removeProponent(username);
else p.addProponent(username);
}
}
/**
* Add a Proposal
*
* @param username The user making the proposal
* @param description Decscription of the proposal
*/
public synchronized void addProposal(String username,
String description)
{
int id;
Proposal p;
id = proposals.size() + 1;
p = new Proposal(id, description);
proposals.add(p);
addProponent(id, username);
}
/**
* Broadcast a message
*
* @param message The message
*/
public synchronized void broadcast(String message)
{
Enumeration<ConnectionHandler> e;
ConnectionHandler tcph;
UDPMessageSender udph;
e = tcpHandlers.elements();
while (e.hasMoreElements())
{
tcph = e.nextElement();
udph = udpHandlers.get(tcph);
if (udph != null) udph.send(message);
}
}
/**
* Get all of the proposals
*
* @return The proposals
*/
public synchronized Enumeration<Proposal> getProposals()
{
return proposals.elements();
}
/**
* Remove a connection handler
*
* @param name The name
*/
public void remove(ConnectionHandler handler)
{
ConnectionHandler tcph;
UDPMessageSender udph;
tcph = tcpHandlers.remove(handler);
udph = udpHandlers.remove(handler);
if (udph != null) udph.stop();
if (tcph != null) tcph.stop();
}
/**
* Remove all connection handlers
*
*/
public void removeAll()
{
Enumeration<ConnectionHandler> e;
ConnectionHandler handler;
e = tcpHandlers.elements();
while (e.hasMoreElements())
{
handler = e.nextElement();
remove(handler);
}
}
/**
* The "entry point" for the new thread of execution
*/
public void run()
{
ConnectionHandler tcph;
UDPMessageSender udph;
Socket s;
while (keepRunning)
{
try
{
s = ss.accept();
udph = new UDPMessageSender(s.getInetAddress());
udph.start();
try
{
tcph =new ConnectionHandler(s,this);
// Use the ConnectionHandler
// as the key in both cases since
// it will initiate the remove later
tcpHandlers.put(tcph, tcph);
udpHandlers.put(tcph, udph);
tcph.start();
}
catch (IOException ioet)
{
ioet.printStackTrace();
}
}
catch (SocketException se)
{
// Unable to create UDP socket or accept() timed-out
}
catch (IOException ioes)
{
// Unable to accept
}
}
// The thread is about to terminate so remove all of the
// handlers
removeAll();
controlThread = null;
}
/**
* Set the port for the UDPMessageSender
*
* @param handler The ConnectionHandler
* @param port The port to use
*/
public void setSenderPort(ConnectionHandler handler,
int port)
{
ConnectionHandler tcph;
UDPMessageSender udph;
tcph = tcpHandlers.get(handler);
udph = udpHandlers.get(handler);
if (udph != null) udph.setPort(port);
}
/**
* Start the new thread of execution
*/
public void start()
{
if (controlThread == null)
{
keepRunning = true;
controlThread = new Thread(this);
controlThread.start();
}
}
/**
* Stop the thread of execution
*/
public void stop()
{
keepRunning = false;
}
}
package jmeetup;
import java.io.*;
import java.net.*;
import java.util.*;
/**
* Handles an individual connection with a
* JMeetUp client
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public class ConnectionHandler implements Runnable
{
private volatile boolean keepRunning;
private BufferedReader in;
private PrintWriter out;
private Socket s;
private String username;
private Thread controlThread;
private Server server;
/**
* Construct a new ConnectionHandler
*
* @param s The Socket to use
* @param server The "controlling" server
*/
public ConnectionHandler(Socket s, Server server)
throws IOException
{
this.server = server;
this.s = s;
in = new BufferedReader(
new InputStreamReader(
s.getInputStream()));
out = new PrintWriter(s.getOutputStream());
}
/**
* Handle a check
*/
private void handleCheck()
{
Enumeration<Proposal> e;
Proposal p;
e = server.getProposals();
while (e.hasMoreElements())
{
p = e.nextElement();
out.print(p+"<BR/>");
}
out.print("\n");
out.flush();
}
/**
* Handle a choice
*/
private void handleChoose(String number)
{
int id;
try
{
id = Integer.parseInt(number);
server.addProponent(id, username);
out.println("OK");
out.flush();
}
catch (NumberFormatException nfe)
{
out.println(number+" is an invalid choice!");
out.flush();
}
}
/**
* Handle a login
*/
private void handleLogin(String name)
{
// Only change the username if it hasn't
// already been set
if (username == null)
{
username = name;
System.out.println("["+username+"] on "+
s.getInetAddress()+", "+
s.getPort());
}
}
/**
* Handle a logout
*/
private void handleLogout()
{
// Close the socket and stop the thread
stop();
}
/**
* Handle a port change
*
* @param s The port
*/
private void handlePort(String s)
{
int port;
try
{
port = Integer.parseInt(s);
server.setSenderPort(this, port);
}
catch (NumberFormatException nfe)
{
// Don't change the port
}
}
/**
* Handle a proposal
*
* @param description The texr of the proposal
*/
private void handlePropose(String description)
{
server.addProposal(username, description);
out.println("OK");
out.flush();
}
/**
* Handle a talk command
*
* @param message The message to send
*/
private void handleTalk(String message)
{
server.broadcast("["+username+"] "+message);
out.println("OK");
out.flush();
}
/**
* Run this ConnectionHandler
*/
public void run()
{
String argument, command, line, name, value;
StringTokenizer st;
while (keepRunning)
{
try
{
line = in.readLine();
command = "";
argument = "";
st = new StringTokenizer(line, ":");
// Parse the command
if (st.hasMoreTokens()) command = st.nextToken();
if (st.hasMoreTokens())
{
argument = st.nextToken().trim();
}
else
{
if (!command.equals("check"))
{
argument = command;
command = "talk";
}
}
// Process the command
//
// Note: This could be improved with the
// Command Pattern
if (command.equals("check"))
{
handleCheck();
}
else if (command.equals("choose"))
{
handleChoose(argument);
}
else if (command.equals("login"))
{
handleLogin(argument);
}
else if (command.equals("logout"))
{
handleLogout();
}
else if (command.equals("port"))
{
handlePort(argument);
}
else if (command.equals("propose"))
{
handlePropose(argument);
}
else if (command.equals("talk"))
{
handleTalk(argument);
}
}
catch (IOException ioe)
{
// Ignore it
}
}
// The thread is about to die
try
{
in.close();
out.close();
s.close();
}
catch (IOException ioe)
{
// Ignore
}
controlThread = null;
}
/**
* Start the new thread of execution
*/
public void start()
{
if (controlThread == null)
{
keepRunning = true;
controlThread = new Thread(this);
controlThread.start();
}
}
/**
* Stop the thread of execution
*/
public void stop()
{
keepRunning = false;
}
}