import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.net.UnknownHostException;
import java.text.MessageFormat;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.SortedMap;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JTextField;
-import java.util.TreeSet;
+import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.swing.JProgressBar;
+import javax.swing.JOptionPane;
import javax.swing.ProgressMonitor;
+import javax.swing.SwingWorker;
import javax.swing.Timer;
import uk.ac.ntu.n0521366.wsyd.libs.WSYD_Member;
-import uk.ac.ntu.n0521366.wsyd.libs.message.MessageLogin;
-import uk.ac.ntu.n0521366.wsyd.libs.message.MessageMember;
-import uk.ac.ntu.n0521366.wsyd.libs.net.Network;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkMessage;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkMessageEvent;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkMessageEventListener;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkServerTCP;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkServerUDP;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkServerUDPMulticast;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkStream;
-import uk.ac.ntu.n0521366.wsyd.libs.net.NetworkStreamManager;
-import uk.ac.ntu.n0521366.wsyd.libs.net.ServiceAddressMap;
-import uk.ac.ntu.n0521366.wsyd.libs.net.WSYD_SocketAddress;
+import uk.ac.ntu.n0521366.wsyd.libs.logging.PacketHandler;
+import uk.ac.ntu.n0521366.wsyd.libs.message.*;
+import uk.ac.ntu.n0521366.wsyd.libs.net.*;
/**
+ * The user client application. Needs ServerSocial and ServerChat for full functionality.
+ *
+ * @see uk.ac.ntu.n0521366.wsyd.server.ServerSocial
+ * @see uk.ac.ntu.n0521366.wsyd.server.ServerChat
+ *
*
* @author Eddie Berrisford-Lynch
*/
-public class ClientGUI extends javax.swing.JFrame implements NetworkMessageEventListener {
-
- private boolean loginSuccessful = false;
-
- private boolean registrationSuccessful = false;
-
- private final Login loginDialog = new Login(this, true);
- private final EditProfile registrationDialog = new EditProfile(this, true);
-
+public class ClientGUI extends javax.swing.JFrame implements NetworkMessageEventListener, PropertyChangeListener {
+
+ /**
+ * Track status of login.
+ */
+ private boolean _loggedIn = false;
+
+ /**
+ * Background task controlling a ProgressMonitor.
+ *
+ * Log-in dialog is not shown until the Social Server is available.
+ */
+ class WaitForServerSocial extends javax.swing.SwingWorker<Boolean, Void> {
+
+ /**
+ * Waits up to 30 seconds for the Social Server to appear.
+ *
+ * @return true if the server was found before the time expires
+ * @throws Exception
+ */
+ @Override
+ @SuppressWarnings("SleepWhileInLoop")
+ protected Boolean doInBackground() throws Exception {
+ boolean result = false;
+
+ int duration = _progressMonitor.getMaximum(); // milliseconds
+ int countdown = duration;
+ int pause = 500;
+ while (countdown > 0 && !result && !isCancelled()) {
+ result = _serviceToAddressMap.containsService("ServerSocialMC");
+ this.setProgress((duration - countdown) / 1000);
+ Thread.sleep(pause);
+ countdown -= pause;
+ }
+ return result;
+ }
+ }
+
+ private Login loginDialog;
+ private EditProfile registrationDialog;
+ private ProgressMonitor _progressMonitor;
+ WaitForServerSocial _waitForServerSocial;
+
/**
* Member record for this client's user.
*/
private WSYD_Member myMember;
-
- Socket socialSocket;
-
+
+ /**
+ * The address of the social server.
+ */
+ Socket socketSocial;
+
+ /**
+ * The address of the chat server.
+ */
+ Socket socketChat;
+
+ /**
+ * Title used before member has authenticated to the server.
+ */
+ static final String DEFAULT_TITLE = "ClientGUI";
+
/**
* Readable/displayable name of this application
- *
- * TODO: title should be assigned userID when SocialServer connection established
*/
- private String _title = null;
-
+ private String _title;
+
+ /**
+ * Name of the network log server to look for in multicast neighbour
+ * discovery
+ */
+ private final String logServiceName = "LogService";
+
+ /**
+ * Address of the Log Server.
+ */
+ InetSocketAddress _serverLog;
+
/**
* Network services to address map.
*/
ServiceAddressMap _serviceToAddressMap;
-
+
/**
* Handles display and sending of log messages.
*/
@SuppressWarnings("NonConstantLogger")
- private static Logger LOGGER;
-
+ private Logger LOGGER;
+
/**
* SortedMap wraps a TreeMap that has been made thread-safe by
* Collections.synchronizedSortedMap() in readMembers().
* WSYD_Member member record
*/
SortedMap<Long, WSYD_Member> _members;
-
+
/**
* userIDs of members currently logged in
*/
ArrayList<Long> _membersOnline;
-
+
+ /**
+ * Regular presence announcements
+ */
Timer _regularTasks;
-
- WSYD_SocketAddress _multicastAdvertiserSA;
-
- NetworkServerUDPMulticast _multicastService;
-
- WSYD_SocketAddress _udpNotificationServiceSA;
-
- NetworkServerUDP _udpNotificationService;
-
- WSYD_SocketAddress _tcpChatServiceSA;
-
- NetworkServerTCP _tcpChatService;
-
- NetworkStreamManager _tcpStreamManager;
-
+
+ /**
+ * Whether process should announce itself using multicast.
+ *
+ * Provides neighbour discovery without DNS or manual IP address configuration.
+ */
+ boolean _multicastAnnouncements = false;
+
/**
- * Creates new form ClientGUI
+ * Multi-cast neighbour advertise and discover service in a SwingWorker thread.
+ */
+ NetworkServerUDPMulticast _multicastService = null;
+
+ /**
+ * Chat request service listener.
+ */
+ NetworkServerTCP _tcpChatService = null;
+
+ /**
+ * Manager of ServerSocial and ServerChat TCP streams.
+ */
+ NetworkStreamManager _tcpStreamManager = null;
+
+ /**
+ * Default constructor. Sets Logger level and initialises GUI and TCP stream manager.
*/
public ClientGUI() {
+ _title = DEFAULT_TITLE;
+ LOGGER = Logger.getLogger(_title);
+ // workaround to ensure all levels of log messages are recorded locally before the ServerLog service is available on the network
+ Logger l = LOGGER;
+ while (l != null) {
+ try {
+ l.setLevel(Level.ALL);
+ System.err.println("LOGGER: set level for logger " + l.getName());
+ } catch (SecurityException ex) {
+ System.err.println("LOGGER: cannot set level for logger " + l.getName());
+ }
+ l = l.getParent();
+ }
+
initComponents();
_serviceToAddressMap = new ServiceAddressMap(_title, LOGGER);
_tcpStreamManager = new NetworkStreamManager();
+ _membersOnline = new ArrayList<>();
+ }
+
+ /**
+ * Creates new form ClientGUI
+ * @param multicastAnnouncements true if application should advertise itself using multicast discovery
+ * @param serverSocial optional manually set IP address for Server Social (if multicast discovery isn't working)
+ */
+ public ClientGUI(boolean multicastAnnouncements, InetAddress serverSocial) {
+ this();
+ this._multicastAnnouncements = multicastAnnouncements;
+ if (serverSocial != null)
+ _serviceToAddressMap.put("ServerSocial", new ServiceAddressMap.LastSeenHost(new InetSocketAddress(serverSocial, Network.PORTS_SERVER_SOCIAL), ServiceAddressMap.LastSeenHost.STATE.STATIC));
+ }
+
+ /**
+ * Custom simplified logging function.
+ *
+ * Encapsulates the commonly repeated code of Logger method calls
+ *
+ * @param level the Logger.Level of this message
+ * @param format MessageFormat.format() formatter
+ * @param message zero or more arguments for MessageFormat.format() to process
+ */
+ protected void logp(Level level, String format, Object... message) {
+ if (LOGGER != null)
+ LOGGER.logp(level, _title, null, MessageFormat.format(format, (Object[]) message));
}
/**
// TODO add your handling code here:
}//GEN-LAST:event_formWindowActivated
- private ClientGUI initNeighbourListener() {
- _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY, WSYD_SocketAddress.Protocol.UDP);
+ /**
+ * Start the multicast neighbour discovery service in order to discover Social Server as soon as possible.
+ *
+ * @return this object
+ * @throws UnknownHostException
+ */
+ private ClientGUI initNeighbourListener() throws UnknownHostException {
+ WSYD_SocketAddress _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IPv4, Network.PORTS_MULTICAST_DISCOVERY, WSYD_SocketAddress.Protocol.UDP);
_multicastService = new NetworkServerUDPMulticast(_multicastAdvertiserSA, _title + "MC", _serviceToAddressMap, LOGGER);
_multicastService.getEventManager().addNetworkMessageEventListener(this, "Neighbour");
_multicastService.execute();
- _serviceToAddressMap.put("all", new ServiceAddressMap.LastSeenHost(new InetSocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY), ServiceAddressMap.LastSeenHost.STATE.STATIC));
-
+ _serviceToAddressMap.put("all", new ServiceAddressMap.LastSeenHost(new InetSocketAddress(Network.MULTICAST_IPv4, Network.PORTS_MULTICAST_DISCOVERY), ServiceAddressMap.LastSeenHost.STATE.STATIC));
+
return this;
}
-
+
+ /**
+ * Start the remaining services and listeners.
+ * @throws UnknownHostException
+ */
private void initListeners() {
-
- _udpNotificationServiceSA = new WSYD_SocketAddress(Network.IPv4_WILDCARD, Network.PORTS_EPHEMERAL, WSYD_SocketAddress.Protocol.UDP);
- _udpNotificationService = new NetworkServerUDP(_udpNotificationServiceSA, _title + "_Notifier", _serviceToAddressMap, LOGGER);
- _udpNotificationService.getEventManager().addNetworkMessageEventListener(this, "Notification");
- _udpNotificationService.execute();
-
- _tcpChatServiceSA = new WSYD_SocketAddress(Network.IPv4_WILDCARD, Network.PORTS_EPHEMERAL, WSYD_SocketAddress.Protocol.TCP);
+
+ WSYD_SocketAddress _tcpChatServiceSA = new WSYD_SocketAddress(Network.IPv4_WILDCARD, Network.PORTS_EPHEMERAL, WSYD_SocketAddress.Protocol.TCP);
_tcpChatService = new NetworkServerTCP(_tcpChatServiceSA, _title + "_Chat", _serviceToAddressMap, _tcpStreamManager, LOGGER);
_tcpChatService.getEventManager().addNetworkMessageEventListener(this, "ChatRequest");
_tcpChatService.execute();
-
+
ActionListener servicesAnnounceActionListener = new ActionListener() {
/**
* Perform regular house-keeping tasks.
- * @param e
+ * @param e
*/
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(ActionEvent e) {
// clean up the known hosts map
ArrayList<String> servicesRemoved = _serviceToAddressMap.cleanServiceAddressMap(5000);
for (String service: servicesRemoved) {
switch (service) {
}
}
-
- // TODO: PING server
+
+ NetworkStream serverSocial = _tcpStreamManager._tcpStreams.get(NetworkStreamManager.SERVERSOCIAL);
+ if (serverSocial != null) {
+ // TODO: PING server
+ }
}
};
-
+
_regularTasks = new Timer(1000, servicesAnnounceActionListener);
_regularTasks.setInitialDelay(100);
_regularTasks.start();
-
}
-
- private void connectionDialog() {
- /* FIXME: progress monitor
- ProgressMonitor pm = new ProgressMonitor(this, "Waiting for the Server...", "", 0, 10);
- pm.setMillisToPopup(100);
- pm.setProgress(1);
- */
- while (!_serviceToAddressMap.containsService("ServerSocialMC"));
-
- // pm.setProgress(10);
-
+
+ /**
+ * Application is closing so shut down listening services and sockets.
+ */
+ private void exitCleanly() {
+ if (_regularTasks != null)
+ _regularTasks.stop();
+ if (_multicastService != null)
+ _multicastService.cancel(true);
+ if(_tcpChatService != null)
+ _tcpChatService.cancel(true);
+ if (_tcpStreamManager != null)
+ _tcpStreamManager.closeAll();
+
+ this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
+ }
+
+ /**
+ * At startup, must wait for Social Server to be available in order to perform Login or Registration.
+ *
+ * Displays a ProgressMonitor for up to 30 seconds before giving up.
+ *
+ * @return this object
+ */
+ private ClientGUI waitForServer() {
+ _progressMonitor = new ProgressMonitor(this, "Waiting 30 seconds for Social Server...", "", 0, 30000);
+ _progressMonitor.setMillisToPopup(100);
+ _progressMonitor.setProgress(0);
+
+ _waitForServerSocial = new WaitForServerSocial();
+ _waitForServerSocial.addPropertyChangeListener(this);
+ _waitForServerSocial.execute();
+
+ return this;
+ }
+
+ /**
+ * Receive change events from the background thread that waits for Server Social to be available.
+ * @param evt
+ */
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ switch (evt.getPropertyName()) {
+ case "progress":
+ int progress = 1000 * (Integer) evt.getNewValue();
+ _progressMonitor.setProgress(progress);
+ break;
+ case "state":
+ SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
+ if (state.equals(SwingWorker.StateValue.DONE)) {
+ _progressMonitor.close();
+ try {
+ if (_waitForServerSocial.get()) {
+ initListeners();
+ connectToServer();
+ doLogin();
+ } else {
+ JOptionPane.showMessageDialog(rootPane, "Unable to locate Social Server", "Connecting", JOptionPane.ERROR_MESSAGE);
+ exitCleanly();
+ }
+ } catch (InterruptedException | ExecutionException ex) {
+ Logger.getLogger(ClientGUI.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+ }
+
+ private void connectToServer()
+ {
try {
- socialSocket = new Socket(_serviceToAddressMap.getServiceAddress("ServerSocialMC").getAddress(), Network.PORTS_SERVER_SOCIAL);
- NetworkStream newStream = new NetworkStream(socialSocket, _tcpStreamManager);
+ socketSocial = new Socket(_serviceToAddressMap.getServiceAddress("ServerSocialMC").getAddress(), Network.PORTS_SERVER_SOCIAL);
+ NetworkStream newStream = new NetworkStream(socketSocial, _tcpStreamManager);
_tcpStreamManager.addStream(NetworkStreamManager.SERVERSOCIAL, newStream);
newStream.getEventManager().addNetworkMessageEventListener(this);
} catch (IOException ex) {
- //Logger.getLogger(ClientGUI.class.getName()).log(Level.SEVERE, null, ex);
- System.err.println("IOException in connectionDialog()");
+ LOGGER.logp(Level.SEVERE, _title, null, "connectToServer()", ex);
}
- loginDialog();
}
-
- private void loginDialog()
+
+ private void doLogin()
{
- //WSYD_Login loginDialog = new Login(this, true);
+ registrationDialog = new EditProfile(this, true);
+ loginDialog = new Login(this, true);
loginDialog.setLocationRelativeTo(null);
loginDialog.setVisible(true);
- if (loginSuccessful)
+ if (_loggedIn)
{
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
-
+
public void loginAbort()
{
this.dispose();
}
-
+
public boolean validateLogin(String uName, String pWord)
{
boolean result = false;
- System.out.println(uName + pWord + "<");
-
+
if (uName.equals("admin") && pWord.equals("admin"))
{
- System.out.println("True");
- loginSuccessful = true;
+ _loggedIn = true;
result = true;
}
else {
NetworkMessage message = new NetworkMessage("Login", null, new MessageLogin(uName, pWord));
NetworkStream ns = _tcpStreamManager._tcpStreams.get(NetworkStreamManager.SERVERSOCIAL);
if (ns != null) {
- ns.write(message);
+ ns.write(message);
result = true;
}
else
- System.err.println(" validateLogin(): do not know where ServerSocial is");
+ LOGGER.logp(Level.WARNING, _title, "validateLogin", "do not know where ServerSocial is");
}
return result;
}
-
+
public void registrationProfileDialog()
{
registrationDialog.setLocationRelativeTo(null);
registrationDialog.setVisible(true);
}
-
+
public void confirmRegistration(WSYD_Member registrationData)
{
- // TODO: confirmRegistration(): submit registrationDialog data to SocialServer
if (registrationData != null) {
NetworkMessage message = new NetworkMessage("Register", null, new MessageMember(registrationData));
NetworkStream ns = this._tcpStreamManager._tcpStreams.get(NetworkStreamManager.SERVERSOCIAL);
ns.write(message);
}
else
- System.err.println("confirmRegistration(): do not know where SocialServer is");
+ logp(Level.WARNING, "confirmRegistration(): do not know where SocialServer is for userID {0} ({1})", registrationData._userID, registrationData._userName);
}
}
-
-
- /**
- * @param args the command line arguments
- */
- public static void main(String args[]) {
- /* Set the Nimbus look and feel */
- //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
- /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
- * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
- */
- try {
- for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
- if ("Nimbus".equals(info.getName())) {
- javax.swing.UIManager.setLookAndFeel(info.getClassName());
- break;
- }
- }
- } catch (ClassNotFoundException ex) {
- java.util.logging.Logger.getLogger(ClientGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
- } catch (InstantiationException ex) {
- java.util.logging.Logger.getLogger(ClientGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
- } catch (IllegalAccessException ex) {
- java.util.logging.Logger.getLogger(ClientGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
- } catch (javax.swing.UnsupportedLookAndFeelException ex) {
- java.util.logging.Logger.getLogger(ClientGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
- }
- //</editor-fold>
- //</editor-fold>
- //</editor-fold>
- //</editor-fold>
-
- /* Create and display the form */
- java.awt.EventQueue.invokeLater(new Runnable() {
- public void run() {
- new ClientGUI().initNeighbourListener().connectionDialog();
- }
- });
- }
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton gButtonAddFriendChat;
private javax.swing.JScrollPane jScrollPane3;
// End of variables declaration//GEN-END:variables
+ /**
+ * Update all service titles that reflect the user identity.
+ * @param userName the new userName or null if newUserID == 0
+ * @param oldUserID the current userID
+ * @param newUserID the new userID or 0 if logged out
+ */
+ private void setServiceTitles(String userName, long oldUserID, long newUserID) {
+ if (newUserID != 0) {
+ _title = "UserID_" + newUserID;
+ this.setTitle("WSYD logged in as " + userName);
+ } else {
+ _title = DEFAULT_TITLE;
+ this.setTitle("WSYD");
+ }
+ this._tcpChatService.setTitle(_title + "_Chat");
+ this._multicastService.setTitle(_title + "_MC");
+ for (java.util.logging.Handler handler : this.LOGGER.getHandlers()) {
+ if (handler instanceof PacketHandler) {
+ ((PacketHandler) handler).setSource(_title);
+ }
+ }
+ _tcpStreamManager.updateKey(oldUserID, newUserID); // replace temporary key in stream manager
+
+ }
+
+ /**
+ * Process received NetworkMessages and update internal status based on them.
+ *
+ * @param event The wrapper around the NetworkMessage
+ */
@Override
public void NetworkMessageReceived(NetworkMessageEvent event) {
NetworkMessage nm = event.getNetworkMessage();
if (nm == null)
return;
- System.err.println(MessageFormat.format("Network Message received with intent {0} from sender {1}", nm.getIntent(), nm.getSender()));
+ String type = nm.getMessage().getMessageType();
+ MessageLogin ml;
switch (nm.getIntent()) {
+ case "Neighbour":
+ if (type.equals(MessagePresence.getType())) { // Presence
+ MessagePresence mp = (MessagePresence) nm.getMessage();
+ // add or update the last-seen time of the Sender host in the known services map
+ ServiceAddressMap.LastSeenHost host = new ServiceAddressMap.LastSeenHost(new InetSocketAddress(nm.getReceivedFrom().getAddress(), mp.socketAddress.getPort()));
+ this._serviceToAddressMap.put(mp.serviceName, host);
+ logp(Level.FINEST, "Added \"{0}\" ({1}) to service map", mp.serviceName, host.address.toString());
+ switch (mp.serviceName) {
+ case "ServerChat":
+ // TODO: NetworkMessageReceived(Neighbour): prepare for keeping ServerChat in sync
+ break;
+
+ case logServiceName:
+ if (this._serverLog == null) {
+ logp(Level.CONFIG, "Switching to network logger");
+ this._serverLog = new InetSocketAddress(this._serviceToAddressMap.getServiceAddress(logServiceName).getAddress(), mp.socketAddress.getPort());
+ LOGGER.addHandler(new PacketHandler(this._serverLog, null, null, _title)); // send messages to the ServerManagement client
+ LOGGER.setUseParentHandlers(false); // don't send messages locally now
+ logp(Level.CONFIG, "Switched to network logger");
+ }
+ break;
+ }
+ }
+ break;
+
case "Login":
- MessageLogin ml = (MessageLogin) nm.getMessage();
+ ml = (MessageLogin) nm.getMessage();
if (ml != null) {
- this.loginSuccessful = ml._loggedIn;
- if (ml._loggedIn)
+ _loggedIn = ml._loggedIn;
+ if (ml._loggedIn) { // update all objects that need to know the user ID
+ this.setServiceTitles(ml._userName, nm.getKey(), ml._userID);
+ _membersOnline.add(ml._userID); // make the member online
+
this.loginDialog.dispose();
+ }
else
loginDialog.setUserName("Invalid Login: retry");
}
break;
+
+ case "Logout":
+ ml = (MessageLogin) nm.getMessage();
+ if(ml != null) {
+ if (! ml._loggedIn) {
+ this.setServiceTitles(null, ml._userID, 0);
+ _membersOnline.remove(ml._userID);
+ _loggedIn = false;
+ }
+ }
+ break;
+
case "Register":
MessageMember mm = (MessageMember) nm.getMessage();
if (mm != null) {
if (mm.getRegistered() == MessageMember.STATE.REGISTERED) {
this.myMember = mm.getMember();
- this.registrationSuccessful = true;
+ this._loggedIn = true;
+ this.setServiceTitles(this.myMember._userName, nm.getKey(), this.myMember._userID);
+
// dismiss the dialogs and show client's main window
registrationDialog.dispose();
loginDialog.dispose();
- this.setTitle("WSYD logged in as " + this.myMember._userName);
this.setLocationRelativeTo(null);
this.setVisible(true);
} else
javax.swing.JOptionPane.showMessageDialog(registrationDialog, mm.getStatus(), "Registration failed", javax.swing.JOptionPane.ERROR_MESSAGE);
}
break;
- default:
- System.err.println(MessageFormat.format("Unhandled NetworkMessage received with intent {0} from sender {1}", nm.getIntent(), nm.getSender()));
-
+
+ default: // log all unhandled messages
+ logp(Level.WARNING, "Unhandled NetworkMessage received with intent: \"{0}\" sender: \"{1}\" target: \"{2}\"", nm.getIntent(), nm.getSender(), nm.getTarget());
+
+ }
+ }
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String args[]) {
+ /* Set the Nimbus look and feel */
+ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
+ /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
+ * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
+ */
+ try {
+ for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
+ if ("Nimbus".equals(info.getName())) {
+ javax.swing.UIManager.setLookAndFeel(info.getClassName());
+ break;
+ }
+ }
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
+ java.util.logging.Logger.getLogger(ClientGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+ }
+ //</editor-fold>
+ //</editor-fold>
+ //</editor-fold>
+ //</editor-fold>
+ class App implements Runnable {
+ public boolean multicastAnnouncements = false;
+ public InetAddress serverSocial = null;
+
+ /**
+ * Constructs, initialises and starts the server management GUI.
+ */
+ @Override
+ public void run() {
+ try {
+ ClientGUI app = new ClientGUI(multicastAnnouncements, serverSocial).initNeighbourListener().waitForServer();
+ }
+ catch(UnknownHostException ex) {
+ Logger.getLogger(ClientGUI.class.getName()).log(Level.SEVERE, null, MessageFormat.format("Error: initNeighbourListener(): {0}", ex.toString()));
+ }
+ }
+ }
+ App app = new App();
+
+ // process command line arguments. Use indexed for in order to easily read values of switch arguments
+ for (int i = 0; i < args.length; i++) {
+ switch (args[i]) {
+ case "-announce":
+ app.multicastAnnouncements = true;
+ break;
+ case "-noannounce":
+ app.multicastAnnouncements = false;
+ break;
+ case "-server":
+ if (args.length >= i+1) {
+ // read the next argument as an IP address
+ InetAddress temp;
+ try {
+ temp = InetAddress.getByName(args[i+1]);
+ app.serverSocial = temp;
+ } catch (UnknownHostException e) {
+ Logger.getLogger(ClientGUI.class.getName()).log(Level.SEVERE, null,MessageFormat.format("Error: {0} is not a valid hostname or IP address", args[i+1]));
+ }
+ }
+ break;
+ }
}
+ java.awt.EventQueue.invokeLater(app);
}
+
}