Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
HealthMonitorDashboard.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2018-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.healthmonitor;
20 
21 import java.awt.Container;
22 import java.awt.Cursor;
23 import java.awt.Dimension;
24 import java.util.Set;
25 import java.util.HashSet;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.Arrays;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.awt.event.ActionEvent;
32 import java.awt.event.ActionListener;
33 import java.io.BufferedWriter;
34 import java.io.File;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.OutputStreamWriter;
38 import javax.swing.Box;
39 import javax.swing.JButton;
40 import javax.swing.JDialog;
41 import javax.swing.JComboBox;
42 import javax.swing.JSeparator;
43 import javax.swing.JCheckBox;
44 import javax.swing.JLabel;
45 import javax.swing.JPanel;
46 import javax.swing.JScrollPane;
47 import javax.swing.BorderFactory;
48 import javax.swing.BoxLayout;
49 import java.awt.GridLayout;
50 import java.nio.charset.StandardCharsets;
51 import java.nio.file.Paths;
52 import java.text.DateFormat;
53 import java.text.SimpleDateFormat;
54 import java.util.Date;
55 import java.util.Collections;
56 import java.util.logging.Level;
57 import java.util.stream.Collectors;
58 import javax.swing.JFileChooser;
59 import org.openide.util.NbBundle;
65 
69 public class HealthMonitorDashboard {
70 
71  private final static Logger logger = Logger.getLogger(HealthMonitorDashboard.class.getName());
72 
73  private final static String ADMIN_ACCESS_FILE_NAME = "admin"; // NON-NLS
74  private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), ADMIN_ACCESS_FILE_NAME).toString();
75 
76  Map<String, List<HealthMonitor.DatabaseTimingResult>> timingData;
77  List<HealthMonitor.UserData> userData;
78 
79  private JComboBox<String> timingDateComboBox = null;
80  private JComboBox<String> timingHostComboBox = null;
81  private JCheckBox timingHostCheckBox = null;
82  private JCheckBox timingShowTrendLineCheckBox = null;
83  private JCheckBox timingSkipOutliersCheckBox = null;
84  private JPanel timingGraphPanel = null;
85  private JComboBox<String> userDateComboBox = null;
86  private JPanel userGraphPanel = null;
87  private JDialog dialog = null;
88  private final Container parentWindow;
89 
91 
97  public HealthMonitorDashboard(Container parent) {
98  timingData = new HashMap<>();
99  userData = new ArrayList<>();
100  parentWindow = parent;
101  chooserHelper = new JFileChooserFactory();
102  }
103 
107  @NbBundle.Messages({"HealthMonitorDashboard.display.errorCreatingDashboard=Error creating health monitor dashboard",
108  "HealthMonitorDashboard.display.dashboardTitle=Health Monitor"})
109  public void display() {
110 
111  // Update the enabled status and get the timing data, then create all
112  // the sub panels.
113  JPanel timingPanel;
114  JPanel userPanel;
115  JPanel adminPanel;
116  try {
117  updateData();
118  timingPanel = createTimingPanel();
119  userPanel = createUserPanel();
120  adminPanel = createAdminPanel();
121  } catch (HealthMonitorException ex) {
122  logger.log(Level.SEVERE, "Error creating panels for health monitor dashboard", ex);
123  MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_display_errorCreatingDashboard());
124  return;
125  }
126 
127  // Create the main panel for the dialog
128  JPanel mainPanel = new JPanel();
129  mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
130 
131  // Add the timing panel
132  mainPanel.add(timingPanel);
133 
134  // Add the user panel
135  mainPanel.add(userPanel);
136 
137  // Add the admin panel if the admin file is present
138  File adminFile = new File(ADMIN_ACCESS_FILE_PATH);
139  if(adminFile.exists()) {
140  mainPanel.add(adminPanel);
141  }
142 
143  // Create and show the dialog
144  dialog = new JDialog();
145  dialog.setTitle(Bundle.HealthMonitorDashboard_display_dashboardTitle());
146  dialog.add(mainPanel);
147  dialog.pack();
148  dialog.setLocationRelativeTo(parentWindow);
149  dialog.setVisible(true);
150  }
151 
156  private void redisplay() {
157  if (dialog != null) {
158  dialog.setVisible(false);
159  dialog.dispose();
160  }
161  display();
162  }
163 
168  private void updateData() throws HealthMonitorException {
169 
170  // Update the monitor status
171  HealthMonitor.getInstance().updateFromGlobalEnabledStatus();
172 
173  if(HealthMonitor.monitorIsEnabled()) {
174  // Get a copy of the timing data from the database
175  timingData = HealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
176 
177  // Get a copy of the user data from the database
178  userData = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
179  }
180  }
181 
187  @NbBundle.Messages({"HealthMonitorDashboard.createTimingPanel.noData=No data to display - monitor is not enabled",
188  "HealthMonitorDashboard.createTimingPanel.timingMetricsTitle=Timing Metrics"})
189  private JPanel createTimingPanel() throws HealthMonitorException {
190 
191  // If the monitor isn't enabled, just add a message
192  if(! HealthMonitor.monitorIsEnabled()) {
193  //timingMetricPanel.setPreferredSize(new Dimension(400,100));
194  JPanel emptyTimingMetricPanel = new JPanel();
195  emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle()));
196  emptyTimingMetricPanel.add(new JLabel(" "));
197  emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_noData()));
198 
199  return emptyTimingMetricPanel;
200  }
201 
202  JPanel timingMetricPanel = new JPanel();
203  timingMetricPanel.setLayout(new BoxLayout(timingMetricPanel, BoxLayout.PAGE_AXIS));
204  timingMetricPanel.setBorder(BorderFactory.createEtchedBorder());
205 
206  // Add title
207  JLabel timingMetricTitle = new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle());
208  timingMetricPanel.add(timingMetricTitle);
209  timingMetricPanel.add(new JSeparator());
210 
211  // Add the controls
212  timingMetricPanel.add(createTimingControlPanel());
213  timingMetricPanel.add(new JSeparator());
214 
215  // Create panel to hold graphs
216  timingGraphPanel = new JPanel();
217  timingGraphPanel.setLayout(new GridLayout(0,2));
218 
219  // Update the graph panel, put it in a scroll pane, and add to the timing metric panel
221  JScrollPane scrollPane = new JScrollPane(timingGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
222  timingMetricPanel.add(scrollPane);
223  timingMetricPanel.revalidate();
224  timingMetricPanel.repaint();
225 
226  return timingMetricPanel;
227  }
228 
233  @NbBundle.Messages({"HealthMonitorDashboard.createTimingControlPanel.filterByHost=Filter by host",
234  "HealthMonitorDashboard.createTimingControlPanel.maxDays=Max days to display",
235  "HealthMonitorDashboard.createTimingControlPanel.skipOutliers=Do not plot outliers",
236  "HealthMonitorDashboard.createTimingControlPanel.showTrendLine=Show trend line"})
237  private JPanel createTimingControlPanel() {
238  JPanel timingControlPanel = new JPanel();
239 
240  // If the monitor is not enabled, don't add any components
241  if(! HealthMonitor.monitorIsEnabled()) {
242  return timingControlPanel;
243  }
244 
245  // Create the combo box for selecting how much data to display
246  String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
247  timingDateComboBox = new JComboBox<>(dateOptionStrings);
248  timingDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
249 
250  // Set up the listener on the date combo box
251  timingDateComboBox.addActionListener(new ActionListener() {
252  @Override
253  public void actionPerformed(ActionEvent arg0) {
254  try {
256  } catch (HealthMonitorException ex) {
257  logger.log(Level.SEVERE, "Error updating timing metric panel", ex);
258  }
259  }
260  });
261 
262  // Create an array of host names
263  Set<String> hostNameSet = new HashSet<>();
264  for(String metricType:timingData.keySet()) {
265  for(HealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
266  hostNameSet.add(result.getHostName());
267  }
268  }
269 
270  // Load the host names into the combo box
271  timingHostComboBox = new JComboBox<>(hostNameSet.toArray(new String[hostNameSet.size()]));
272 
273  // Set up the listener on the combo box
274  timingHostComboBox.addActionListener(new ActionListener() {
275  @Override
276  public void actionPerformed(ActionEvent arg0) {
277  try {
278  if((timingHostCheckBox != null) && timingHostCheckBox.isSelected()) {
280  }
281  } catch (HealthMonitorException ex) {
282  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
283  }
284  }
285  });
286 
287  // Create the host checkbox
288  timingHostCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_filterByHost());
289  timingHostCheckBox.setSelected(false);
290  timingHostComboBox.setEnabled(false);
291 
292  // Set up the listener on the checkbox
293  timingHostCheckBox.addActionListener(new ActionListener() {
294  @Override
295  public void actionPerformed(ActionEvent arg0) {
296  try {
297  timingHostComboBox.setEnabled(timingHostCheckBox.isSelected());
299  } catch (HealthMonitorException ex) {
300  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
301  }
302  }
303  });
304 
305  // Create the checkbox for showing the trend line
306  timingShowTrendLineCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_showTrendLine());
307  timingShowTrendLineCheckBox.setSelected(true);
308 
309  // Set up the listener on the checkbox
310  timingShowTrendLineCheckBox.addActionListener(new ActionListener() {
311  @Override
312  public void actionPerformed(ActionEvent arg0) {
313  try {
315  } catch (HealthMonitorException ex) {
316  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
317  }
318  }
319  });
320 
321  // Create the checkbox for omitting outliers
322  timingSkipOutliersCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_skipOutliers());
323  timingSkipOutliersCheckBox.setSelected(false);
324 
325  // Set up the listener on the checkbox
326  timingSkipOutliersCheckBox.addActionListener(new ActionListener() {
327  @Override
328  public void actionPerformed(ActionEvent arg0) {
329  try {
331  } catch (HealthMonitorException ex) {
332  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
333  }
334  }
335  });
336 
337  // Add the date range combo box and label to the panel
338  timingControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingControlPanel_maxDays()));
339  timingControlPanel.add(timingDateComboBox);
340 
341  // Put some space between the elements
342  timingControlPanel.add(Box.createHorizontalStrut(100));
343 
344  // Add the host combo box and checkbox to the panel
345  timingControlPanel.add(timingHostCheckBox);
346  timingControlPanel.add(timingHostComboBox);
347 
348  // Put some space between the elements
349  timingControlPanel.add(Box.createHorizontalStrut(100));
350 
351  // Add the skip outliers checkbox
352  timingControlPanel.add(this.timingShowTrendLineCheckBox);
353 
354  // Put some space between the elements
355  timingControlPanel.add(Box.createHorizontalStrut(100));
356 
357  // Add the skip outliers checkbox
358  timingControlPanel.add(this.timingSkipOutliersCheckBox);
359 
360  return timingControlPanel;
361  }
362 
367  @NbBundle.Messages({"HealthMonitorDashboard.updateTimingMetricGraphs.noData=No data to display"})
368  private void updateTimingMetricGraphs() throws HealthMonitorException {
369 
370  // Clear out any old graphs
371  timingGraphPanel.removeAll();
372 
373  if(timingData.keySet().isEmpty()) {
374  // There are no timing metrics in the database
375  timingGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateTimingMetricGraphs_noData()));
376  return;
377  }
378 
379  for(String metricName:timingData.keySet()) {
380 
381  // If necessary, trim down the list of results to fit the selected time range
382  List<HealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
383  if(timingDateComboBox.getSelectedItem() != null) {
384  DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
385  long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
386  intermediateTimingDataForDisplay = timingData.get(metricName).stream()
387  .filter(t -> t.getTimestamp() > threshold)
388  .collect(Collectors.toList());
389  } else {
390  intermediateTimingDataForDisplay = timingData.get(metricName);
391  }
392 
393  // Get the name of the selected host, if there is one.
394  // The graph always uses the data from all hosts to generate the x and y scales
395  // so we don't filter anything out here.
396  String hostToDisplay = null;
397  if(timingHostCheckBox.isSelected() && (timingHostComboBox.getSelectedItem() != null)) {
398  hostToDisplay = timingHostComboBox.getSelectedItem().toString();
399  }
400 
401  // Generate the graph
402  TimingMetricGraphPanel singleTimingGraphPanel = new TimingMetricGraphPanel(intermediateTimingDataForDisplay,
403  hostToDisplay, true, metricName, timingSkipOutliersCheckBox.isSelected(), timingShowTrendLineCheckBox.isSelected());
404  singleTimingGraphPanel.setPreferredSize(new Dimension(700,200));
405 
406  timingGraphPanel.add(singleTimingGraphPanel);
407  }
408  timingGraphPanel.revalidate();
409  timingGraphPanel.repaint();
410  }
411 
417  @NbBundle.Messages({"HealthMonitorDashboard.createUserPanel.noData=No data to display - monitor is not enabled",
418  "HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
419  private JPanel createUserPanel() throws HealthMonitorException {
420  // If the monitor isn't enabled, just add a message
421  if(! HealthMonitor.monitorIsEnabled()) {
422  JPanel emptyUserMetricPanel = new JPanel();
423  emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
424  emptyUserMetricPanel.add(new JLabel(" "));
425  emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_noData()));
426 
427  return emptyUserMetricPanel;
428  }
429 
430  JPanel userMetricPanel = new JPanel();
431  userMetricPanel.setLayout(new BoxLayout(userMetricPanel, BoxLayout.PAGE_AXIS));
432  userMetricPanel.setBorder(BorderFactory.createEtchedBorder());
433 
434  // Add title
435  JLabel userMetricTitle = new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle());
436  userMetricPanel.add(userMetricTitle);
437  userMetricPanel.add(new JSeparator());
438 
439  // Add the controls
440  userMetricPanel.add(createUserControlPanel());
441  userMetricPanel.add(new JSeparator());
442 
443  // Create panel to hold graphs
444  userGraphPanel = new JPanel();
445  userGraphPanel.setLayout(new GridLayout(0,2));
446 
447  // Update the graph panel, put it in a scroll pane, and add to the timing metric panel
449  JScrollPane scrollPane = new JScrollPane(userGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
450  userMetricPanel.add(scrollPane);
451  userMetricPanel.revalidate();
452  userMetricPanel.repaint();
453 
454  return userMetricPanel;
455  }
456 
461  @NbBundle.Messages({"HealthMonitorDashboard.createUserControlPanel.maxDays=Max days to display",
462  "HealthMonitorDashboard.createUserControlPanel.userReportButton=Generate Report",
463  "HealthMonitorDashboard.createUserControlPanel.reportError=Error generating report",
464  "# {0} - Report file name",
465  "HealthMonitorDashboard.createUserControlPanel.reportDone=Report saved to: {0}"})
466  private JPanel createUserControlPanel() {
467  JPanel userControlPanel = new JPanel();
468 
469  // If the monitor is not enabled, don't add any components
470  if(! HealthMonitor.monitorIsEnabled()) {
471  return userControlPanel;
472  }
473 
474  // Create the combo box for selecting how much data to display
475  String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
476  userDateComboBox = new JComboBox<>(dateOptionStrings);
477  userDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
478 
479  // Set up the listener on the date combo box
480  userDateComboBox.addActionListener(new ActionListener() {
481  @Override
482  public void actionPerformed(ActionEvent arg0) {
483  try {
485  } catch (HealthMonitorException ex) {
486  logger.log(Level.SEVERE, "Error updating user metric panel", ex);
487  }
488  }
489  });
490 
491  // Add the date range combo box and label to the panel
492  userControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserControlPanel_maxDays()));
493  userControlPanel.add(userDateComboBox);
494 
495  // Create a button to create a user report
496  JButton reportButton = new JButton(Bundle.HealthMonitorDashboard_createUserControlPanel_userReportButton());
497 
498  // Set up a listener on the report button
499  reportButton.addActionListener(new ActionListener() {
500  @Override
501  public void actionPerformed(ActionEvent arg0) {
502  JFileChooser reportFileChooser = chooserHelper.getChooser();
503  reportFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
504  reportFileChooser.setCurrentDirectory(new File(UserPreferences.getHealthMonitorReportPath()));
505  final DateFormat csvTimestampFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
506  String fileName = "UserReport_" + csvTimestampFormat.format(new Date())+ ".csv";
507  reportFileChooser.setSelectedFile(new File(fileName));
508 
509  int returnVal = reportFileChooser.showSaveDialog(userControlPanel);
510  if (returnVal == JFileChooser.APPROVE_OPTION) {
511 
512  File selectedFile = reportFileChooser.getSelectedFile();
513  UserPreferences.setHealthMonitorReportPath(selectedFile.getParent());
514  try {
515  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
516  generateCSVUserReport(selectedFile);
517  MessageNotifyUtil.Message.info(Bundle.HealthMonitorDashboard_createUserControlPanel_reportDone(selectedFile.getAbsoluteFile()));
518  } catch (HealthMonitorException ex) {
519  logger.log(Level.SEVERE, "Error generating report", ex);
520  MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_createUserControlPanel_reportError());
521  } finally {
522  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
523  }
524  }
525  }
526  });
527  userControlPanel.add(reportButton);
528 
529  return userControlPanel;
530  }
531 
539  private void generateCSVUserReport(File reportFile) throws HealthMonitorException {
540  final DateFormat timestampFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
541 
542  try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportFile), StandardCharsets.UTF_8))) {
543  // Write header
544  writer.write("Case open,Case close,Duration,Host,User,Case name");
545  writer.newLine();
546 
547  // Get the list of user data sorted by timestamp
548  List<HealthMonitor.UserData> dataForReport = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.ONE_WEEK.getTimestampRange());
549  Collections.sort(dataForReport);
550 
551  // Go through the list of events in order of timestamp. For each case open event, look for the next case closed
552  // event for that host/user/case name.
553  for (int caseOpenIndex = 0; caseOpenIndex < dataForReport.size() - 1; caseOpenIndex++) {
554  if (! dataForReport.get(caseOpenIndex).getEventType().equals(HealthMonitor.UserEvent.CASE_OPEN)) {
555  continue;
556  }
557 
558  // Try to find the next event logged for this user/host. We do not check that
559  // it is a case closed event.
560  HealthMonitor.UserData caseOpenEvent = dataForReport.get(caseOpenIndex);
561  HealthMonitor.UserData nextEventAfterCaseOpen = null;
562  for (int nextEventIndex = caseOpenIndex + 1; nextEventIndex < dataForReport.size(); nextEventIndex++) {
563  HealthMonitor.UserData nextEvent = dataForReport.get(nextEventIndex);
564  // If the user and host name do not match, ignore this event
565  if ( nextEvent.getHostname().equals(caseOpenEvent.getHostname())
566  && nextEvent.getUserName().equals(caseOpenEvent.getUserName())) {
567  nextEventAfterCaseOpen = nextEvent;
568  break;
569  }
570  }
571 
572  // Prepare the columns
573  String caseOpenTime = timestampFormat.format(caseOpenEvent.getTimestamp());
574 
575  // If everything is recorded properly then the next event for a given user after
576  // a case open will be a case close. In this case we record the close time and
577  // how long the case was open. If the next event was not a case close event
578  // or if there is no next event (which could happen if Autopsy crashed or if
579  // there were network issues, or if the user simply still has the case open),
580  // leave the close time and duration blank.
581  String caseCloseTime = "";
582  String duration = "";
583  if (nextEventAfterCaseOpen != null
584  && nextEventAfterCaseOpen.getEventType().equals(HealthMonitor.UserEvent.CASE_CLOSE)
585  && nextEventAfterCaseOpen.getCaseName().equals(caseOpenEvent.getCaseName())) {
586  caseCloseTime = timestampFormat.format(nextEventAfterCaseOpen.getTimestamp());
587  duration = getDuration(caseOpenEvent.getTimestamp(), nextEventAfterCaseOpen.getTimestamp());
588  }
589 
590  String host = caseOpenEvent.getHostname();
591  String user = caseOpenEvent.getUserName();
592  String caseName = caseOpenEvent.getCaseName();
593 
594  String csvEntry = caseOpenTime + "," + caseCloseTime + "," + duration + "," + host + "," + user + ",\"" + caseName + "\"";
595  writer.write(csvEntry);
596  writer.newLine();
597  }
598  } catch (IOException ex) {
599  throw new HealthMonitorException("Error writing to output file " + reportFile.getAbsolutePath(), ex);
600  }
601  }
602 
612  private String getDuration(long start, long end) {
613  long durationInSeconds = (end - start) / 1000;
614  long second = durationInSeconds % 60;
615  long minute = (durationInSeconds / 60) % 60;
616  long hours = durationInSeconds / (60 * 60);
617 
618  return String.format("%d:%02d:%02d", hours, minute, second);
619  }
620 
625  @NbBundle.Messages({"HealthMonitorDashboard.updateUserMetricGraphs.noData=No data to display"})
626  private void updateUserMetricGraphs() throws HealthMonitorException {
627 
628  // Clear out any old graphs
629  userGraphPanel.removeAll();
630 
631  if(userData.isEmpty()) {
632  // There are no user metrics in the database
633  userGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateUserMetricGraphs_noData()));
634  return;
635  }
636 
637  // Calculate the minimum timestamp for the graph.
638  // Unlike the timing graphs, we do not filter the list of user metrics here.
639  // This is because even if we're only displaying one day, the
640  // last metric for a host may be that it logged on two days ago, so we would want
641  // to show that node as logged on.
642  long timestampThreshold;
643  if(userDateComboBox.getSelectedItem() != null) {
644  DateRange selectedDateRange = DateRange.fromLabel(userDateComboBox.getSelectedItem().toString());
645  timestampThreshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
646 
647  } else {
648  timestampThreshold = System.currentTimeMillis() - DateRange.getMaximumTimestampRange();
649  }
650 
651  // Generate the graphs
652  UserMetricGraphPanel caseGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, true);
653  caseGraphPanel.setPreferredSize(new Dimension(700,200));
654 
655  UserMetricGraphPanel logonGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, false);
656  logonGraphPanel.setPreferredSize(new Dimension(700,200));
657 
658  userGraphPanel.add(caseGraphPanel);
659  userGraphPanel.add(logonGraphPanel);
660  userGraphPanel.revalidate();
661  userGraphPanel.repaint();
662  }
663 
669  @NbBundle.Messages({"HealthMonitorDashboard.createAdminPanel.enableButton=Enable monitor",
670  "HealthMonitorDashboard.createAdminPanel.disableButton=Disable monitor"})
671  private JPanel createAdminPanel() {
672 
673  JPanel adminPanel = new JPanel();
674  adminPanel.setBorder(BorderFactory.createEtchedBorder());
675 
676  // Create the buttons for enabling/disabling the monitor
677  JButton enableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_enableButton());
678  JButton disableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_disableButton());
679 
680  boolean isEnabled = HealthMonitor.monitorIsEnabled();
681  enableButton.setEnabled(! isEnabled);
682  disableButton.setEnabled(isEnabled);
683 
684  // Set up a listener on the enable button
685  enableButton.addActionListener(new ActionListener() {
686  @Override
687  public void actionPerformed(ActionEvent arg0) {
688  try {
689  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
690  HealthMonitor.setEnabled(true);
691  redisplay();
692  } catch (HealthMonitorException ex) {
693  logger.log(Level.SEVERE, "Error enabling monitoring", ex);
694  } finally {
695  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
696  }
697  }
698  });
699 
700  // Set up a listener on the disable button
701  disableButton.addActionListener(new ActionListener() {
702  @Override
703  public void actionPerformed(ActionEvent arg0) {
704  try {
705  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
706  HealthMonitor.setEnabled(false);
707  redisplay();
708  } catch (HealthMonitorException ex) {
709  logger.log(Level.SEVERE, "Error disabling monitoring", ex);
710  } finally {
711  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
712  }
713  }
714  });
715 
716  // Add the buttons
717  adminPanel.add(enableButton);
718  adminPanel.add(Box.createHorizontalStrut(25));
719  adminPanel.add(disableButton);
720 
721  return adminPanel;
722  }
723 
727  @NbBundle.Messages({"HealthMonitorDashboard.DateRange.oneMonth=One month",
728  "HealthMonitorDashboard.DateRange.twoWeeks=Two weeks",
729  "HealthMonitorDashboard.DateRange.oneWeek=One week",
730  "HealthMonitorDashboard.DateRange.oneDay=One day"})
731  private enum DateRange {
732  ONE_DAY(Bundle.HealthMonitorDashboard_DateRange_oneDay(), 1),
733  ONE_WEEK(Bundle.HealthMonitorDashboard_DateRange_oneWeek(), 7),
734  TWO_WEEKS(Bundle.HealthMonitorDashboard_DateRange_twoWeeks(), 14),
735  ONE_MONTH(Bundle.HealthMonitorDashboard_DateRange_oneMonth(), 31);
736 
737  private final String label;
738  private final long numberOfDays;
739  private static final long MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24;
740 
741  DateRange(String label, long numberOfDays) {
742  this.label = label;
743  this.numberOfDays = numberOfDays;
744  }
745 
750  String getLabel() {
751  return label;
752  }
753 
761  if (numberOfDays > 0) {
762  return numberOfDays * MILLISECONDS_PER_DAY;
763  } else {
764  return Long.MAX_VALUE;
765  }
766  }
767 
773  static long getMaximumTimestampRange() {
774  long maxRange = Long.MIN_VALUE;
775  for (DateRange dateRange : DateRange.values()) {
776  if (dateRange.getTimestampRange() > maxRange) {
777  maxRange = dateRange.getTimestampRange();
778  }
779  }
780  return maxRange;
781  }
782 
783  static DateRange fromLabel(String text) {
784  for (DateRange dateRange : DateRange.values()) {
785  if (dateRange.label.equalsIgnoreCase(text)) {
786  return dateRange;
787  }
788  }
789  return ONE_DAY; // If the comparison failed, return a default
790  }
791  }
792 
793 }
static void setHealthMonitorReportPath(String reportPath)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.