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.*;
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";
77 ServiceAddressMap _serviceToAddressMap;
79 * The UDP listener address for incoming log messages
81 WSYD_SocketAddress _logServerSA = null;
84 * UDP multi-cast presence advertiser
86 WSYD_SocketAddress _multicastAdvertiserSA = null;
89 * Log service running in a SwingWorker thread.
91 NetworkServerUDP _logServer = null;
94 * Multi-cast neighbour advertise and discover service in a SwingWorker thread.
96 NetworkServerUDPMulticast _multicastServer = null;
98 boolean _multicastAnnouncements = false;
101 * Enable or suspend logging
103 private boolean _doLogging;
106 * Enable or suspend table auto-scroll
108 private boolean _autoScroll;
111 * Regular presence announcements
113 Timer multicastAnnounce;
117 * Instantiating code <em>must</em> also call initListeners()
119 * @see #initListeners()
121 public ServerManagement() {
122 if (LOGGER == null) // single instance of the Logger shared by all class objects
123 LOGGER = Logger.getLogger(_title);
124 LOGGER.setLevel(Level.ALL);
125 _serviceToAddressMap = new ServiceAddressMap(_title, LOGGER);
129 setLocationRelativeTo(null); // center on screen
130 // XXX: workaround for bug in NetBeans that doesn't set the displayed background colour, only the component colour, from the Properties editor
131 gDialogAbout.getContentPane().setBackground(gDialogAbout.getBackground());
135 * Creates new Server Management GUI that also announces itself using Multicast Neighbour discovery.
136 * @param multicastAnnouncements true if it should announce itself
137 * @param serverSocial IP address of ServerSocial - if non-null prevents ServerSocial map entry being treated as stale
139 public ServerManagement(boolean multicastAnnouncements, InetAddress serverSocial) {
141 this._multicastAnnouncements = multicastAnnouncements;
142 // 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
145 * Initialise listeners and other objects that require a reference to 'this'.
147 * Passing 'this' from within the constructor is unsafe since the object is not
148 * fully constructed, so do it here. The compiler and virtual machine are free to move 'final'
149 * properties outside the constructor which means they may not be correctly
150 * initialised before the constructor returns. This is especially problematic
151 * in multi-threading applications.
153 * @return a reference to 'this' so method calls can be chained (e.g. new ServerManagement().initListeners().setVisible(true) )
154 * @throws UnknownHostException
156 public ServerManagement initListeners() throws UnknownHostException {
157 LOGGER.addHandler(new TableModelHandler(this)); // send messages to the GUI log table
158 LOGGER.setUseParentHandlers(false); // don't send messages to the default error stream logger of the parent
159 LOGGER.log(Level.INFO, "Server Management starting");
161 _logServerSA = new WSYD_SocketAddress(Network.PORTS_SERVER_LOG, Protocol.UDP);
162 _logServer = new NetworkServerUDP(_logServerSA, _title, _serviceToAddressMap, LOGGER);
163 _logServer.addNetworkMessageEventListener(this, "Log");
164 _logServer.setSimulate(false);
165 _logServer.execute();
167 _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY, Protocol.UDP);
168 _multicastServer = new NetworkServerUDPMulticast(_multicastAdvertiserSA, "ServerManagementMC", _serviceToAddressMap, LOGGER);
169 _multicastServer.addNetworkMessageEventListener(this, "Neighbour");
170 _multicastServer.execute();
172 if (this._multicastAnnouncements) {
173 ActionListener multicastAnnounceActionListener = new ActionListener() {
175 * Activated by timer events to send multi-cast neighbour
176 * announcements for the Log Service.
181 public void actionPerformed(ActionEvent e) {
182 // Create local log report first
183 LogRecord record = new LogRecord(Level.FINEST, "Multicast: Announcing Presence");
184 record.setSourceClassName("ServerLog");
185 record.setMillis(System.currentTimeMillis());
188 // Announce the Log Server service
189 MessagePresence mp = new MessagePresence("ServerLog", Network.PORTS_SERVER_LOG);
190 NetworkMessage nm = NetworkMessage.createNetworkMessage("Neighbour", "all", mp);
191 nm.setSender("ServerLog");
192 _multicastServer.queueMessage(nm);
194 // clean up the known hosts map and keep Server menu up-to-date
195 ArrayList<String> servicesRemoved = _serviceToAddressMap.cleanServiceAddressMap(5000);
196 for (String service : servicesRemoved) {
199 gMenuServerSocial.setEnabled(false);
202 gMenuServerChat.setEnabled(false);
209 multicastAnnounce = new Timer(1000, multicastAnnounceActionListener);
210 multicastAnnounce.setInitialDelay(100);
211 multicastAnnounce.start();
218 * Add a log record to the log table if logging is enabled.
220 * Abusing an already-existing logging interface. This method isn't filtering, it is called by
221 * the Logger's TableModelHandler to publish records.
223 * @see TableModelHandler
225 * @return true if logging is enabled
228 public boolean isLoggable(LogRecord record) {
230 if (record != null) {
231 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
232 // add the log record to the log table
233 ((DefaultTableModel)gLogTable.getModel()).addRow(
235 df.format(new Date(record.getMillis())),
236 record.getLevel().toString(),
237 record.getSourceClassName(),
241 if (_autoScroll) { // keep last record added in the view
242 int row = gLogTable.getModel().getRowCount();
243 gLogTable.scrollRectToVisible(gLogTable.getCellRect(row, 0, true));
250 protected boolean UDPSend(NetworkMessage message) {
251 boolean result = false;
253 if (message != null) {
254 InetSocketAddress address = this._serviceToAddressMap.getServiceAddress(message.getTarget());
255 if (address != null) {
256 message.setSender("ServerManagement");
258 byte[] dataSend = NetworkMessage.serialize(message);
259 DatagramPacket packetSend = new DatagramPacket(dataSend, dataSend.length);
260 // set target's remote host address and port
261 packetSend.setAddress(address.getAddress());
262 packetSend.setPort(address.getPort());
264 DatagramSocket socket = new DatagramSocket();
265 // acknowledge receipt
266 socket.send(packetSend);
267 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()));
269 result = true; // successful
270 } catch (IOException e) {
271 // TODO: serverSend() add IOException handler
280 * This method is called from within the constructor to initialize the form.
281 * WARNING: Do NOT modify this code. The content of this method is always
282 * regenerated by the Form Editor.
284 @SuppressWarnings("unchecked")
285 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
286 private void initComponents() {
288 buttonGroup1 = new javax.swing.ButtonGroup();
289 gDialogAbout = new javax.swing.JDialog();
290 gTextAreaAbout = new javax.swing.JTextArea();
291 gBtnAbout = new javax.swing.JButton();
292 gFileChooser = new javax.swing.JFileChooser();
293 gLogScroller = new javax.swing.JScrollPane();
294 gLogTable = new javax.swing.JTable();
295 gMenuBar = new javax.swing.JMenuBar();
296 gMenuFile = new javax.swing.JMenu();
297 gMenuFileSave = new javax.swing.JMenuItem();
298 gMenuLog = new javax.swing.JMenu();
299 gMenuLogClear = new javax.swing.JMenuItem();
300 gMenuLogControl = new javax.swing.JCheckBoxMenuItem();
301 gMenuLogAutoScroll = new javax.swing.JCheckBoxMenuItem();
302 gMenuServers = new javax.swing.JMenu();
303 gMenuServerSocial = new javax.swing.JMenu();
304 gMenuServerSocialRestart = new javax.swing.JMenuItem();
305 gMenuServerSocialStop = new javax.swing.JMenuItem();
306 gMenuServerChat = new javax.swing.JMenu();
307 gMenuServerChatRestart = new javax.swing.JMenuItem();
308 gMenuServerChatStop = new javax.swing.JMenuItem();
309 gMenuHelp = new javax.swing.JMenu();
310 gMenuHelpAbout = new javax.swing.JMenuItem();
312 gDialogAbout.setTitle("About");
313 gDialogAbout.setBackground(new java.awt.Color(255, 255, 255));
314 gDialogAbout.setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
315 gDialogAbout.setMinimumSize(new java.awt.Dimension(590, 340));
316 gDialogAbout.setResizable(false);
317 gDialogAbout.getContentPane().setLayout(null);
319 gTextAreaAbout.setEditable(false);
320 gTextAreaAbout.setColumns(20);
321 gTextAreaAbout.setRows(5);
322 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");
323 gTextAreaAbout.setBorder(null);
324 gDialogAbout.getContentPane().add(gTextAreaAbout);
325 gTextAreaAbout.setBounds(310, 30, 270, 200);
327 gBtnAbout.setBackground(new java.awt.Color(255, 255, 255));
328 gBtnAbout.setFont(new java.awt.Font("Dialog", 1, 18)); // NOI18N
329 gBtnAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ntu/n0521366/wsyd/resources/ScroogledKeepCalmMug.png"))); // NOI18N
330 gBtnAbout.setText("We Stealz Your Dataz");
331 gBtnAbout.setBorder(null);
332 gBtnAbout.setBorderPainted(false);
333 gBtnAbout.setContentAreaFilled(false);
334 gBtnAbout.setDefaultCapable(false);
335 gBtnAbout.setFocusPainted(false);
336 gBtnAbout.setRolloverEnabled(false);
337 gBtnAbout.setVerticalAlignment(javax.swing.SwingConstants.TOP);
338 gBtnAbout.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
339 gBtnAbout.addActionListener(new java.awt.event.ActionListener() {
340 public void actionPerformed(java.awt.event.ActionEvent evt) {
344 gDialogAbout.getContentPane().add(gBtnAbout);
345 gBtnAbout.setBounds(0, 0, 530, 324);
347 gFileChooser.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
348 gFileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
349 gFileChooser.setDialogTitle("Save As");
351 setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
352 setTitle("We Stealz Your Dataz Servers Management");
353 setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
355 gLogScroller.setAutoscrolls(true);
357 gLogTable.setModel(new javax.swing.table.DefaultTableModel(
359 {null, null, null, null}
362 "Time", "Level", "Facility", "Message"
365 Class[] types = new Class [] {
366 java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
368 boolean[] canEdit = new boolean [] {
369 false, false, false, false
372 public Class getColumnClass(int columnIndex) {
373 return types [columnIndex];
376 public boolean isCellEditable(int rowIndex, int columnIndex) {
377 return canEdit [columnIndex];
380 gLogTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
381 gLogTable.setFillsViewportHeight(true);
382 gLogTable.getTableHeader().setReorderingAllowed(false);
383 gLogScroller.setViewportView(gLogTable);
384 if (gLogTable.getColumnModel().getColumnCount() > 0) {
385 gLogTable.getColumnModel().getColumn(0).setPreferredWidth(128);
386 gLogTable.getColumnModel().getColumn(1).setPreferredWidth(128);
387 gLogTable.getColumnModel().getColumn(2).setPreferredWidth(128);
390 getContentPane().add(gLogScroller, java.awt.BorderLayout.CENTER);
392 gMenuFile.setText("File");
394 gMenuFileSave.setText("Save...");
395 gMenuFileSave.setActionCommand("FileSave");
396 gMenuFileSave.addActionListener(new java.awt.event.ActionListener() {
397 public void actionPerformed(java.awt.event.ActionEvent evt) {
398 gMenuFileSaveActionPerformed(evt);
401 gMenuFile.add(gMenuFileSave);
403 gMenuBar.add(gMenuFile);
405 gMenuLog.setText("Log");
407 gMenuLogClear.setText("Clear");
408 gMenuLogClear.setActionCommand("LogTableClear");
409 gMenuLogClear.addActionListener(new java.awt.event.ActionListener() {
410 public void actionPerformed(java.awt.event.ActionEvent evt) {
411 gMenuLogClearActionPerformed(evt);
414 gMenuLog.add(gMenuLogClear);
416 gMenuLogControl.setSelected(true);
417 gMenuLogControl.setText("Running");
418 gMenuLogControl.setActionCommand("LogControl");
419 gMenuLogControl.addActionListener(new java.awt.event.ActionListener() {
420 public void actionPerformed(java.awt.event.ActionEvent evt) {
421 gMenuLogControlActionPerformed(evt);
424 gMenuLog.add(gMenuLogControl);
426 gMenuLogAutoScroll.setSelected(true);
427 gMenuLogAutoScroll.setText("Auto-scroll");
428 gMenuLogAutoScroll.setActionCommand("LogAutoScroll");
429 gMenuLogAutoScroll.addActionListener(new java.awt.event.ActionListener() {
430 public void actionPerformed(java.awt.event.ActionEvent evt) {
431 gMenuLogAutoScrollActionPerformed(evt);
434 gMenuLog.add(gMenuLogAutoScroll);
436 gMenuBar.add(gMenuLog);
438 gMenuServers.setText("Servers");
440 gMenuServerSocial.setText("Social");
441 gMenuServerSocial.setEnabled(false);
443 gMenuServerSocialRestart.setText("Restart");
444 gMenuServerSocialRestart.setActionCommand("SocialRestart");
445 gMenuServerSocialRestart.addActionListener(new java.awt.event.ActionListener() {
446 public void actionPerformed(java.awt.event.ActionEvent evt) {
447 gMenuServerSocialRestartActionPerformed(evt);
450 gMenuServerSocial.add(gMenuServerSocialRestart);
452 gMenuServerSocialStop.setText("Stop");
453 gMenuServerSocialStop.setActionCommand("SocialStop");
454 gMenuServerSocial.add(gMenuServerSocialStop);
456 gMenuServers.add(gMenuServerSocial);
458 gMenuServerChat.setText("Chat");
459 gMenuServerChat.setEnabled(false);
461 gMenuServerChatRestart.setText("Restart");
462 gMenuServerChatRestart.setActionCommand("ChatRestart");
463 gMenuServerChat.add(gMenuServerChatRestart);
465 gMenuServerChatStop.setText("Stop");
466 gMenuServerChatStop.setActionCommand("ChatStop");
467 gMenuServerChat.add(gMenuServerChatStop);
469 gMenuServers.add(gMenuServerChat);
471 gMenuBar.add(gMenuServers);
473 gMenuHelp.setText("Help");
475 gMenuHelpAbout.setText("About");
476 gMenuHelpAbout.addActionListener(new java.awt.event.ActionListener() {
477 public void actionPerformed(java.awt.event.ActionEvent evt) {
478 gMenuHelpAboutActionPerformed(evt);
481 gMenuHelp.add(gMenuHelpAbout);
483 gMenuBar.add(gMenuHelp);
485 setJMenuBar(gMenuBar);
488 }// </editor-fold>//GEN-END:initComponents
490 private void gMenuServerSocialRestartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuServerSocialRestartActionPerformed
491 // TODO add your handling code here:
492 LOGGER.logp(Level.FINEST, _title, null, "Requesting ServerSocial Restart");
493 MessageServerControl mc = new MessageServerControl(MessageServerControl.EXIT.NO , MessageServerControl.RESTART.YES);
494 NetworkMessage nm = NetworkMessage.createNetworkMessage("Control", "ServerSocialControl", mc);
495 nm.setSender(_title);
499 }//GEN-LAST:event_gMenuServerSocialRestartActionPerformed
502 * When the (disguised) mug-icon button is pressed load a web page in the system default browser.
504 * Displays a news story about Microsoft Store's 'Scroogle' mug which coincidentally has a tag line
505 * that is almost identical to the chosen name of this application.
509 private void AboutAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AboutAction
511 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"));
512 } catch(IOException e) {
514 }//GEN-LAST:event_AboutAction
517 * Show the Help>About dialog and auto-close it after 20 seconds.
521 private void gMenuHelpAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuHelpAboutActionPerformed
522 ActionListener autoCloseAboutDlg = new ActionListener() {
524 public void actionPerformed(ActionEvent e) {
525 gDialogAbout.setVisible(false);
529 gDialogAbout.setLocationRelativeTo(this); // center in application window
530 gDialogAbout.setVisible(true);
531 Timer autoClose = new Timer(20000, autoCloseAboutDlg);
533 }//GEN-LAST:event_gMenuHelpAboutActionPerformed
536 * Save log entries to a file.
540 private void gMenuFileSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuFileSaveActionPerformed
541 if (gFileChooser.showSaveDialog(this) == javax.swing.JFileChooser.APPROVE_OPTION) {
542 File saveAs = gFileChooser.getSelectedFile();
544 BufferedWriter writer = new BufferedWriter(new FileWriter(saveAs));
547 for (int row = 0; row < gLogTable.getModel().getRowCount(); row++) {
548 StringBuilder record = new StringBuilder();
549 int colMax = gLogTable.getModel().getColumnCount();
550 for (int col = 0; col < colMax; col++) {
551 record.append(gLogTable.getModel().getValueAt(row, col));
552 if (col < colMax - 1) {
556 writer.write(record.toString());
560 } catch (IOException e) {
561 System.err.println("Unable to write to file");
564 }//GEN-LAST:event_gMenuFileSaveActionPerformed
567 * Clear the log table.
570 private void gMenuLogClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogClearActionPerformed
571 ((DefaultTableModel)gLogTable.getModel()).setRowCount(0);
572 }//GEN-LAST:event_gMenuLogClearActionPerformed
575 * Enable or disable logging.
578 private void gMenuLogControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogControlActionPerformed
579 _doLogging = !_doLogging;
580 gMenuLogControl.setSelected(_doLogging);
581 }//GEN-LAST:event_gMenuLogControlActionPerformed
584 * Enable or disable automatic scrolling of the log table.
587 private void gMenuLogAutoScrollActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogAutoScrollActionPerformed
588 _autoScroll = !_autoScroll;
589 gMenuLogAutoScroll.setSelected(_autoScroll);
590 }//GEN-LAST:event_gMenuLogAutoScrollActionPerformed
593 * Receive a NetworkMessageEvent and dispose of it
597 public void NetworkMessageReceived(NetworkMessageEvent event) {
598 NetworkMessage nm = event.getNetworkMessage();
599 if (nm == null || !_doLogging)
601 // is it a LogRecord?
602 switch (nm.getIntent()) {
604 MessageLogRecord m = (MessageLogRecord) nm.getMessage();
607 this.isLoggable(m.record);
610 String type = nm.getMessage().getMessageType();
611 if (type.equals(MessagePresence.getType())) { // Presence
612 MessagePresence mp = (MessagePresence)nm.getMessage();
613 switch (mp.serviceName) {
615 gMenuServerSocial.setEnabled(true);
618 gMenuServerChat.setEnabled(true);
624 default: // log all unhandled messages
625 LogRecord record = new LogRecord(Level.WARNING,
626 MessageFormat.format("Unhandled NetworkMessage received with intent: \"{0}\" sender: \"{1}\" target: \"{2}\"",
627 nm.getIntent(), nm.getSender(), nm.getTarget() )
629 record.setMillis(System.currentTimeMillis());
635 * @param args the command line arguments
637 public static void main(String args[]) {
638 /* Set the Nimbus look and feel */
639 //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
640 /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
641 * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
644 for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
645 if ("Nimbus".equals(info.getName())) {
646 javax.swing.UIManager.setLookAndFeel(info.getClassName());
650 } catch (ClassNotFoundException|InstantiationException|IllegalAccessException|javax.swing.UnsupportedLookAndFeelException ex) {
651 java.util.logging.Logger.getLogger(ServerManagement.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
657 /* Create and display the form */
658 class App implements Runnable {
659 public boolean multicastAnnouncements = false;
660 public InetAddress serverSocial = null;
664 new ServerManagement(multicastAnnouncements, serverSocial).initListeners().setVisible(true);
666 catch(UnknownHostException e) {
667 System.err.println("Error: cannot create log server listener socket");
673 // process command line arguments
674 for (int i = 0; i < args.length; i++) {
677 app.multicastAnnouncements = true;
680 if (args.length >= i+1) {
681 // read the next argument as an IP address
684 temp = InetAddress.getByName(args[i+1]);
685 app.serverSocial = temp;
686 } catch (UnknownHostException e) {
687 System.err.println(MessageFormat.format("Error: {0} is not a valid hostname or IP address", args[i+1]));
693 java.awt.EventQueue.invokeLater(app);
696 // Variables declaration - do not modify//GEN-BEGIN:variables
697 private javax.swing.ButtonGroup buttonGroup1;
698 private javax.swing.JButton gBtnAbout;
699 private javax.swing.JDialog gDialogAbout;
700 private javax.swing.JFileChooser gFileChooser;
701 private javax.swing.JScrollPane gLogScroller;
702 private javax.swing.JTable gLogTable;
703 private javax.swing.JMenuBar gMenuBar;
704 private javax.swing.JMenu gMenuFile;
705 private javax.swing.JMenuItem gMenuFileSave;
706 private javax.swing.JMenu gMenuHelp;
707 private javax.swing.JMenuItem gMenuHelpAbout;
708 private javax.swing.JMenu gMenuLog;
709 private javax.swing.JCheckBoxMenuItem gMenuLogAutoScroll;
710 private javax.swing.JMenuItem gMenuLogClear;
711 private javax.swing.JCheckBoxMenuItem gMenuLogControl;
712 private javax.swing.JMenu gMenuServerChat;
713 private javax.swing.JMenuItem gMenuServerChatRestart;
714 private javax.swing.JMenuItem gMenuServerChatStop;
715 private javax.swing.JMenu gMenuServerSocial;
716 private javax.swing.JMenuItem gMenuServerSocialRestart;
717 private javax.swing.JMenuItem gMenuServerSocialStop;
718 private javax.swing.JMenu gMenuServers;
719 private javax.swing.JTextArea gTextAreaAbout;
720 // End of variables declaration//GEN-END:variables