80cdee151cf79c6a0d191ee297bb48d747919601
[WeStealzYourDataz.git] / src / uk / ac / ntu / n0521366 / wsyd / management / ServerManagement.java
1 /*
2  * The MIT License
3  *
4  * Copyright 2015 TJ <hacker@iam.tj>.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  */
24 package uk.ac.ntu.n0521366.wsyd.management;
25
26 import java.io.FileWriter;
27 import java.io.BufferedWriter;
28 import java.io.File;
29 import javax.swing.ImageIcon;
30 import java.awt.Desktop;
31 import java.net.URI;
32 import java.io.IOException;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.net.DatagramPacket;
36 import java.net.DatagramSocket;
37 import java.net.InetSocketAddress;
38 import javax.swing.Timer;
39 import javax.swing.table.DefaultTableModel;
40 import java.net.UnknownHostException;
41 import java.util.logging.Logger;
42 import java.util.logging.Level;
43 import java.util.logging.LogRecord;
44 import java.util.logging.Filter;
45 import java.util.Date;
46 import java.text.SimpleDateFormat;
47 import java.text.MessageFormat;
48 import java.util.ArrayList;
49 import uk.ac.ntu.n0521366.wsyd.libs.logging.TableModelHandler;
50 import uk.ac.ntu.n0521366.wsyd.libs.message.MessageLogRecord;
51 import uk.ac.ntu.n0521366.wsyd.libs.message.MessagePresence;
52 import uk.ac.ntu.n0521366.wsyd.libs.message.MessageServerControl;
53 import uk.ac.ntu.n0521366.wsyd.libs.net.WSYD_SocketAddress.Protocol;
54 import uk.ac.ntu.n0521366.wsyd.libs.net.*;
55
56 /**
57  *
58  * @author TJ <hacker@iam.tj>
59  */
60 public class ServerManagement extends javax.swing.JFrame implements NetworkMessageEventListener, Filter {
61     /**
62      * class-wide logger
63      */
64     static final Logger LOGGER = Logger.getLogger("ServerManagement");
65     
66     /**
67      * Location of resource bundles, images, icons
68      */
69     private static final String resourcePath = "/uk/ac/ntu/n0521366/wsyd/resources";
70
71     /**
72      * Readable/displayable name of this application
73      */
74     String _title;
75
76     /**
77      * The UDP listener address for incoming log messages
78      */
79     WSYD_SocketAddress _logServerSA = null;
80
81     /**
82      * UDP multi-cast presence advertiser
83      */
84     WSYD_SocketAddress _multicastAdvertiserSA = null;
85     
86     /**
87      * Log service running in a SwingWorker thread.
88      */
89     NetworkServerUDP _logServer = null;
90
91     /**
92      * Multi-cast neighbour advertise and discover service in a SwingWorker thread.
93      */
94     NetworkServerUDPMulticast _multicastServer = null;
95     
96
97     /**
98      * Enable or suspend logging
99      */
100     private boolean _doLogging;
101     
102     /**
103      * Enable or suspend table auto-scroll
104      */
105     private boolean _autoScroll;
106     
107     /**
108      * Regular presence announcements
109      */
110     Timer multicastAnnounce;
111     
112     /**
113      * Creates new GUI
114      * Instantiating code <em>must</em> also call initListeners()
115      * 
116      * @see #initListeners()
117      */
118     public ServerManagement() {
119         _title = "ServerManagement";
120         LOGGER.setLevel(Level.ALL);
121         initComponents();
122         _doLogging = true;
123         _autoScroll = true;
124         setLocationRelativeTo(null); // center on screen
125         // XXX: workaround for bug in NetBeans that doesn't set the displayed background colour, only the component colour, from the Properties editor
126         gDialogAbout.getContentPane().setBackground(gDialogAbout.getBackground());
127     }
128
129     /**
130      * Initialise listeners and other objects that require a reference to 'this'.
131      * 
132      * Passing 'this' from within the constructor is unsafe since the object is not
133      * fully constructed, so do it here. The compiler and virtual machine are free to move 'final'
134      * properties outside the constructor which means they may not be correctly
135      * initialised before the constructor returns. This is especially problematic
136      * in multi-threading applications.
137      * 
138      * @return a reference to 'this' so method calls can be chained (e.g. new ServerManagement().initListeners().setVisible(true) )
139      * @throws UnknownHostException
140      */
141     public ServerManagement initListeners() throws UnknownHostException {        
142         LOGGER.addHandler(new TableModelHandler(this)); // send messages to the GUI log table
143         LOGGER.setUseParentHandlers(false); // don't send messages to the default error stream logger of the parent
144         LOGGER.log(Level.INFO, "Server Management starting");
145         
146         _logServerSA = new WSYD_SocketAddress(Network.PORTS_SERVER_LOG, Protocol.UDP);
147         _logServer = new NetworkServerUDP(_logServerSA, "ServerLog", LOGGER);
148         _logServer.addNetworkMessageEventListener(this, "Log");
149         _logServer.setSimulate(false);
150         _logServer.execute();
151         _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY, Protocol.UDP);
152         _multicastServer = new NetworkServerUDPMulticast(_multicastAdvertiserSA, "ServerLogMC", LOGGER);
153         _multicastServer.addNetworkMessageEventListener(this, "Neighbour");
154         _multicastServer.execute();
155
156         ActionListener multicastAnnounceActionListener = new ActionListener() {
157             /**
158              * Activated by timer events to send multi-cast neighbour announcements for the Log Service.
159              * @param e 
160              */
161             @Override
162             public void actionPerformed(ActionEvent e) {
163                 // Create local log report first
164                 LogRecord record = new LogRecord(Level.FINEST, "Multicast: Announcing Presence");
165                 record.setSourceClassName("ServerLog");
166                 record.setMillis(System.currentTimeMillis());
167                 LOGGER.log(record);
168
169                 // Announce the Log Server service
170                 MessagePresence mp = new MessagePresence("ServerLog", Network.PORTS_SERVER_LOG);
171                 NetworkMessage nm = NetworkMessage.createNetworkMessage("Neighbour", "all", mp);
172                 nm.setSender("ServerLog");
173                 _multicastServer.queueMessage(nm);
174                 
175                 // clean up the known hosts map and keep Server menu up-to-date
176                 ArrayList<String> servicesRemoved = _multicastServer.cleanServiceToHostMap(5000);
177                 for (String service: servicesRemoved) {
178                         switch (service) {
179                             case "ServerSocial":
180                                 gMenuServerSocial.setEnabled(false);
181                                 break;
182                             case "ServerChat":
183                                 gMenuServerChat.setEnabled(false);
184                                 break;                                
185                         }
186                 }
187
188             }
189         };
190         multicastAnnounce = new Timer(1000, multicastAnnounceActionListener);
191         multicastAnnounce.setInitialDelay(100);
192         multicastAnnounce.start();
193         
194         return this;
195     }
196
197     /**
198      * Add a log record to the log table if logging is enabled.
199      * 
200      * Abusing an already-existing logging interface. This method isn't filtering, it is called by
201      * the Logger's TableModelHandler to publish records.
202      * 
203      * @see TableModelHandler
204      * @param record
205      * @return true if logging is enabled
206      */
207     @Override
208     public boolean isLoggable(LogRecord record) {
209         if (_doLogging) {
210             if (record != null) {
211                 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
212                 // add the log record to the log table
213                 ((DefaultTableModel)gLogTable.getModel()).addRow(
214                         new Object[]{
215                             df.format(new Date(record.getMillis())),
216                             record.getLevel().toString(),
217                             record.getSourceClassName(),
218                             record.getMessage()
219                         }
220                 );
221                 if (_autoScroll) { // keep last record added in the view
222                     int row = gLogTable.getModel().getRowCount();
223                     gLogTable.scrollRectToVisible(gLogTable.getCellRect(row, 0, true));
224                 }
225             }
226         }
227         return _doLogging;
228     }
229
230     protected boolean UDPSend(NetworkMessage message) {
231         boolean result = false;
232
233         if (message != null) {
234             InetSocketAddress address = this._multicastServer.getTargetAddress(message.getTarget());
235             if (address != null) {
236                 message.setSender("ServerManagement");
237                 try {
238                     byte[] dataSend = NetworkMessage.serialize(message);
239                     DatagramPacket packetSend = new DatagramPacket(dataSend, dataSend.length);
240                     // set target's remote host address and port
241                     packetSend.setAddress(address.getAddress());
242                     packetSend.setPort(address.getPort());
243
244                     DatagramSocket socket = new DatagramSocket();
245                     // acknowledge receipt
246                     socket.send(packetSend);
247                     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()));
248
249                     result = true; // successful
250                 } catch (IOException e) {
251                     // TODO: serverSend() add IOException handler
252                     e.printStackTrace();
253                 }
254             }
255         }
256         return result;
257     }
258
259     /**
260      * This method is called from within the constructor to initialize the form.
261      * WARNING: Do NOT modify this code. The content of this method is always
262      * regenerated by the Form Editor.
263      */
264     @SuppressWarnings("unchecked")
265     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
266     private void initComponents() {
267
268         buttonGroup1 = new javax.swing.ButtonGroup();
269         gDialogAbout = new javax.swing.JDialog();
270         gTextAreaAbout = new javax.swing.JTextArea();
271         gBtnAbout = new javax.swing.JButton();
272         gFileChooser = new javax.swing.JFileChooser();
273         gLogScroller = new javax.swing.JScrollPane();
274         gLogTable = new javax.swing.JTable();
275         gMenuBar = new javax.swing.JMenuBar();
276         gMenuFile = new javax.swing.JMenu();
277         gMenuFileSave = new javax.swing.JMenuItem();
278         gMenuLog = new javax.swing.JMenu();
279         gMenuLogClear = new javax.swing.JMenuItem();
280         gMenuLogControl = new javax.swing.JCheckBoxMenuItem();
281         gMenuLogAutoScroll = new javax.swing.JCheckBoxMenuItem();
282         gMenuServers = new javax.swing.JMenu();
283         gMenuServerSocial = new javax.swing.JMenu();
284         gMenuServerSocialRestart = new javax.swing.JMenuItem();
285         gMenuServerSocialStop = new javax.swing.JMenuItem();
286         gMenuServerChat = new javax.swing.JMenu();
287         gMenuServerChatRestart = new javax.swing.JMenuItem();
288         gMenuServerChatStop = new javax.swing.JMenuItem();
289         gMenuHelp = new javax.swing.JMenu();
290         gMenuHelpAbout = new javax.swing.JMenuItem();
291
292         gDialogAbout.setTitle("About");
293         gDialogAbout.setBackground(new java.awt.Color(255, 255, 255));
294         gDialogAbout.setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
295         gDialogAbout.setMinimumSize(new java.awt.Dimension(590, 340));
296         gDialogAbout.setResizable(false);
297         gDialogAbout.getContentPane().setLayout(null);
298
299         gTextAreaAbout.setEditable(false);
300         gTextAreaAbout.setColumns(20);
301         gTextAreaAbout.setRows(5);
302         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");
303         gTextAreaAbout.setBorder(null);
304         gDialogAbout.getContentPane().add(gTextAreaAbout);
305         gTextAreaAbout.setBounds(310, 30, 270, 200);
306
307         gBtnAbout.setBackground(new java.awt.Color(255, 255, 255));
308         gBtnAbout.setFont(new java.awt.Font("Dialog", 1, 18)); // NOI18N
309         gBtnAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ntu/n0521366/wsyd/resources/ScroogledKeepCalmMug.png"))); // NOI18N
310         gBtnAbout.setText("We Stealz Your Dataz");
311         gBtnAbout.setBorder(null);
312         gBtnAbout.setBorderPainted(false);
313         gBtnAbout.setContentAreaFilled(false);
314         gBtnAbout.setDefaultCapable(false);
315         gBtnAbout.setFocusPainted(false);
316         gBtnAbout.setRolloverEnabled(false);
317         gBtnAbout.setVerticalAlignment(javax.swing.SwingConstants.TOP);
318         gBtnAbout.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
319         gBtnAbout.addActionListener(new java.awt.event.ActionListener() {
320             public void actionPerformed(java.awt.event.ActionEvent evt) {
321                 AboutAction(evt);
322             }
323         });
324         gDialogAbout.getContentPane().add(gBtnAbout);
325         gBtnAbout.setBounds(0, 0, 530, 324);
326
327         gFileChooser.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
328         gFileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
329         gFileChooser.setDialogTitle("Save As");
330
331         setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
332         setTitle("We Stealz Your Dataz Servers Management");
333         setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
334
335         gLogScroller.setAutoscrolls(true);
336
337         gLogTable.setModel(new javax.swing.table.DefaultTableModel(
338             new Object [][] {
339                 {null, null, null, null}
340             },
341             new String [] {
342                 "Time", "Level", "Facility", "Message"
343             }
344         ) {
345             Class[] types = new Class [] {
346                 java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
347             };
348             boolean[] canEdit = new boolean [] {
349                 false, false, false, false
350             };
351
352             public Class getColumnClass(int columnIndex) {
353                 return types [columnIndex];
354             }
355
356             public boolean isCellEditable(int rowIndex, int columnIndex) {
357                 return canEdit [columnIndex];
358             }
359         });
360         gLogTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
361         gLogTable.setFillsViewportHeight(true);
362         gLogTable.getTableHeader().setReorderingAllowed(false);
363         gLogScroller.setViewportView(gLogTable);
364         if (gLogTable.getColumnModel().getColumnCount() > 0) {
365             gLogTable.getColumnModel().getColumn(0).setPreferredWidth(128);
366             gLogTable.getColumnModel().getColumn(1).setPreferredWidth(128);
367             gLogTable.getColumnModel().getColumn(2).setPreferredWidth(128);
368         }
369
370         getContentPane().add(gLogScroller, java.awt.BorderLayout.CENTER);
371
372         gMenuFile.setText("File");
373
374         gMenuFileSave.setText("Save...");
375         gMenuFileSave.setActionCommand("FileSave");
376         gMenuFileSave.addActionListener(new java.awt.event.ActionListener() {
377             public void actionPerformed(java.awt.event.ActionEvent evt) {
378                 gMenuFileSaveActionPerformed(evt);
379             }
380         });
381         gMenuFile.add(gMenuFileSave);
382
383         gMenuBar.add(gMenuFile);
384
385         gMenuLog.setText("Log");
386
387         gMenuLogClear.setText("Clear");
388         gMenuLogClear.setActionCommand("LogTableClear");
389         gMenuLogClear.addActionListener(new java.awt.event.ActionListener() {
390             public void actionPerformed(java.awt.event.ActionEvent evt) {
391                 gMenuLogClearActionPerformed(evt);
392             }
393         });
394         gMenuLog.add(gMenuLogClear);
395
396         gMenuLogControl.setSelected(true);
397         gMenuLogControl.setText("Running");
398         gMenuLogControl.setActionCommand("LogControl");
399         gMenuLogControl.addActionListener(new java.awt.event.ActionListener() {
400             public void actionPerformed(java.awt.event.ActionEvent evt) {
401                 gMenuLogControlActionPerformed(evt);
402             }
403         });
404         gMenuLog.add(gMenuLogControl);
405
406         gMenuLogAutoScroll.setSelected(true);
407         gMenuLogAutoScroll.setText("Auto-scroll");
408         gMenuLogAutoScroll.setActionCommand("LogAutoScroll");
409         gMenuLogAutoScroll.addActionListener(new java.awt.event.ActionListener() {
410             public void actionPerformed(java.awt.event.ActionEvent evt) {
411                 gMenuLogAutoScrollActionPerformed(evt);
412             }
413         });
414         gMenuLog.add(gMenuLogAutoScroll);
415
416         gMenuBar.add(gMenuLog);
417
418         gMenuServers.setText("Servers");
419
420         gMenuServerSocial.setText("Social");
421         gMenuServerSocial.setEnabled(false);
422
423         gMenuServerSocialRestart.setText("Restart");
424         gMenuServerSocialRestart.setActionCommand("SocialRestart");
425         gMenuServerSocialRestart.addActionListener(new java.awt.event.ActionListener() {
426             public void actionPerformed(java.awt.event.ActionEvent evt) {
427                 gMenuServerSocialRestartActionPerformed(evt);
428             }
429         });
430         gMenuServerSocial.add(gMenuServerSocialRestart);
431
432         gMenuServerSocialStop.setText("Stop");
433         gMenuServerSocialStop.setActionCommand("SocialStop");
434         gMenuServerSocial.add(gMenuServerSocialStop);
435
436         gMenuServers.add(gMenuServerSocial);
437
438         gMenuServerChat.setText("Chat");
439         gMenuServerChat.setEnabled(false);
440
441         gMenuServerChatRestart.setText("Restart");
442         gMenuServerChatRestart.setActionCommand("ChatRestart");
443         gMenuServerChat.add(gMenuServerChatRestart);
444
445         gMenuServerChatStop.setText("Stop");
446         gMenuServerChatStop.setActionCommand("ChatStop");
447         gMenuServerChat.add(gMenuServerChatStop);
448
449         gMenuServers.add(gMenuServerChat);
450
451         gMenuBar.add(gMenuServers);
452
453         gMenuHelp.setText("Help");
454
455         gMenuHelpAbout.setText("About");
456         gMenuHelpAbout.addActionListener(new java.awt.event.ActionListener() {
457             public void actionPerformed(java.awt.event.ActionEvent evt) {
458                 gMenuHelpAboutActionPerformed(evt);
459             }
460         });
461         gMenuHelp.add(gMenuHelpAbout);
462
463         gMenuBar.add(gMenuHelp);
464
465         setJMenuBar(gMenuBar);
466
467         pack();
468     }// </editor-fold>//GEN-END:initComponents
469
470     private void gMenuServerSocialRestartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuServerSocialRestartActionPerformed
471         // TODO add your handling code here:
472         System.err.println("Requesting ServerSocial Restart");
473         MessageServerControl mc = new MessageServerControl(MessageServerControl.EXIT.NO , MessageServerControl.RESTART.YES);
474         NetworkMessage nm = NetworkMessage.createNetworkMessage("Control", "ServerSocial", mc);
475         nm.setSender("ServerLog");
476         UDPSend(nm);
477
478                 
479     }//GEN-LAST:event_gMenuServerSocialRestartActionPerformed
480
481     /**
482      * When the (disguised) mug-icon button is pressed load a web page in the system default browser.
483      * 
484      * Displays a news story about Microsoft Store's 'Scroogle' mug which coincidentally has a tag line
485      * that is almost identical to the chosen name of this application.
486      * 
487      * @param evt 
488      */
489     private void AboutAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AboutAction
490         try {
491             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"));
492         } catch(IOException e) {
493         }
494     }//GEN-LAST:event_AboutAction
495
496     /**
497      * Show the Help>About dialog and auto-close it after 20 seconds.
498      * 
499      * @param evt
500      */
501     private void gMenuHelpAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuHelpAboutActionPerformed
502         ActionListener autoCloseAboutDlg = new ActionListener() {
503             @Override
504             public void actionPerformed(ActionEvent e) {
505                 gDialogAbout.setVisible(false);
506             }
507         };
508
509         gDialogAbout.setLocationRelativeTo(this); // center in application window
510         gDialogAbout.setVisible(true);
511         Timer autoClose = new Timer(20000, autoCloseAboutDlg);
512         autoClose.start();
513     }//GEN-LAST:event_gMenuHelpAboutActionPerformed
514
515     /**
516      * Save log entries to a file.
517      * 
518      * @param evt 
519      */
520     private void gMenuFileSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuFileSaveActionPerformed
521         if (gFileChooser.showSaveDialog(this) == javax.swing.JFileChooser.APPROVE_OPTION) {
522             File saveAs = gFileChooser.getSelectedFile();
523             try (
524                 BufferedWriter writer = new BufferedWriter(new FileWriter(saveAs));
525             )
526             {
527                 for (int row = 0; row < gLogTable.getModel().getRowCount(); row++) {
528                     StringBuilder record = new StringBuilder();
529                     int colMax = gLogTable.getModel().getColumnCount();
530                     for (int col = 0; col < colMax; col++) {
531                         record.append(gLogTable.getModel().getValueAt(row, col));
532                         if (col < colMax - 1) {
533                             record.append(",");
534                         }
535                     }
536                     writer.write(record.toString());
537                     writer.newLine();
538                 }
539                 writer.close();
540             } catch (IOException e) {
541                 System.err.println("Unable to write to file");
542             }
543         }
544     }//GEN-LAST:event_gMenuFileSaveActionPerformed
545
546     /**
547      * Clear the log table.
548      * @param evt 
549      */
550     private void gMenuLogClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogClearActionPerformed
551         ((DefaultTableModel)gLogTable.getModel()).setRowCount(0);
552     }//GEN-LAST:event_gMenuLogClearActionPerformed
553
554     /**
555      * Enable or disable logging.
556      * @param evt 
557      */
558     private void gMenuLogControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogControlActionPerformed
559         _doLogging = !_doLogging;
560         gMenuLogControl.setSelected(_doLogging);
561     }//GEN-LAST:event_gMenuLogControlActionPerformed
562
563     /**
564      * Enable or disable automatic scrolling of the log table.
565      * @param evt 
566      */
567     private void gMenuLogAutoScrollActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogAutoScrollActionPerformed
568         _autoScroll = !_autoScroll;
569         gMenuLogAutoScroll.setSelected(_autoScroll);
570     }//GEN-LAST:event_gMenuLogAutoScrollActionPerformed
571
572     /**
573      * Receive a NetworkMessageEvent and dispose of it
574      * @param event
575      */
576     @Override
577     public void NetworkMessageReceived(NetworkMessageEvent event) {
578         NetworkMessage nm = event.getNetworkMessage();
579         if (nm == null || !_doLogging)
580             return;
581         // is it a LogRecord?
582         switch (nm.getIntent()) {
583             case "Log":
584                 MessageLogRecord m = (MessageLogRecord) nm.getMessage();
585                 if (m == null)
586                     return;
587                 this.isLoggable(m.record);
588                 break;
589             case "Neighbour":
590                 // TODO: NetworkMessageReceived(): Test Multicast message received handler to enable menu items for recognised servers
591                 String type = nm.getMessage().getMessageType();
592                     if (type.equals(MessagePresence.getType())) { // Presence
593                         MessagePresence mp = (MessagePresence)nm.getMessage();
594                         switch (mp.serviceName) {
595                             case "ServerSocial":
596                                 gMenuServerSocial.setEnabled(true);
597                                 break;
598                             case "ServerChat":
599                                 gMenuServerChat.setEnabled(true);
600                                 break;                                
601                         }
602                     }
603
604
605             default: // log all unhandled messages
606                 LogRecord record = new LogRecord(Level.WARNING,
607                     MessageFormat.format("Unhandled NetworkMessage received with intent: \"{0}\" sender: \"{1}\" target: \"{2}\"",
608                         nm.getIntent(), nm.getSender(), nm.getTarget() )
609                 );
610                 record.setMillis(System.currentTimeMillis());
611                 LOGGER.log(record);
612         }
613     }
614
615     /**
616      * @param args the command line arguments
617      */
618     public static void main(String args[]) {
619         /* Set the Nimbus look and feel */
620         //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
621         /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
622          * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
623          */
624         try {
625             for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
626                 if ("Nimbus".equals(info.getName())) {
627                     javax.swing.UIManager.setLookAndFeel(info.getClassName());
628                     break;
629                 }
630             }
631         } catch (ClassNotFoundException|InstantiationException|IllegalAccessException|javax.swing.UnsupportedLookAndFeelException ex) {
632             java.util.logging.Logger.getLogger(ServerManagement.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
633         }
634         //</editor-fold>
635         //</editor-fold>
636         //</editor-fold>
637         //</editor-fold>
638
639         /* Create and display the form */
640         java.awt.EventQueue.invokeLater(new Runnable() {
641             @Override
642             public void run() {
643                 try {
644                 new ServerManagement().initListeners().setVisible(true);
645                 }
646                 catch(UnknownHostException e) {
647                     System.err.println("Error: cannot create log server listener socket");
648                 }
649             }
650         });
651     }
652
653     // Variables declaration - do not modify//GEN-BEGIN:variables
654     private javax.swing.ButtonGroup buttonGroup1;
655     private javax.swing.JButton gBtnAbout;
656     private javax.swing.JDialog gDialogAbout;
657     private javax.swing.JFileChooser gFileChooser;
658     private javax.swing.JScrollPane gLogScroller;
659     private javax.swing.JTable gLogTable;
660     private javax.swing.JMenuBar gMenuBar;
661     private javax.swing.JMenu gMenuFile;
662     private javax.swing.JMenuItem gMenuFileSave;
663     private javax.swing.JMenu gMenuHelp;
664     private javax.swing.JMenuItem gMenuHelpAbout;
665     private javax.swing.JMenu gMenuLog;
666     private javax.swing.JCheckBoxMenuItem gMenuLogAutoScroll;
667     private javax.swing.JMenuItem gMenuLogClear;
668     private javax.swing.JCheckBoxMenuItem gMenuLogControl;
669     private javax.swing.JMenu gMenuServerChat;
670     private javax.swing.JMenuItem gMenuServerChatRestart;
671     private javax.swing.JMenuItem gMenuServerChatStop;
672     private javax.swing.JMenu gMenuServerSocial;
673     private javax.swing.JMenuItem gMenuServerSocialRestart;
674     private javax.swing.JMenuItem gMenuServerSocialStop;
675     private javax.swing.JMenu gMenuServers;
676     private javax.swing.JTextArea gTextAreaAbout;
677     // End of variables declaration//GEN-END:variables
678 }