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