diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java index 254d404c4e..aa1bd3a474 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java @@ -22,7 +22,6 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.Serializable; -import java.net.URISyntaxException; import java.net.UnknownHostException; import java.time.Duration; import java.time.Instant; @@ -36,45 +35,35 @@ import java.util.UUID; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import javax.jms.Connection; -import javax.jms.JMSException; -import org.apache.activemq.ActiveMQConnectionFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; -import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent; -import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; -import org.sleuthkit.datamodel.CaseDbConnectionInfo; /** * A collaboration monitor listens to local events and translates them into - * collaboration tasks that are broadcast to collaborating nodes, informs the - * user of collaboration tasks on other nodes using progress bars, and monitors - * the health of key collaboration services. + * collaboration tasks that are broadcast to collaborating nodes and informs the + * user of collaboration tasks on other nodes using progress bars. */ final class CollaborationMonitor { private static final String EVENT_CHANNEL_NAME = "%s-Collaboration-Monitor-Events"; private static final String COLLABORATION_MONITOR_EVENT = "COLLABORATION_MONITOR_EVENT"; private static final Set CASE_EVENTS_OF_INTEREST = new HashSet<>(Arrays.asList(new String[]{Case.Events.ADDING_DATA_SOURCE.toString(), Case.Events.DATA_SOURCE_ADDED.toString(), Case.Events.ADDING_DATA_SOURCE_FAILED.toString()})); - private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 3; + private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 2; private static final String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d"; private static final long HEARTBEAT_INTERVAL_MINUTES = 1; private static final long MAX_MISSED_HEARTBEATS = 5; private static final long STALE_TASKS_DETECTION_INTERVAL_MINUTES = 2; - private static final long CRASH_DETECTION_INTERVAL_MINUTES = 2; private static final long EXECUTOR_TERMINATION_WAIT_SECS = 30; private static final Logger logger = Logger.getLogger(CollaborationMonitor.class.getName()); private final String hostName; @@ -129,12 +118,10 @@ final class CollaborationMonitor { * * 1. Send heartbeats to collaboration monitors on other nodes.
* 2. Check for stale remote tasks.
- * 3. Check the availability of key collaboration services.
*/ periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build()); periodicTasksExecutor.scheduleAtFixedRate(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES); periodicTasksExecutor.scheduleAtFixedRate(new StaleTaskDetectionTask(), STALE_TASKS_DETECTION_INTERVAL_MINUTES, STALE_TASKS_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES); - periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES); } /** @@ -514,80 +501,6 @@ final class CollaborationMonitor { } } - /** - * A Runnable task that periodically checks the availability of - * collaboration resources (PostgreSQL server, Solr server, Active MQ - * message broker) and reports status to the user in case of a gap in - * service. - */ - private final static class CrashDetectionTask implements Runnable { - - private static boolean dbServerIsRunning = true; - private static boolean solrServerIsRunning = true; - private static boolean messageServerIsRunning = true; - private static final Object lock = new Object(); - - /** - * Monitor the availability of collaboration resources - */ - @Override - public void run() { - synchronized (lock) { - CaseDbConnectionInfo dbInfo = UserPreferences.getDatabaseConnectionInfo(); - if (dbInfo.canConnect()) { - if (!dbServerIsRunning) { - dbServerIsRunning = true; - logger.log(Level.INFO, "Connection to PostgreSQL server restored"); //NON-NLS - MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredDbService.notify.msg")); - } - } else { - if (dbServerIsRunning) { - dbServerIsRunning = false; - logger.log(Level.SEVERE, "Failed to connect to PostgreSQL server"); //NON-NLS - MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedDbService.notify.msg")); - } - } - - KeywordSearchService kwsService = Case.getCurrentCase().getServices().getKeywordSearchService(); - - if (kwsService.canConnectToRemoteSolrServer()) { - if (!solrServerIsRunning) { - solrServerIsRunning = true; - logger.log(Level.INFO, "Connection to Solr server restored"); //NON-NLS - MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredSolrService.notify.msg")); - } - } - else { - if (solrServerIsRunning) { - solrServerIsRunning = false; - logger.log(Level.SEVERE, "Failed to connect to Solr server"); //NON-NLS - MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedSolrService.notify.msg")); - } - } - - MessageServiceConnectionInfo msgInfo = UserPreferences.getMessageServiceConnectionInfo(); - try { - ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(msgInfo.getUserName(), msgInfo.getPassword(), msgInfo.getURI()); - Connection connection = connectionFactory.createConnection(); - connection.start(); - connection.close(); - if (!messageServerIsRunning) { - messageServerIsRunning = true; - logger.log(Level.INFO, "Connection to ActiveMQ server restored"); //NON-NLS - MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredMessageService.notify.msg")); - } - } catch (URISyntaxException | JMSException ex) { - if (messageServerIsRunning) { - messageServerIsRunning = false; - logger.log(Level.SEVERE, "Failed to connect to ActiveMQ server", ex); //NON-NLS - MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedMessageService.notify.msg")); - } - } - } - } - - } - /** * An Autopsy event to be sent in event messages to the collaboration * monitors on other Autopsy nodes. diff --git a/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java b/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java new file mode 100644 index 0000000000..48b3bd1e6e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java @@ -0,0 +1,166 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013-2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.core; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.net.URISyntaxException; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import javax.jms.Connection; +import javax.jms.JMSException; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.events.AutopsyEventPublisher; +import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; +import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; +import org.sleuthkit.datamodel.CaseDbConnectionInfo; + +/** + * This class periodically checks availability of collaboration resources + * (PostgreSQL server, Solr server, Active MQ message broker) and reports status + * to the user in case of a gap in service. + */ +public class ServicesMonitor { + + private AutopsyEventPublisher eventPublisher; + private static final Logger logger = Logger.getLogger(ServicesMonitor.class.getName()); + private static ServicesMonitor instance; + private final ScheduledThreadPoolExecutor periodicTasksExecutor; + + private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d"; + private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1; + private static final long CRASH_DETECTION_INTERVAL_MINUTES = 2; + + /** + * List of services that are being monitored. + */ + public enum Service { + + /** + * Property change event fired when ....TODO.... The old value of the + * PropertyChangeEvent object is set to the ingest job id, and the new + * value is set to null. + */ + REMOTE_CASE_DATABASE, + REMOTE_KEYWORD_SEARCH, + MESSAGING + }; + + enum ServiceStatus { + + UP, + DOWN + }; + + public synchronized static ServicesMonitor getInstance() { + if (instance == null) { + instance = new ServicesMonitor(); + } + return instance; + } + + private ServicesMonitor() { + + this.eventPublisher = new AutopsyEventPublisher(); + + /** + * Start periodic task that check the availability of key collaboration + * services. + */ + periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build()); + periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES); + } + + /** + * A Runnable task that periodically checks the availability of + * collaboration resources (PostgreSQL server, Solr server, Active MQ + * message broker) and reports status to the user in case of a gap in + * service. + */ + private final static class CrashDetectionTask implements Runnable { + + private static boolean dbServerIsRunning = true; + private static boolean solrServerIsRunning = true; + private static boolean messageServerIsRunning = true; + private static final Object lock = new Object(); + + /** + * Monitor the availability of collaboration resources + */ + @Override + public void run() { + synchronized (lock) { + CaseDbConnectionInfo dbInfo = UserPreferences.getDatabaseConnectionInfo(); + if (dbInfo.canConnect()) { + if (!dbServerIsRunning) { + dbServerIsRunning = true; + logger.log(Level.INFO, "Connection to PostgreSQL server restored"); //NON-NLS + //MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredDbService.notify.msg")); + } + } else { + if (dbServerIsRunning) { + dbServerIsRunning = false; + logger.log(Level.SEVERE, "Failed to connect to PostgreSQL server"); //NON-NLS + //MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedDbService.notify.msg")); + } + } + + KeywordSearchService kwsService = Case.getCurrentCase().getServices().getKeywordSearchService(); + + if (kwsService.canConnectToRemoteSolrServer()) { + if (!solrServerIsRunning) { + solrServerIsRunning = true; + logger.log(Level.INFO, "Connection to Solr server restored"); //NON-NLS + //MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredSolrService.notify.msg")); + } + } else { + if (solrServerIsRunning) { + solrServerIsRunning = false; + logger.log(Level.SEVERE, "Failed to connect to Solr server"); //NON-NLS + //MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedSolrService.notify.msg")); + } + } + + MessageServiceConnectionInfo msgInfo = UserPreferences.getMessageServiceConnectionInfo(); + try { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(msgInfo.getUserName(), msgInfo.getPassword(), msgInfo.getURI()); + Connection connection = connectionFactory.createConnection(); + connection.start(); + connection.close(); + if (!messageServerIsRunning) { + messageServerIsRunning = true; + logger.log(Level.INFO, "Connection to ActiveMQ server restored"); //NON-NLS + //MessageNotifyUtil.Notify.info(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.restoredMessageService.notify.msg")); + } + } catch (URISyntaxException | JMSException ex) { + if (messageServerIsRunning) { + messageServerIsRunning = false; + logger.log(Level.SEVERE, "Failed to connect to ActiveMQ server", ex); //NON-NLS + //MessageNotifyUtil.Notify.error(NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedService.notify.title"), NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.failedMessageService.notify.msg")); + } + } + } + } + + } +}