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 =
"Args.*.eq=-DSTOP.KEY=" + KEY +
",Args.*.eq=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();
1647 public boolean queryIsIndexed(
long contentID)
throws KeywordSearchModuleException, NoOpenCoreException {
1648 currentCoreLock.readLock().lock();
1650 if (null == currentCollection) {
1651 throw new NoOpenCoreException();
1654 return currentCollection.queryIsIndexed(contentID);
1655 }
catch (Exception ex) {
1657 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryIsIdxd.exception.msg"), ex);
1661 currentCoreLock.readLock().unlock();
1677 currentCoreLock.readLock().lock();
1679 if (null == currentCollection) {
1680 throw new NoOpenCoreException();
1683 return currentCollection.queryNumFileChunks(fileID);
1684 }
catch (Exception ex) {
1686 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumFileChunks.exception.msg"), ex);
1689 currentCoreLock.readLock().unlock();
1703 public QueryResponse
query(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException, IOException {
1704 currentCoreLock.readLock().lock();
1706 if (null == currentCollection) {
1707 throw new NoOpenCoreException();
1710 return currentCollection.query(sq);
1711 }
catch (Exception ex) {
1713 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1714 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query.exception.msg", sq.getQuery()), ex);
1717 currentCoreLock.readLock().unlock();
1732 public QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws KeywordSearchModuleException, NoOpenCoreException {
1733 currentCoreLock.readLock().lock();
1735 if (null == currentCollection) {
1736 throw new NoOpenCoreException();
1739 return currentCollection.query(sq, method);
1740 }
catch (Exception ex) {
1742 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1743 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query2.exception.msg", sq.getQuery()), ex);
1746 currentCoreLock.readLock().unlock();
1760 public TermsResponse
queryTerms(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException {
1761 currentCoreLock.readLock().lock();
1763 if (null == currentCollection) {
1764 throw new NoOpenCoreException();
1767 return currentCollection.queryTerms(sq);
1768 }
catch (Exception ex) {
1770 logger.log(Level.SEVERE,
"Solr terms query failed: " + sq.getQuery(), ex);
1771 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryTerms.exception.msg", sq.getQuery()), ex);
1774 currentCoreLock.readLock().unlock();
1785 void deleteDataSource(Long dataSourceId)
throws IOException, KeywordSearchModuleException, NoOpenCoreException, SolrServerException {
1787 currentCoreLock.writeLock().lock();
1788 if (null == currentCollection) {
1789 throw new NoOpenCoreException();
1791 currentCollection.deleteDataSource(dataSourceId);
1792 currentCollection.commit();
1794 currentCoreLock.writeLock().unlock();
1806 @NbBundle.Messages({
1807 "Server.getAllTerms.error=Extraction of all unique Solr terms failed:"})
1808 void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws KeywordSearchModuleException, NoOpenCoreException {
1810 currentCoreLock.writeLock().lock();
1811 if (null == currentCollection) {
1812 throw new NoOpenCoreException();
1815 currentCollection.extractAllTermsForDataSource(outputFile, progressPanel);
1816 }
catch (Exception ex) {
1818 logger.log(Level.SEVERE,
"Extraction of all unique Solr terms failed: ", ex);
1819 throw new KeywordSearchModuleException(Bundle.Server_getAllTerms_error(), ex);
1822 currentCoreLock.writeLock().unlock();
1836 currentCoreLock.readLock().lock();
1838 if (null == currentCollection) {
1839 throw new NoOpenCoreException();
1841 return currentCollection.getSolrContent(content.getId(), 0);
1843 currentCoreLock.readLock().unlock();
1859 public String
getSolrContent(
final Content content,
int chunkID)
throws NoOpenCoreException {
1860 currentCoreLock.readLock().lock();
1862 if (null == currentCollection) {
1863 throw new NoOpenCoreException();
1865 return currentCollection.getSolrContent(content.getId(), chunkID);
1867 currentCoreLock.readLock().unlock();
1881 currentCoreLock.readLock().lock();
1883 if (null == currentCollection) {
1884 throw new NoOpenCoreException();
1886 return currentCollection.getSolrContent(objectID, 0);
1888 currentCoreLock.readLock().unlock();
1902 public String
getSolrContent(
final long objectID,
final int chunkID)
throws NoOpenCoreException {
1903 currentCoreLock.readLock().lock();
1905 if (null == currentCollection) {
1906 throw new NoOpenCoreException();
1908 return currentCollection.getSolrContent(objectID, chunkID);
1910 currentCoreLock.readLock().unlock();
1935 CoreAdminRequest.getStatus(null, localSolrServer);
1950 void connectToSolrServer(String host, String port)
throws SolrServerException, IOException {
1951 try (HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr")) {
1952 connectToSolrServer(solrServer);
1967 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1968 CollectionAdminResponse statusResponse = statusRequest.process(solrServer);
1969 int statusCode = Integer.valueOf(((NamedList) statusResponse.getResponse().get(
"responseHeader")).
get(
"status").toString());
1970 if (statusCode != 0) {
1971 logger.log(Level.WARNING,
"Could not connect to Solr server ");
1973 logger.log(Level.INFO,
"Connected to Solr server ");
1978 private List<String>
getSolrServerList(String host, String port)
throws KeywordSearchModuleException {
1979 HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr");
1983 private List<String>
getSolrServerList(HttpSolrClient solrServer)
throws KeywordSearchModuleException {
1986 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1987 CollectionAdminResponse statusResponse;
1989 statusResponse = statusRequest.process(solrServer);
1990 }
catch (RemoteSolrException ex) {
1992 return Collections.emptyList();
1995 if (statusResponse == null) {
1996 return Collections.emptyList();
1999 NamedList<?> error = (NamedList) statusResponse.getResponse().get(
"error");
2000 if (error != null) {
2001 return Collections.emptyList();
2004 NamedList<?> cluster = (NamedList) statusResponse.getResponse().get(
"cluster");
2005 @SuppressWarnings(
"unchecked")
2006 ArrayList<String> liveNodes = (ArrayList) cluster.get(
"live_nodes");
2008 }
catch (Exception ex) {
2010 throw new KeywordSearchModuleException(
2011 NbBundle.getMessage(
this.getClass(),
"Server.serverList.exception.msg", solrServer.getBaseURL()));
2018 private final String name;
2022 private final Index textIndex;
2028 private HttpSolrClient queryClient;
2029 private SolrClient indexingClient;
2031 private final int maxBufferSize;
2032 private final List<SolrInputDocument> buffer;
2033 private final Object bufferLock;
2038 private static final int MAX_NUM_CONSECUTIVE_FAILURES = 5;
2039 private AtomicInteger numConsecutiveFailures =
new AtomicInteger(0);
2040 private AtomicBoolean skipIndexing =
new AtomicBoolean(
false);
2042 private final ScheduledThreadPoolExecutor periodicTasksExecutor;
2043 private static final long PERIODIC_BATCH_SEND_INTERVAL_MINUTES = 10;
2044 private static final int NUM_BATCH_UPDATE_RETRIES = 10;
2045 private static final long SLEEP_BETWEEN_RETRIES_MS = 10000;
2047 private Collection(String name,
Case theCase, Index index)
throws TimeoutException, InterruptedException, KeywordSearchModuleException {
2050 this.textIndex = index;
2051 bufferLock =
new Object();
2055 queryClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2056 indexingClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2062 if (IndexFinder.getCurrentSolrVersion().equals(index.getSolrVersion())) {
2064 indexingClient =
getCloudSolrClient(properties.getHost(), properties.getPort(), name);
2072 logger.log(Level.INFO,
"Using Solr document queue size = {0}", maxBufferSize);
2073 buffer =
new ArrayList<>(maxBufferSize);
2074 periodicTasksExecutor =
new ScheduledThreadPoolExecutor(1,
new ThreadFactoryBuilder().setNameFormat(
"periodic-batched-document-task-%d").build());
2075 periodicTasksExecutor.scheduleWithFixedDelay(
new SendBatchedDocumentsTask(), PERIODIC_BATCH_SEND_INTERVAL_MINUTES, PERIODIC_BATCH_SEND_INTERVAL_MINUTES, TimeUnit.MINUTES);
2089 if (skipIndexing.get()) {
2093 List<SolrInputDocument> clone;
2094 synchronized (bufferLock) {
2096 if (buffer.isEmpty()) {
2102 clone = buffer.stream().collect(toList());
2108 sendBufferedDocs(clone);
2109 }
catch (KeywordSearchModuleException ex) {
2110 logger.log(Level.SEVERE,
"Periodic batched document update failed", ex);
2124 private Index getIndexInfo() {
2125 return this.textIndex;
2128 private QueryResponse
query(SolrQuery sq)
throws SolrServerException, IOException {
2129 return queryClient.query(sq);
2132 private NamedList<Object> request(SolrRequest<?> request)
throws SolrServerException, RemoteSolrException {
2134 return queryClient.request(request);
2135 }
catch (Exception e) {
2137 logger.log(Level.WARNING,
"Could not issue Solr request. ", e);
2138 throw new SolrServerException(
2139 NbBundle.getMessage(
this.getClass(),
"Server.request.exception.exception.msg"), e);
2144 private QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws SolrServerException, IOException {
2145 return queryClient.query(sq, method);
2148 private TermsResponse
queryTerms(SolrQuery sq)
throws SolrServerException, IOException {
2149 QueryResponse qres = queryClient.query(sq);
2150 return qres.getTermsResponse();
2153 private void commit() throws SolrServerException {
2154 List<SolrInputDocument> clone;
2155 synchronized (bufferLock) {
2158 clone = buffer.stream().collect(toList());
2163 sendBufferedDocs(clone);
2164 }
catch (KeywordSearchModuleException ex) {
2165 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), ex);
2170 indexingClient.commit(
true,
true);
2171 }
catch (Exception e) {
2173 logger.log(Level.WARNING,
"Could not commit index. ", e);
2174 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), e);
2178 private void deleteDataSource(Long dsObjId)
throws IOException, SolrServerException {
2179 String dataSourceId = Long.toString(dsObjId);
2180 String deleteQuery =
"image_id:" + dataSourceId;
2182 queryClient.deleteByQuery(deleteQuery);
2196 @NbBundle.Messages({
2197 "# {0} - Number of extracted terms",
2198 "ExtractAllTermsReport.numberExtractedTerms=Extracted {0} terms..."
2200 private void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws IOException, SolrServerException, NoCurrentCaseException, KeywordSearchModuleException {
2202 Files.deleteIfExists(outputFile);
2203 OpenOption[] options =
new OpenOption[] { java.nio.file.StandardOpenOption.CREATE, java.nio.file.StandardOpenOption.APPEND };
2206 int termStep = 1000;
2207 long numExtractedTerms = 0;
2208 String firstTerm =
"";
2210 SolrQuery
query =
new SolrQuery();
2211 query.setRequestHandler(
"/terms");
2212 query.setTerms(
true);
2213 query.setTermsLimit(termStep);
2214 query.setTermsLower(firstTerm);
2215 query.setTermsLowerInclusive(
false);
2220 query.setTermsSortString(
"index");
2223 query.addTermsField(Server.Schema.TEXT.toString());
2224 query.setTermsMinCount(0);
2229 QueryRequest request =
new QueryRequest(query);
2230 TermsResponse response = request.process(queryClient).getTermsResponse();
2231 List<Term> terms = response.getTerms(Server.Schema.TEXT.toString());
2233 if (terms == null || terms.isEmpty()) {
2234 numExtractedTerms += terms.size();
2235 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2240 firstTerm = terms.get(terms.size()-1).getTerm();
2242 List<String> listTerms = terms.stream().map(Term::getTerm).collect(Collectors.toList());
2243 Files.write(outputFile, listTerms, options);
2245 numExtractedTerms += termStep;
2246 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2258 void addDocument(SolrInputDocument doc)
throws KeywordSearchModuleException {
2260 if (skipIndexing.get()) {
2264 List<SolrInputDocument> clone;
2265 synchronized (bufferLock) {
2268 if (buffer.size() < maxBufferSize) {
2274 clone = buffer.stream().collect(toList());
2279 sendBufferedDocs(clone);
2289 @NbBundle.Messages({
2290 "Collection.unableToIndexData.error=Unable to add data to text index. All future text indexing for the current case will be skipped.",
2293 private void sendBufferedDocs(List<SolrInputDocument> docBuffer)
throws KeywordSearchModuleException {
2295 if (docBuffer.isEmpty()) {
2300 boolean success =
true;
2301 for (
int reTryAttempt = 0; reTryAttempt < NUM_BATCH_UPDATE_RETRIES; reTryAttempt++) {
2304 indexingClient.add(docBuffer);
2305 }
catch (Exception ex) {
2307 if (reTryAttempt < NUM_BATCH_UPDATE_RETRIES - 1) {
2308 logger.log(Level.WARNING,
"Unable to send document batch to Solr. Re-trying...", ex);
2310 Thread.sleep(SLEEP_BETWEEN_RETRIES_MS);
2311 }
catch (InterruptedException ignore) {
2312 throw new KeywordSearchModuleException(
2313 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2318 numConsecutiveFailures.set(0);
2319 if (reTryAttempt > 0) {
2320 logger.log(Level.INFO,
"Batch update suceeded after {0} re-try", reTryAttempt);
2326 logger.log(Level.SEVERE,
"Unable to send document batch to Solr. All re-try attempts failed!");
2327 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2328 }
catch (Exception ex) {
2330 numConsecutiveFailures.incrementAndGet();
2331 logger.log(Level.SEVERE,
"Could not add batched documents to index", ex);
2334 MessageNotifyUtil.Notify.error(
2335 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2336 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2337 throw new KeywordSearchModuleException(
2338 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2340 if (numConsecutiveFailures.get() >= MAX_NUM_CONSECUTIVE_FAILURES) {
2342 skipIndexing.set(
true);
2343 logger.log(Level.SEVERE,
"Unable to add data to text index. All future text indexing for the current case will be skipped!");
2346 MessageNotifyUtil.Notify.error(
2347 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2348 Bundle.Collection_unableToIndexData_error());
2349 if (RuntimeProperties.runningWithGUI()) {
2350 MessageNotifyUtil.Message.error(Bundle.Collection_unableToIndexData_error());
2368 final SolrQuery q =
new SolrQuery();
2370 String filterQuery = Schema.ID.toString() +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2372 filterQuery = filterQuery + Server.CHUNK_ID_SEPARATOR + chunkID;
2374 q.addFilterQuery(filterQuery);
2375 q.setFields(Schema.TEXT.toString());
2378 SolrDocumentList solrDocuments = queryClient.query(q).getResults();
2380 if (!solrDocuments.isEmpty()) {
2381 SolrDocument solrDocument = solrDocuments.get(0);
2382 if (solrDocument != null) {
2383 java.util.Collection<Object> fieldValues = solrDocument.getFieldValues(Schema.TEXT.toString());
2384 if (fieldValues.size() == 1)
2386 return fieldValues.toArray(
new String[0])[0];
2390 return fieldValues.toArray(
new String[0])[1];
2394 }
catch (Exception ex) {
2396 logger.log(Level.SEVERE,
"Error getting content from Solr. Solr document id " + contentID +
", chunk id " + chunkID +
", query: " + filterQuery, ex);
2403 synchronized void close() throws KeywordSearchModuleException {
2408 ThreadUtils.shutDownTaskExecutor(periodicTasksExecutor);
2415 CoreAdminRequest.unloadCore(this.name, localSolrServer);
2416 }
catch (Exception ex) {
2418 throw new KeywordSearchModuleException(
2419 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg"), ex);
2422 queryClient.close();
2424 indexingClient.close();
2425 indexingClient = null;
2426 }
catch (IOException ex) {
2427 throw new KeywordSearchModuleException(
2428 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg2"), ex);
2456 SolrQuery q =
new SolrQuery(Server.Schema.ID +
":*" + Server.CHUNK_ID_SEPARATOR +
"*");
2458 int numChunks = (int)
query(q).getResults().getNumFound();
2473 SolrQuery q =
new SolrQuery(
"*:*");
2475 return (
int)
query(q).getResults().getNumFound();
2487 private boolean queryIsIndexed(
long contentID)
throws SolrServerException, IOException {
2488 String
id = KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2489 SolrQuery q =
new SolrQuery(
"*:*");
2490 q.addFilterQuery(Server.Schema.ID.toString() +
":" + id);
2493 return (
int)
query(q).getResults().getNumFound() != 0;
2507 private int queryNumFileChunks(
long contentID)
throws SolrServerException, IOException {
2508 String
id = KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2510 =
new SolrQuery(Server.Schema.ID +
":" +
id + Server.CHUNK_ID_SEPARATOR +
"*");
2512 return (
int)
query(q).getResults().getNumFound();
2516 class ServerAction
extends AbstractAction {
2518 private static final long serialVersionUID = 1L;
2521 public void actionPerformed(ActionEvent e) {
2522 logger.log(Level.INFO, e.paramString().trim());
2529 class SolrServerNoPortException
extends SocketException {
2531 private static final long serialVersionUID = 1L;
2536 private final int port;
2538 SolrServerNoPortException(
int port) {
2539 super(NbBundle.getMessage(Server.class,
"Server.solrServerNoPortException.msg", port,
2540 Server.PROPERTIES_CURRENT_SERVER_PORT));
2544 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)
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)
boolean queryIsIndexed(long contentID)
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)