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
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 gMenuLogServiceAnnounce.setSelected(_multicastAnnouncements);
147 // TODO: implement constructor setting IP address of SocialServer from command-line value
148 if (serverSocial != null)
149 _serviceToAddressMap.put("ServerSocial", new LastSeenHost(new InetSocketAddress(serverSocial, Network.PORTS_SERVER_SOCIAL), LastSeenHost.STATE.STATIC));
152 * Initialise listeners and other objects that require a reference to 'this'.
154 * Passing 'this' from within the constructor is unsafe since the object is not
155 * fully constructed, so do it here. The compiler and virtual machine are free to move 'final'
156 * properties outside the constructor which means they may not be correctly
157 * initialised before the constructor returns. This is especially problematic
158 * in multi-threading applications.
160 * @return a reference to 'this' so method calls can be chained (e.g. new ServerManagement().initListeners().setVisible(true) )
161 * @throws UnknownHostException
163 public ServerManagement initListeners() throws UnknownHostException {
164 LOGGER.addHandler(new TableModelHandler(this)); // send messages to the GUI log table
165 LOGGER.setUseParentHandlers(false); // don't send messages to the default error stream logger of the parent
166 LOGGER.logp(Level.INFO, _title, null, "Server Management starting");
168 _udpLogServiceSA = new WSYD_SocketAddress(Network.PORTS_SERVER_LOG, Protocol.UDP);
169 _udpLogService = new NetworkServerUDP(_udpLogServiceSA, _title + "Log", _serviceToAddressMap, LOGGER);
170 _udpLogService.getEventManager().addNetworkMessageEventListener(this, "Log");
171 _udpLogService.setSimulate(false);
172 _udpLogService.execute();
174 _multicastAdvertiserSA = new WSYD_SocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY, Protocol.UDP);
175 _multicastServer = new NetworkServerUDPMulticast(_multicastAdvertiserSA, _title + "MC", _serviceToAddressMap, LOGGER);
176 _multicastServer.getEventManager().addNetworkMessageEventListener(this, "Neighbour");
177 _multicastServer.execute();
178 // permit broadcasting to pseudo-host 'all' since this is multicast
179 _serviceToAddressMap.put("all", new LastSeenHost(new InetSocketAddress(Network.MULTICAST_IP, Network.PORTS_MULTICAST_DISCOVERY), LastSeenHost.STATE.STATIC));
181 // log any static entries in the service map
182 for (java.util.Map.Entry<String, LastSeenHost> entry: this._serviceToAddressMap.getEntrySet()) {
183 LastSeenHost host = entry.getValue();
184 if (host.state == LastSeenHost.STATE.STATIC)
185 LOGGER.logp(Level.FINER, _title, null, MessageFormat.format("Static Service: {0} = {1}:{2,number,#####}", entry.getKey(), host.address.getHostString(), host.address.getPort()));
188 ActionListener regularTasksActionListener = new ActionListener() {
189 // provide a way to read the current version of the parent process object's fields
190 ServerManagement owner;
192 // XXX: Anonymous class initialisation - effectively used as the body of the object's constructor
194 // XXX: access to the outer class's instance object
195 owner = ServerManagement.this;
199 * Activated by timer events to send multi-cast neighbour
200 * announcements for the Log Service.
205 public void actionPerformed(ActionEvent e) {
206 String serviceName = "LogService";
207 // check the current value ofthe parent process' flag
208 if (owner._multicastAnnouncements) {
209 // Create local log report first
210 LogRecord record = new LogRecord(Level.FINEST, "Multicast: Announcing Presence");
211 record.setSourceClassName(serviceName);
212 record.setMillis(System.currentTimeMillis());
215 // Announce the log service
216 MessagePresence mp = new MessagePresence(_title + serviceName, _udpLogService.getSocketAddress());
217 NetworkMessage nm = NetworkMessage.createNetworkMessage("Neighbour", "all", mp);
218 nm.setSender(_title + serviceName);
219 _multicastServer.queueMessage(nm);
221 // clean up the known hosts map
222 ArrayList<String> servicesRemoved = _serviceToAddressMap.cleanServiceAddressMap(5000);
223 // keep Server menu up-to-date
224 for (String service : servicesRemoved) {
227 gMenuServerSocial.setEnabled(false);
230 gMenuServerChat.setEnabled(false);
237 regularTasks = new Timer(1000, regularTasksActionListener);
238 regularTasks.setInitialDelay(100);
239 regularTasks.start();
245 * Add a log record to the log table if logging is enabled.
247 * Abusing an already-existing logging interface. This method isn't filtering, it is called by
248 * the Logger's TableModelHandler to publish records.
250 * @see TableModelHandler
252 * @return true if logging is enabled
255 public boolean isLoggable(LogRecord record) {
257 if (record != null) {
258 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
259 // add the log record to the log table
260 ((DefaultTableModel)gLogTable.getModel()).addRow(
262 df.format(new Date(record.getMillis())),
263 record.getLevel().toString(),
264 record.getSourceClassName(),
268 if (_autoScroll) { // keep last record added in the view
269 int row = gLogTable.getModel().getRowCount();
270 gLogTable.scrollRectToVisible(gLogTable.getCellRect(row, 0, true));
277 protected boolean UDPSend(NetworkMessage message) {
278 boolean result = false;
280 if (message != null) {
281 InetSocketAddress address = this._serviceToAddressMap.getServiceAddress(message.getTarget());
282 if (address != null) {
283 message.setSender("ServerManagement");
285 byte[] dataSend = NetworkMessage.serialize(message);
286 DatagramPacket packetSend = new DatagramPacket(dataSend, dataSend.length);
287 // set target's remote host address and port
288 packetSend.setAddress(address.getAddress());
289 packetSend.setPort(address.getPort());
291 DatagramSocket socket = new DatagramSocket();
292 // acknowledge receipt
293 socket.send(packetSend);
294 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()));
296 result = true; // successful
297 } catch (IOException e) {
298 // TODO: serverSend() add IOException handler
307 * This method is called from within the constructor to initialize the form.
308 * WARNING: Do NOT modify this code. The content of this method is always
309 * regenerated by the Form Editor.
311 @SuppressWarnings("unchecked")
312 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
313 private void initComponents() {
315 buttonGroup1 = new javax.swing.ButtonGroup();
316 gDialogAbout = new javax.swing.JDialog();
317 gTextAreaAbout = new javax.swing.JTextArea();
318 gBtnAbout = new javax.swing.JButton();
319 gFileChooser = new javax.swing.JFileChooser();
320 gLogScroller = new javax.swing.JScrollPane();
321 gLogTable = new javax.swing.JTable();
322 gMenuBar = new javax.swing.JMenuBar();
323 gMenuFile = new javax.swing.JMenu();
324 gMenuFileSave = new javax.swing.JMenuItem();
325 gMenuLog = new javax.swing.JMenu();
326 gMenuLogClear = new javax.swing.JMenuItem();
327 gMenuLogControl = new javax.swing.JCheckBoxMenuItem();
328 gMenuLogAutoScroll = new javax.swing.JCheckBoxMenuItem();
329 gMenuLogServiceAnnounce = new javax.swing.JCheckBoxMenuItem();
330 gMenuServers = new javax.swing.JMenu();
331 gMenuServerSocial = new javax.swing.JMenu();
332 gMenuServerSocialRestart = new javax.swing.JMenuItem();
333 gMenuServerSocialStop = new javax.swing.JMenuItem();
334 gMenuServerChat = new javax.swing.JMenu();
335 gMenuServerChatRestart = new javax.swing.JMenuItem();
336 gMenuServerChatStop = new javax.swing.JMenuItem();
337 gMenuHelp = new javax.swing.JMenu();
338 gMenuHelpAbout = new javax.swing.JMenuItem();
340 gDialogAbout.setTitle("About");
341 gDialogAbout.setBackground(new java.awt.Color(255, 255, 255));
342 gDialogAbout.setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
343 gDialogAbout.setMinimumSize(new java.awt.Dimension(590, 340));
344 gDialogAbout.setResizable(false);
345 gDialogAbout.getContentPane().setLayout(null);
347 gTextAreaAbout.setEditable(false);
348 gTextAreaAbout.setColumns(20);
349 gTextAreaAbout.setRows(5);
350 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");
351 gTextAreaAbout.setBorder(null);
352 gDialogAbout.getContentPane().add(gTextAreaAbout);
353 gTextAreaAbout.setBounds(310, 30, 270, 200);
355 gBtnAbout.setBackground(new java.awt.Color(255, 255, 255));
356 gBtnAbout.setFont(new java.awt.Font("Dialog", 1, 18)); // NOI18N
357 gBtnAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ntu/n0521366/wsyd/resources/ScroogledKeepCalmMug.png"))); // NOI18N
358 gBtnAbout.setText("We Stealz Your Dataz");
359 gBtnAbout.setBorder(null);
360 gBtnAbout.setBorderPainted(false);
361 gBtnAbout.setContentAreaFilled(false);
362 gBtnAbout.setDefaultCapable(false);
363 gBtnAbout.setFocusPainted(false);
364 gBtnAbout.setRolloverEnabled(false);
365 gBtnAbout.setVerticalAlignment(javax.swing.SwingConstants.TOP);
366 gBtnAbout.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
367 gBtnAbout.addActionListener(new java.awt.event.ActionListener() {
368 public void actionPerformed(java.awt.event.ActionEvent evt) {
372 gDialogAbout.getContentPane().add(gBtnAbout);
373 gBtnAbout.setBounds(0, 0, 530, 324);
375 gFileChooser.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
376 gFileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
377 gFileChooser.setDialogTitle("Save As");
379 setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
380 setTitle("We Stealz Your Dataz Servers Management");
381 setIconImage(new ImageIcon( getClass().getResource(resourcePath +"/ScroogledKeepCalmMug.icon.png")).getImage());
383 gLogScroller.setAutoscrolls(true);
385 gLogTable.setModel(new javax.swing.table.DefaultTableModel(
387 {null, null, null, null}
390 "Time", "Level", "Facility", "Message"
393 Class[] types = new Class [] {
394 java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
396 boolean[] canEdit = new boolean [] {
397 false, false, false, false
400 public Class getColumnClass(int columnIndex) {
401 return types [columnIndex];
404 public boolean isCellEditable(int rowIndex, int columnIndex) {
405 return canEdit [columnIndex];
408 gLogTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
409 gLogTable.setFillsViewportHeight(true);
410 gLogTable.getTableHeader().setReorderingAllowed(false);
411 gLogScroller.setViewportView(gLogTable);
412 if (gLogTable.getColumnModel().getColumnCount() > 0) {
413 gLogTable.getColumnModel().getColumn(0).setPreferredWidth(128);
414 gLogTable.getColumnModel().getColumn(1).setPreferredWidth(128);
415 gLogTable.getColumnModel().getColumn(2).setPreferredWidth(128);
418 getContentPane().add(gLogScroller, java.awt.BorderLayout.CENTER);
420 gMenuFile.setText("File");
422 gMenuFileSave.setText("Save...");
423 gMenuFileSave.setActionCommand("FileSave");
424 gMenuFileSave.addActionListener(new java.awt.event.ActionListener() {
425 public void actionPerformed(java.awt.event.ActionEvent evt) {
426 gMenuFileSaveActionPerformed(evt);
429 gMenuFile.add(gMenuFileSave);
431 gMenuBar.add(gMenuFile);
433 gMenuLog.setText("Log");
435 gMenuLogClear.setText("Clear");
436 gMenuLogClear.setActionCommand("LogTableClear");
437 gMenuLogClear.addActionListener(new java.awt.event.ActionListener() {
438 public void actionPerformed(java.awt.event.ActionEvent evt) {
439 gMenuLogClearActionPerformed(evt);
442 gMenuLog.add(gMenuLogClear);
444 gMenuLogControl.setSelected(true);
445 gMenuLogControl.setText("Running");
446 gMenuLogControl.setActionCommand("LogControl");
447 gMenuLogControl.addActionListener(new java.awt.event.ActionListener() {
448 public void actionPerformed(java.awt.event.ActionEvent evt) {
449 gMenuLogControlActionPerformed(evt);
452 gMenuLog.add(gMenuLogControl);
454 gMenuLogAutoScroll.setSelected(true);
455 gMenuLogAutoScroll.setText("Auto-scroll");
456 gMenuLogAutoScroll.setActionCommand("LogAutoScroll");
457 gMenuLogAutoScroll.addActionListener(new java.awt.event.ActionListener() {
458 public void actionPerformed(java.awt.event.ActionEvent evt) {
459 gMenuLogAutoScrollActionPerformed(evt);
462 gMenuLog.add(gMenuLogAutoScroll);
464 gMenuLogServiceAnnounce.setSelected(true);
465 gMenuLogServiceAnnounce.setText("Multicast Announce");
466 gMenuLogServiceAnnounce.addActionListener(new java.awt.event.ActionListener() {
467 public void actionPerformed(java.awt.event.ActionEvent evt) {
468 gMenuLogServiceAnnounceActionPerformed(evt);
471 gMenuLog.add(gMenuLogServiceAnnounce);
473 gMenuBar.add(gMenuLog);
475 gMenuServers.setText("Servers");
477 gMenuServerSocial.setText("Social");
478 gMenuServerSocial.setEnabled(false);
480 gMenuServerSocialRestart.setText("Restart");
481 gMenuServerSocialRestart.setActionCommand("SocialRestart");
482 gMenuServerSocialRestart.addActionListener(new java.awt.event.ActionListener() {
483 public void actionPerformed(java.awt.event.ActionEvent evt) {
484 gMenuServerSocialRestartActionPerformed(evt);
487 gMenuServerSocial.add(gMenuServerSocialRestart);
489 gMenuServerSocialStop.setText("Stop");
490 gMenuServerSocialStop.setActionCommand("SocialStop");
491 gMenuServerSocial.add(gMenuServerSocialStop);
493 gMenuServers.add(gMenuServerSocial);
495 gMenuServerChat.setText("Chat");
496 gMenuServerChat.setEnabled(false);
498 gMenuServerChatRestart.setText("Restart");
499 gMenuServerChatRestart.setActionCommand("ChatRestart");
500 gMenuServerChat.add(gMenuServerChatRestart);
502 gMenuServerChatStop.setText("Stop");
503 gMenuServerChatStop.setActionCommand("ChatStop");
504 gMenuServerChat.add(gMenuServerChatStop);
506 gMenuServers.add(gMenuServerChat);
508 gMenuBar.add(gMenuServers);
510 gMenuHelp.setText("Help");
512 gMenuHelpAbout.setText("About");
513 gMenuHelpAbout.addActionListener(new java.awt.event.ActionListener() {
514 public void actionPerformed(java.awt.event.ActionEvent evt) {
515 gMenuHelpAboutActionPerformed(evt);
518 gMenuHelp.add(gMenuHelpAbout);
520 gMenuBar.add(gMenuHelp);
522 setJMenuBar(gMenuBar);
525 }// </editor-fold>//GEN-END:initComponents
527 private void gMenuServerSocialRestartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuServerSocialRestartActionPerformed
528 // TODO add your handling code here:
529 LOGGER.logp(Level.FINEST, _title, null, "Requesting ServerSocial Restart");
530 MessageServerControl mc = new MessageServerControl(MessageServerControl.EXIT.NO , MessageServerControl.RESTART.YES);
531 NetworkMessage nm = NetworkMessage.createNetworkMessage("Control", "ServerSocialControl", mc);
532 nm.setSender(_title);
536 }//GEN-LAST:event_gMenuServerSocialRestartActionPerformed
539 * When the (disguised) mug-icon button is pressed load a web page in the system default browser.
541 * Displays a news story about Microsoft Store's 'Scroogle' mug which coincidentally has a tag line
542 * that is almost identical to the chosen name of this application.
546 private void AboutAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AboutAction
548 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"));
549 } catch(IOException e) {
551 }//GEN-LAST:event_AboutAction
554 * Show the Help>About dialog and auto-close it after 20 seconds.
558 private void gMenuHelpAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuHelpAboutActionPerformed
559 ActionListener autoCloseAboutDlg = new ActionListener() {
561 public void actionPerformed(ActionEvent e) {
562 gDialogAbout.setVisible(false);
566 gDialogAbout.setLocationRelativeTo(this); // center in application window
567 gDialogAbout.setVisible(true);
568 Timer autoClose = new Timer(20000, autoCloseAboutDlg);
570 }//GEN-LAST:event_gMenuHelpAboutActionPerformed
573 * Save log entries to a file.
577 private void gMenuFileSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuFileSaveActionPerformed
578 if (gFileChooser.showSaveDialog(this) == javax.swing.JFileChooser.APPROVE_OPTION) {
579 File saveAs = gFileChooser.getSelectedFile();
581 BufferedWriter writer = new BufferedWriter(new FileWriter(saveAs));
584 for (int row = 0; row < gLogTable.getModel().getRowCount(); row++) {
585 StringBuilder record = new StringBuilder();
586 int colMax = gLogTable.getModel().getColumnCount();
587 for (int col = 0; col < colMax; col++) {
588 record.append(gLogTable.getModel().getValueAt(row, col));
589 if (col < colMax - 1) {
593 writer.write(record.toString());
597 } catch (IOException e) {
598 System.err.println("Unable to write to file");
601 }//GEN-LAST:event_gMenuFileSaveActionPerformed
604 * Clear the log table.
607 private void gMenuLogClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogClearActionPerformed
608 ((DefaultTableModel)gLogTable.getModel()).setRowCount(0);
609 }//GEN-LAST:event_gMenuLogClearActionPerformed
612 * Enable or disable logging.
615 private void gMenuLogControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogControlActionPerformed
616 _doLogging = !_doLogging;
617 gMenuLogControl.setSelected(_doLogging);
618 }//GEN-LAST:event_gMenuLogControlActionPerformed
621 * Enable or disable automatic scrolling of the log table.
624 private void gMenuLogAutoScrollActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogAutoScrollActionPerformed
625 _autoScroll = !_autoScroll;
626 gMenuLogAutoScroll.setSelected(_autoScroll);
627 }//GEN-LAST:event_gMenuLogAutoScrollActionPerformed
630 * Enable or disable multicast log service announcements.
633 private void gMenuLogServiceAnnounceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gMenuLogServiceAnnounceActionPerformed
634 this._multicastAnnouncements = gMenuLogServiceAnnounce.isSelected();
635 }//GEN-LAST:event_gMenuLogServiceAnnounceActionPerformed
638 * Receive a NetworkMessageEvent and dispose of it
642 public void NetworkMessageReceived(NetworkMessageEvent event) {
643 NetworkMessage nm = event.getNetworkMessage();
644 if (nm == null || !_doLogging)
646 // is it a LogRecord?
647 switch (nm.getIntent()) {
649 MessageLogRecord m = (MessageLogRecord) nm.getMessage();
652 this.isLoggable(m.record);
655 String type = nm.getMessage().getMessageType();
656 if (type.equals(MessagePresence.getType())) { // Presence
657 MessagePresence mp = (MessagePresence)nm.getMessage();
658 switch (mp.serviceName) {
660 gMenuServerSocial.setEnabled(true);
663 gMenuServerChat.setEnabled(true);
669 default: // log all unhandled messages
670 LogRecord record = new LogRecord(Level.WARNING,
671 MessageFormat.format("Unhandled NetworkMessage received with intent: \"{0}\" sender: \"{1}\" target: \"{2}\"",
672 nm.getIntent(), nm.getSender(), nm.getTarget() )
674 record.setMillis(System.currentTimeMillis());
680 * @param args the command line arguments
682 public static void main(String args[]) {
683 /* Set the Nimbus look and feel */
684 //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
685 /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
686 * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
689 for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
690 if ("Nimbus".equals(info.getName())) {
691 javax.swing.UIManager.setLookAndFeel(info.getClassName());
695 } catch (ClassNotFoundException|InstantiationException|IllegalAccessException|javax.swing.UnsupportedLookAndFeelException ex) {
696 java.util.logging.Logger.getLogger(ServerManagement.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
702 /* Create and display the form */
703 class App implements Runnable {
704 public boolean multicastAnnouncements = false;
705 public InetAddress serverSocial = null;
709 new ServerManagement(multicastAnnouncements, serverSocial).initListeners().setVisible(true);
711 catch(UnknownHostException e) {
712 System.err.println("Error: cannot create log server listener socket");
718 // process command line arguments
719 for (int i = 0; i < args.length; i++) {
722 app.multicastAnnouncements = true;
725 if (args.length >= i+1) {
726 // read the next argument as an IP address
729 temp = InetAddress.getByName(args[i+1]);
730 app.serverSocial = temp;
731 } catch (UnknownHostException e) {
732 System.err.println(MessageFormat.format("Error: {0} is not a valid hostname or IP address", args[i+1]));
738 java.awt.EventQueue.invokeLater(app);
741 // Variables declaration - do not modify//GEN-BEGIN:variables
742 private javax.swing.ButtonGroup buttonGroup1;
743 private javax.swing.JButton gBtnAbout;
744 private javax.swing.JDialog gDialogAbout;
745 private javax.swing.JFileChooser gFileChooser;
746 private javax.swing.JScrollPane gLogScroller;
747 private javax.swing.JTable gLogTable;
748 private javax.swing.JMenuBar gMenuBar;
749 private javax.swing.JMenu gMenuFile;
750 private javax.swing.JMenuItem gMenuFileSave;
751 private javax.swing.JMenu gMenuHelp;
752 private javax.swing.JMenuItem gMenuHelpAbout;
753 private javax.swing.JMenu gMenuLog;
754 private javax.swing.JCheckBoxMenuItem gMenuLogAutoScroll;
755 private javax.swing.JMenuItem gMenuLogClear;
756 private javax.swing.JCheckBoxMenuItem gMenuLogControl;
757 private javax.swing.JCheckBoxMenuItem gMenuLogServiceAnnounce;
758 private javax.swing.JMenu gMenuServerChat;
759 private javax.swing.JMenuItem gMenuServerChatRestart;
760 private javax.swing.JMenuItem gMenuServerChatStop;
761 private javax.swing.JMenu gMenuServerSocial;
762 private javax.swing.JMenuItem gMenuServerSocialRestart;
763 private javax.swing.JMenuItem gMenuServerSocialStop;
764 private javax.swing.JMenu gMenuServers;
765 private javax.swing.JTextArea gTextAreaAbout;
766 // End of variables declaration//GEN-END:variables