Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ServicesMonitor.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-2020 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.core;
20 
22 import com.google.common.util.concurrent.ThreadFactoryBuilder;
23 import java.beans.PropertyChangeListener;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ScheduledThreadPoolExecutor;
27 import java.util.concurrent.TimeUnit;
28 import java.util.logging.Level;
29 import java.util.stream.Collectors;
30 import java.util.stream.Stream;
31 import org.openide.util.Lookup;
32 import org.openide.util.NbBundle;
40 import org.sleuthkit.datamodel.CaseDbConnectionInfo;
41 import org.sleuthkit.datamodel.SleuthkitCase;
42 import org.sleuthkit.datamodel.TskCoreException;
43 
51 public class ServicesMonitor {
52 
59  public enum Service {
60  REMOTE_CASE_DATABASE(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.remoteCaseDatabase.displayName.text")),
61  REMOTE_KEYWORD_SEARCH(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.remoteKeywordSearch.displayName.text")),
62  MESSAGING(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.messaging.displayName.text"));
63 
64  private final String displayName;
65 
66  private Service(String displayName) {
67  this.displayName = displayName;
68  }
69 
70  public String getDisplayName() {
71  return displayName;
72  }
73  };
74 
78  public enum ServiceStatus {
79  UP,
80  DOWN
81  };
82 
83  private static final Logger logger = Logger.getLogger(ServicesMonitor.class.getName());
84  private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d"; //NON-NLS
85  private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1;
86  private static final long CRASH_DETECTION_INTERVAL_MINUTES = 15;
87  private static final Set<String> coreServices = Stream.of(ServicesMonitor.Service.values()).map(Service::toString).collect(Collectors.toSet());
89  private final ScheduledThreadPoolExecutor periodicTasksExecutor;
90  private final ConcurrentHashMap<String, String> statusByService;
92 
100  public synchronized static ServicesMonitor getInstance() {
101  if (servicesMonitor == null) {
102  servicesMonitor = new ServicesMonitor();
103  }
104  return servicesMonitor;
105  }
106 
112  private ServicesMonitor() {
113  eventPublisher = new AutopsyEventPublisher();
114  statusByService = new ConcurrentHashMap<>();
115 
116  /*
117  * The first service statuses check is performed immediately in the
118  * current thread.
119  */
121 
125  periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
126  periodicTasksExecutor.scheduleWithFixedDelay(new ServicesMonitoringTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
127  }
128 
138  public void setServiceStatus(String service, String status, String details) {
139  if (statusByService.containsKey(service) && status.equals(statusByService.get(service))) {
140  return;
141  }
142 
143  statusByService.put(service, status);
144 
145  String serviceDisplayName;
146  try {
147  serviceDisplayName = ServicesMonitor.Service.valueOf(service).getDisplayName();
148  } catch (IllegalArgumentException ignore) {
149  serviceDisplayName = service;
150  }
151 
152  if (status.equals(ServiceStatus.UP.toString())) {
153  logger.log(Level.INFO, "Connection to {0} is up", serviceDisplayName); //NON-NLS
155  NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.title"),
156  NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.msg", serviceDisplayName));
157  } else if (status.equals(ServiceStatus.DOWN.toString())) {
158  logger.log(Level.SEVERE, "Failed to connect to {0}. Reason: {1}", new Object[]{serviceDisplayName, details}); //NON-NLS
160  NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.title"),
161  NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.msg", serviceDisplayName));
162  } else {
163  logger.log(Level.INFO, "Status for {0} is {1} ({2})", new Object[]{serviceDisplayName, status}); //NON-NLS
165  NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.title"),
166  NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.msg", new Object[]{serviceDisplayName, status, details}));
167  }
168 
169  eventPublisher.publishLocally(new ServiceEvent(service, status, details));
170  }
171 
182  public String getServiceStatus(String service) throws ServicesMonitorException {
183 
184  if (service == null || service.isEmpty()) {
185  throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.nullServiceName.excepton.txt"));
186  }
187 
188  /*
189  * If the request is for a core service, perform an "on demand" check to
190  * get the current status.
191  */
192  if (coreServices.contains(service)) {
193  checkServiceStatus(service);
194  }
195 
196  String status = statusByService.get(service);
197  if (status == null) {
198  throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.unknownServiceName.excepton.txt", service));
199  }
200  return status;
201  }
202 
208  public void addSubscriber(PropertyChangeListener subscriber) {
209  eventPublisher.addSubscriber(coreServices, subscriber);
210  }
211 
219  public void addSubscriber(Set<String> services, PropertyChangeListener subscriber) {
220  eventPublisher.addSubscriber(services, subscriber);
221  }
222 
230  public void addSubscriber(String service, PropertyChangeListener subscriber) {
231  eventPublisher.addSubscriber(service, subscriber);
232  }
233 
239  public void removeSubscriber(PropertyChangeListener subscriber) {
240  eventPublisher.removeSubscriber(coreServices, subscriber);
241  }
242 
250  public void removeSubscriber(Set<String> services, PropertyChangeListener subscriber) {
251  eventPublisher.removeSubscriber(services, subscriber);
252  }
253 
261  public void removeSubscriber(String service, PropertyChangeListener subscriber) {
262  eventPublisher.removeSubscriber(service, subscriber);
263  }
264 
271  private void checkAllServices() {
273  return;
274  }
275 
276  for (String service : coreServices) {
277  checkServiceStatus(service);
278  }
279  }
280 
287  private final class ServicesMonitoringTask implements Runnable {
288 
289  @Override
290  public void run() {
291  try {
293  } catch (Exception ex) { // Exception firewall
294  logger.log(Level.SEVERE, "An error occurred during services monitoring", ex); //NON-NLS
295  }
296  }
297  }
298 
302  public class ServicesMonitorException extends Exception {
303 
304  private static final long serialVersionUID = 1L;
305 
306  public ServicesMonitorException(String message) {
307  super(message);
308  }
309 
310  public ServicesMonitorException(String message, Throwable cause) {
311  super(message, cause);
312  }
313  }
314 
320  private void checkServiceStatus(String service) {
321  if (service.equals(Service.REMOTE_CASE_DATABASE.toString())) {
323  } else if (service.equals(Service.REMOTE_KEYWORD_SEARCH.toString())) {
325  } else if (service.equals(Service.MESSAGING.toString())) {
327  }
328  }
329 
334  CaseDbConnectionInfo info;
335  try {
337  } catch (UserPreferencesException ex) {
338  logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
339  setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.DOWN.toString(), NbBundle.getMessage(this.getClass(), "ServicesMonitor.databaseConnectionInfo.error.msg"));
340  return;
341  }
342  try {
343  SleuthkitCase.tryConnect(info);
344  setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.UP.toString(), "");
345  } catch (TskCoreException ex) {
346  setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.DOWN.toString(), ex.getMessage());
347  }
348  }
349 
354  KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
355  try {
356  if (kwsService != null) {
358  // check Solr 8
359  String kwsHostName = UserPreferences.getIndexingServerHost();
360  if (!kwsHostName.isEmpty()) {
361  int port = Integer.parseUnsignedInt(UserPreferences.getIndexingServerPort());
363  status = ServiceStatus.UP;
364  }
365 
366  // check Solr 4
367  if (!UserPreferences.getSolr4ServerHost().trim().isEmpty()) {
368  int port = Integer.parseUnsignedInt(UserPreferences.getSolr4ServerPort().trim());
369  kwsService.tryConnect(UserPreferences.getSolr4ServerHost().trim(), port);
370  status = ServiceStatus.UP;
371  }
372  setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), status.toString(), "");
373  } else {
375  NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.KeywordSearchNull"));
376  }
377  } catch (NumberFormatException ex) {
378  String rootCause = NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.InvalidPortNumber");
379  logger.log(Level.SEVERE, "Unable to connect to Keyword Search server: " + rootCause, ex); //NON-NLS
380  setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.DOWN.toString(), rootCause);
381  } catch (KeywordSearchServiceException ex) {
382  String rootCause = ex.getMessage();
383  logger.log(Level.SEVERE, "Unable to connect to Keyword Search server: " + rootCause, ex); //NON-NLS
384  setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.DOWN.toString(), rootCause);
385  }
386  }
387 
393  try {
395  } catch (UserPreferencesException ex) {
396  logger.log(Level.SEVERE, "Error accessing messaging service connection info", ex); //NON-NLS
397  setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.DOWN.toString(), NbBundle.getMessage(this.getClass(), "ServicesMonitor.messagingService.connErr.text"));
398  return;
399  }
400 
401  try {
402  info.tryConnect();
403  setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.UP.toString(), "");
404  } catch (MessageServiceException ex) {
405  String rootCause = ex.getMessage();
406  logger.log(Level.SEVERE, "Unable to connect to messaging server: " + rootCause, ex); //NON-NLS
407  setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.DOWN.toString(), rootCause);
408  }
409  }
410 
411 }
void addSubscriber(Set< String > services, PropertyChangeListener subscriber)
void removeSubscriber(Set< String > services, PropertyChangeListener subscriber)
void setServiceStatus(String service, String status, String details)
void addSubscriber(String service, PropertyChangeListener subscriber)
void addSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
final ConcurrentHashMap< String, String > statusByService
static CaseDbConnectionInfo getDatabaseConnectionInfo()
void addSubscriber(PropertyChangeListener subscriber)
final ScheduledThreadPoolExecutor periodicTasksExecutor
static synchronized ServicesMonitor getInstance()
static void info(String title, String message)
final AutopsyEventPublisher eventPublisher
void removeSubscriber(PropertyChangeListener subscriber)
void removeSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
void removeSubscriber(String service, PropertyChangeListener subscriber)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static MessageServiceConnectionInfo getMessageServiceConnectionInfo()

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