4 * Copyright 2015 TJ <hacker@iam.tj>.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 package uk.ac.ntu.n0521366.wsyd.management;
26 import java.io.FileWriter;
27 import java.io.BufferedWriter;
29 import javax.swing.ImageIcon;
30 import java.awt.Desktop;
32 import java.net.InetAddress;
33 import java.io.IOException;
34 import java.awt.event.ActionEvent;
35 import java.awt.event.ActionListener;
36 import java.net.DatagramPacket;
37 import java.net.DatagramSocket;
38 import java.net.InetSocketAddress;
39 import javax.swing.Timer;
40 import javax.swing.table.DefaultTableModel;
41 import java.net.UnknownHostException;
42 import java.util.logging.Logger;
43 import java.util.logging.Level;
44 import java.util.logging.LogRecord;
45 import java.util.logging.Filter;
46 import java.util.Date;
47 import java.text.SimpleDateFormat;
48 import java.text.MessageFormat;
49 import java.util.ArrayList;
50 import uk.ac.ntu.n0521366.wsyd.libs.logging.TableModelHandler;
51 import uk.ac.ntu.n0521366.wsyd.libs.message.MessageLogRecord;
52 import uk.ac.ntu.n0521366.wsyd.libs.message.MessagePresence;
53 import uk.ac.ntu.n0521366.wsyd.libs.message.MessageServerControl;
54 import uk.ac.ntu.n0521366.wsyd.libs.net.WSYD_SocketAddress.Protocol;
55 import uk.ac.ntu.n0521366.wsyd.libs.net.*;
56 import uk.ac.ntu.n0521366.wsyd.libs.net.ServiceAddressMap.LastSeenHost;
59 * @author TJ <hacker@iam.tj>
61 public class ServerManagement extends javax.swing.JFrame implements NetworkMessageEventListener, Filter {
68 * Location of resource bundles, images, icons
70 private static final String resourcePath = "/uk/ac/ntu/n0521366/wsyd/resources";
73 * Readable/displayable name of this application
75 final String _title = "ServerManagement";
78 * Network services to address map.
80 ServiceAddressMap _serviceToAddressMap;
83 * The UDP listener address for incoming log messages
85 WSYD_SocketAddress _udpLogServiceSA = null;
88 * UDP multi-cast presence advertiser
90 WSYD_SocketAddress _multicastAdvertiserSA = null;
93 * Log service running in a SwingWorker thread.
95 NetworkServerUDP _udpLogService = null;
98 * Multi-cast neighbour advertise and discover service in a SwingWorker thread.
100 NetworkServerUDPMulticast _multicastServer = null;
102 boolean _multicastAnnouncements = false;
105 * Enable or suspend logging
107 private boolean _doLogging;
110 * Enable or suspend table auto-scroll
112 private boolean _autoScroll;
115 * Regular presence announcements
117 Timer multicastAnnounce;
121 * Instantiating code <em>must</em> also call initListeners()
123 * @see #initListeners()
125 public ServerManagement() {
126 if (LOGGER == null) // single instance of the Logger shared by all class objects
127 LOGGER = Logger.getLogger(_title);
128 LOGGER.setLevel(Level.ALL);
129 _serviceToAddressMap = new ServiceAddressMap(_title, LOGGER);
133 setLocationRelativeTo(null); // center on screen
134 // XXX: workaround for bug in NetBeans that doesn't set the displayed background colour, only the component colour, from the Properties editor
135 gDialogAbout.getContentPane().setBackground(gDialogAbout.getBackground());
139 * Creates new Server Management GUI that also announces itself using Multicast Neighbour discovery.
140 * @param multicastAnnouncements true if it should announce itself
141 * @param serverSocial IP address of ServerSocial - if non-null prevents ServerSocial map entry being treated as stale
143 public ServerManagement(boolean multicastAnnouncements, InetAddress serverSocial) {
145 this._multicastAnnouncements = multicastAnnouncements;
146 // 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
149 * Initialise listeners and other objects that require a reference to 'this'.
151 * Passing 'this' from within the constructor is unsafe since the object is not
152 * fully constructed, so do it here. The compiler and virtual machine are free to move 'final'
153 * properties outside the constructor which means they may not be correctly
154 * initialised before the constructor returns. This is especially problematic
155 * in multi-threading applications.
157 * @return a reference to 'this' so method calls can be chained (e.g. new ServerManagement().initListeners().setVisible(true) )
158 * @throws UnknownHostException
160 public ServerManagement initListeners() throws UnknownHostException {
161 LOGGER.addHandler(new TableModelHandler(this)); // send messages to the GUI log table
162 LOGGER.setUseParentHandlers(false); // don't send messages to the default error stream logger of the parent
163 LOGGER.log(Level.INFO, "Server Management starting");
165 _udpLogServiceSA = new WSYD_SocketAddress(Network.PORTS_SERVER_LOG, Protocol.UDP);
166 _udpLogService = new NetworkServerUDP(_udpLogServiceSA, _title + "Log", _serviceToAddressMap, LOGGER);
167 _udpLogService.addNetworkMessageEventListener(this, "Log");
168 _udpLogService.setSimulate(false);
169 _udpLogService.execute();
171 _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY, Protocol.UDP);
172 _multicastServer = new NetworkServerUDPMulticast(_multicastAdvertiserSA, _title + "MC", _serviceToAddressMap, LOGGER);
173 _multicastServer.addNetworkMessageEventListener(this, "Neighbour");
174 _multicastServer.execute();
175 // permit broadcasting to pseudo-host 'all' since this is multicast
176 _serviceToAddressMap.put("all", new LastSeenHost(new InetSocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY), LastSeenHost.STATE.STATIC));
178 if (this._multicastAnnouncements) {
179 ActionListener multicastAnnounceActionListener = new ActionListener() {
181 * Activated by timer events to send multi-cast neighbour
182 * announcements for the Log Service.
187 public void actionPerformed(ActionEvent e) {
188 // Create local log report first
189 LogRecord record = new LogRecord(Level.FINEST, "Multicast: Announcing Presence");
190 record.setSourceClassName("ServerLog");
191 record.setMillis(System.currentTimeMillis());
194 // Announce the Log Server service
195 MessagePresence mp = new MessagePresence(_title + "Log", _udpLogService.getSocketAddress());
196 NetworkMessage nm = NetworkMessage.createNetworkMessage("Neighbour", "all", mp);
197 nm.setSender(_title + "Log");
198 _multicastServer.queueMessage(nm);
200 // clean up the known hosts map and keep Server menu up-to-date
201 ArrayList<String> servicesRemoved = _serviceToAddressMap.cleanServiceAddressMap(5000);
202 for (String service : servicesRemoved) {
205 gMenuServerSocial.setEnabled(false);
208 gMenuServerChat.setEnabled(false);
215 multicastAnnounce = new Timer(1000, multicastAnnounceActionListener);
216 multicastAnnounce.setInitialDelay(100);
217 multicastAnnounce.start();
224 * Add a log record to the log table if logging is enabled.
226 * Abusing an already-existing logging interface. This method isn't filtering, it is called by
227 * the Logger's TableModelHandler to publish records.
229 * @see TableModelHandler
231 * @return true if logging is enabled
234 public boolean isLoggable(LogRecord record) {
236 if (record != null) {
237 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
238 // add the log record to the log table
239 ((DefaultTableModel)gLogTable.getModel()).addRow(
241 df.format(new Date(record.getMillis())),
242 record.getLevel().toString(),
243 record.getSourceClassName(),
247 if (_autoScroll) { // keep last record added in the view
248 int row = gLogTable.getModel().getRowCount();
249 gLogTable.scrollRectToVisible(gLogTable.getCellRect(row, 0, true));
256 protected boolean UDPSend(NetworkMessage message) {
257 boolean result = false;
259 if (message != null) {
260 InetSocketAddress address = this._serviceToAddressMap.getServiceAddress(message.getTarget());
261 if (address != null) {
262 message.setSender("ServerManagement");
264 byte[] dataSend = NetworkMessage.serialize(message);
265 DatagramPacket packetSend = new DatagramPacket(dataSend, dataSend.length);
266 // set target's remote host address and port
267 packetSend.setAddress(address.getAddress());
268 packetSend.setPort(address.getPort());
270 DatagramSocket socket = new DatagramSocket();
271 // acknowledge receipt
272 socket.send(packetSend);
273 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()));
275 result = true; // successful
276 } catch (IOException e) {
277 // TODO: serverSend() add IOException handler
286 * This method is called from within the constructor to initialize the form.
287 * WARNING: Do NOT modify this code. The content of this method is always
288 * regenerated by the Form Editor.
290 @SuppressWarnings("unchecked")
291 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
292 private void initComponents() {
294 buttonGroup1 = new javax.swing.ButtonGroup();
295 gDialogAbout = new javax.swing.JDialog();
296 gTextAreaAbout = new javax.swing.JTextArea();
297 gBtnAbout = new javax.swing.JButton();
298 gFileChooser = new javax.swing.JFileChooser();
299 gLogScroller = new javax.swing.JScrollPane();
300 gLogTable = new javax.swing.JTable();
301 gMenuBar = new javax.swing.JMenuBar();
302 gMenuFile = new javax.swing.JMenu();
303 gMenuFileSave = new javax.swing.JMenuItem();
304 gMenuLog = new javax.swing.JMenu();
305 gMenuLogClear = new javax.swing.JMenuItem();
306 gMenuLogControl = new javax.swing.JCheckBoxMenuItem();
307 gMenuLogAutoScroll = new javax.swing.JCheckBoxMenuItem();
308 gMenuServers = new javax.swing.JMenu();
309 gMenuServerSocial = new javax.swing.JMenu();
310 gMenuServerSocialRestart = new javax.swing.JMenuItem();
311 gMenuServerSocialStop = new javax.swing.JMenuItem();
312 gMenuServerChat = new javax.swing.JMenu();
313 gMenuServerChatRestart = new javax.swing.JMenuItem();
314 gMenuServerChatStop = new javax.swing.JMenuItem();
315 gMenuHelp = new javax.swing.JMenu();
316 gMenuHelpAbout = new javax.swing.JMenuItem();
318 gDialogAbout.setTitle("About");
319 gDialogAbout.setBackground(new java.awt.Color(255, 255, 255));
320 gDialogAbout.setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
321 gDialogAbout.setMinimumSize(new java.awt.Dimension(590, 340));
322 gDialogAbout.setResizable(false);
323 gDialogAbout.getContentPane().setLayout(null);
325 gTextAreaAbout.setEditable(false);
326 gTextAreaAbout.setColumns(20);
327 gTextAreaAbout.setRows(5);
328 gTextAreaAbout.setText("Server Management client\n© Copyright 2015 TJ <hacker@iam.tj>\n\n<<< Click on the mug to learn more!\n\nI will disappear in 20 seconds.\n\n");
329 gTextAreaAbout.setBorder(null);
330 gDialogAbout.getContentPane().add(gTextAreaAbout);
331 gTextAreaAbout.setBounds(310, 30, 270, 200);
333 gBtnAbout.setBackground(new java.awt.Color(255, 255, 255));
334 gBtnAbout.setFont(new java.awt.Font("Dialog", 1, 18)); // NOI18N
335 gBtnAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ntu/n0521366/wsyd/resources/ScroogledKeepCalmMug.png"))); // NOI18N
336 gBtnAbout.setText("We Stealz Your Dataz");
337 gBtnAbout.setBorder(null);
338 gBtnAbout.setBorderPainted(false);
339 gBtnAbout.setContentAreaFilled(false);
340 gBtnAbout.setDefaultCapable(false);
341 gBtnAbout.setFocusPainted(false);
342 gBtnAbout.setRolloverEnabled(false);
343 gBtnAbout.setVerticalAlignment(javax.swing.SwingConstants.TOP);
344 gBtnAbout.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
345 gBtnAbout.addActionListener(new java.awt.event.ActionListener() {
346 public void actionPerformed(java.awt.event.ActionEvent evt) {
350 gDialogAbout.getContentPane().add(gBtnAbout);
351 gBtnAbout.setBounds(0, 0, 530, 324);
353 gFileChooser.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
354 gFileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
355 gFileChooser.setDialogTitle("Save As");
357 setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
358 setTitle("We Stealz Your Dataz Servers Management");
359 setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
361 gLogScroller.setAutoscrolls(true);
363 gLogTable.setModel(new javax.swing.table.DefaultTableModel(
365 {null, null, null, null}
368 "Time", "Level", "Facility", "Message"
371 Class[] types = new Class [] {
372 java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
374 boolean[] canEdit = new boolean [] {
375 false, false, false, false
378 public Class getColumnClass(int columnIndex) {
379 return types [columnIndex];
382 public boolean isCellEditable(int rowIndex, int columnIndex) {
383 return canEdit [columnIndex];
386 gLogTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
387 gLogTable.setFillsViewportHeight(true);
388 gLogTable.getTableHeader().setReorderingAllowed(false);
389 gLogScroller.setViewportView(gLogTable);
390 if (gLogTable.getColumnModel().getColumnCount() > 0) {
391 gLogTable.getColumnModel().getColumn(0).setPreferredWidth(128);
392 gLogTable.getColumnModel().getColumn(1).setPreferredWidth(128);
393 gLogTable.getColumnModel().getColumn(2).setPreferredWidth(128);
396 getContentPane().add(gLogScroller, java.awt.BorderLayout.CENTER);
398 gMenuFile.setText("File");
400 gMenuFileSave.setText("Save...");
401 gMenuFileSave.setActionCommand("FileSave");
402 gMenuFileSave.addActionListener(new java.awt.event.ActionListener() {
403 public void actionPerformed(java.awt.event.ActionEvent evt) {
404 gMenuFileSaveActionPerformed(evt);
407 gMenuFile.add(gMenuFileSave);
409 gMenuBar.add(gMenuFile);
411 gMenuLog.setText("Log");
413 gMenuLogClear.setText("Clear");
414 gMenuLogClear.setActionCommand("LogTableClear");
415 gMenuLogClear.addActionListener(new java.awt.event.ActionListener() {
416 public void actionPerformed(java.awt.event.ActionEvent evt) {
417 gMenuLogClearActionPerformed(evt);
420 gMenuLog.add(gMenuLogClear);
422 gMenuLogControl.setSelected(true);
423 gMenuLogControl.setText("Running");
424 gMenuLogControl.setActionCommand("LogControl");
425 gMenuLogControl.addActionListener(new java.awt.event.ActionListener() {
426 public void actionPerformed(java.awt.event.ActionEvent evt) {
427 gMenuLogControlActionPerformed(evt);
430 gMenuLog.add(gMenuLogControl);
432 gMenuLogAutoScroll.setSelected(true);
433 gMenuLogAutoScroll.setText("Auto-scroll");
434 gMenuLogAutoScroll.setActionCommand("LogAutoScroll");
435 gMenuLogAutoScroll.addActionListener(new java.awt.event.ActionListener() {
436 public void actionPerformed(java.awt.event.ActionEvent evt) {
437 gMenuLogAutoScrollActionPerformed(evt);
440 gMenuLog.add(gMenuLogAutoScroll);
442 gMenuBar.add(gMenuLog);
444 gMenuServers.setText("Servers");
446 gMenuServerSocial.setText("Social");
447 gMenuServerSocial.setEnabled(false);
449 gMenuServerSocialRestart.setText("Restart");
450 gMenuServerSocialRestart.setActionCommand("SocialRestart");
451 gMenuServerSocialRestart.addActionListener(new java.awt.event.ActionListener() {
452 public void actionPerformed(java.awt.event.ActionEvent evt) {
453 gMenuServerSocialRestartActionPerformed(evt);
456 gMenuServerSocial.add(gMenuServerSocialRestart);
458 gMenuServerSocialStop.setText("Stop");
459 gMenuServerSocialStop.setActionCommand("SocialStop");
460 gMenuServerSocial.add(gMenuServerSocialStop);
462 gMenuServers.add(gMenuServerSocial);
464 gMenuServerChat.setText("Chat");
465 gMenuServerChat.setEnabled(false);
467 gMenuServerChatRestart.setText("Restart");
468 gMenuServerChatRestart.setActionCommand("ChatRestart");
469 gMenuServerChat.add(gMenuServerChatRestart);
471 gMenuServerChatStop.setText("Stop");
472 gMenuServerChatStop.setActionCommand("ChatStop");
473 gMenuServerChat.add(gMenuServerChatStop);
475 gMenuServers.add(gMenuServerChat);
477 gMenuBar.add(gMenuServers);
479 gMenuHelp.setText("Help");
481 gMenuHelpAbout.setText("About");
482 gMenuHelpAbout.addActionListener(new java.awt.event.ActionListener() {
483 public void actionPerformed(java.awt.event.ActionEvent evt) {
484 gMenuHelpAboutActionPerformed(evt);
487 gMenuHelp.add(gMenuHelpAbout);
489 gMenuBar.add(gMenuHelp);
491 setJMenuBar(gMenuBar);
494 }// </editor-fold>//GEN-END:initComponents
496 private void gMenuServerSocialRestartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuServerSocialRestartActionPerformed
497 // TODO add your handling code here:
498 LOGGER.logp(Level.FINEST, _title, null, "Requesting ServerSocial Restart");
499 MessageServerControl mc = new MessageServerControl(MessageServerControl.EXIT.NO , MessageServerControl.RESTART.YES);
500 NetworkMessage nm = NetworkMessage.createNetworkMessage("Control", "ServerSocialControl", mc);
501 nm.setSender(_title);
505 }//GEN-LAST:event_gMenuServerSocialRestartActionPerformed
508 * When the (disguised) mug-icon button is pressed load a web page in the system default browser.
510 * Displays a news story about Microsoft Store's 'Scroogle' mug which coincidentally has a tag line
511 * that is almost identical to the chosen name of this application.
515 private void AboutAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AboutAction
517 Desktop.getDesktop().browse(URI.create("http://www.slate.com/blogs/future_tense/2013/11/20/microsoft_scroogled_gear_anti_google_t_shirts_mugs_say_keep_calm_while_we.html"));
518 } catch(IOException e) {
520 }//GEN-LAST:event_AboutAction
523 * Show the Help>About dialog and auto-close it after 20 seconds.
527 private void gMenuHelpAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuHelpAboutActionPerformed
528 ActionListener autoCloseAboutDlg = new ActionListener() {
530 public void actionPerformed(ActionEvent e) {
531 gDialogAbout.setVisible(false);
535 gDialogAbout.setLocationRelativeTo(this); // center in application window
536 gDialogAbout.setVisible(true);
537 Timer autoClose = new Timer(20000, autoCloseAboutDlg);
539 }//GEN-LAST:event_gMenuHelpAboutActionPerformed
542 * Save log entries to a file.
546 private void gMenuFileSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuFileSaveActionPerformed
547 if (gFileChooser.showSaveDialog(this) == javax.swing.JFileChooser.APPROVE_OPTION) {
548 File saveAs = gFileChooser.getSelectedFile();
550 BufferedWriter writer = new BufferedWriter(new FileWriter(saveAs));
553 for (int row = 0; row < gLogTable.getModel().getRowCount(); row++) {
554 StringBuilder record = new StringBuilder();
555 int colMax = gLogTable.getModel().getColumnCount();
556 for (int col = 0; col < colMax; col++) {
557 record.append(gLogTable.getModel().getValueAt(row, col));
558 if (col < colMax - 1) {
562 writer.write(record.toString());
566 } catch (IOException e) {
567 System.err.println("Unable to write to file");
570 }//GEN-LAST:event_gMenuFileSaveActionPerformed
573 * Clear the log table.
576 private void gMenuLogClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogClearActionPerformed
577 ((DefaultTableModel)gLogTable.getModel()).setRowCount(0);
578 }//GEN-LAST:event_gMenuLogClearActionPerformed
581 * Enable or disable logging.
584 private void gMenuLogControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogControlActionPerformed
585 _doLogging = !_doLogging;
586 gMenuLogControl.setSelected(_doLogging);
587 }//GEN-LAST:event_gMenuLogControlActionPerformed
590 * Enable or disable automatic scrolling of the log table.
593 private void gMenuLogAutoScrollActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogAutoScrollActionPerformed
594 _autoScroll = !_autoScroll;
595 gMenuLogAutoScroll.setSelected(_autoScroll);
596 }//GEN-LAST:event_gMenuLogAutoScrollActionPerformed
599 * Receive a NetworkMessageEvent and dispose of it
603 public void NetworkMessageReceived(NetworkMessageEvent event) {
604 NetworkMessage nm = event.getNetworkMessage();
605 if (nm == null || !_doLogging)
607 // is it a LogRecord?
608 switch (nm.getIntent()) {
610 MessageLogRecord m = (MessageLogRecord) nm.getMessage();
613 this.isLoggable(m.record);
616 String type = nm.getMessage().getMessageType();
617 if (type.equals(MessagePresence.getType())) { // Presence
618 MessagePresence mp = (MessagePresence)nm.getMessage();
619 switch (mp.serviceName) {
621 gMenuServerSocial.setEnabled(true);
624 gMenuServerChat.setEnabled(true);
630 default: // log all unhandled messages
631 LogRecord record = new LogRecord(Level.WARNING,
632 MessageFormat.format("Unhandled NetworkMessage received with intent: \"{0}\" sender: \"{1}\" target: \"{2}\"",
633 nm.getIntent(), nm.getSender(), nm.getTarget() )
635 record.setMillis(System.currentTimeMillis());
641 * @param args the command line arguments
643 public static void main(String args[]) {
644 /* Set the Nimbus look and feel */
645 //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
646 /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
647 * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
650 for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
651 if ("Nimbus".equals(info.getName())) {
652 javax.swing.UIManager.setLookAndFeel(info.getClassName());
656 } catch (ClassNotFoundException|InstantiationException|IllegalAccessException|javax.swing.UnsupportedLookAndFeelException ex) {
657 java.util.logging.Logger.getLogger(ServerManagement.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
663 /* Create and display the form */
664 class App implements Runnable {
665 public boolean multicastAnnouncements = false;
666 public InetAddress serverSocial = null;
670 new ServerManagement(multicastAnnouncements, serverSocial).initListeners().setVisible(true);
672 catch(UnknownHostException e) {
673 System.err.println("Error: cannot create log server listener socket");
679 // process command line arguments
680 for (int i = 0; i < args.length; i++) {
683 app.multicastAnnouncements = true;
686 if (args.length >= i+1) {
687 // read the next argument as an IP address
690 temp = InetAddress.getByName(args[i+1]);
691 app.serverSocial = temp;
692 } catch (UnknownHostException e) {
693 System.err.println(MessageFormat.format("Error: {0} is not a valid hostname or IP address", args[i+1]));
699 java.awt.EventQueue.invokeLater(app);
702 // Variables declaration - do not modify//GEN-BEGIN:variables
703 private javax.swing.ButtonGroup buttonGroup1;
704 private javax.swing.JButton gBtnAbout;
705 private javax.swing.JDialog gDialogAbout;
706 private javax.swing.JFileChooser gFileChooser;
707 private javax.swing.JScrollPane gLogScroller;
708 private javax.swing.JTable gLogTable;
709 private javax.swing.JMenuBar gMenuBar;
710 private javax.swing.JMenu gMenuFile;
711 private javax.swing.JMenuItem gMenuFileSave;
712 private javax.swing.JMenu gMenuHelp;
713 private javax.swing.JMenuItem gMenuHelpAbout;
714 private javax.swing.JMenu gMenuLog;
715 private javax.swing.JCheckBoxMenuItem gMenuLogAutoScroll;
716 private javax.swing.JMenuItem gMenuLogClear;
717 private javax.swing.JCheckBoxMenuItem gMenuLogControl;
718 private javax.swing.JMenu gMenuServerChat;
719 private javax.swing.JMenuItem gMenuServerChatRestart;
720 private javax.swing.JMenuItem gMenuServerChatStop;
721 private javax.swing.JMenu gMenuServerSocial;
722 private javax.swing.JMenuItem gMenuServerSocialRestart;
723 private javax.swing.JMenuItem gMenuServerSocialStop;
724 private javax.swing.JMenu gMenuServers;
725 private javax.swing.JTextArea gTextAreaAbout;
726 // End of variables declaration//GEN-END:variables