From: TJ Date: Sun, 3 May 2015 18:50:30 +0000 (+0100) Subject: Move ServiceToHostMap into stand-alone class ServiceAddressMap and refactor accordingly X-Git-Url: https://iam.tj/gitweb/gitweb.cgi?p=WeStealzYourDataz.git;a=commitdiff_plain;h=35f98f8506590534227fa6a4193ae564369b4efc Move ServiceToHostMap into stand-alone class ServiceAddressMap and refactor accordingly --- diff --git a/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerAbstract.java b/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerAbstract.java index 691afc6..4119a5c 100644 --- a/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerAbstract.java +++ b/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerAbstract.java @@ -101,6 +101,7 @@ public abstract class NetworkServerAbstract extends SwingWorker _sendMessageQueue = new ConcurrentLinkedQueue<>(); - /** - * Encapsulates a unique network host and the last time it was seen. - */ - protected class LastSeenHost { - final long timeInMillis; - final InetSocketAddress address; - - LastSeenHost(InetSocketAddress address, long timeInMillis) { - this.address = address; - this.timeInMillis = timeInMillis; - } - LastSeenHost(InetSocketAddress host) { - this(host, System.currentTimeMillis()); - } - - /** - * Formatted string representation of IneAddress and timestamp. - * @return the representation - */ - @Override - public String toString() { - return MessageFormat.format("{0}:{1,number,integer}@{2}", this.address.getHostString(), this.address.getPort(), this.timeInMillis); - } - }; - /** - * Maps service _title to its parent network host. - *

- * Used by methods on the Owner Thread to determine the list of valid service - * names it can submit messages to (by iterating the keys using keySet()).

- *

- * New service names can be added in two ways:
- *

    - *
  1. by the Worker Thread from received messages
  2. - *
  3. by the Owner or (other thread) from a service discovery helper (such as multicast discovery)
  4. - *
- */ - protected ConcurrentHashMap _serviceToHostMap = new ConcurrentHashMap<>();; - /** * Wrapper for filtering NetworkMessageEvents based on the message intent */ @@ -209,6 +172,7 @@ public abstract class NetworkServerAbstract extends SwingWorker InetSocketAddress lookups * @param logger An instance of Logger to be used by all objects of this class */ - public NetworkServerAbstract(WSYD_SocketAddress socketAddress, String title, Logger logger) { + public NetworkServerAbstract(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap, Logger logger) { this._connectionCount = 0; this._title = title; this._socketAddress = socketAddress; + this._serviceToHostMap = serviceToHostMap; if (LOGGER == null) // do not replace existing logger reference LOGGER = logger; } @@ -235,9 +201,10 @@ public abstract class NetworkServerAbstract extends SwingWorker InetSocketAddress lookups */ - public NetworkServerAbstract(WSYD_SocketAddress socketAddress, String title) { - this(socketAddress, title, null); + public NetworkServerAbstract(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap) { + this(socketAddress, title, serviceToHostMap, null); } /** @@ -403,16 +370,6 @@ public abstract class NetworkServerAbstract extends SwingWorker 0) { - LastSeenHost host = this._serviceToHostMap.get(target); - if (host != null) - result = host.address; - } - - return result; - } - /** * Add a NetworkMessageEvent listener. * diff --git a/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDP.java b/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDP.java index f3ad6e5..b514fa8 100644 --- a/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDP.java +++ b/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDP.java @@ -35,6 +35,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.LogRecord; import uk.ac.ntu.n0521366.wsyd.libs.message.MessageLogRecord; +import uk.ac.ntu.n0521366.wsyd.libs.net.ServiceAddressMap; @@ -63,10 +64,11 @@ public class NetworkServerUDP extends NetworkServerAbstract { * * @param socketAddress The socket to listen on * @param title source identifier for use in log messages and sent NetworkMessage objects + * @param serviceToHostMap the map object used for host <> InetSocketAddress lookups * @param logger An instance of Logger to be used by all objects of this class */ - public NetworkServerUDP(WSYD_SocketAddress socketAddress, String title, Logger logger) { - super(socketAddress, title, logger); + public NetworkServerUDP(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap, Logger logger) { + super(socketAddress, title, serviceToHostMap, logger); } /** @@ -76,9 +78,10 @@ public class NetworkServerUDP extends NetworkServerAbstract { * * @param socketAddress The socket to listen on * @param title source identifier for use in log messages and sent NetworkMessage objects + * @param serviceToHostMap the map object used for host <> InetSocketAddress lookups */ - public NetworkServerUDP(WSYD_SocketAddress socketAddress, String title) { - super(socketAddress, title); + public NetworkServerUDP(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap) { + super(socketAddress, title, serviceToHostMap); } /** @@ -145,7 +148,7 @@ public class NetworkServerUDP extends NetworkServerAbstract { if (!messageReceived.getSender().equals(_title)) { // add or update the last-seen time of the Sender host in the known services map - LastSeenHost host = new LastSeenHost((InetSocketAddress)packetReceive.getSocketAddress()); + ServiceAddressMap.LastSeenHost host = new ServiceAddressMap.LastSeenHost((InetSocketAddress)packetReceive.getSocketAddress()); this._serviceToHostMap.put(messageReceived.getSender(), host); log(Level.FINEST, _title, MessageFormat.format("Added \"{0}\" to service map", messageReceived.getSender())); @@ -199,7 +202,7 @@ public class NetworkServerUDP extends NetworkServerAbstract { boolean result = false; if (message != null) { - LastSeenHost host = _serviceToHostMap.get(message.getTarget()); + ServiceAddressMap.LastSeenHost host = _serviceToHostMap.get(message.getTarget()); if (host != null) { InetSocketAddress address = host.address; if (address != null) { diff --git a/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDPMulticast.java b/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDPMulticast.java index 28c3f4f..559e81b 100644 --- a/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDPMulticast.java +++ b/src/uk/ac/ntu/n0521366/wsyd/libs/net/NetworkServerUDPMulticast.java @@ -31,6 +31,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.ArrayList; import java.util.Enumeration; +import uk.ac.ntu.n0521366.wsyd.libs.net.ServiceAddressMap; /** * @@ -52,12 +53,13 @@ public class NetworkServerUDPMulticast extends NetworkServerUDP { * * @param socketAddress The socket to listen on * @param title source identifier for use in log messages and sent NetworkMessage objects + * @param serviceToHostMap the map object used for host <> InetSocketAddress lookups * @param logger An instance of Logger to be used by all objects of this class */ - public NetworkServerUDPMulticast(WSYD_SocketAddress socketAddress, String title, Logger logger) { - super(socketAddress, title, logger); + public NetworkServerUDPMulticast(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap, Logger logger) { + super(socketAddress, title, serviceToHostMap, logger); // permit broadcasting to pseudo-host 'all' since this is multicast - this._serviceToHostMap.put("all", new LastSeenHost(socketAddress.getSocketAddress())); + this._serviceToHostMap.put("all", new ServiceAddressMap.LastSeenHost(socketAddress.getSocketAddress())); } /** @@ -67,9 +69,10 @@ public class NetworkServerUDPMulticast extends NetworkServerUDP { * * @param socketAddress The socket to listen on * @param title source identifier for use in log messages and sent NetworkMessage objects + * @param serviceToHostMap the map object used for host <> InetSocketAddress lookups */ - public NetworkServerUDPMulticast(WSYD_SocketAddress socketAddress, String title) { - super(socketAddress, title); + public NetworkServerUDPMulticast(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap) { + super(socketAddress, title, serviceToHostMap); } /** @@ -143,36 +146,4 @@ public class NetworkServerUDPMulticast extends NetworkServerUDP { } } - - /** - * Remove stale service records. - * - * @param ageInMillis milliseconds since last seen to be considered stale - * @return quantity of records removed - */ - public ArrayList cleanServiceToHostMap(long ageInMillis) { - ArrayList result = new ArrayList<>(); - long expireTime = System.currentTimeMillis() - ageInMillis; - java.util.Enumeration keys = this._serviceToHostMap.keys(); - while (keys.hasMoreElements()) { - String key = keys.nextElement(); - - // XXX: special handling for "all" target - never remove it - if (!key.equals("all")) { - LastSeenHost host = _serviceToHostMap.get(key); - if (host != null) { - if (host.timeInMillis < expireTime) { - if (_serviceToHostMap.remove(key, host)) { - result.add(key); - ArrayList messages = new ArrayList<>(); - messages.add(key); - log(Level.INFO, _title, "Removed \"{0}\" from service map", messages); - } - } - } - } - } - return result; - } - } diff --git a/src/uk/ac/ntu/n0521366/wsyd/libs/net/ServiceAddressMap.java b/src/uk/ac/ntu/n0521366/wsyd/libs/net/ServiceAddressMap.java new file mode 100644 index 0000000..72f4fef --- /dev/null +++ b/src/uk/ac/ntu/n0521366/wsyd/libs/net/ServiceAddressMap.java @@ -0,0 +1,185 @@ +/* + * The MIT License + * + * Copyright 2015 TJ . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package uk.ac.ntu.n0521366.wsyd.libs.net; + +import java.net.InetSocketAddress; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Maps service names on hosts to an InetAddress:Port pair. + * + * @author TJ + */ +public class ServiceAddressMap { + /** + * Multi-thread safe map keyed on the service name. + */ + protected ConcurrentHashMap _serviceToAddressMap = new ConcurrentHashMap<>(); + + /** + * Encapsulates a unique network host and the last time it was seen. + */ + public static class LastSeenHost { + /** + * State of a record: + * + * STATIC = was manually entered and should not be removed + * DYNAMIC = was discovered via multicast announcement or new connection and can be removed + */ + public static enum STATE {STATIC, DYNAMIC} + + final STATE state; + final long timeInMillis; + final InetSocketAddress address; + + /** + * Constructs a new instance of a host. + * + * @param address The current address:port + * @param timeInMillis time last seen + * @param state whether record was added through dynamic discovery + */ + LastSeenHost(InetSocketAddress address, long timeInMillis, STATE state) { + this.address = address; + this.timeInMillis = timeInMillis; + this.state = state; + } + + /** + * Construct a new instance of a dynamically announced host. + * + * @param host + */ + LastSeenHost(InetSocketAddress host) { + this(host, System.currentTimeMillis(), STATE.DYNAMIC); + } + + /** + * Formatted string representation of InetAddress and timestamp. + * @return the representation + */ + @Override + public String toString() { + return MessageFormat.format("{0}:{1,number,integer}@{2}", this.address.getHostString(), this.address.getPort(), this.timeInMillis); + } + }; + + /** + * The Logger to use. + */ + private static Logger LOGGER = null; + + /** + * Facility name for logger + */ + private String _facility = null; + + /** + * Construct a map with a Logger. + * + * @param facility The log facility to tag messages with + * @param logger The Logger + */ + public ServiceAddressMap(String facility, Logger logger) { + this._facility = facility; + LOGGER = logger; + } + + /** + * Log some message. + * @param level + * @param message + */ + private void log(Level level, String message) { + if (LOGGER == null) + return; + LOGGER.logp(level, _facility, null, message); + + } + /** + * Remove stale service records. + * + * @param ageInMillis milliseconds since last seen to be considered stale + * @return quantity of records removed + */ + public ArrayList cleanServiceAddressMap(long ageInMillis) { + ArrayList result = new ArrayList<>(); + long expireTime = System.currentTimeMillis() - ageInMillis; + java.util.Enumeration keys = this._serviceToAddressMap.keys(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + + // XXX: special handling for "all" target - never remove it + LastSeenHost host = _serviceToAddressMap.get(key); + if (host != null && host.state == LastSeenHost.STATE.DYNAMIC) { + if (host.timeInMillis < expireTime) { + if (_serviceToAddressMap.remove(key, host)) { + result.add(key); + log(Level.INFO, MessageFormat.format("Removed \"{0}\" from service map", key)); + } + } + } + } + return result; + } + + /** + * Ensure service is in the map of known hosts. + * @param service the service name to check + * @return true is the target service is known + */ + protected boolean isServiceValid(String service) { + return this._serviceToAddressMap.containsKey(service); + } + + /** + * Get the current InetSocketAddress of a target. + * + * @param target name of the service + * @return IP address and port of the service + */ + public InetSocketAddress getServiceAddress(String target) { + InetSocketAddress result = null; + + if (target != null && target.length() > 0) { + LastSeenHost host = this._serviceToAddressMap.get(target); + if (host != null) + result = host.address; + } + + return result; + } + + public void put(String service, LastSeenHost host) { + this._serviceToAddressMap.put(service, host); + } + + public LastSeenHost get(String service) { + return this._serviceToAddressMap.get(service); + } +} diff --git a/src/uk/ac/ntu/n0521366/wsyd/management/ServerManagement.java b/src/uk/ac/ntu/n0521366/wsyd/management/ServerManagement.java index 80cdee1..575d2ed 100644 --- a/src/uk/ac/ntu/n0521366/wsyd/management/ServerManagement.java +++ b/src/uk/ac/ntu/n0521366/wsyd/management/ServerManagement.java @@ -29,6 +29,7 @@ import java.io.File; import javax.swing.ImageIcon; import java.awt.Desktop; import java.net.URI; +import java.net.InetAddress; import java.io.IOException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -61,7 +62,7 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa /** * class-wide logger */ - static final Logger LOGGER = Logger.getLogger("ServerManagement"); + Logger LOGGER = null; /** * Location of resource bundles, images, icons @@ -71,8 +72,9 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa /** * Readable/displayable name of this application */ - String _title; + final String _title = "ServerManagement"; + ServiceAddressMap _serviceToAddressMap; /** * The UDP listener address for incoming log messages */ @@ -92,7 +94,8 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa * Multi-cast neighbour advertise and discover service in a SwingWorker thread. */ NetworkServerUDPMulticast _multicastServer = null; - + + boolean _multicastAnnouncements = false; /** * Enable or suspend logging @@ -116,8 +119,10 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa * @see #initListeners() */ public ServerManagement() { - _title = "ServerManagement"; + if (LOGGER == null) // single instance of the Logger shared by all class objects + LOGGER = Logger.getLogger(_title); LOGGER.setLevel(Level.ALL); + _serviceToAddressMap = new ServiceAddressMap(_title, LOGGER); initComponents(); _doLogging = true; _autoScroll = true; @@ -126,6 +131,16 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa gDialogAbout.getContentPane().setBackground(gDialogAbout.getBackground()); } + /** + * Creates new Server Management GUI that also announces itself using Multicast Neighbour discovery. + * @param multicastAnnouncements true if it should announce itself + * @param serverSocial IP address of ServerSocial - if non-null prevents ServerSocial map entry being treated as stale + */ + public ServerManagement(boolean multicastAnnouncements, InetAddress serverSocial) { + this(); + this._multicastAnnouncements = multicastAnnouncements; + // TODO: implement constructor setting IP address of SocialServer from command-line value - needs ServiceToHostMap separating from NetworkServerAbstract and do not allow manually added service map element being treated as stale + } /** * Initialise listeners and other objects that require a reference to 'this'. * @@ -144,52 +159,57 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa LOGGER.log(Level.INFO, "Server Management starting"); _logServerSA = new WSYD_SocketAddress(Network.PORTS_SERVER_LOG, Protocol.UDP); - _logServer = new NetworkServerUDP(_logServerSA, "ServerLog", LOGGER); + _logServer = new NetworkServerUDP(_logServerSA, _title, _serviceToAddressMap, LOGGER); _logServer.addNetworkMessageEventListener(this, "Log"); _logServer.setSimulate(false); _logServer.execute(); + _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY, Protocol.UDP); - _multicastServer = new NetworkServerUDPMulticast(_multicastAdvertiserSA, "ServerLogMC", LOGGER); + _multicastServer = new NetworkServerUDPMulticast(_multicastAdvertiserSA, "ServerManagementMC", _serviceToAddressMap, LOGGER); _multicastServer.addNetworkMessageEventListener(this, "Neighbour"); _multicastServer.execute(); - - ActionListener multicastAnnounceActionListener = new ActionListener() { - /** - * Activated by timer events to send multi-cast neighbour announcements for the Log Service. - * @param e - */ - @Override - public void actionPerformed(ActionEvent e) { - // Create local log report first - LogRecord record = new LogRecord(Level.FINEST, "Multicast: Announcing Presence"); - record.setSourceClassName("ServerLog"); - record.setMillis(System.currentTimeMillis()); - LOGGER.log(record); - - // Announce the Log Server service - MessagePresence mp = new MessagePresence("ServerLog", Network.PORTS_SERVER_LOG); - NetworkMessage nm = NetworkMessage.createNetworkMessage("Neighbour", "all", mp); - nm.setSender("ServerLog"); - _multicastServer.queueMessage(nm); - - // clean up the known hosts map and keep Server menu up-to-date - ArrayList servicesRemoved = _multicastServer.cleanServiceToHostMap(5000); - for (String service: servicesRemoved) { + + if (this._multicastAnnouncements) { + ActionListener multicastAnnounceActionListener = new ActionListener() { + /** + * Activated by timer events to send multi-cast neighbour + * announcements for the Log Service. + * + * @param e + */ + @Override + public void actionPerformed(ActionEvent e) { + // Create local log report first + LogRecord record = new LogRecord(Level.FINEST, "Multicast: Announcing Presence"); + record.setSourceClassName("ServerLog"); + record.setMillis(System.currentTimeMillis()); + LOGGER.log(record); + + // Announce the Log Server service + MessagePresence mp = new MessagePresence("ServerLog", Network.PORTS_SERVER_LOG); + NetworkMessage nm = NetworkMessage.createNetworkMessage("Neighbour", "all", mp); + nm.setSender("ServerLog"); + _multicastServer.queueMessage(nm); + + // clean up the known hosts map and keep Server menu up-to-date + ArrayList servicesRemoved = _serviceToAddressMap.cleanServiceAddressMap(5000); + for (String service : servicesRemoved) { switch (service) { case "ServerSocial": gMenuServerSocial.setEnabled(false); break; case "ServerChat": gMenuServerChat.setEnabled(false); - break; + break; } - } + } - } - }; - multicastAnnounce = new Timer(1000, multicastAnnounceActionListener); - multicastAnnounce.setInitialDelay(100); - multicastAnnounce.start(); + } + }; + multicastAnnounce = new Timer(1000, multicastAnnounceActionListener); + multicastAnnounce.setInitialDelay(100); + multicastAnnounce.start(); + } return this; } @@ -231,7 +251,7 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa boolean result = false; if (message != null) { - InetSocketAddress address = this._multicastServer.getTargetAddress(message.getTarget()); + InetSocketAddress address = this._serviceToAddressMap.getServiceAddress(message.getTarget()); if (address != null) { message.setSender("ServerManagement"); try { @@ -244,7 +264,7 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa DatagramSocket socket = new DatagramSocket(); // acknowledge receipt socket.send(packetSend); - System.err.println(MessageFormat.format("Sending packet for {0} to {1} ({3}:{4}) from {2}", message.getIntent(), message.getTarget(), message.getSender(), packetSend.getAddress().getHostAddress(), packetSend.getPort())); + LOGGER.logp(Level.FINEST, _title, null, MessageFormat.format("Sending packet for {0} to {1} ({3}:{4,number,integer}) from {2}", message.getIntent(), message.getTarget(), message.getSender(), packetSend.getAddress().getHostAddress(), packetSend.getPort())); result = true; // successful } catch (IOException e) { @@ -469,10 +489,10 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa private void gMenuServerSocialRestartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuServerSocialRestartActionPerformed // TODO add your handling code here: - System.err.println("Requesting ServerSocial Restart"); + LOGGER.logp(Level.FINEST, _title, null, "Requesting ServerSocial Restart"); MessageServerControl mc = new MessageServerControl(MessageServerControl.EXIT.NO , MessageServerControl.RESTART.YES); - NetworkMessage nm = NetworkMessage.createNetworkMessage("Control", "ServerSocial", mc); - nm.setSender("ServerLog"); + NetworkMessage nm = NetworkMessage.createNetworkMessage("Control", "ServerSocialControl", mc); + nm.setSender(_title); UDPSend(nm); @@ -587,7 +607,6 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa this.isLoggable(m.record); break; case "Neighbour": - // TODO: NetworkMessageReceived(): Test Multicast message received handler to enable menu items for recognised servers String type = nm.getMessage().getMessageType(); if (type.equals(MessagePresence.getType())) { // Presence MessagePresence mp = (MessagePresence)nm.getMessage(); @@ -635,19 +654,43 @@ public class ServerManagement extends javax.swing.JFrame implements NetworkMessa // // // - /* Create and display the form */ - java.awt.EventQueue.invokeLater(new Runnable() { + class App implements Runnable { + public boolean multicastAnnouncements = false; + public InetAddress serverSocial = null; @Override public void run() { try { - new ServerManagement().initListeners().setVisible(true); + new ServerManagement(multicastAnnouncements, serverSocial).initListeners().setVisible(true); } catch(UnknownHostException e) { System.err.println("Error: cannot create log server listener socket"); } } - }); + } + App app = new App(); + + // process command line arguments + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "-announce": + app.multicastAnnouncements = true; + 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) { + System.err.println(MessageFormat.format("Error: {0} is not a valid hostname or IP address", args[i+1])); + } + } + break; + } + } + java.awt.EventQueue.invokeLater(app); } // Variables declaration - do not modify//GEN-BEGIN:variables