19 package org.sleuthkit.autopsy.keywordsearch;
 
   22 import java.io.IOException;
 
   23 import java.io.Reader;
 
   24 import java.lang.reflect.InvocationTargetException;
 
   25 import java.net.InetAddress;
 
   26 import java.util.ArrayList;
 
   27 import java.util.List;
 
   28 import java.util.MissingResourceException;
 
   29 import java.util.logging.Level;
 
   30 import javax.swing.JDialog;
 
   31 import javax.swing.JOptionPane;
 
   32 import javax.swing.SwingUtilities;
 
   33 import org.apache.commons.lang.math.NumberUtils;
 
   34 import org.apache.commons.io.FileUtils;
 
   35 import org.apache.solr.client.solrj.SolrServerException;
 
   36 import org.apache.solr.client.solrj.impl.HttpSolrServer;
 
   37 import org.openide.util.NbBundle;
 
   38 import org.openide.util.lookup.ServiceProvider;
 
   39 import org.openide.util.lookup.ServiceProviders;
 
   59 @ServiceProviders(value = {
 
   60     @ServiceProvider(service = KeywordSearchService.class)
 
   62     @ServiceProvider(service = AutopsyService.class)}
 
   66     private static final String BAD_IP_ADDRESS_FORMAT = 
"ioexception occurred when talking to server"; 
 
   67     private static final String SERVER_REFUSED_CONNECTION = 
"server refused connection"; 
 
   68     private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
 
   69     private static final int LARGE_INDEX_SIZE_GB = 50;
 
   70     private static final int GIANT_INDEX_SIZE_GB = 500;
 
   89     public void index(Content content) 
throws TskCoreException {
 
  103         if (content == null) {
 
  106         final Ingester ingester = Ingester.getDefault();
 
  107         if (content instanceof BlackboardArtifact) {
 
  108             BlackboardArtifact artifact = (BlackboardArtifact) content;
 
  109             if (artifact.getArtifactID() > 0) {
 
  119                 Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
 
  120                 String sourceName = artifact.getDisplayName() + 
"_" + artifact.getArtifactID();
 
  121                 ingester.indexMetaDataOnly(artifact, sourceName);
 
  122                 ingester.indexText(blackboardExtractedTextReader, artifact.getArtifactID(), sourceName, content, null);
 
  124                 throw new TskCoreException(
"Error indexing artifact", ex);
 
  129                 Reader contentExtractedTextReader = contentExtractor.
getReader();
 
  130                 ingester.indexText(contentExtractedTextReader, content.getId(), content.getName(), content, null);
 
  135                     Reader stringsExtractedTextReader = stringsExtractor.
getReader();
 
  136                     ingester.indexText(stringsExtractedTextReader,content.getId(),content.getName(), content, null);
 
  138                     throw new TskCoreException(
"Error indexing content", ex1);
 
  155         HttpSolrServer solrServer = null;
 
  156         if (host == null || host.isEmpty()) {
 
  160             solrServer = 
new HttpSolrServer(
"http://" + host + 
":" + Integer.toString(port) + 
"/solr"); 
 
  162         } 
catch (SolrServerException ex) {
 
  164         } 
catch (IOException ex) {
 
  165             String result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  166             String message = ex.getCause().getMessage().toLowerCase();
 
  167             if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
 
  169                     if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
 
  171                         result = Bundle.SolrConnectionCheck_Port();
 
  173                         result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  175                 } 
catch (IOException | MissingResourceException any) {
 
  177                     result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.HostnameOrPort"); 
 
  179             } 
else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
 
  180                 result = NbBundle.getMessage(
SolrSearchService.class, 
"SolrConnectionCheck.Hostname"); 
 
  183         } 
catch (NumberFormatException ex) {
 
  185         } 
catch (IllegalArgumentException ex) {
 
  188             if (null != solrServer) {
 
  189                 solrServer.shutdown();
 
  200         "# {0} - case directory", 
"SolrSearchService.exceptionMessage.noIndexMetadata=Unable to create IndexMetaData from case directory: {0}",
 
  201         "SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata did not contain a current Solr core so could not delete the case",
 
  202         "# {0} - index folder path", 
"SolrSearchService.exceptionMessage.failedToDeleteIndexFiles=Failed to delete text index files at {0}" 
  207         IndexMetadata indexMetadata;
 
  209             indexMetadata = 
new IndexMetadata(caseDirectory);
 
  210         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  211             logger.log(Level.WARNING, NbBundle.getMessage(
SolrSearchService.class, 
"SolrSearchService.exceptionMessage.noIndexMetadata", caseDirectory), ex);
 
  215         String currentSchema = IndexFinder.getCurrentSchemaVersion();
 
  216         String currentSolr = IndexFinder.getCurrentSolrVersion();
 
  217         for (Index index : indexMetadata.getIndexes()) {
 
  218             if (index.getSolrVersion().equals(currentSolr) && index.getSchemaVersion().equals(currentSchema)) {
 
  233                 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  235                 "SolrSearchService.exceptionMessage.noCurrentSolrCore"));
 
  239     public void close() throws IOException {
 
  244         return NbBundle.getMessage(this.getClass(), 
"SolrSearchService.ServiceName");
 
  257         "SolrSearch.lookingForMetadata.msg=Looking for text index metadata file",
 
  258         "SolrSearch.readingIndexes.msg=Reading text index metadata file",
 
  259         "SolrSearch.findingIndexes.msg=Looking for existing text index directories",
 
  260         "SolrSearch.creatingNewIndex.msg=Creating new text index",
 
  261         "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version",
 
  262         "SolrSearch.indentifyingIndex.msg=Identifying text index to use",
 
  263         "SolrSearch.openCore.msg=Opening text index",
 
  264         "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.",
 
  265         "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.",
 
  266         "SolrSearch.complete.msg=Text index successfully opened"})
 
  273         int totalNumProgressUnits = 7;
 
  274         int progressUnitsCompleted = 0;
 
  278         List<Index> indexes = 
new ArrayList<>();
 
  279         progress.
start(Bundle.SolrSearch_lookingForMetadata_msg(), totalNumProgressUnits);
 
  280         if (IndexMetadata.isMetadataFilePresent(caseDirPath)) {
 
  283                 progressUnitsCompleted++;
 
  284                 progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  285                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath);
 
  286                 indexes = indexMetadata.getIndexes();
 
  287             } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  288                 logger.log(Level.SEVERE, String.format(
"Unable to read text index metadata file"), ex);
 
  294             progressUnitsCompleted++;
 
  295             progress.
progress(Bundle.SolrSearch_findingIndexes_msg(), progressUnitsCompleted);
 
  296             Index oldIndex = IndexFinder.findOldIndexDir(theCase);
 
  297             if (oldIndex != null) {
 
  299                 indexes.add(oldIndex);
 
  308         Index currentVersionIndex = null;
 
  309         if (indexes.isEmpty()) {
 
  311             progressUnitsCompleted++;
 
  312             progress.
progress(Bundle.SolrSearch_creatingNewIndex_msg(), progressUnitsCompleted);
 
  313             currentVersionIndex = IndexFinder.createLatestVersionIndexDir(theCase);
 
  315             indexes.add(currentVersionIndex);
 
  318             progressUnitsCompleted++;
 
  319             progress.
progress(Bundle.SolrSearch_checkingForLatestIndex_msg(), progressUnitsCompleted);
 
  320             currentVersionIndex = IndexFinder.findLatestVersionIndexDir(indexes);
 
  321             if (currentVersionIndex == null) {
 
  323                 progressUnitsCompleted++;
 
  324                 progress.
progress(Bundle.SolrSearch_indentifyingIndex_msg(), progressUnitsCompleted);
 
  325                 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
 
  326                 if (indexToUse == null) {
 
  335                 double currentSolrVersion = NumberUtils.toDouble(IndexFinder.getCurrentSolrVersion());
 
  336                 double indexSolrVersion = NumberUtils.toDouble(indexToUse.getSolrVersion());
 
  337                 if (indexSolrVersion == currentSolrVersion) {
 
  341                         JOptionPane optionPane = 
new JOptionPane(
 
  342                                 NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.msg"),
 
  343                                 JOptionPane.WARNING_MESSAGE,
 
  344                                 JOptionPane.DEFAULT_OPTION);
 
  346                             SwingUtilities.invokeAndWait(() -> {
 
  347                                 JDialog dialog = optionPane.createDialog(NbBundle.getMessage(
this.getClass(), 
"SolrSearchService.IndexReadOnlyDialog.title"));
 
  348                                 dialog.setVisible(
true);
 
  350                         } 
catch (InterruptedException ex) {
 
  353                         } 
catch (InvocationTargetException ex) {
 
  358                     currentVersionIndex = indexToUse;
 
  368             if (!indexes.isEmpty()) {
 
  369                 IndexMetadata indexMetadata = 
new IndexMetadata(caseDirPath, indexes);
 
  371         } 
catch (IndexMetadata.TextIndexMetadataException ex) {
 
  378             long indexSizeInBytes = FileUtils.sizeOfDirectory(
new File(currentVersionIndex.getIndexPath()));
 
  379             long sizeInGb = indexSizeInBytes / 1000000000;
 
  380             if (sizeInGb < LARGE_INDEX_SIZE_GB) {
 
  381                 progress.
progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1);
 
  382             } 
else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) {
 
  393         progress.
progress(Bundle.SolrSearch_complete_msg(), totalNumProgressUnits);
 
  412         AdHocSearchChildFactory.BlackboardResultWriter.stopAllWriters();
 
  415         } 
catch (InterruptedException ex) {
 
  416             logger.log(Level.SEVERE, 
"Unexpected interrupt while waiting for BlackboardResultWriters to terminate", ex);
 
  437     public void indexArtifact(BlackboardArtifact artifact) 
throws TskCoreException {
 
  438         if (artifact == null) {
 
  444         if (artifact.getArtifactID() > 0) {
 
  447         final Ingester ingester = Ingester.getDefault();
 
  450             String sourceName = artifact.getDisplayName() + 
"_" + artifact.getArtifactID();
 
  452             Reader blackboardExtractedTextReader = blackboardExtractor.
getReader();
 
  453             ingester.indexMetaDataOnly(artifact, sourceName);
 
  454             ingester.indexText(blackboardExtractedTextReader, artifact.getId(), sourceName, artifact, null);
 
  456             throw new TskCoreException(ex.getCause().getMessage(), ex);
 
void index(Content content)
void indexArtifact(BlackboardArtifact artifact)
static boolean runningWithGUI
void start(String message, int totalWorkUnits)
void openCaseResources(CaseContext context)
String getCaseDirectory()
static synchronized Server getServer()
ProgressIndicator getProgressIndicator()
volatile boolean cancelRequested
void closeCaseResources(CaseContext context)
void deleteTextIndex(CaseMetadata metadata)
synchronized static Logger getLogger(String name)
static boolean deleteDir(File dirPath)
void progress(String message)
void tryConnect(String host, int port)
void switchToIndeterminate(String message)