19 package org.sleuthkit.autopsy.keywordsearch;
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.awt.event.ActionEvent;
23 import java.beans.PropertyChangeListener;
24 import java.io.BufferedReader;
25 import java.io.BufferedWriter;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.InputStreamReader;
31 import java.io.OutputStream;
32 import java.io.OutputStreamWriter;
33 import java.net.ConnectException;
34 import java.net.DatagramSocket;
35 import java.net.ServerSocket;
36 import java.net.SocketException;
37 import java.nio.charset.Charset;
38 import java.nio.file.Files;
39 import java.nio.file.OpenOption;
40 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
41 import java.nio.file.Path;
42 import java.nio.file.Paths;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.Iterator;
47 import java.util.List;
48 import java.util.Random;
49 import java.util.concurrent.ScheduledThreadPoolExecutor;
50 import java.util.concurrent.TimeUnit;
51 import java.util.concurrent.locks.ReentrantReadWriteLock;
52 import java.util.logging.Level;
53 import javax.swing.AbstractAction;
54 import org.apache.commons.io.FileUtils;
55 import java.util.concurrent.TimeoutException;
56 import java.util.concurrent.atomic.AtomicBoolean;
57 import java.util.concurrent.atomic.AtomicInteger;
58 import java.util.stream.Collectors;
59 import static java.util.stream.Collectors.toList;
60 import org.apache.solr.client.solrj.SolrQuery;
61 import org.apache.solr.client.solrj.SolrRequest;
62 import org.apache.solr.client.solrj.SolrServerException;
63 import org.apache.solr.client.solrj.SolrClient;
64 import org.apache.solr.client.solrj.impl.HttpSolrClient;
65 import org.apache.solr.client.solrj.impl.CloudSolrClient;
66 import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrClient;
67 import org.apache.solr.client.solrj.impl.XMLResponseParser;
68 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
69 import org.apache.solr.client.solrj.response.CollectionAdminResponse;
70 import org.apache.solr.client.solrj.request.CoreAdminRequest;
71 import org.apache.solr.client.solrj.response.CoreAdminResponse;
72 import org.apache.solr.client.solrj.impl.BaseHttpSolrClient.RemoteSolrException;
73 import org.apache.solr.client.solrj.request.QueryRequest;
74 import org.apache.solr.client.solrj.response.QueryResponse;
75 import org.apache.solr.client.solrj.response.TermsResponse;
76 import org.apache.solr.client.solrj.response.TermsResponse.Term;
77 import org.apache.solr.common.SolrDocument;
78 import org.apache.solr.common.SolrDocumentList;
79 import org.apache.solr.common.SolrException;
80 import org.apache.solr.common.SolrInputDocument;
81 import org.apache.solr.common.util.NamedList;
82 import org.openide.modules.InstalledFileLocator;
83 import org.openide.modules.Places;
84 import org.openide.util.NbBundle;
85 import org.openide.windows.WindowManager;
117 public String toString() {
123 public String toString() {
130 public String toString() {
137 public String toString() {
138 return "content_str";
144 public String toString() {
152 public String toString() {
158 public String toString() {
164 public String toString() {
170 public String toString() {
177 public String toString() {
184 public String toString() {
191 public String toString() {
198 public String toString() {
204 public String toString() {
210 public String toString() {
221 public String toString() {
238 static final String PROPERTIES_FILE = KeywordSearchSettings.MODULE_NAME;
239 static final String PROPERTIES_CURRENT_SERVER_PORT =
"IndexingServerPort";
240 static final String PROPERTIES_CURRENT_STOP_PORT =
"IndexingServerStopPort";
241 private static final String
KEY =
"jjk#09s";
242 static final String DEFAULT_SOLR_SERVER_HOST =
"localhost";
243 static final int DEFAULT_SOLR_SERVER_PORT = 23232;
244 static final int DEFAULT_SOLR_STOP_PORT = 34343;
248 private static final String
SOLR =
"solr";
250 private static final boolean DEBUG =
false;
285 localSolrServer =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr");
287 serverAction =
new ServerAction();
288 File solr8Folder = InstalledFileLocator.getDefault().locate(
"solr",
Server.class.getPackage().getName(),
false);
289 File solr4Folder = InstalledFileLocator.getDefault().locate(
"solr4",
Server.class.getPackage().getName(),
false);
300 if (!solr8Home.toFile().exists()) {
301 Files.createDirectory(solr8Home);
306 Files.copy(Paths.get(solr8Folder.getAbsolutePath(),
"server",
"solr",
"solr.xml"), solr8Home.resolve(
"solr.xml"), REPLACE_EXISTING);
307 Files.copy(Paths.get(solr8Folder.getAbsolutePath(),
"server",
"solr",
"zoo.cfg"), solr8Home.resolve(
"zoo.cfg"), REPLACE_EXISTING);
308 FileUtils.copyDirectory(Paths.get(solr8Folder.getAbsolutePath(),
"server",
"solr",
"configsets").toFile(), solr8Home.resolve(
"configsets").toFile());
309 }
catch (IOException ex) {
310 logger.log(Level.SEVERE,
"Failed to create Solr 8 home folder:", ex);
316 if (!solr4Home.toFile().exists()) {
317 Files.createDirectory(solr4Home);
319 Files.copy(Paths.get(solr4Folder.getAbsolutePath(),
"solr",
"solr.xml"), solr4Home.resolve(
"solr.xml"), REPLACE_EXISTING);
320 Files.copy(Paths.get(solr4Folder.getAbsolutePath(),
"solr",
"zoo.cfg"), solr4Home.resolve(
"zoo.cfg"), REPLACE_EXISTING);
321 }
catch (IOException ex) {
322 logger.log(Level.SEVERE,
"Failed to create Solr 4 home folder:", ex);
325 currentCoreLock =
new ReentrantReadWriteLock(
true);
327 logger.log(Level.INFO,
"Created Server instance using Java at {0}", javaPath);
335 }
catch (NumberFormatException nfe) {
336 logger.log(Level.WARNING,
"Could not decode indexing server port, value was not a valid port number, using the default. ", nfe);
337 localSolrServerPort = DEFAULT_SOLR_SERVER_PORT;
340 localSolrServerPort = DEFAULT_SOLR_SERVER_PORT;
347 }
catch (NumberFormatException nfe) {
348 logger.log(Level.WARNING,
"Could not decode indexing server stop port, value was not a valid port number, using default", nfe);
349 localSolrStopPort = DEFAULT_SOLR_STOP_PORT;
352 localSolrStopPort = DEFAULT_SOLR_STOP_PORT;
359 return new HttpSolrClient.Builder(solrUrl)
360 .withSocketTimeout(connectionTimeoutMs)
361 .withConnectionTimeout(connectionTimeoutMs)
362 .withResponseParser(
new XMLResponseParser())
370 logger.log(Level.INFO,
"Creating new ConcurrentUpdateSolrClient: {0}", solrUrl);
371 logger.log(Level.INFO,
"Queue size = {0}, Number of threads = {1}, Connection Timeout (ms) = {2}",
new Object[]{numDocs, numThreads, connectionTimeoutMs});
372 ConcurrentUpdateSolrClient client =
new ConcurrentUpdateSolrClient.Builder(solrUrl)
373 .withQueueSize(numDocs)
374 .withThreadCount(numThreads)
375 .withSocketTimeout(connectionTimeoutMs)
376 .withConnectionTimeout(connectionTimeoutMs)
377 .withResponseParser(
new XMLResponseParser())
385 List<String> solrUrls =
new ArrayList<>();
386 for (String server : solrServerList) {
387 solrUrls.add(
"http://" + server +
"/solr");
388 logger.log(Level.INFO,
"Using Solr server: {0}", server);
391 logger.log(Level.INFO,
"Creating new CloudSolrClient");
393 CloudSolrClient client =
new CloudSolrClient.Builder(solrUrls)
394 .withConnectionTimeout(connectionTimeoutMs)
395 .withSocketTimeout(connectionTimeoutMs)
396 .withResponseParser(
new XMLResponseParser())
398 if (!defaultCollectionName.isEmpty()) {
399 client.setDefaultCollection(defaultCollectionName);
406 public void finalize() throws java.lang.Throwable {
412 serverAction.addPropertyChangeListener(l);
415 int getLocalSolrServerPort() {
419 int getLocalSolrStopPort() {
430 volatile boolean doRun =
true;
433 this.stream = stream;
435 final String log = Places.getUserDirectory().getAbsolutePath()
436 + File.separator +
"var" + File.separator +
"log"
437 + File.separator +
"solr.log." + type;
438 File outputFile =
new File(log.concat(
".0"));
439 File first =
new File(log.concat(
".1"));
440 File second =
new File(log.concat(
".2"));
441 if (second.exists()) {
444 if (first.exists()) {
445 first.renameTo(second);
447 if (outputFile.exists()) {
448 outputFile.renameTo(first);
450 outputFile.createNewFile();
452 out =
new FileOutputStream(outputFile);
454 }
catch (Exception ex) {
455 logger.log(Level.WARNING,
"Failed to create solr log file", ex);
466 try (InputStreamReader isr =
new InputStreamReader(stream);
467 BufferedReader br =
new BufferedReader(isr);
469 BufferedWriter bw =
new BufferedWriter(osw);) {
472 while (doRun && (line = br.readLine()) != null) {
481 }
catch (IOException ex) {
482 logger.log(Level.SEVERE,
"Error redirecting Solr output stream", ex);
500 File solr8Folder = InstalledFileLocator.getDefault().locate(
"solr",
Server.class.getPackage().getName(),
false);
503 solr8CmdPath = Paths.get(solr8Folder.getAbsolutePath(),
"bin",
"autopsy-solr.cmd");
505 solr8CmdPath = Paths.get(solr8Folder.getAbsolutePath(),
"bin",
"autopsy-solr");
509 List<String> commandLine =
new ArrayList<>();
510 commandLine.add(solr8CmdPath.toString());
511 commandLine.addAll(solrArguments);
513 ProcessBuilder solrProcessBuilder =
new ProcessBuilder(commandLine);
514 solrProcessBuilder.directory(solr8Folder);
517 Path solrStdoutPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stdout");
518 solrProcessBuilder.redirectOutput(solrStdoutPath.toFile());
520 Path solrStderrPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stderr");
521 solrProcessBuilder.redirectError(solrStderrPath.toFile());
524 String jreFolderPath =
new File(javaPath).getParentFile().getParentFile().getAbsolutePath();
526 solrProcessBuilder.environment().put(
"SOLR_JAVA_HOME", jreFolderPath);
527 solrProcessBuilder.environment().put(
"SOLR_HOME", solr8Home.toString());
528 solrProcessBuilder.environment().put(
"STOP_KEY", KEY);
529 solrProcessBuilder.environment().put(
"SOLR_JAVA_MEM", MAX_SOLR_MEM_MB_PAR);
530 logger.log(Level.INFO,
"Setting Solr 8 directory: {0}", solr8Folder.toString());
531 logger.log(Level.INFO,
"Running Solr 8 command: {0} from {1}",
new Object[]{solrProcessBuilder.command(), solr8Folder.toString()});
532 Process process = solrProcessBuilder.start();
533 logger.log(Level.INFO,
"Finished running Solr 8 command");
548 File solr4Folder = InstalledFileLocator.getDefault().locate(
"solr4",
Server.class.getPackage().getName(),
false);
550 List<String> commandLine =
new ArrayList<>();
551 commandLine.add(javaPath);
552 commandLine.add(MAX_SOLR_MEM_MB_PAR);
553 commandLine.add(
"-DSTOP.PORT=" + localSolrStopPort);
554 commandLine.add(
"-Djetty.port=" + localSolrServerPort);
555 commandLine.add(
"-DSTOP.KEY=" + KEY);
556 commandLine.add(
"-jar");
557 commandLine.add(
"start.jar");
559 commandLine.addAll(solrArguments);
561 ProcessBuilder solrProcessBuilder =
new ProcessBuilder(commandLine);
562 solrProcessBuilder.directory(solr4Folder);
565 Path solrStdoutPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stdout");
566 solrProcessBuilder.redirectOutput(solrStdoutPath.toFile());
568 Path solrStderrPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stderr");
569 solrProcessBuilder.redirectError(solrStderrPath.toFile());
571 logger.log(Level.INFO,
"Running Solr 4 command: {0}", solrProcessBuilder.command());
572 Process process = solrProcessBuilder.start();
573 logger.log(Level.INFO,
"Finished running Solr 4 command");
582 List<Long> getSolrPIDs() {
583 List<Long> pids =
new ArrayList<>();
586 final String pidsQuery =
"-DSTOP.KEY=" + KEY +
"%start.jar";
589 if (pidsArr != null) {
590 for (
int i = 0; i < pidsArr.length; ++i) {
591 pids.add(pidsArr[i]);
603 List<Long> solrPids = getSolrPIDs();
604 for (
long pid : solrPids) {
605 logger.log(Level.INFO,
"Trying to kill old Solr process, PID: {0}", pid);
606 PlatformUtil.killProcess(pid);
610 void start() throws KeywordSearchModuleException, SolrServerNoPortException, SolrServerException {
611 startLocalSolr(SOLR_VERSION.SOLR8);
620 if (IndexFinder.getCurrentSolrVersion().equals(index.getSolrVersion())) {
627 if (!this.isLocalSolrRunning()) {
628 logger.log(Level.SEVERE,
"Local Solr server is not running");
629 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.msg"));
636 connectToSolrServer(remoteSolrServer);
638 }
catch (SolrServerException | IOException ex) {
639 throw new KeywordSearchModuleException(NbBundle.getMessage(
Server.class,
"Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
661 if (properties.
host.isEmpty() || properties.
port.isEmpty()) {
662 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.connectionInfoMissing.exception.msg", index.getSolrVersion()));
664 String solrUrl =
"http://" + properties.
host +
":" + properties.
port +
"/solr";
666 if (!name.isEmpty()) {
667 solrUrl = solrUrl +
"/" + name;
680 "Server.status.failed.msg=Local Solr server did not respond to status request. This may be because the server failed to start or is taking too long to initialize.",})
681 synchronized void startLocalSolr(SOLR_VERSION version)
throws KeywordSearchModuleException, SolrServerNoPortException, SolrServerException {
683 logger.log(Level.INFO,
"Starting local Solr " + version +
" server");
684 if (version == SOLR_VERSION.SOLR8) {
685 localSolrFolder = InstalledFileLocator.getDefault().locate(
"solr", Server.class.getPackage().getName(),
false);
688 localSolrFolder = InstalledFileLocator.getDefault().locate(
"solr4", Server.class.getPackage().getName(),
false);
691 if (isLocalSolrRunning()) {
692 if (localServerVersion.equals(version)) {
694 logger.log(Level.INFO,
"Local Solr " + version +
" server is already running");
703 localServerVersion = version;
705 if (!isPortAvailable(localSolrServerPort)) {
709 final List<Long> pids = this.getSolrPIDs();
713 if (pids.isEmpty()) {
714 throw new SolrServerNoPortException(localSolrServerPort);
723 if (!isPortAvailable(localSolrServerPort)) {
724 throw new SolrServerNoPortException(localSolrServerPort);
726 if (!isPortAvailable(localSolrStopPort)) {
727 throw new SolrServerNoPortException(localSolrStopPort);
731 if (isPortAvailable(localSolrServerPort)) {
732 logger.log(Level.INFO,
"Port [{0}] available, starting Solr", localSolrServerPort);
734 if (version == SOLR_VERSION.SOLR8) {
735 logger.log(Level.INFO,
"Starting Solr 8 server");
737 Integer.toString(localSolrServerPort))));
740 logger.log(Level.INFO,
"Starting Solr 4 server");
742 Arrays.asList(
"-Dbootstrap_confdir=../solr/configsets/AutopsyConfig/conf",
743 "-Dcollection.configName=AutopsyConfig")));
748 if (isLocalSolrRunning()) {
749 final List<Long> pids = this.getSolrPIDs();
750 logger.log(Level.INFO,
"New Solr process PID: {0}", pids);
757 TimeUnit.SECONDS.sleep(EMBEDDED_SERVER_RETRY_WAIT_SEC);
758 }
catch (InterruptedException ex) {
759 logger.log(Level.WARNING,
"Timer interrupted");
765 logger.log(Level.WARNING,
"Local Solr server failed to respond to status requests.");
766 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
769 MessageNotifyUtil.Notify.error(
770 NbBundle.getMessage(
this.getClass(),
"Installer.errorInitKsmMsg"),
771 Bundle.Server_status_failed_msg());
774 }
catch (SecurityException ex) {
775 throw new KeywordSearchModuleException(
776 NbBundle.getMessage(
this.getClass(),
"Server.start.exception.cantStartSolr.msg"), ex);
777 }
catch (IOException ex) {
778 throw new KeywordSearchModuleException(
779 NbBundle.getMessage(
this.getClass(),
"Server.start.exception.cantStartSolr.msg2"), ex);
790 static boolean isPortAvailable(
int port) {
792 if (port < 1 || port > 65535) {
793 throw new IllegalArgumentException(
"Invalid start port: " + port);
796 ServerSocket ss = null;
797 DatagramSocket ds = null;
799 ss =
new ServerSocket(port);
800 ss.setReuseAddress(
true);
801 ds =
new DatagramSocket(port);
802 ds.setReuseAddress(
true);
804 }
catch (IOException e) {
813 }
catch (IOException e) {
828 void changeSolrServerPort(
int port) {
829 localSolrServerPort = port;
830 ModuleSettings.setConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_SERVER_PORT, String.valueOf(port));
838 void changeSolrStopPort(
int port) {
839 localSolrStopPort = port;
840 ModuleSettings.setConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_STOP_PORT, String.valueOf(port));
848 synchronized void stop() {
853 }
catch (KeywordSearchModuleException e) {
854 logger.log(Level.WARNING,
"Failed to close core: ", e);
868 logger.log(Level.INFO,
"Stopping Solr 8 server");
869 process =
runLocalSolr8ControlCommand(
new ArrayList<>(Arrays.asList(
"stop",
"-k", KEY,
"-p", Integer.toString(localSolrServerPort))));
872 logger.log(Level.INFO,
"Stopping Solr 4 server");
876 logger.log(Level.INFO,
"Waiting for Solr server to stop");
880 if (curSolrProcess != null) {
881 curSolrProcess.destroy();
882 curSolrProcess = null;
885 }
catch (IOException | InterruptedException ex) {
886 logger.log(Level.WARNING,
"Error while attempting to stop Solr server", ex);
890 if (errorRedirectThread != null) {
891 errorRedirectThread.stopRun();
892 errorRedirectThread = null;
899 logger.log(Level.INFO,
"Finished stopping Solr server");
910 synchronized boolean isLocalSolrRunning() throws KeywordSearchModuleException {
913 if (isPortAvailable(localSolrServerPort)) {
922 logger.log(Level.INFO,
"Solr server is running");
923 }
catch (SolrServerException ex) {
925 Throwable cause = ex.getRootCause();
930 if (cause instanceof ConnectException || cause instanceof SocketException) {
931 logger.log(Level.INFO,
"Solr server is not running, cause: {0}", cause.getMessage());
934 throw new KeywordSearchModuleException(
935 NbBundle.getMessage(
this.getClass(),
"Server.isRunning.exception.errCheckSolrRunning.msg"), ex);
937 }
catch (SolrException ex) {
939 logger.log(Level.INFO,
"Solr server is not running", ex);
941 }
catch (IOException ex) {
942 throw new KeywordSearchModuleException(
943 NbBundle.getMessage(
this.getClass(),
"Server.isRunning.exception.errCheckSolrRunning.msg2"), ex);
961 void openCoreForCase(Case theCase, Index index)
throws KeywordSearchModuleException {
962 currentCoreLock.writeLock().lock();
964 currentCollection =
openCore(theCase, index);
969 }
catch (NoOpenCoreException ex) {
970 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
973 serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STARTED);
975 currentCoreLock.writeLock().unlock();
984 boolean coreIsOpen() {
985 currentCoreLock.readLock().lock();
987 return (null != currentCollection);
989 currentCoreLock.readLock().unlock();
993 Index getIndexInfo() throws NoOpenCoreException {
994 currentCoreLock.readLock().lock();
996 if (null == currentCollection) {
997 throw new NoOpenCoreException();
999 return currentCollection.getIndexInfo();
1001 currentCoreLock.readLock().unlock();
1005 void closeCore() throws KeywordSearchModuleException {
1006 currentCoreLock.writeLock().lock();
1008 if (null != currentCollection) {
1009 currentCollection.close();
1010 serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STOPPED);
1013 currentCollection = null;
1014 currentCoreLock.writeLock().unlock();
1018 void addDocument(SolrInputDocument doc)
throws KeywordSearchModuleException, NoOpenCoreException {
1019 currentCoreLock.readLock().lock();
1021 if (null == currentCollection) {
1022 throw new NoOpenCoreException();
1024 TimingMetric metric = HealthMonitor.getTimingMetric(
"Solr: Index chunk");
1025 currentCollection.addDocument(doc);
1026 HealthMonitor.submitTimingMetric(metric);
1028 currentCoreLock.readLock().unlock();
1040 @NbBundle.Messages({
1041 "# {0} - colelction name",
"Server.deleteCore.exception.msg=Failed to delete Solr colelction {0}",})
1042 void deleteCollection(String coreName, CaseMetadata metadata)
throws KeywordSearchServiceException, KeywordSearchModuleException {
1044 HttpSolrClient solrServer;
1045 if (metadata.getCaseType() == CaseType.SINGLE_USER_CASE) {
1046 solrServer =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr");
1047 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, solrServer);
1048 if (null != response.getCoreStatus(coreName).get(
"instanceDir")) {
1058 org.apache.solr.client.solrj.request.CoreAdminRequest.unloadCore(coreName,
true,
true, solrServer);
1062 solrServer =
getSolrClient(
"http://" + properties.getHost() +
":" + properties.getPort() +
"/solr");
1063 connectToSolrServer(solrServer);
1065 CollectionAdminRequest.Delete deleteCollectionRequest = CollectionAdminRequest.deleteCollection(coreName);
1066 CollectionAdminResponse response = deleteCollectionRequest.process(solrServer);
1067 if (response.isSuccess()) {
1068 logger.log(Level.INFO,
"Deleted collection {0}", coreName);
1070 logger.log(Level.WARNING,
"Unable to delete collection {0}", coreName);
1073 }
catch (SolrServerException | IOException ex) {
1076 if (!ex.getMessage().equals(
"Already closed")) {
1077 throw new KeywordSearchServiceException(Bundle.Server_deleteCore_exception_msg(coreName), ex);
1093 @NbBundle.Messages({
1094 "Server.exceptionMessage.unableToCreateCollection=Unable to create Solr collection",
1095 "Server.exceptionMessage.unableToBackupCollection=Unable to backup Solr collection",
1096 "Server.exceptionMessage.unableToRestoreCollection=Unable to restore Solr collection",
1098 private Collection
openCore(
Case theCase, Index index)
throws KeywordSearchModuleException {
1100 int numShardsToUse = 1;
1109 }
catch (Exception ex) {
1111 throw new KeywordSearchModuleException(NbBundle.getMessage(
Server.class,
"Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
1115 String collectionName = index.getIndexName();
1122 boolean doRetry =
false;
1127 }
catch (Exception ex) {
1128 if (reTryAttempt >= NUM_COLLECTION_CREATION_RETRIES) {
1129 logger.log(Level.SEVERE,
"Unable to create Solr collection " + collectionName, ex);
1130 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
1132 logger.log(Level.SEVERE,
"Unable to create Solr collection " + collectionName +
". Re-trying...", ex);
1133 Thread.sleep(1000L);
1145 File dataDir =
new File(
new File(index.getIndexPath()).getParent());
1146 if (!dataDir.exists()) {
1153 Path corePropertiesFile = Paths.get(localSolrFolder.toString(),
SOLR, collectionName,
CORE_PROPERTIES);
1154 if (corePropertiesFile.toFile().exists()) {
1156 corePropertiesFile.toFile().delete();
1157 }
catch (Exception ex) {
1158 logger.log(Level.INFO,
"Could not delete pre-existing core.properties prior to opening the core.");
1164 CoreAdminRequest.Create createCoreRequest =
new CoreAdminRequest.Create();
1165 createCoreRequest.setDataDir(dataDir.getAbsolutePath());
1166 createCoreRequest.setCoreName(collectionName);
1167 createCoreRequest.setConfigSet(
"AutopsyConfig");
1168 createCoreRequest.setIsLoadOnStartup(
false);
1169 createCoreRequest.setIsTransient(
true);
1170 localSolrServer.request(createCoreRequest);
1173 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.noIndexDir.msg"));
1178 return new Collection(collectionName, theCase, index);
1180 }
catch (Exception ex) {
1181 logger.log(Level.SEVERE,
"Exception during Solr collection creation.", ex);
1182 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
1196 return solrServerList.size();
1212 private boolean collectionExists(String collectionName)
throws SolrServerException, IOException {
1213 CollectionAdminRequest.List req =
new CollectionAdminRequest.List();
1214 CollectionAdminResponse response = req.process(remoteSolrServer);
1215 List<?> existingCollections = (List<?>) response.getResponse().get(
"collections");
1216 if (existingCollections == null) {
1217 existingCollections =
new ArrayList<>();
1219 return existingCollections.contains(collectionName);
1257 private void createMultiUserCollection(String collectionName,
int numShardsToUse)
throws KeywordSearchModuleException, SolrServerException, IOException {
1264 Integer numShards = numShardsToUse;
1265 logger.log(Level.INFO,
"numShardsToUse: {0}", numShardsToUse);
1266 Integer numNrtReplicas = 1;
1267 Integer numTlogReplicas = 0;
1268 Integer numPullReplicas = 0;
1269 CollectionAdminRequest.Create createCollectionRequest = CollectionAdminRequest.createCollection(collectionName,
"AutopsyConfig", numShards, numNrtReplicas, numTlogReplicas, numPullReplicas);
1271 CollectionAdminResponse createResponse = createCollectionRequest.process(remoteSolrServer);
1272 if (createResponse.isSuccess()) {
1273 logger.log(Level.INFO,
"Collection {0} successfully created.", collectionName);
1275 logger.log(Level.SEVERE,
"Unable to create Solr collection {0}", collectionName);
1276 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToCreateCollection());
1283 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.noIndexDir.msg"));
1287 private void backupCollection(String collectionName, String backupName, String pathToBackupLocation)
throws SolrServerException, IOException, KeywordSearchModuleException {
1288 CollectionAdminRequest.Backup backup = CollectionAdminRequest.backupCollection(collectionName, backupName)
1289 .setLocation(pathToBackupLocation);
1291 CollectionAdminResponse backupResponse = backup.process(remoteSolrServer);
1292 if (backupResponse.isSuccess()) {
1293 logger.log(Level.INFO,
"Collection {0} successfully backep up.", collectionName);
1295 logger.log(Level.SEVERE,
"Unable to back up Solr collection {0}", collectionName);
1296 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToBackupCollection());
1300 private void restoreCollection(String backupName, String restoreCollectionName, String pathToBackupLocation)
throws SolrServerException, IOException, KeywordSearchModuleException {
1302 CollectionAdminRequest.Restore restore = CollectionAdminRequest.restoreCollection(restoreCollectionName, backupName)
1303 .setLocation(pathToBackupLocation);
1305 CollectionAdminResponse restoreResponse = restore.process(remoteSolrServer);
1306 if (restoreResponse.isSuccess()) {
1307 logger.log(Level.INFO,
"Collection {0} successfully resored.", restoreCollectionName);
1309 logger.log(Level.SEVERE,
"Unable to restore Solr collection {0}", restoreCollectionName);
1310 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToRestoreCollection());
1328 private boolean coreIsLoaded(String coreName)
throws SolrServerException, IOException {
1329 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, localSolrServer);
1330 return response.getCoreStatus(coreName).get(
"instanceDir") != null;
1346 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, localSolrServer);
1347 Object dataDirPath = response.getCoreStatus(coreName).get(
"dataDir");
1348 if (null != dataDirPath) {
1349 File indexDir = Paths.get((String) dataDirPath,
"index").toFile();
1350 return indexDir.exists();
1370 Path serverFilePath = Paths.get(caseDirectory,
"solrserver.txt");
1371 if (serverFilePath.toFile().exists()) {
1373 List<String> lines = Files.readAllLines(serverFilePath);
1374 if (lines.isEmpty()) {
1375 logger.log(Level.SEVERE,
"solrserver.txt file does not contain any data");
1376 }
else if (!lines.get(0).contains(
",")) {
1377 logger.log(Level.SEVERE,
"solrserver.txt file is corrupt - could not read host/port from " + lines.get(0));
1379 String[] parts = lines.get(0).split(
",");
1380 if (parts.length != 2) {
1381 logger.log(Level.SEVERE,
"solrserver.txt file is corrupt - could not read host/port from " + lines.get(0));
1386 }
catch (IOException ex) {
1387 logger.log(Level.SEVERE,
"solrserver.txt file could not be read", ex);
1392 List<Index> indexes =
new ArrayList<>();
1394 IndexMetadata indexMetadata =
new IndexMetadata(caseDirectory);
1395 indexes = indexMetadata.getIndexes();
1396 }
catch (IndexMetadata.TextIndexMetadataException ex) {
1397 logger.log(Level.SEVERE,
"Unable to read text index metadata file: " + caseDirectory, ex);
1407 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
1408 if (indexToUse == null) {
1410 logger.log(Level.SEVERE,
"Unable to find index that can be used for case: {0}", caseDirectory);
1419 if (IndexFinder.getCurrentSolrVersion().equals(indexToUse.getSolrVersion())) {
1443 public static void selectSolrServerForCase(Path rootOutputDirectory, Path caseDirectoryPath)
throws KeywordSearchModuleException {
1445 String serverListName =
"solrServerList.txt";
1446 Path serverListPath = Paths.get(rootOutputDirectory.toString(), serverListName);
1447 if (serverListPath.toFile().exists()) {
1452 lines = Files.readAllLines(serverListPath);
1453 }
catch (IOException ex) {
1454 throw new KeywordSearchModuleException(serverListName +
" could not be read", ex);
1458 for (Iterator<String> iterator = lines.iterator(); iterator.hasNext();) {
1459 String line = iterator.next();
1460 if (!line.contains(
",")) {
1465 if (lines.isEmpty()) {
1466 throw new KeywordSearchModuleException(serverListName +
" had no valid server information");
1470 int rnd =
new Random().nextInt(lines.size());
1471 String[] parts = lines.get(rnd).split(
",");
1472 if (parts.length != 2) {
1473 throw new KeywordSearchModuleException(
"Invalid server data: " + lines.get(rnd));
1477 String host = parts[0];
1478 String port = parts[1];
1479 if (host.isEmpty() || port.isEmpty()) {
1480 throw new KeywordSearchModuleException(
"Invalid server data: " + lines.get(rnd));
1484 Path serverFile = Paths.get(caseDirectoryPath.toString(),
"solrserver.txt");
1486 caseDirectoryPath.toFile().mkdirs();
1487 if (!caseDirectoryPath.toFile().exists()) {
1488 throw new KeywordSearchModuleException(
"Case directory " + caseDirectoryPath.toString() +
" does not exist");
1490 Files.write(serverFile, lines.get(rnd).getBytes());
1491 }
catch (IOException ex) {
1492 throw new KeywordSearchModuleException(serverFile.toString() +
" could not be written", ex);
1534 void commit() throws SolrServerException, NoOpenCoreException {
1535 currentCoreLock.readLock().lock();
1537 if (null == currentCollection) {
1538 throw new NoOpenCoreException();
1540 currentCollection.commit();
1542 currentCoreLock.readLock().unlock();
1546 NamedList<Object> request(SolrRequest<?> request)
throws SolrServerException, RemoteSolrException, NoOpenCoreException {
1547 currentCoreLock.readLock().lock();
1549 if (null == currentCollection) {
1550 throw new NoOpenCoreException();
1552 return currentCollection.request(request);
1554 currentCoreLock.readLock().unlock();
1569 currentCoreLock.readLock().lock();
1571 if (null == currentCollection) {
1572 throw new NoOpenCoreException();
1575 return currentCollection.queryNumIndexedFiles();
1576 }
catch (Exception ex) {
1578 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxFiles.exception.msg"), ex);
1581 currentCoreLock.readLock().unlock();
1595 currentCoreLock.readLock().lock();
1597 if (null == currentCollection) {
1598 throw new NoOpenCoreException();
1601 return currentCollection.queryNumIndexedChunks();
1602 }
catch (Exception ex) {
1604 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxChunks.exception.msg"), ex);
1607 currentCoreLock.readLock().unlock();
1621 currentCoreLock.readLock().lock();
1623 if (null == currentCollection) {
1624 throw new NoOpenCoreException();
1627 return currentCollection.queryNumIndexedDocuments();
1628 }
catch (Exception ex) {
1630 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxDocs.exception.msg"), ex);
1633 currentCoreLock.readLock().unlock();
1648 currentCoreLock.readLock().lock();
1650 if (null == currentCollection) {
1651 throw new NoOpenCoreException();
1654 int totalNumChunks = currentCollection.queryTotalNumFileChunks(contentID);
1655 if (totalNumChunks == 0) {
1659 int numIndexedChunks = currentCollection.queryNumIndexedChunks(contentID);
1660 return numIndexedChunks == totalNumChunks;
1661 }
catch (Exception ex) {
1663 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryIsIdxd.exception.msg"), ex);
1667 currentCoreLock.readLock().unlock();
1683 currentCoreLock.readLock().lock();
1685 if (null == currentCollection) {
1686 throw new NoOpenCoreException();
1689 return currentCollection.queryTotalNumFileChunks(fileID);
1690 }
catch (Exception ex) {
1692 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumFileChunks.exception.msg"), ex);
1695 currentCoreLock.readLock().unlock();
1709 public QueryResponse
query(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException, IOException {
1710 currentCoreLock.readLock().lock();
1712 if (null == currentCollection) {
1713 throw new NoOpenCoreException();
1716 return currentCollection.query(sq);
1717 }
catch (Exception ex) {
1719 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1720 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query.exception.msg", sq.getQuery()), ex);
1723 currentCoreLock.readLock().unlock();
1738 public QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws KeywordSearchModuleException, NoOpenCoreException {
1739 currentCoreLock.readLock().lock();
1741 if (null == currentCollection) {
1742 throw new NoOpenCoreException();
1745 return currentCollection.query(sq, method);
1746 }
catch (Exception ex) {
1748 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1749 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query2.exception.msg", sq.getQuery()), ex);
1752 currentCoreLock.readLock().unlock();
1766 public TermsResponse
queryTerms(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException {
1767 currentCoreLock.readLock().lock();
1769 if (null == currentCollection) {
1770 throw new NoOpenCoreException();
1773 return currentCollection.queryTerms(sq);
1774 }
catch (Exception ex) {
1776 logger.log(Level.SEVERE,
"Solr terms query failed: " + sq.getQuery(), ex);
1777 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryTerms.exception.msg", sq.getQuery()), ex);
1780 currentCoreLock.readLock().unlock();
1791 void deleteDataSource(Long dataSourceId)
throws IOException, KeywordSearchModuleException, NoOpenCoreException, SolrServerException {
1793 currentCoreLock.writeLock().lock();
1794 if (null == currentCollection) {
1795 throw new NoOpenCoreException();
1797 currentCollection.deleteDataSource(dataSourceId);
1798 currentCollection.commit();
1800 currentCoreLock.writeLock().unlock();
1812 @NbBundle.Messages({
1813 "Server.getAllTerms.error=Extraction of all unique Solr terms failed:"})
1814 void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws KeywordSearchModuleException, NoOpenCoreException {
1816 currentCoreLock.writeLock().lock();
1817 if (null == currentCollection) {
1818 throw new NoOpenCoreException();
1821 currentCollection.extractAllTermsForDataSource(outputFile, progressPanel);
1822 }
catch (Exception ex) {
1824 logger.log(Level.SEVERE,
"Extraction of all unique Solr terms failed: ", ex);
1825 throw new KeywordSearchModuleException(Bundle.Server_getAllTerms_error(), ex);
1828 currentCoreLock.writeLock().unlock();
1842 currentCoreLock.readLock().lock();
1844 if (null == currentCollection) {
1845 throw new NoOpenCoreException();
1847 return currentCollection.getSolrContent(content.getId(), 0);
1849 currentCoreLock.readLock().unlock();
1865 public String
getSolrContent(
final Content content,
int chunkID)
throws NoOpenCoreException {
1866 currentCoreLock.readLock().lock();
1868 if (null == currentCollection) {
1869 throw new NoOpenCoreException();
1871 return currentCollection.getSolrContent(content.getId(), chunkID);
1873 currentCoreLock.readLock().unlock();
1887 currentCoreLock.readLock().lock();
1889 if (null == currentCollection) {
1890 throw new NoOpenCoreException();
1892 return currentCollection.getSolrContent(objectID, 0);
1894 currentCoreLock.readLock().unlock();
1908 public String
getSolrContent(
final long objectID,
final int chunkID)
throws NoOpenCoreException {
1909 currentCoreLock.readLock().lock();
1911 if (null == currentCollection) {
1912 throw new NoOpenCoreException();
1914 return currentCollection.getSolrContent(objectID, chunkID);
1916 currentCoreLock.readLock().unlock();
1941 CoreAdminRequest.getStatus(null, localSolrServer);
1956 void connectToSolrServer(String host, String port)
throws SolrServerException, IOException {
1957 try (HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr")) {
1958 connectToSolrServer(solrServer);
1973 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1974 CollectionAdminResponse statusResponse = statusRequest.process(solrServer);
1975 int statusCode = Integer.valueOf(((NamedList) statusResponse.getResponse().get(
"responseHeader")).
get(
"status").toString());
1976 if (statusCode != 0) {
1977 logger.log(Level.WARNING,
"Could not connect to Solr server ");
1979 logger.log(Level.INFO,
"Connected to Solr server ");
1984 private List<String>
getSolrServerList(String host, String port)
throws KeywordSearchModuleException {
1985 HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr");
1989 private List<String>
getSolrServerList(HttpSolrClient solrServer)
throws KeywordSearchModuleException {
1992 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1993 CollectionAdminResponse statusResponse;
1995 statusResponse = statusRequest.process(solrServer);
1996 }
catch (RemoteSolrException ex) {
1998 return Collections.emptyList();
2001 if (statusResponse == null) {
2002 return Collections.emptyList();
2005 NamedList<?> error = (NamedList) statusResponse.getResponse().get(
"error");
2006 if (error != null) {
2007 return Collections.emptyList();
2010 NamedList<?> cluster = (NamedList) statusResponse.getResponse().get(
"cluster");
2011 @SuppressWarnings(
"unchecked")
2012 List<String> liveNodes = (ArrayList) cluster.get(
"live_nodes");
2014 if (liveNodes != null) {
2015 liveNodes = liveNodes.stream()
2016 .map(serverStr -> serverStr.endsWith(
"_solr")
2017 ? serverStr.substring(0, serverStr.length() -
"_solr".length())
2019 .collect(Collectors.toList());
2022 }
catch (Exception ex) {
2024 throw new KeywordSearchModuleException(
2025 NbBundle.getMessage(
this.getClass(),
"Server.serverList.exception.msg", solrServer.getBaseURL()));
2032 private final String name;
2036 private final Index textIndex;
2042 private HttpSolrClient queryClient;
2043 private SolrClient indexingClient;
2045 private final int maxBufferSize;
2046 private final List<SolrInputDocument> buffer;
2047 private final Object bufferLock;
2052 private static final int MAX_NUM_CONSECUTIVE_FAILURES = 5;
2053 private AtomicInteger numConsecutiveFailures =
new AtomicInteger(0);
2054 private AtomicBoolean skipIndexing =
new AtomicBoolean(
false);
2056 private final ScheduledThreadPoolExecutor periodicTasksExecutor;
2057 private static final long PERIODIC_BATCH_SEND_INTERVAL_MINUTES = 10;
2058 private static final int NUM_BATCH_UPDATE_RETRIES = 10;
2059 private static final long SLEEP_BETWEEN_RETRIES_MS = 10000;
2061 private Collection(String name,
Case theCase, Index index)
throws TimeoutException, InterruptedException, KeywordSearchModuleException {
2064 this.textIndex = index;
2065 bufferLock =
new Object();
2069 queryClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2070 indexingClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2076 if (IndexFinder.getCurrentSolrVersion().equals(index.getSolrVersion())) {
2078 indexingClient =
getCloudSolrClient(properties.getHost(), properties.getPort(), name);
2086 logger.log(Level.INFO,
"Using Solr document queue size = {0}", maxBufferSize);
2087 buffer =
new ArrayList<>(maxBufferSize);
2088 periodicTasksExecutor =
new ScheduledThreadPoolExecutor(1,
new ThreadFactoryBuilder().setNameFormat(
"periodic-batched-document-task-%d").build());
2089 periodicTasksExecutor.scheduleWithFixedDelay(
new SendBatchedDocumentsTask(), PERIODIC_BATCH_SEND_INTERVAL_MINUTES, PERIODIC_BATCH_SEND_INTERVAL_MINUTES, TimeUnit.MINUTES);
2103 if (skipIndexing.get()) {
2107 List<SolrInputDocument> clone;
2108 synchronized (bufferLock) {
2110 if (buffer.isEmpty()) {
2116 clone = buffer.stream().collect(toList());
2122 sendBufferedDocs(clone);
2123 }
catch (KeywordSearchModuleException ex) {
2124 logger.log(Level.SEVERE,
"Periodic batched document update failed", ex);
2138 private Index getIndexInfo() {
2139 return this.textIndex;
2142 private QueryResponse
query(SolrQuery sq)
throws SolrServerException, IOException {
2143 return queryClient.query(sq);
2146 private NamedList<Object> request(SolrRequest<?> request)
throws SolrServerException, RemoteSolrException {
2148 return queryClient.request(request);
2149 }
catch (Exception e) {
2151 logger.log(Level.WARNING,
"Could not issue Solr request. ", e);
2152 throw new SolrServerException(
2153 NbBundle.getMessage(
this.getClass(),
"Server.request.exception.exception.msg"), e);
2158 private QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws SolrServerException, IOException {
2159 return queryClient.query(sq, method);
2162 private TermsResponse
queryTerms(SolrQuery sq)
throws SolrServerException, IOException {
2163 QueryResponse qres = queryClient.query(sq);
2164 return qres.getTermsResponse();
2167 private void commit() throws SolrServerException {
2168 List<SolrInputDocument> clone;
2169 synchronized (bufferLock) {
2172 clone = buffer.stream().collect(toList());
2177 sendBufferedDocs(clone);
2178 }
catch (KeywordSearchModuleException ex) {
2179 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), ex);
2184 indexingClient.commit(
true,
true);
2185 }
catch (Exception e) {
2187 logger.log(Level.WARNING,
"Could not commit index. ", e);
2188 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), e);
2192 private void deleteDataSource(Long dsObjId)
throws IOException, SolrServerException {
2193 String dataSourceId = Long.toString(dsObjId);
2194 String deleteQuery =
"image_id:" + dataSourceId;
2196 queryClient.deleteByQuery(deleteQuery);
2210 @NbBundle.Messages({
2211 "# {0} - Number of extracted terms",
2212 "ExtractAllTermsReport.numberExtractedTerms=Extracted {0} terms..."
2214 private void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws IOException, SolrServerException, NoCurrentCaseException, KeywordSearchModuleException {
2216 Files.deleteIfExists(outputFile);
2217 OpenOption[] options =
new OpenOption[] { java.nio.file.StandardOpenOption.CREATE, java.nio.file.StandardOpenOption.APPEND };
2220 int termStep = 1000;
2221 long numExtractedTerms = 0;
2222 String firstTerm =
"";
2224 SolrQuery
query =
new SolrQuery();
2225 query.setRequestHandler(
"/terms");
2226 query.setTerms(
true);
2227 query.setTermsLimit(termStep);
2228 query.setTermsLower(firstTerm);
2229 query.setTermsLowerInclusive(
false);
2234 query.setTermsSortString(
"index");
2237 query.addTermsField(Server.Schema.TEXT.toString());
2238 query.setTermsMinCount(0);
2243 QueryRequest request =
new QueryRequest(query);
2244 TermsResponse response = request.process(queryClient).getTermsResponse();
2245 List<Term> terms = response.getTerms(Server.Schema.TEXT.toString());
2247 if (terms == null || terms.isEmpty()) {
2248 numExtractedTerms += terms.size();
2249 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2254 firstTerm = terms.get(terms.size()-1).getTerm();
2256 List<String> listTerms = terms.stream().map(Term::getTerm).collect(Collectors.toList());
2257 Files.write(outputFile, listTerms, options);
2259 numExtractedTerms += termStep;
2260 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2272 void addDocument(SolrInputDocument doc)
throws KeywordSearchModuleException {
2274 if (skipIndexing.get()) {
2278 List<SolrInputDocument> clone;
2279 synchronized (bufferLock) {
2282 if (buffer.size() < maxBufferSize) {
2288 clone = buffer.stream().collect(toList());
2293 sendBufferedDocs(clone);
2303 @NbBundle.Messages({
2304 "Collection.unableToIndexData.error=Unable to add data to text index. All future text indexing for the current case will be skipped.",
2307 private void sendBufferedDocs(List<SolrInputDocument> docBuffer)
throws KeywordSearchModuleException {
2309 if (docBuffer.isEmpty()) {
2314 boolean success =
true;
2315 for (
int reTryAttempt = 0; reTryAttempt < NUM_BATCH_UPDATE_RETRIES; reTryAttempt++) {
2318 indexingClient.add(docBuffer);
2319 }
catch (Exception ex) {
2321 if (reTryAttempt < NUM_BATCH_UPDATE_RETRIES - 1) {
2322 logger.log(Level.WARNING,
"Unable to send document batch to Solr. Re-trying...", ex);
2324 Thread.sleep(SLEEP_BETWEEN_RETRIES_MS);
2325 }
catch (InterruptedException ignore) {
2326 throw new KeywordSearchModuleException(
2327 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2332 numConsecutiveFailures.set(0);
2333 if (reTryAttempt > 0) {
2334 logger.log(Level.INFO,
"Batch update suceeded after {0} re-try", reTryAttempt);
2340 logger.log(Level.SEVERE,
"Unable to send document batch to Solr. All re-try attempts failed!");
2341 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2342 }
catch (Exception ex) {
2344 numConsecutiveFailures.incrementAndGet();
2345 logger.log(Level.SEVERE,
"Could not add batched documents to index", ex);
2348 MessageNotifyUtil.Notify.error(
2349 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2350 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2351 throw new KeywordSearchModuleException(
2352 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2354 if (numConsecutiveFailures.get() >= MAX_NUM_CONSECUTIVE_FAILURES) {
2356 skipIndexing.set(
true);
2357 logger.log(Level.SEVERE,
"Unable to add data to text index. All future text indexing for the current case will be skipped!");
2360 MessageNotifyUtil.Notify.error(
2361 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2362 Bundle.Collection_unableToIndexData_error());
2363 if (RuntimeProperties.runningWithGUI()) {
2364 MessageNotifyUtil.Message.error(Bundle.Collection_unableToIndexData_error());
2382 final SolrQuery q =
new SolrQuery();
2384 String filterQuery = Schema.ID.toString() +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2386 filterQuery = filterQuery + Server.CHUNK_ID_SEPARATOR + chunkID;
2388 q.addFilterQuery(filterQuery);
2389 q.setFields(Schema.TEXT.toString());
2392 SolrDocumentList solrDocuments = queryClient.query(q).getResults();
2394 if (!solrDocuments.isEmpty()) {
2395 SolrDocument solrDocument = solrDocuments.get(0);
2396 if (solrDocument != null) {
2397 java.util.Collection<Object> fieldValues = solrDocument.getFieldValues(Schema.TEXT.toString());
2398 if (fieldValues.size() == 1)
2400 return fieldValues.toArray(
new String[0])[0];
2404 return fieldValues.toArray(
new String[0])[1];
2408 }
catch (Exception ex) {
2410 logger.log(Level.SEVERE,
"Error getting content from Solr. Solr document id " + contentID +
", chunk id " + chunkID +
", query: " + filterQuery, ex);
2417 synchronized void close() throws KeywordSearchModuleException {
2422 ThreadUtils.shutDownTaskExecutor(periodicTasksExecutor);
2429 CoreAdminRequest.unloadCore(this.name, localSolrServer);
2430 }
catch (Exception ex) {
2432 throw new KeywordSearchModuleException(
2433 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg"), ex);
2436 queryClient.close();
2438 indexingClient.close();
2439 indexingClient = null;
2440 }
catch (IOException ex) {
2441 throw new KeywordSearchModuleException(
2442 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg2"), ex);
2470 SolrQuery q =
new SolrQuery(Server.Schema.ID +
":*" + Server.CHUNK_ID_SEPARATOR +
"*");
2472 int numChunks = (int)
query(q).getResults().getNumFound();
2487 SolrQuery q =
new SolrQuery(
"*:*");
2489 return (
int)
query(q).getResults().getNumFound();
2501 private boolean queryIsIndexed(
long contentID)
throws SolrServerException, IOException {
2502 String
id = KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2503 SolrQuery q =
new SolrQuery(
"*:*");
2504 q.addFilterQuery(Server.Schema.ID.toString() +
":" + id);
2507 return (
int)
query(q).getResults().getNumFound() != 0;
2524 private int queryTotalNumFileChunks(
long contentID)
throws SolrServerException, IOException {
2525 final SolrQuery q =
new SolrQuery();
2527 String filterQuery = Schema.ID.toString() +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2528 q.addFilterQuery(filterQuery);
2529 q.setFields(Schema.NUM_CHUNKS.toString());
2531 SolrDocumentList solrDocuments =
query(q).getResults();
2532 if (!solrDocuments.isEmpty()) {
2533 SolrDocument solrDocument = solrDocuments.get(0);
2534 if (solrDocument != null && !solrDocument.isEmpty()) {
2535 Object fieldValue = solrDocument.getFieldValue(Schema.NUM_CHUNKS.toString());
2536 return (Integer)fieldValue;
2539 }
catch (Exception ex) {
2541 logger.log(Level.SEVERE,
"Error getting content from Solr. Solr document id " + contentID +
", query: " + filterQuery, ex);
2560 SolrQuery q =
new SolrQuery(Server.Schema.ID +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID)) + Server.CHUNK_ID_SEPARATOR +
"*");
2562 int numChunks = (int)
query(q).getResults().getNumFound();
2567 class ServerAction
extends AbstractAction {
2569 private static final long serialVersionUID = 1L;
2572 public void actionPerformed(ActionEvent e) {
2573 logger.log(Level.INFO, e.paramString().trim());
2580 class SolrServerNoPortException
extends SocketException {
2582 private static final long serialVersionUID = 1L;
2587 private final int port;
2589 SolrServerNoPortException(
int port) {
2590 super(NbBundle.getMessage(Server.class,
"Server.solrServerNoPortException.msg", port,
2591 Server.PROPERTIES_CURRENT_SERVER_PORT));
2595 int getPortNumber() {
static synchronized String getConfigSetting(String moduleName, String settingName)
HttpSolrClient localSolrServer
int queryNumIndexedFiles()
String getSolrContent(final long objectID)
final ReentrantReadWriteLock currentCoreLock
int queryNumIndexedChunks()
ConcurrentUpdateSolrClient getConcurrentClient(String solrUrl)
boolean queryIsFullyIndexed(long contentID)
static String getSolr4ServerPort()
static final int NUM_EMBEDDED_SERVER_RETRIES
static final char ID_CHUNK_SEP
final ServerAction serverAction
static String getIndexingServerPort()
static IndexingServerProperties getMultiUserServerProperties(String caseDirectory)
String getCaseDirectory()
Collection openCore(Case theCase, Index index)
static final String CORE_PROPERTIES
void connectToSolrServer(HttpSolrClient solrServer)
boolean coreIsLoaded(String coreName)
Process runLocalSolr8ControlCommand(List< String > solrArguments)
static final int EMBEDDED_SERVER_RETRY_WAIT_SEC
List< String > getSolrServerList(String host, String port)
static final int NUM_COLLECTION_CREATION_RETRIES
void backupCollection(String collectionName, String backupName, String pathToBackupLocation)
void configureSolrConnection(Case theCase, Index index)
CloudSolrClient getCloudSolrClient(String host, String port, String defaultCollectionName)
boolean collectionExists(String collectionName)
Collection currentCollection
static final Logger logger
static TimingMetric getTimingMetric(String name)
SOLR_VERSION localServerVersion
static int getMaxSolrVMSize()
static void selectSolrServerForCase(Path rootOutputDirectory, Path caseDirectoryPath)
void addServerActionListener(PropertyChangeListener l)
static synchronized boolean settingExists(String moduleName, String settingName)
static final String HL_ANALYZE_CHARS_UNLIMITED
String getSolrContent(final Content content)
static final long MAX_CONTENT_SIZE
HttpSolrClient remoteSolrServer
boolean coreIndexFolderExists(String coreName)
void restoreCollection(String backupName, String restoreCollectionName, String pathToBackupLocation)
int queryNumIndexedDocuments()
static synchronized void setConfigSetting(String moduleName, String settingName, String settingVal)
HttpSolrClient configureMultiUserConnection(Case theCase, Index index, String name)
static final String CHUNK_ID_SEPARATOR
static final String CORE_EVT
static final Charset DEFAULT_INDEXED_TEXT_CHARSET
default Charset to index text as
static String getSolr4ServerHost()
InputStreamPrinterThread errorRedirectThread
Process runLocalSolr4ControlCommand(List< String > solrArguments)
List< String > getSolrServerList(HttpSolrClient solrServer)
QueryResponse query(SolrQuery sq)
static void submitTimingMetric(TimingMetric metric)
TermsResponse queryTerms(SolrQuery sq)
void connectToEmbeddedSolrServer()
void createMultiUserCollection(String collectionName, int numShardsToUse)
String getSolrContent(final Content content, int chunkID)
String getSolrContent(final long objectID, final int chunkID)
HttpSolrClient getSolrClient(String solrUrl)
synchronized static Logger getLogger(String name)
static String getChunkIdString(long parentID, int childID)
static boolean deleteDir(File dirPath)
static String getIndexingServerHost()
int queryNumFileChunks(long fileID)
static final boolean DEBUG
QueryResponse query(SolrQuery sq, SolrRequest.METHOD method)