419 lines
12 KiB
Java
419 lines
12 KiB
Java
package nettext.client;
|
|
|
|
import java.util.List;
|
|
import java.util.Vector;
|
|
|
|
import nettext.messaging.MessageFactory;
|
|
import nettext.messaging.MessageSettings;
|
|
import nettext.messaging.AbstractMessage;
|
|
import nettext.client.networking.ClientNetworking;
|
|
import nettext.client.gui.ClientUI;
|
|
import nettext.document.Document;
|
|
|
|
import nettext.file.ASCIIDocumentReader;
|
|
import nettext.file.HTMLDocumentReader;
|
|
|
|
import nettext.file.ASCIIOutputHandler;
|
|
import nettext.file.HTMLOutputHandler;
|
|
|
|
/**
|
|
* Class Client: This singleton class will tie everything together -
|
|
* the networking, the ui, etc.
|
|
*
|
|
* <PRE>
|
|
* Revision History:
|
|
* v1.0 (Feb. 20, 2004) - Created the Client class
|
|
* </PRE>
|
|
*
|
|
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
|
|
* @version Version 1.0, Feb. 20, 2004
|
|
*/
|
|
public final class Client {
|
|
|
|
/**
|
|
* YASLI: Yet Another SingLeton Instance.
|
|
*/
|
|
private static Client instance;
|
|
|
|
/**
|
|
* This is the name under which the user is connected to the
|
|
* server. If no name was provided, a generic name will be used.
|
|
*/
|
|
private String userName;
|
|
|
|
/**
|
|
* The object that encapsulates the networking functionality for the
|
|
* client.
|
|
*/
|
|
private ClientNetworking network;
|
|
|
|
/**
|
|
* This guy will be used to handle all of the message processing for
|
|
* the client.
|
|
*/
|
|
private MessageProcessor processor;
|
|
|
|
/**
|
|
* Creates a new <code>Client</code> instance.
|
|
*/
|
|
private Client() {
|
|
userName = null;
|
|
|
|
network = new ClientNetworking();
|
|
processor = new MessageProcessor();
|
|
}
|
|
|
|
/**
|
|
* That's right... Another singleton! God, am I getting sick of
|
|
* reimplementing them over and over! Why? Why doesn't java 1.4 have
|
|
* templates, so I could just make ONE bloody singleton class and
|
|
* inherit from a templated copy of it? :(
|
|
*
|
|
* @return a <code>Client</code> value
|
|
*/
|
|
public static Client getInstance() {
|
|
if (instance == null) {
|
|
instance = new Client();
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
/**
|
|
* Returns the name under which the user is connected to the server.
|
|
*
|
|
* @return a <code>String</code> value
|
|
*/
|
|
public String getUsername() {
|
|
return userName;
|
|
}
|
|
|
|
/**
|
|
* Gives the user a new name.
|
|
*
|
|
* @param name a <code>String</code> value
|
|
*/
|
|
protected void setUsername(final String name) {
|
|
this.userName = name;
|
|
}
|
|
|
|
/**
|
|
* Attempts to connect to the server specified in the parameters.
|
|
*
|
|
* @param host The hostname of the server to connect to.
|
|
* @param port The port at which we want to connect to the server.
|
|
* @param username The username that we want to use for this connection.
|
|
* @return True if the connection was successful, and false if it failed.
|
|
*/
|
|
public boolean connectToServer(final String host,
|
|
final int port,
|
|
final String username) {
|
|
boolean result = false;
|
|
List data = new Vector();
|
|
AbstractMessage message = null;
|
|
|
|
if (username != null) {
|
|
setUsername(username);
|
|
}
|
|
|
|
//Connect to the server
|
|
result = network.connect(host, port);
|
|
if (!result) {
|
|
//Could not connect to the server...
|
|
//Tell ClientUI to issue a warning saying the connection failed.
|
|
ClientUI.getInstance().showWarning("Connection Failed",
|
|
"Could not connect to the server.");
|
|
return false;
|
|
}
|
|
|
|
//Issue a helo message
|
|
data.add(getUsername());
|
|
message = MessageFactory.getInstance()
|
|
.makeMessage(MessageSettings.JOIN_TYPE, data);
|
|
|
|
result = sendMessage(message);
|
|
if (!result) {
|
|
//Failed to send the HELO message
|
|
|
|
if (ClientSettings.VERBOSE) {
|
|
System.out.println("Client: Could not send HELO message...");
|
|
}
|
|
|
|
//Tell ClientUI to issue a warning
|
|
ClientUI.getInstance().showWarning("Connection Failed",
|
|
"Could not send a join message to"
|
|
+ " the server.");
|
|
network.shutDown();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function will issue a QUIT message to the server and then
|
|
* tell client networking to shut down.
|
|
* @param clean Specifies whether or not a QUIT message should be
|
|
* issued. If this parameter is false, the client will just close
|
|
* the socket.
|
|
*/
|
|
public void disconnectFromServer(final boolean clean) {
|
|
List data = new Vector();
|
|
AbstractMessage message = null;
|
|
|
|
if (!network.isConnected()) {
|
|
return;
|
|
}
|
|
|
|
if (clean) {
|
|
//Issue a quit message:
|
|
data.add(getUsername());
|
|
message = MessageFactory.getInstance()
|
|
.makeMessage(MessageSettings.QUIT_TYPE, data);
|
|
sendMessage(message);
|
|
}
|
|
|
|
//Shut down networking:
|
|
network.shutDown();
|
|
|
|
ClientUI.getInstance().hideDocumentListFrame();
|
|
}
|
|
|
|
/**
|
|
* Returns true if the client is currrently connected to the server,
|
|
* and false if he is not.
|
|
*
|
|
* @return a <code>boolean</code> value
|
|
*/
|
|
public boolean isConnected() {
|
|
return network.isConnected();
|
|
}
|
|
|
|
/**
|
|
* Sends a message to the server. If the send succeeds, returns
|
|
* true. Otherwise returns false.
|
|
*
|
|
* @param message an <code>AbstractMessage</code> value
|
|
* @return a <code>boolean</code> value
|
|
*/
|
|
public boolean sendMessage(final AbstractMessage message) {
|
|
if (message == null) {
|
|
return false;
|
|
}
|
|
|
|
if (!network.isConnected()) {
|
|
return false;
|
|
}
|
|
|
|
network.sendMessage(message);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This will be called when the client wishes to create a new
|
|
* document.
|
|
*/
|
|
public void createDocument() {
|
|
//See if we are connected
|
|
if (!isConnected()) {
|
|
return;
|
|
}
|
|
|
|
//Ask the user for a document name
|
|
String name = ClientUI.getInstance()
|
|
.showInputDialog("Choose Document Name",
|
|
"Please choose the name for your new document:",
|
|
"Document1");
|
|
if (name == null) {
|
|
return;
|
|
}
|
|
|
|
//Tell the server we have created a new document. It should either
|
|
//tell us that the document has been added by sending us a DCMT
|
|
//message, or that one with the same name already exists.
|
|
List data = new Vector();
|
|
Document doc = new Document();
|
|
doc.setDocumentName(name);
|
|
doc.setDocumentLoaded(true);
|
|
doc.updateDocument();
|
|
data.add(doc);
|
|
|
|
sendMessage(MessageFactory.getInstance()
|
|
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE, data));
|
|
}
|
|
|
|
/**
|
|
* Shows the open dialog first and then performs the loading of the
|
|
* document, after which, this document is send over to the server
|
|
* for approval.
|
|
*/
|
|
public void importDocument() {
|
|
//written by Jose Caban
|
|
|
|
//Check for connection
|
|
if (!isConnected()) {
|
|
return;
|
|
}
|
|
|
|
//Pop up the thingamabob to select the file
|
|
String fileName = ClientUI.getInstance().browseLoadFileName(null);
|
|
|
|
if (fileName == null) {
|
|
return;
|
|
}
|
|
|
|
//Check the file type
|
|
if (fileName.endsWith(".txt")) {
|
|
/* Load ASCII */
|
|
ASCIIDocumentReader asciiDocReader = new ASCIIDocumentReader();
|
|
|
|
if (!asciiDocReader.initialize(fileName)) {
|
|
System.err.println("Error Loading Document");
|
|
System.err.flush();
|
|
|
|
ClientUI.getInstance()
|
|
.showError("File I/O Error",
|
|
"Error accessing the File");
|
|
return;
|
|
}
|
|
|
|
Document docImportMe = asciiDocReader.readDocument();
|
|
|
|
if (docImportMe == null) {
|
|
System.err.println("Error loading the document");
|
|
return;
|
|
}
|
|
|
|
asciiDocReader.cleanUp();
|
|
|
|
docImportMe.updateDocument();
|
|
|
|
List v = new Vector();
|
|
v.add(docImportMe);
|
|
|
|
sendMessage(MessageFactory.getInstance()
|
|
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE, v));
|
|
|
|
|
|
} else if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
|
|
/* Load HTML */
|
|
HTMLDocumentReader htmlDocReader = new HTMLDocumentReader();
|
|
|
|
if (!htmlDocReader.initialize(fileName)) {
|
|
System.err.println("Error Loading Document");
|
|
System.err.flush();
|
|
|
|
ClientUI.getInstance()
|
|
.showError("File I/O Error",
|
|
"Error accessing the File");
|
|
return;
|
|
}
|
|
|
|
Document docImportMe = htmlDocReader.readDocument();
|
|
|
|
if (docImportMe == null) {
|
|
System.err.println("Error loading the document");
|
|
return;
|
|
}
|
|
|
|
htmlDocReader.cleanUp();
|
|
|
|
List v = new Vector();
|
|
v.add(docImportMe);
|
|
|
|
sendMessage(MessageFactory.getInstance()
|
|
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE, v));
|
|
|
|
} else {
|
|
ClientUI.getInstance()
|
|
.showError("File Type Unsupported",
|
|
"The file you selected is not Supported");
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Export a Document
|
|
* @param docExportMe the Document to export
|
|
*/
|
|
public void exportDocument(Document docExportMe) {
|
|
String fileName = ClientUI.getInstance().browseSaveFileName(null);
|
|
|
|
if (fileName == null) {
|
|
return;
|
|
}
|
|
|
|
fileName = fileName.substring(0, fileName.length() - 4);
|
|
|
|
if (ClientSettings.VERBOSE) {
|
|
System.out.println("Export file: " + fileName);
|
|
}
|
|
|
|
//Check the file type
|
|
if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
|
|
HTMLOutputHandler htmlOutputHandler = new HTMLOutputHandler();
|
|
|
|
htmlOutputHandler.initialize(fileName);
|
|
|
|
if (!htmlOutputHandler.writeToDisk(docExportMe)) {
|
|
ClientUI.getInstance().showError("Error Writing File",
|
|
"The system encountered an error writing the file to disk."
|
|
+ " This is most likely Linux's fault");
|
|
}
|
|
|
|
} else {
|
|
ASCIIOutputHandler asciiOutputHandler = new ASCIIOutputHandler();
|
|
|
|
asciiOutputHandler.initialize(fileName);
|
|
|
|
if (!asciiOutputHandler.writeToDisk(docExportMe)) {
|
|
ClientUI.getInstance().showError("Error Writing File",
|
|
"The system encountered an error writing the file to disk."
|
|
+ " This is most likely Linux's fault");
|
|
}
|
|
|
|
asciiOutputHandler.cleanUp();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* This function receives the message from the server. It needs to
|
|
* check the type of message first. Then, if the message is a
|
|
* graphics message, this should send it to the message list, and
|
|
* tell the graphics panel to rerender. If it is a chat message, it
|
|
* should be sent to the message list, and then to the chat
|
|
* panel. Etc.
|
|
*
|
|
* @param message an <code>AbstractMessage</code> value
|
|
*/
|
|
public void processMessage(final AbstractMessage message) {
|
|
processor.processMessage(message);
|
|
}
|
|
|
|
/**
|
|
* This function will be called by the server listener when the
|
|
* server drops the connection. It will take appropriate steps to
|
|
* shut down the connection and notify the user of the problem.
|
|
*/
|
|
public void serverQuit() {
|
|
ClientUI.getInstance().showWarning("Server Lost",
|
|
"The connection to the server has "
|
|
+ "been lost...");
|
|
network.shutDown();
|
|
}
|
|
|
|
/**
|
|
* Shuts down the client.
|
|
*/
|
|
public void shutDown() {
|
|
//FIXME: Implement a clean shutdown.
|
|
System.exit(0);
|
|
}
|
|
}
|
|
|