Autopsy  4.19.0
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 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;
64 
68 public class HealthMonitorDashboard {
69 
70  private final static Logger logger = Logger.getLogger(HealthMonitorDashboard.class.getName());
71 
72  private final static String ADMIN_ACCESS_FILE_NAME = "admin"; // NON-NLS
73  private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), ADMIN_ACCESS_FILE_NAME).toString();
74 
75  Map<String, List<HealthMonitor.DatabaseTimingResult>> timingData;
76  List<HealthMonitor.UserData> userData;
77 
78  private JComboBox<String> timingDateComboBox = null;
79  private JComboBox<String> timingHostComboBox = null;
80  private JCheckBox timingHostCheckBox = null;
81  private JCheckBox timingShowTrendLineCheckBox = null;
82  private JCheckBox timingSkipOutliersCheckBox = null;
83  private JPanel timingGraphPanel = null;
84  private JComboBox<String> userDateComboBox = null;
85  private JPanel userGraphPanel = null;
86  private JDialog dialog = null;
87  private final Container parentWindow;
88 
94  public HealthMonitorDashboard(Container parent) {
95  timingData = new HashMap<>();
96  userData = new ArrayList<>();
97  parentWindow = parent;
98  }
99 
103  @NbBundle.Messages({"HealthMonitorDashboard.display.errorCreatingDashboard=Error creating health monitor dashboard",
104  "HealthMonitorDashboard.display.dashboardTitle=Health Monitor"})
105  public void display() {
106 
107  // Update the enabled status and get the timing data, then create all
108  // the sub panels.
109  JPanel timingPanel;
110  JPanel userPanel;
111  JPanel adminPanel;
112  try {
113  updateData();
114  timingPanel = createTimingPanel();
115  userPanel = createUserPanel();
116  adminPanel = createAdminPanel();
117  } catch (HealthMonitorException ex) {
118  logger.log(Level.SEVERE, "Error creating panels for health monitor dashboard", ex);
119  MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_display_errorCreatingDashboard());
120  return;
121  }
122 
123  // Create the main panel for the dialog
124  JPanel mainPanel = new JPanel();
125  mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
126 
127  // Add the timing panel
128  mainPanel.add(timingPanel);
129 
130  // Add the user panel
131  mainPanel.add(userPanel);
132 
133  // Add the admin panel if the admin file is present
134  File adminFile = new File(ADMIN_ACCESS_FILE_PATH);
135  if(adminFile.exists()) {
136  mainPanel.add(adminPanel);
137  }
138 
139  // Create and show the dialog
140  dialog = new JDialog();
141  dialog.setTitle(Bundle.HealthMonitorDashboard_display_dashboardTitle());
142  dialog.add(mainPanel);
143  dialog.pack();
144  dialog.setLocationRelativeTo(parentWindow);
145  dialog.setVisible(true);
146  }
147 
152  private void redisplay() {
153  if (dialog != null) {
154  dialog.setVisible(false);
155  dialog.dispose();
156  }
157  display();
158  }
159 
164  private void updateData() throws HealthMonitorException {
165 
166  // Update the monitor status
167  HealthMonitor.getInstance().updateFromGlobalEnabledStatus();
168 
169  if(HealthMonitor.monitorIsEnabled()) {
170  // Get a copy of the timing data from the database
171  timingData = HealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
172 
173  // Get a copy of the user data from the database
174  userData = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
175  }
176  }
177 
183  @NbBundle.Messages({"HealthMonitorDashboard.createTimingPanel.noData=No data to display - monitor is not enabled",
184  "HealthMonitorDashboard.createTimingPanel.timingMetricsTitle=Timing Metrics"})
185  private JPanel createTimingPanel() throws HealthMonitorException {
186 
187  // If the monitor isn't enabled, just add a message
188  if(! HealthMonitor.monitorIsEnabled()) {
189  //timingMetricPanel.setPreferredSize(new Dimension(400,100));
190  JPanel emptyTimingMetricPanel = new JPanel();
191  emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle()));
192  emptyTimingMetricPanel.add(new JLabel(" "));
193  emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_noData()));
194 
195  return emptyTimingMetricPanel;
196  }
197 
198  JPanel timingMetricPanel = new JPanel();
199  timingMetricPanel.setLayout(new BoxLayout(timingMetricPanel, BoxLayout.PAGE_AXIS));
200  timingMetricPanel.setBorder(BorderFactory.createEtchedBorder());
201 
202  // Add title
203  JLabel timingMetricTitle = new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle());
204  timingMetricPanel.add(timingMetricTitle);
205  timingMetricPanel.add(new JSeparator());
206 
207  // Add the controls
208  timingMetricPanel.add(createTimingControlPanel());
209  timingMetricPanel.add(new JSeparator());
210 
211  // Create panel to hold graphs
212  timingGraphPanel = new JPanel();
213  timingGraphPanel.setLayout(new GridLayout(0,2));
214 
215  // Update the graph panel, put it in a scroll pane, and add to the timing metric panel
217  JScrollPane scrollPane = new JScrollPane(timingGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
218  timingMetricPanel.add(scrollPane);
219  timingMetricPanel.revalidate();
220  timingMetricPanel.repaint();
221 
222  return timingMetricPanel;
223  }
224 
229  @NbBundle.Messages({"HealthMonitorDashboard.createTimingControlPanel.filterByHost=Filter by host",
230  "HealthMonitorDashboard.createTimingControlPanel.maxDays=Max days to display",
231  "HealthMonitorDashboard.createTimingControlPanel.skipOutliers=Do not plot outliers",
232  "HealthMonitorDashboard.createTimingControlPanel.showTrendLine=Show trend line"})
233  private JPanel createTimingControlPanel() {
234  JPanel timingControlPanel = new JPanel();
235 
236  // If the monitor is not enabled, don't add any components
237  if(! HealthMonitor.monitorIsEnabled()) {
238  return timingControlPanel;
239  }
240 
241  // Create the combo box for selecting how much data to display
242  String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
243  timingDateComboBox = new JComboBox<>(dateOptionStrings);
244  timingDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
245 
246  // Set up the listener on the date combo box
247  timingDateComboBox.addActionListener(new ActionListener() {
248  @Override
249  public void actionPerformed(ActionEvent arg0) {
250  try {
252  } catch (HealthMonitorException ex) {
253  logger.log(Level.SEVERE, "Error updating timing metric panel", ex);
254  }
255  }
256  });
257 
258  // Create an array of host names
259  Set<String> hostNameSet = new HashSet<>();
260  for(String metricType:timingData.keySet()) {
261  for(HealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
262  hostNameSet.add(result.getHostName());
263  }
264  }
265 
266  // Load the host names into the combo box
267  timingHostComboBox = new JComboBox<>(hostNameSet.toArray(new String[hostNameSet.size()]));
268 
269  // Set up the listener on the combo box
270  timingHostComboBox.addActionListener(new ActionListener() {
271  @Override
272  public void actionPerformed(ActionEvent arg0) {
273  try {
274  if((timingHostCheckBox != null) && timingHostCheckBox.isSelected()) {
276  }
277  } catch (HealthMonitorException ex) {
278  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
279  }
280  }
281  });
282 
283  // Create the host checkbox
284  timingHostCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_filterByHost());
285  timingHostCheckBox.setSelected(false);
286  timingHostComboBox.setEnabled(false);
287 
288  // Set up the listener on the checkbox
289  timingHostCheckBox.addActionListener(new ActionListener() {
290  @Override
291  public void actionPerformed(ActionEvent arg0) {
292  try {
293  timingHostComboBox.setEnabled(timingHostCheckBox.isSelected());
295  } catch (HealthMonitorException ex) {
296  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
297  }
298  }
299  });
300 
301  // Create the checkbox for showing the trend line
302  timingShowTrendLineCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_showTrendLine());
303  timingShowTrendLineCheckBox.setSelected(true);
304 
305  // Set up the listener on the checkbox
306  timingShowTrendLineCheckBox.addActionListener(new ActionListener() {
307  @Override
308  public void actionPerformed(ActionEvent arg0) {
309  try {
311  } catch (HealthMonitorException ex) {
312  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
313  }
314  }
315  });
316 
317  // Create the checkbox for omitting outliers
318  timingSkipOutliersCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_skipOutliers());
319  timingSkipOutliersCheckBox.setSelected(false);
320 
321  // Set up the listener on the checkbox
322  timingSkipOutliersCheckBox.addActionListener(new ActionListener() {
323  @Override
324  public void actionPerformed(ActionEvent arg0) {
325  try {
327  } catch (HealthMonitorException ex) {
328  logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
329  }
330  }
331  });
332 
333  // Add the date range combo box and label to the panel
334  timingControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingControlPanel_maxDays()));
335  timingControlPanel.add(timingDateComboBox);
336 
337  // Put some space between the elements
338  timingControlPanel.add(Box.createHorizontalStrut(100));
339 
340  // Add the host combo box and checkbox to the panel
341  timingControlPanel.add(timingHostCheckBox);
342  timingControlPanel.add(timingHostComboBox);
343 
344  // Put some space between the elements
345  timingControlPanel.add(Box.createHorizontalStrut(100));
346 
347  // Add the skip outliers checkbox
348  timingControlPanel.add(this.timingShowTrendLineCheckBox);
349 
350  // Put some space between the elements
351  timingControlPanel.add(Box.createHorizontalStrut(100));
352 
353  // Add the skip outliers checkbox
354  timingControlPanel.add(this.timingSkipOutliersCheckBox);
355 
356  return timingControlPanel;
357  }
358 
363  @NbBundle.Messages({"HealthMonitorDashboard.updateTimingMetricGraphs.noData=No data to display"})
364  private void updateTimingMetricGraphs() throws HealthMonitorException {
365 
366  // Clear out any old graphs
367  timingGraphPanel.removeAll();
368 
369  if(timingData.keySet().isEmpty()) {
370  // There are no timing metrics in the database
371  timingGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateTimingMetricGraphs_noData()));
372  return;
373  }
374 
375  for(String metricName:timingData.keySet()) {
376 
377  // If necessary, trim down the list of results to fit the selected time range
378  List<HealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
379  if(timingDateComboBox.getSelectedItem() != null) {
380  DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
381  long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
382  intermediateTimingDataForDisplay = timingData.get(metricName).stream()
383  .filter(t -> t.getTimestamp() > threshold)
384  .collect(Collectors.toList());
385  } else {
386  intermediateTimingDataForDisplay = timingData.get(metricName);
387  }
388 
389  // Get the name of the selected host, if there is one.
390  // The graph always uses the data from all hosts to generate the x and y scales
391  // so we don't filter anything out here.
392  String hostToDisplay = null;
393  if(timingHostCheckBox.isSelected() && (timingHostComboBox.getSelectedItem() != null)) {
394  hostToDisplay = timingHostComboBox.getSelectedItem().toString();
395  }
396 
397  // Generate the graph
398  TimingMetricGraphPanel singleTimingGraphPanel = new TimingMetricGraphPanel(intermediateTimingDataForDisplay,
399  hostToDisplay, true, metricName, timingSkipOutliersCheckBox.isSelected(), timingShowTrendLineCheckBox.isSelected());
400  singleTimingGraphPanel.setPreferredSize(new Dimension(700,200));
401 
402  timingGraphPanel.add(singleTimingGraphPanel);
403  }
404  timingGraphPanel.revalidate();
405  timingGraphPanel.repaint();
406  }
407 
413  @NbBundle.Messages({"HealthMonitorDashboard.createUserPanel.noData=No data to display - monitor is not enabled",
414  "HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
415  private JPanel createUserPanel() throws HealthMonitorException {
416  // If the monitor isn't enabled, just add a message
417  if(! HealthMonitor.monitorIsEnabled()) {
418  JPanel emptyUserMetricPanel = new JPanel();
419  emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
420  emptyUserMetricPanel.add(new JLabel(" "));
421  emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_noData()));
422 
423  return emptyUserMetricPanel;
424  }
425 
426  JPanel userMetricPanel = new JPanel();
427  userMetricPanel.setLayout(new BoxLayout(userMetricPanel, BoxLayout.PAGE_AXIS));
428  userMetricPanel.setBorder(BorderFactory.createEtchedBorder());
429 
430  // Add title
431  JLabel userMetricTitle = new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle());
432  userMetricPanel.add(userMetricTitle);
433  userMetricPanel.add(new JSeparator());
434 
435  // Add the controls
436  userMetricPanel.add(createUserControlPanel());
437  userMetricPanel.add(new JSeparator());
438 
439  // Create panel to hold graphs
440  userGraphPanel = new JPanel();
441  userGraphPanel.setLayout(new GridLayout(0,2));
442 
443  // Update the graph panel, put it in a scroll pane, and add to the timing metric panel
445  JScrollPane scrollPane = new JScrollPane(userGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
446  userMetricPanel.add(scrollPane);
447  userMetricPanel.revalidate();
448  userMetricPanel.repaint();
449 
450  return userMetricPanel;
451  }
452 
457  @NbBundle.Messages({"HealthMonitorDashboard.createUserControlPanel.maxDays=Max days to display",
458  "HealthMonitorDashboard.createUserControlPanel.userReportButton=Generate Report",
459  "HealthMonitorDashboard.createUserControlPanel.reportError=Error generating report",
460  "# {0} - Report file name",
461  "HealthMonitorDashboard.createUserControlPanel.reportDone=Report saved to: {0}"})
462  private JPanel createUserControlPanel() {
463  JPanel userControlPanel = new JPanel();
464 
465  // If the monitor is not enabled, don't add any components
466  if(! HealthMonitor.monitorIsEnabled()) {
467  return userControlPanel;
468  }
469 
470  // Create the combo box for selecting how much data to display
471  String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
472  userDateComboBox = new JComboBox<>(dateOptionStrings);
473  userDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
474 
475  // Set up the listener on the date combo box
476  userDateComboBox.addActionListener(new ActionListener() {
477  @Override
478  public void actionPerformed(ActionEvent arg0) {
479  try {
481  } catch (HealthMonitorException ex) {
482  logger.log(Level.SEVERE, "Error updating user metric panel", ex);
483  }
484  }
485  });
486 
487  // Add the date range combo box and label to the panel
488  userControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserControlPanel_maxDays()));
489  userControlPanel.add(userDateComboBox);
490 
491  // Create a button to create a user report
492  JButton reportButton = new JButton(Bundle.HealthMonitorDashboard_createUserControlPanel_userReportButton());
493 
494  // Set up a listener on the report button
495  reportButton.addActionListener(new ActionListener() {
496  @Override
497  public void actionPerformed(ActionEvent arg0) {
498  JFileChooser reportFileChooser = new JFileChooser();
499  reportFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
500  reportFileChooser.setCurrentDirectory(new File(UserPreferences.getHealthMonitorReportPath()));
501  final DateFormat csvTimestampFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
502  String fileName = "UserReport_" + csvTimestampFormat.format(new Date())+ ".csv";
503  reportFileChooser.setSelectedFile(new File(fileName));
504 
505  int returnVal = reportFileChooser.showSaveDialog(userControlPanel);
506  if (returnVal == JFileChooser.APPROVE_OPTION) {
507 
508  File selectedFile = reportFileChooser.getSelectedFile();
509  UserPreferences.setHealthMonitorReportPath(selectedFile.getParent());
510  try {
511  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
512  generateCSVUserReport(selectedFile);
513  MessageNotifyUtil.Message.info(Bundle.HealthMonitorDashboard_createUserControlPanel_reportDone(selectedFile.getAbsoluteFile()));
514  } catch (HealthMonitorException ex) {
515  logger.log(Level.SEVERE, "Error generating report", ex);
516  MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_createUserControlPanel_reportError());
517  } finally {
518  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
519  }
520  }
521  }
522  });
523  userControlPanel.add(reportButton);
524 
525  return userControlPanel;
526  }
527 
535  private void generateCSVUserReport(File reportFile) throws HealthMonitorException {
536  final DateFormat timestampFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
537 
538  try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportFile), StandardCharsets.UTF_8))) {
539  // Write header
540  writer.write("Case open,Case close,Duration,Host,User,Case name");
541  writer.newLine();
542 
543  // Get the list of user data sorted by timestamp
544  List<HealthMonitor.UserData> dataForReport = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.ONE_WEEK.getTimestampRange());
545  Collections.sort(dataForReport);
546 
547  // Go through the list of events in order of timestamp. For each case open event, look for the next case closed
548  // event for that host/user/case name.
549  for (int caseOpenIndex = 0; caseOpenIndex < dataForReport.size() - 1; caseOpenIndex++) {
550  if (! dataForReport.get(caseOpenIndex).getEventType().equals(HealthMonitor.UserEvent.CASE_OPEN)) {
551  continue;
552  }
553 
554  // Try to find the next event logged for this user/host. We do not check that
555  // it is a case closed event.
556  HealthMonitor.UserData caseOpenEvent = dataForReport.get(caseOpenIndex);
557  HealthMonitor.UserData nextEventAfterCaseOpen = null;
558  for (int nextEventIndex = caseOpenIndex + 1; nextEventIndex < dataForReport.size(); nextEventIndex++) {
559  HealthMonitor.UserData nextEvent = dataForReport.get(nextEventIndex);
560  // If the user and host name do not match, ignore this event
561  if ( nextEvent.getHostname().equals(caseOpenEvent.getHostname())
562  && nextEvent.getUserName().equals(caseOpenEvent.getUserName())) {
563  nextEventAfterCaseOpen = nextEvent;
564  break;
565  }
566  }
567 
568  // Prepare the columns
569  String caseOpenTime = timestampFormat.format(caseOpenEvent.getTimestamp());
570 
571  // If everything is recorded properly then the next event for a given user after
572  // a case open will be a case close. In this case we record the close time and
573  // how long the case was open. If the next event was not a case close event
574  // or if there is no next event (which could happen if Autopsy crashed or if
575  // there were network issues, or if the user simply still has the case open),
576  // leave the close time and duration blank.
577  String caseCloseTime = "";
578  String duration = "";
579  if (nextEventAfterCaseOpen != null
580  && nextEventAfterCaseOpen.getEventType().equals(HealthMonitor.UserEvent.CASE_CLOSE)
581  && nextEventAfterCaseOpen.getCaseName().equals(caseOpenEvent.getCaseName())) {
582  caseCloseTime = timestampFormat.format(nextEventAfterCaseOpen.getTimestamp());
583  duration = getDuration(caseOpenEvent.getTimestamp(), nextEventAfterCaseOpen.getTimestamp());
584  }
585 
586  String host = caseOpenEvent.getHostname();
587  String user = caseOpenEvent.getUserName();
588  String caseName = caseOpenEvent.getCaseName();
589 
590  String csvEntry = caseOpenTime + "," + caseCloseTime + "," + duration + "," + host + "," + user + ",\"" + caseName + "\"";
591  writer.write(csvEntry);
592  writer.newLine();
593  }
594  } catch (IOException ex) {
595  throw new HealthMonitorException("Error writing to output file " + reportFile.getAbsolutePath(), ex);
596  }
597  }
598 
608  private String getDuration(long start, long end) {
609  long durationInSeconds = (end - start) / 1000;
610  long second = durationInSeconds % 60;
611  long minute = (durationInSeconds / 60) % 60;
612  long hours = durationInSeconds / (60 * 60);
613 
614  return String.format("%d:%02d:%02d", hours, minute, second);
615  }
616 
621  @NbBundle.Messages({"HealthMonitorDashboard.updateUserMetricGraphs.noData=No data to display"})
622  private void updateUserMetricGraphs() throws HealthMonitorException {
623 
624  // Clear out any old graphs
625  userGraphPanel.removeAll();
626 
627  if(userData.isEmpty()) {
628  // There are no user metrics in the database
629  userGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateUserMetricGraphs_noData()));
630  return;
631  }
632 
633  // Calculate the minimum timestamp for the graph.
634  // Unlike the timing graphs, we do not filter the list of user metrics here.
635  // This is because even if we're only displaying one day, the
636  // last metric for a host may be that it logged on two days ago, so we would want
637  // to show that node as logged on.
638  long timestampThreshold;
639  if(userDateComboBox.getSelectedItem() != null) {
640  DateRange selectedDateRange = DateRange.fromLabel(userDateComboBox.getSelectedItem().toString());
641  timestampThreshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
642 
643  } else {
644  timestampThreshold = System.currentTimeMillis() - DateRange.getMaximumTimestampRange();
645  }
646 
647  // Generate the graphs
648  UserMetricGraphPanel caseGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, true);
649  caseGraphPanel.setPreferredSize(new Dimension(700,200));
650 
651  UserMetricGraphPanel logonGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, false);
652  logonGraphPanel.setPreferredSize(new Dimension(700,200));
653 
654  userGraphPanel.add(caseGraphPanel);
655  userGraphPanel.add(logonGraphPanel);
656  userGraphPanel.revalidate();
657  userGraphPanel.repaint();
658  }
659 
665  @NbBundle.Messages({"HealthMonitorDashboard.createAdminPanel.enableButton=Enable monitor",
666  "HealthMonitorDashboard.createAdminPanel.disableButton=Disable monitor"})
667  private JPanel createAdminPanel() {
668 
669  JPanel adminPanel = new JPanel();
670  adminPanel.setBorder(BorderFactory.createEtchedBorder());
671 
672  // Create the buttons for enabling/disabling the monitor
673  JButton enableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_enableButton());
674  JButton disableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_disableButton());
675 
676  boolean isEnabled = HealthMonitor.monitorIsEnabled();
677  enableButton.setEnabled(! isEnabled);
678  disableButton.setEnabled(isEnabled);
679 
680  // Set up a listener on the enable button
681  enableButton.addActionListener(new ActionListener() {
682  @Override
683  public void actionPerformed(ActionEvent arg0) {
684  try {
685  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
686  HealthMonitor.setEnabled(true);
687  redisplay();
688  } catch (HealthMonitorException ex) {
689  logger.log(Level.SEVERE, "Error enabling monitoring", ex);
690  } finally {
691  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
692  }
693  }
694  });
695 
696  // Set up a listener on the disable button
697  disableButton.addActionListener(new ActionListener() {
698  @Override
699  public void actionPerformed(ActionEvent arg0) {
700  try {
701  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
702  HealthMonitor.setEnabled(false);
703  redisplay();
704  } catch (HealthMonitorException ex) {
705  logger.log(Level.SEVERE, "Error disabling monitoring", ex);
706  } finally {
707  dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
708  }
709  }
710  });
711 
712  // Add the buttons
713  adminPanel.add(enableButton);
714  adminPanel.add(Box.createHorizontalStrut(25));
715  adminPanel.add(disableButton);
716 
717  return adminPanel;
718  }
719 
723  @NbBundle.Messages({"HealthMonitorDashboard.DateRange.oneMonth=One month",
724  "HealthMonitorDashboard.DateRange.twoWeeks=Two weeks",
725  "HealthMonitorDashboard.DateRange.oneWeek=One week",
726  "HealthMonitorDashboard.DateRange.oneDay=One day"})
727  private enum DateRange {
728  ONE_DAY(Bundle.HealthMonitorDashboard_DateRange_oneDay(), 1),
729  ONE_WEEK(Bundle.HealthMonitorDashboard_DateRange_oneWeek(), 7),
730  TWO_WEEKS(Bundle.HealthMonitorDashboard_DateRange_twoWeeks(), 14),
731  ONE_MONTH(Bundle.HealthMonitorDashboard_DateRange_oneMonth(), 31);
732 
733  private final String label;
734  private final long numberOfDays;
735  private static final long MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24;
736 
737  DateRange(String label, long numberOfDays) {
738  this.label = label;
739  this.numberOfDays = numberOfDays;
740  }
741 
746  String getLabel() {
747  return label;
748  }
749 
757  if (numberOfDays > 0) {
758  return numberOfDays * MILLISECONDS_PER_DAY;
759  } else {
760  return Long.MAX_VALUE;
761  }
762  }
763 
769  static long getMaximumTimestampRange() {
770  long maxRange = Long.MIN_VALUE;
771  for (DateRange dateRange : DateRange.values()) {
772  if (dateRange.getTimestampRange() > maxRange) {
773  maxRange = dateRange.getTimestampRange();
774  }
775  }
776  return maxRange;
777  }
778 
779  static DateRange fromLabel(String text) {
780  for (DateRange dateRange : DateRange.values()) {
781  if (dateRange.label.equalsIgnoreCase(text)) {
782  return dateRange;
783  }
784  }
785  return ONE_DAY; // If the comparison failed, return a default
786  }
787  }
788 
789 }
static void setHealthMonitorReportPath(String reportPath)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2021 Basis Technology. Generated on: Fri Aug 6 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.