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 javax.swing.JOptionPane;
61 import org.apache.solr.client.solrj.SolrQuery;
62 import org.apache.solr.client.solrj.SolrRequest;
63 import org.apache.solr.client.solrj.SolrServerException;
64 import org.apache.solr.client.solrj.SolrClient;
65 import org.apache.solr.client.solrj.impl.HttpSolrClient;
66 import org.apache.solr.client.solrj.impl.CloudSolrClient;
67 import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrClient;
68 import org.apache.solr.client.solrj.impl.XMLResponseParser;
69 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
70 import org.apache.solr.client.solrj.response.CollectionAdminResponse;
71 import org.apache.solr.client.solrj.request.CoreAdminRequest;
72 import org.apache.solr.client.solrj.response.CoreAdminResponse;
73 import org.apache.solr.client.solrj.impl.BaseHttpSolrClient.RemoteSolrException;
74 import org.apache.solr.client.solrj.request.QueryRequest;
75 import org.apache.solr.client.solrj.response.QueryResponse;
76 import org.apache.solr.client.solrj.response.TermsResponse;
77 import org.apache.solr.client.solrj.response.TermsResponse.Term;
78 import org.apache.solr.common.SolrDocument;
79 import org.apache.solr.common.SolrDocumentList;
80 import org.apache.solr.common.SolrException;
81 import org.apache.solr.common.SolrInputDocument;
82 import org.apache.solr.common.util.NamedList;
83 import org.openide.modules.InstalledFileLocator;
84 import org.openide.modules.Places;
85 import org.openide.util.NbBundle;
86 import org.openide.util.NbBundle.Messages;
87 import org.openide.windows.WindowManager;
119 public String toString() {
125 public String toString() {
132 public String toString() {
139 public String toString() {
140 return "content_str";
146 public String toString() {
154 public String toString() {
160 public String toString() {
166 public String toString() {
172 public String toString() {
179 public String toString() {
186 public String toString() {
193 public String toString() {
200 public String toString() {
206 public String toString() {
212 public String toString() {
223 public String toString() {
240 static final String PROPERTIES_FILE = KeywordSearchSettings.MODULE_NAME;
241 static final String PROPERTIES_CURRENT_SERVER_PORT =
"IndexingServerPort";
242 static final String PROPERTIES_CURRENT_STOP_PORT =
"IndexingServerStopPort";
243 private static final String
KEY =
"jjk#09s";
244 static final String DEFAULT_SOLR_SERVER_HOST =
"localhost";
245 static final int DEFAULT_SOLR_SERVER_PORT = 23232;
246 static final int DEFAULT_SOLR_STOP_PORT = 34343;
250 private static final String
SOLR =
"solr";
252 private static final boolean DEBUG =
false;
287 localSolrServer =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr");
289 serverAction =
new ServerAction();
290 File solr8Folder = InstalledFileLocator.getDefault().locate(
"solr",
Server.class.getPackage().getName(),
false);
291 File solr4Folder = InstalledFileLocator.getDefault().locate(
"solr4",
Server.class.getPackage().getName(),
false);
302 if (!solr8Home.toFile().exists()) {
303 Files.createDirectory(solr8Home);
308 Files.copy(Paths.get(solr8Folder.getAbsolutePath(),
"server",
"solr",
"solr.xml"), solr8Home.resolve(
"solr.xml"), REPLACE_EXISTING);
309 Files.copy(Paths.get(solr8Folder.getAbsolutePath(),
"server",
"solr",
"zoo.cfg"), solr8Home.resolve(
"zoo.cfg"), REPLACE_EXISTING);
310 FileUtils.copyDirectory(Paths.get(solr8Folder.getAbsolutePath(),
"server",
"solr",
"configsets").toFile(), solr8Home.resolve(
"configsets").toFile());
311 }
catch (IOException ex) {
312 logger.log(Level.SEVERE,
"Failed to create Solr 8 home folder:", ex);
318 if (!solr4Home.toFile().exists()) {
319 Files.createDirectory(solr4Home);
321 Files.copy(Paths.get(solr4Folder.getAbsolutePath(),
"solr",
"solr.xml"), solr4Home.resolve(
"solr.xml"), REPLACE_EXISTING);
322 Files.copy(Paths.get(solr4Folder.getAbsolutePath(),
"solr",
"zoo.cfg"), solr4Home.resolve(
"zoo.cfg"), REPLACE_EXISTING);
323 }
catch (IOException ex) {
324 logger.log(Level.SEVERE,
"Failed to create Solr 4 home folder:", ex);
327 currentCoreLock =
new ReentrantReadWriteLock(
true);
329 logger.log(Level.INFO,
"Created Server instance using Java at {0}", javaPath);
337 }
catch (NumberFormatException nfe) {
338 logger.log(Level.WARNING,
"Could not decode indexing server port, value was not a valid port number, using the default. ", nfe);
339 localSolrServerPort = DEFAULT_SOLR_SERVER_PORT;
342 localSolrServerPort = DEFAULT_SOLR_SERVER_PORT;
349 }
catch (NumberFormatException nfe) {
350 logger.log(Level.WARNING,
"Could not decode indexing server stop port, value was not a valid port number, using default", nfe);
351 localSolrStopPort = DEFAULT_SOLR_STOP_PORT;
354 localSolrStopPort = DEFAULT_SOLR_STOP_PORT;
361 return new HttpSolrClient.Builder(solrUrl)
362 .withSocketTimeout(connectionTimeoutMs)
363 .withConnectionTimeout(connectionTimeoutMs)
364 .withResponseParser(
new XMLResponseParser())
372 logger.log(Level.INFO,
"Creating new ConcurrentUpdateSolrClient: {0}", solrUrl);
373 logger.log(Level.INFO,
"Queue size = {0}, Number of threads = {1}, Connection Timeout (ms) = {2}",
new Object[]{numDocs, numThreads, connectionTimeoutMs});
374 ConcurrentUpdateSolrClient client =
new ConcurrentUpdateSolrClient.Builder(solrUrl)
375 .withQueueSize(numDocs)
376 .withThreadCount(numThreads)
377 .withSocketTimeout(connectionTimeoutMs)
378 .withConnectionTimeout(connectionTimeoutMs)
379 .withResponseParser(
new XMLResponseParser())
387 List<String> solrUrls =
new ArrayList<>();
388 for (String server : solrServerList) {
389 solrUrls.add(
"http://" + server +
"/solr");
390 logger.log(Level.INFO,
"Using Solr server: {0}", server);
393 logger.log(Level.INFO,
"Creating new CloudSolrClient");
395 CloudSolrClient client =
new CloudSolrClient.Builder(solrUrls)
396 .withConnectionTimeout(connectionTimeoutMs)
397 .withSocketTimeout(connectionTimeoutMs)
398 .withResponseParser(
new XMLResponseParser())
400 if (!defaultCollectionName.isEmpty()) {
401 client.setDefaultCollection(defaultCollectionName);
408 public void finalize() throws java.lang.Throwable {
414 serverAction.addPropertyChangeListener(l);
417 int getLocalSolrServerPort() {
421 int getLocalSolrStopPort() {
432 volatile boolean doRun =
true;
435 this.stream = stream;
437 final String log = Places.getUserDirectory().getAbsolutePath()
438 + File.separator +
"var" + File.separator +
"log"
439 + File.separator +
"solr.log." + type;
440 File outputFile =
new File(log.concat(
".0"));
441 File first =
new File(log.concat(
".1"));
442 File second =
new File(log.concat(
".2"));
443 if (second.exists()) {
446 if (first.exists()) {
447 first.renameTo(second);
449 if (outputFile.exists()) {
450 outputFile.renameTo(first);
452 outputFile.createNewFile();
454 out =
new FileOutputStream(outputFile);
456 }
catch (Exception ex) {
457 logger.log(Level.WARNING,
"Failed to create solr log file", ex);
468 try (InputStreamReader isr =
new InputStreamReader(stream);
469 BufferedReader br =
new BufferedReader(isr);
471 BufferedWriter bw =
new BufferedWriter(osw);) {
474 while (doRun && (line = br.readLine()) != null) {
483 }
catch (IOException ex) {
484 logger.log(Level.SEVERE,
"Error redirecting Solr output stream", ex);
502 File solr8Folder = InstalledFileLocator.getDefault().locate(
"solr",
Server.class.getPackage().getName(),
false);
505 solr8CmdPath = Paths.get(solr8Folder.getAbsolutePath(),
"bin",
"autopsy-solr.cmd");
507 solr8CmdPath = Paths.get(solr8Folder.getAbsolutePath(),
"bin",
"autopsy-solr");
511 List<String> commandLine =
new ArrayList<>();
512 commandLine.add(solr8CmdPath.toString());
513 commandLine.addAll(solrArguments);
515 ProcessBuilder solrProcessBuilder =
new ProcessBuilder(commandLine);
516 solrProcessBuilder.directory(solr8Folder);
519 Path solrStdoutPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stdout");
520 solrProcessBuilder.redirectOutput(solrStdoutPath.toFile());
522 Path solrStderrPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stderr");
523 solrProcessBuilder.redirectError(solrStderrPath.toFile());
526 String jreFolderPath =
new File(javaPath).getParentFile().getParentFile().getAbsolutePath();
528 solrProcessBuilder.environment().put(
"SOLR_JAVA_HOME", jreFolderPath);
529 solrProcessBuilder.environment().put(
"SOLR_HOME", solr8Home.toString());
530 solrProcessBuilder.environment().put(
"STOP_KEY", KEY);
531 solrProcessBuilder.environment().put(
"SOLR_JAVA_MEM", MAX_SOLR_MEM_MB_PAR);
532 logger.log(Level.INFO,
"Setting Solr 8 directory: {0}", solr8Folder.toString());
533 logger.log(Level.INFO,
"Running Solr 8 command: {0} from {1}",
new Object[]{solrProcessBuilder.command(), solr8Folder.toString()});
534 Process process = solrProcessBuilder.start();
535 logger.log(Level.INFO,
"Finished running Solr 8 command");
550 File solr4Folder = InstalledFileLocator.getDefault().locate(
"solr4",
Server.class.getPackage().getName(),
false);
552 List<String> commandLine =
new ArrayList<>();
553 commandLine.add(javaPath);
554 commandLine.add(MAX_SOLR_MEM_MB_PAR);
555 commandLine.add(
"-DSTOP.PORT=" + localSolrStopPort);
556 commandLine.add(
"-Djetty.port=" + localSolrServerPort);
557 commandLine.add(
"-DSTOP.KEY=" + KEY);
558 commandLine.add(
"-jar");
559 commandLine.add(
"start.jar");
561 commandLine.addAll(solrArguments);
563 ProcessBuilder solrProcessBuilder =
new ProcessBuilder(commandLine);
564 solrProcessBuilder.directory(solr4Folder);
567 Path solrStdoutPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stdout");
568 solrProcessBuilder.redirectOutput(solrStdoutPath.toFile());
570 Path solrStderrPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stderr");
571 solrProcessBuilder.redirectError(solrStderrPath.toFile());
573 logger.log(Level.INFO,
"Running Solr 4 command: {0}", solrProcessBuilder.command());
574 Process process = solrProcessBuilder.start();
575 logger.log(Level.INFO,
"Finished running Solr 4 command");
584 List<Long> getSolrPIDs() {
585 List<Long> pids =
new ArrayList<>();
588 final String pidsQuery =
"-DSTOP.KEY=" + KEY +
"%start.jar";
591 if (pidsArr != null) {
592 for (
int i = 0; i < pidsArr.length; ++i) {
593 pids.add(pidsArr[i]);
605 List<Long> solrPids = getSolrPIDs();
606 for (
long pid : solrPids) {
607 logger.log(Level.INFO,
"Trying to kill old Solr process, PID: {0}", pid);
608 PlatformUtil.killProcess(pid);
612 void start() throws KeywordSearchModuleException, SolrServerNoPortException, SolrServerException {
613 startLocalSolr(SOLR_VERSION.SOLR8);
617 "# {0} - indexVersion",
618 "Server_configureSolrConnection_illegalSolrVersion=The solr version in the case: {0}, is not supported."
626 if (!IndexFinder.getCurrentSolrVersion().equals(index.getSolrVersion())) {
633 if (!this.isLocalSolrRunning()) {
634 logger.log(Level.SEVERE,
"Local Solr server is not running");
642 connectToSolrServer(remoteSolrServer);
644 }
catch (SolrServerException | IOException ex) {
667 if (properties.
host.isEmpty() || properties.
port.isEmpty()) {
668 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.connectionInfoMissing.exception.msg", index.getSolrVersion()));
670 String solrUrl =
"http://" + properties.
host +
":" + properties.
port +
"/solr";
672 if (!name.isEmpty()) {
673 solrUrl = solrUrl +
"/" + name;
686 "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.",})
687 synchronized void startLocalSolr(SOLR_VERSION version)
throws KeywordSearchModuleException, SolrServerNoPortException, SolrServerException {
689 logger.log(Level.INFO,
"Starting local Solr " + version +
" server");
690 if (version == SOLR_VERSION.SOLR8) {
691 localSolrFolder = InstalledFileLocator.getDefault().locate(
"solr", Server.class.getPackage().getName(),
false);
693 throw new KeywordSearchModuleException(Bundle.Server_configureSolrConnection_illegalSolrVersion(version.name()));
696 if (isLocalSolrRunning()) {
697 if (localServerVersion.equals(version)) {
699 logger.log(Level.INFO,
"Local Solr " + version +
" server is already running");
708 localServerVersion = version;
710 if (!isPortAvailable(localSolrServerPort)) {
714 final List<Long> pids = this.getSolrPIDs();
718 if (pids.isEmpty()) {
719 throw new SolrServerNoPortException(localSolrServerPort);
728 if (!isPortAvailable(localSolrServerPort)) {
729 throw new SolrServerNoPortException(localSolrServerPort);
731 if (!isPortAvailable(localSolrStopPort)) {
732 throw new SolrServerNoPortException(localSolrStopPort);
736 if (isPortAvailable(localSolrServerPort)) {
737 logger.log(Level.INFO,
"Port [{0}] available, starting Solr", localSolrServerPort);
739 if (version == SOLR_VERSION.SOLR8) {
740 logger.log(Level.INFO,
"Starting Solr 8 server");
742 Integer.toString(localSolrServerPort))));
745 logger.log(Level.INFO,
"Starting Solr 4 server");
747 Arrays.asList(
"-Dbootstrap_confdir=../solr/configsets/AutopsyConfig/conf",
748 "-Dcollection.configName=AutopsyConfig")));
753 if (isLocalSolrRunning()) {
754 final List<Long> pids = this.getSolrPIDs();
755 logger.log(Level.INFO,
"New Solr process PID: {0}", pids);
762 TimeUnit.SECONDS.sleep(EMBEDDED_SERVER_RETRY_WAIT_SEC);
763 }
catch (InterruptedException ex) {
764 logger.log(Level.WARNING,
"Timer interrupted");
770 logger.log(Level.WARNING,
"Local Solr server failed to respond to status requests.");
771 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
774 MessageNotifyUtil.Notify.error(
775 NbBundle.getMessage(
this.getClass(),
"Installer.errorInitKsmMsg"),
776 Bundle.Server_status_failed_msg());
779 }
catch (SecurityException ex) {
780 throw new KeywordSearchModuleException(
781 NbBundle.getMessage(
this.getClass(),
"Server.start.exception.cantStartSolr.msg"), ex);
782 }
catch (IOException ex) {
783 throw new KeywordSearchModuleException(
784 NbBundle.getMessage(
this.getClass(),
"Server.start.exception.cantStartSolr.msg2"), ex);
795 static boolean isPortAvailable(
int port) {
797 if (port < 1 || port > 65535) {
798 throw new IllegalArgumentException(
"Invalid start port: " + port);
801 ServerSocket ss = null;
802 DatagramSocket ds = null;
804 ss =
new ServerSocket(port);
805 ss.setReuseAddress(
true);
806 ds =
new DatagramSocket(port);
807 ds.setReuseAddress(
true);
809 }
catch (IOException e) {
818 }
catch (IOException e) {
833 void changeSolrServerPort(
int port) {
834 localSolrServerPort = port;
835 ModuleSettings.setConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_SERVER_PORT, String.valueOf(port));
843 void changeSolrStopPort(
int port) {
844 localSolrStopPort = port;
845 ModuleSettings.setConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_STOP_PORT, String.valueOf(port));
853 synchronized void stop() {
858 }
catch (KeywordSearchModuleException e) {
859 logger.log(Level.WARNING,
"Failed to close core: ", e);
873 logger.log(Level.INFO,
"Stopping Solr 8 server");
874 process =
runLocalSolr8ControlCommand(
new ArrayList<>(Arrays.asList(
"stop",
"-k", KEY,
"-p", Integer.toString(localSolrServerPort))));
877 logger.log(Level.INFO,
"Stopping Solr 4 server");
881 logger.log(Level.INFO,
"Waiting for Solr server to stop");
885 if (curSolrProcess != null) {
886 curSolrProcess.destroy();
887 curSolrProcess = null;
890 }
catch (IOException | InterruptedException ex) {
891 logger.log(Level.WARNING,
"Error while attempting to stop Solr server", ex);
895 if (errorRedirectThread != null) {
896 errorRedirectThread.stopRun();
897 errorRedirectThread = null;
904 logger.log(Level.INFO,
"Finished stopping Solr server");
918 if (isPortAvailable(localSolrServerPort)) {
927 logger.log(Level.INFO,
"Solr server is running");
928 }
catch (SolrServerException ex) {
930 Throwable cause = ex.getRootCause();
935 if (cause instanceof ConnectException || cause instanceof SocketException) {
936 logger.log(Level.INFO,
"Solr server is not running, cause: {0}", cause.getMessage());
939 throw new KeywordSearchModuleException(
940 NbBundle.getMessage(
this.getClass(),
"Server.isRunning.exception.errCheckSolrRunning.msg"), ex);
942 }
catch (SolrException ex) {
944 logger.log(Level.INFO,
"Solr server is not running", ex);
946 }
catch (IOException ex) {
947 throw new KeywordSearchModuleException(
948 NbBundle.getMessage(
this.getClass(),
"Server.isRunning.exception.errCheckSolrRunning.msg2"), ex);
966 void openCoreForCase(Case theCase, Index index)
throws KeywordSearchModuleException {
967 currentCoreLock.writeLock().lock();
969 currentCollection =
openCore(theCase, index);
974 }
catch (NoOpenCoreException ex) {
975 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
978 serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STARTED);
980 currentCoreLock.writeLock().unlock();
989 boolean coreIsOpen() {
990 currentCoreLock.readLock().lock();
992 return (null != currentCollection);
994 currentCoreLock.readLock().unlock();
998 Index getIndexInfo() throws NoOpenCoreException {
999 currentCoreLock.readLock().lock();
1001 if (null == currentCollection) {
1002 throw new NoOpenCoreException();
1004 return currentCollection.getIndexInfo();
1006 currentCoreLock.readLock().unlock();
1010 void closeCore() throws KeywordSearchModuleException {
1011 currentCoreLock.writeLock().lock();
1013 if (null != currentCollection) {
1014 currentCollection.close();
1015 serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STOPPED);
1018 currentCollection = null;
1019 currentCoreLock.writeLock().unlock();
1023 void addDocument(SolrInputDocument doc)
throws KeywordSearchModuleException, NoOpenCoreException {
1024 currentCoreLock.readLock().lock();
1026 if (null == currentCollection) {
1027 throw new NoOpenCoreException();
1029 TimingMetric metric = HealthMonitor.getTimingMetric(
"Solr: Index chunk");
1030 currentCollection.addDocument(doc);
1031 HealthMonitor.submitTimingMetric(metric);
1033 currentCoreLock.readLock().unlock();
1045 @NbBundle.Messages({
1046 "# {0} - colelction name",
"Server.deleteCore.exception.msg=Failed to delete Solr colelction {0}",})
1047 void deleteCollection(String coreName, CaseMetadata metadata)
throws KeywordSearchServiceException, KeywordSearchModuleException {
1049 HttpSolrClient solrServer;
1050 if (metadata.getCaseType() == CaseType.SINGLE_USER_CASE) {
1051 solrServer =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr");
1052 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, solrServer);
1053 if (null != response.getCoreStatus(coreName).get(
"instanceDir")) {
1063 org.apache.solr.client.solrj.request.CoreAdminRequest.unloadCore(coreName,
true,
true, solrServer);
1067 solrServer =
getSolrClient(
"http://" + properties.getHost() +
":" + properties.getPort() +
"/solr");
1068 connectToSolrServer(solrServer);
1070 CollectionAdminRequest.Delete deleteCollectionRequest = CollectionAdminRequest.deleteCollection(coreName);
1071 CollectionAdminResponse response = deleteCollectionRequest.process(solrServer);
1072 if (response.isSuccess()) {
1073 logger.log(Level.INFO,
"Deleted collection {0}", coreName);
1075 logger.log(Level.WARNING,
"Unable to delete collection {0}", coreName);
1078 }
catch (SolrServerException | IOException ex) {
1081 if (!ex.getMessage().equals(
"Already closed")) {
1082 throw new KeywordSearchServiceException(Bundle.Server_deleteCore_exception_msg(coreName), ex);
1098 @NbBundle.Messages({
1099 "Server.exceptionMessage.unableToCreateCollection=Unable to create Solr collection",
1100 "Server.exceptionMessage.unableToBackupCollection=Unable to backup Solr collection",
1101 "Server.exceptionMessage.unableToRestoreCollection=Unable to restore Solr collection",
1103 private Collection
openCore(
Case theCase, Index index)
throws KeywordSearchModuleException {
1105 int numShardsToUse = 1;
1114 }
catch (Exception ex) {
1116 throw new KeywordSearchModuleException(NbBundle.getMessage(
Server.class,
"Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
1120 String collectionName = index.getIndexName();
1127 boolean doRetry =
false;
1132 }
catch (Exception ex) {
1133 if (reTryAttempt >= NUM_COLLECTION_CREATION_RETRIES) {
1134 logger.log(Level.SEVERE,
"Unable to create Solr collection " + collectionName, ex);
1135 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
1137 logger.log(Level.SEVERE,
"Unable to create Solr collection " + collectionName +
". Re-trying...", ex);
1138 Thread.sleep(1000L);
1150 File dataDir =
new File(
new File(index.getIndexPath()).getParent());
1151 if (!dataDir.exists()) {
1158 Path corePropertiesFile = Paths.get(localSolrFolder.toString(),
SOLR, collectionName,
CORE_PROPERTIES);
1159 if (corePropertiesFile.toFile().exists()) {
1161 corePropertiesFile.toFile().delete();
1162 }
catch (Exception ex) {
1163 logger.log(Level.INFO,
"Could not delete pre-existing core.properties prior to opening the core.");
1169 CoreAdminRequest.Create createCoreRequest =
new CoreAdminRequest.Create();
1170 createCoreRequest.setDataDir(dataDir.getAbsolutePath());
1171 createCoreRequest.setCoreName(collectionName);
1172 createCoreRequest.setConfigSet(
"AutopsyConfig");
1173 createCoreRequest.setIsLoadOnStartup(
false);
1174 createCoreRequest.setIsTransient(
true);
1175 localSolrServer.request(createCoreRequest);
1178 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.noIndexDir.msg"));
1183 return new Collection(collectionName, theCase, index);
1185 }
catch (Exception ex) {
1186 logger.log(Level.SEVERE,
"Exception during Solr collection creation.", ex);
1187 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
1201 return solrServerList.size();
1217 private boolean collectionExists(String collectionName)
throws SolrServerException, IOException {
1218 CollectionAdminRequest.List req =
new CollectionAdminRequest.List();
1219 CollectionAdminResponse response = req.process(remoteSolrServer);
1220 List<?> existingCollections = (List<?>) response.getResponse().get(
"collections");
1221 if (existingCollections == null) {
1222 existingCollections =
new ArrayList<>();
1224 return existingCollections.contains(collectionName);
1262 private void createMultiUserCollection(String collectionName,
int numShardsToUse)
throws KeywordSearchModuleException, SolrServerException, IOException {
1269 Integer numShards = numShardsToUse;
1270 logger.log(Level.INFO,
"numShardsToUse: {0}", numShardsToUse);
1271 Integer numNrtReplicas = 1;
1272 Integer numTlogReplicas = 0;
1273 Integer numPullReplicas = 0;
1274 CollectionAdminRequest.Create createCollectionRequest = CollectionAdminRequest.createCollection(collectionName,
"AutopsyConfig", numShards, numNrtReplicas, numTlogReplicas, numPullReplicas);
1276 CollectionAdminResponse createResponse = createCollectionRequest.process(remoteSolrServer);
1277 if (createResponse.isSuccess()) {
1278 logger.log(Level.INFO,
"Collection {0} successfully created.", collectionName);
1280 logger.log(Level.SEVERE,
"Unable to create Solr collection {0}", collectionName);
1281 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToCreateCollection());
1288 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.noIndexDir.msg"));
1292 private void backupCollection(String collectionName, String backupName, String pathToBackupLocation)
throws SolrServerException, IOException, KeywordSearchModuleException {
1293 CollectionAdminRequest.Backup backup = CollectionAdminRequest.backupCollection(collectionName, backupName)
1294 .setLocation(pathToBackupLocation);
1296 CollectionAdminResponse backupResponse = backup.process(remoteSolrServer);
1297 if (backupResponse.isSuccess()) {
1298 logger.log(Level.INFO,
"Collection {0} successfully backep up.", collectionName);
1300 logger.log(Level.SEVERE,
"Unable to back up Solr collection {0}", collectionName);
1301 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToBackupCollection());
1305 private void restoreCollection(String backupName, String restoreCollectionName, String pathToBackupLocation)
throws SolrServerException, IOException, KeywordSearchModuleException {
1307 CollectionAdminRequest.Restore restore = CollectionAdminRequest.restoreCollection(restoreCollectionName, backupName)
1308 .setLocation(pathToBackupLocation);
1310 CollectionAdminResponse restoreResponse = restore.process(remoteSolrServer);
1311 if (restoreResponse.isSuccess()) {
1312 logger.log(Level.INFO,
"Collection {0} successfully resored.", restoreCollectionName);
1314 logger.log(Level.SEVERE,
"Unable to restore Solr collection {0}", restoreCollectionName);
1315 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToRestoreCollection());
1333 private boolean coreIsLoaded(String coreName)
throws SolrServerException, IOException {
1334 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, localSolrServer);
1335 return response.getCoreStatus(coreName).get(
"instanceDir") != null;
1351 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, localSolrServer);
1352 Object dataDirPath = response.getCoreStatus(coreName).get(
"dataDir");
1353 if (null != dataDirPath) {
1354 File indexDir = Paths.get((String) dataDirPath,
"index").toFile();
1355 return indexDir.exists();
1375 Path serverFilePath = Paths.get(caseDirectory,
"solrserver.txt");
1376 if (serverFilePath.toFile().exists()) {
1378 List<String> lines = Files.readAllLines(serverFilePath);
1379 if (lines.isEmpty()) {
1380 logger.log(Level.SEVERE,
"solrserver.txt file does not contain any data");
1381 }
else if (!lines.get(0).contains(
",")) {
1382 logger.log(Level.SEVERE,
"solrserver.txt file is corrupt - could not read host/port from " + lines.get(0));
1384 String[] parts = lines.get(0).split(
",");
1385 if (parts.length != 2) {
1386 logger.log(Level.SEVERE,
"solrserver.txt file is corrupt - could not read host/port from " + lines.get(0));
1391 }
catch (IOException ex) {
1392 logger.log(Level.SEVERE,
"solrserver.txt file could not be read", ex);
1397 List<Index> indexes =
new ArrayList<>();
1399 IndexMetadata indexMetadata =
new IndexMetadata(caseDirectory);
1400 indexes = indexMetadata.getIndexes();
1401 }
catch (IndexMetadata.TextIndexMetadataException ex) {
1402 logger.log(Level.SEVERE,
"Unable to read text index metadata file: " + caseDirectory, ex);
1412 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
1413 if (indexToUse == null) {
1415 logger.log(Level.SEVERE,
"Unable to find index that can be used for case: {0}", caseDirectory);
1424 if (IndexFinder.getCurrentSolrVersion().equals(indexToUse.getSolrVersion())) {
1448 public static void selectSolrServerForCase(Path rootOutputDirectory, Path caseDirectoryPath)
throws KeywordSearchModuleException {
1450 String serverListName =
"solrServerList.txt";
1451 Path serverListPath = Paths.get(rootOutputDirectory.toString(), serverListName);
1452 if (serverListPath.toFile().exists()) {
1457 lines = Files.readAllLines(serverListPath);
1458 }
catch (IOException ex) {
1459 throw new KeywordSearchModuleException(serverListName +
" could not be read", ex);
1463 for (Iterator<String> iterator = lines.iterator(); iterator.hasNext();) {
1464 String line = iterator.next();
1465 if (!line.contains(
",")) {
1470 if (lines.isEmpty()) {
1471 throw new KeywordSearchModuleException(serverListName +
" had no valid server information");
1475 int rnd =
new Random().nextInt(lines.size());
1476 String[] parts = lines.get(rnd).split(
",");
1477 if (parts.length != 2) {
1478 throw new KeywordSearchModuleException(
"Invalid server data: " + lines.get(rnd));
1482 String host = parts[0];
1483 String port = parts[1];
1484 if (host.isEmpty() || port.isEmpty()) {
1485 throw new KeywordSearchModuleException(
"Invalid server data: " + lines.get(rnd));
1489 Path serverFile = Paths.get(caseDirectoryPath.toString(),
"solrserver.txt");
1491 caseDirectoryPath.toFile().mkdirs();
1492 if (!caseDirectoryPath.toFile().exists()) {
1493 throw new KeywordSearchModuleException(
"Case directory " + caseDirectoryPath.toString() +
" does not exist");
1495 Files.write(serverFile, lines.get(rnd).getBytes());
1496 }
catch (IOException ex) {
1497 throw new KeywordSearchModuleException(serverFile.toString() +
" could not be written", ex);
1539 void commit() throws SolrServerException, NoOpenCoreException {
1540 currentCoreLock.readLock().lock();
1542 if (null == currentCollection) {
1543 throw new NoOpenCoreException();
1545 currentCollection.commit();
1547 currentCoreLock.readLock().unlock();
1551 NamedList<Object> request(SolrRequest<?> request)
throws SolrServerException, RemoteSolrException, NoOpenCoreException {
1552 currentCoreLock.readLock().lock();
1554 if (null == currentCollection) {
1555 throw new NoOpenCoreException();
1557 return currentCollection.request(request);
1559 currentCoreLock.readLock().unlock();
1574 currentCoreLock.readLock().lock();
1576 if (null == currentCollection) {
1577 throw new NoOpenCoreException();
1580 return currentCollection.queryNumIndexedFiles();
1581 }
catch (Exception ex) {
1583 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxFiles.exception.msg"), ex);
1586 currentCoreLock.readLock().unlock();
1600 currentCoreLock.readLock().lock();
1602 if (null == currentCollection) {
1603 throw new NoOpenCoreException();
1606 return currentCollection.queryNumIndexedChunks();
1607 }
catch (Exception ex) {
1609 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxChunks.exception.msg"), ex);
1612 currentCoreLock.readLock().unlock();
1626 currentCoreLock.readLock().lock();
1628 if (null == currentCollection) {
1629 throw new NoOpenCoreException();
1632 return currentCollection.queryNumIndexedDocuments();
1633 }
catch (Exception ex) {
1635 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxDocs.exception.msg"), ex);
1638 currentCoreLock.readLock().unlock();
1653 currentCoreLock.readLock().lock();
1655 if (null == currentCollection) {
1656 throw new NoOpenCoreException();
1659 int totalNumChunks = currentCollection.queryTotalNumFileChunks(contentID);
1660 if (totalNumChunks == 0) {
1664 int numIndexedChunks = currentCollection.queryNumIndexedChunks(contentID);
1665 return numIndexedChunks == totalNumChunks;
1666 }
catch (Exception ex) {
1668 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryIsIdxd.exception.msg"), ex);
1672 currentCoreLock.readLock().unlock();
1688 currentCoreLock.readLock().lock();
1690 if (null == currentCollection) {
1691 throw new NoOpenCoreException();
1694 return currentCollection.queryTotalNumFileChunks(fileID);
1695 }
catch (Exception ex) {
1697 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumFileChunks.exception.msg"), ex);
1700 currentCoreLock.readLock().unlock();
1714 public QueryResponse
query(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException, IOException {
1715 currentCoreLock.readLock().lock();
1717 if (null == currentCollection) {
1718 throw new NoOpenCoreException();
1721 return currentCollection.query(sq);
1722 }
catch (Exception ex) {
1724 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1725 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query.exception.msg", sq.getQuery()), ex);
1728 currentCoreLock.readLock().unlock();
1743 public QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws KeywordSearchModuleException, NoOpenCoreException {
1744 currentCoreLock.readLock().lock();
1746 if (null == currentCollection) {
1747 throw new NoOpenCoreException();
1750 return currentCollection.query(sq, method);
1751 }
catch (Exception ex) {
1753 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1754 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query2.exception.msg", sq.getQuery()), ex);
1757 currentCoreLock.readLock().unlock();
1771 public TermsResponse
queryTerms(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException {
1772 currentCoreLock.readLock().lock();
1774 if (null == currentCollection) {
1775 throw new NoOpenCoreException();
1778 return currentCollection.queryTerms(sq);
1779 }
catch (Exception ex) {
1781 logger.log(Level.SEVERE,
"Solr terms query failed: " + sq.getQuery(), ex);
1782 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryTerms.exception.msg", sq.getQuery()), ex);
1785 currentCoreLock.readLock().unlock();
1796 void deleteDataSource(Long dataSourceId)
throws IOException, KeywordSearchModuleException, NoOpenCoreException, SolrServerException {
1798 currentCoreLock.writeLock().lock();
1799 if (null == currentCollection) {
1800 throw new NoOpenCoreException();
1802 currentCollection.deleteDataSource(dataSourceId);
1803 currentCollection.commit();
1805 currentCoreLock.writeLock().unlock();
1817 @NbBundle.Messages({
1818 "Server.getAllTerms.error=Extraction of all unique Solr terms failed:"})
1819 void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws KeywordSearchModuleException, NoOpenCoreException {
1821 currentCoreLock.writeLock().lock();
1822 if (null == currentCollection) {
1823 throw new NoOpenCoreException();
1826 currentCollection.extractAllTermsForDataSource(outputFile, progressPanel);
1827 }
catch (Exception ex) {
1829 logger.log(Level.SEVERE,
"Extraction of all unique Solr terms failed: ", ex);
1830 throw new KeywordSearchModuleException(Bundle.Server_getAllTerms_error(), ex);
1833 currentCoreLock.writeLock().unlock();
1847 currentCoreLock.readLock().lock();
1849 if (null == currentCollection) {
1850 throw new NoOpenCoreException();
1852 return currentCollection.getSolrContent(content.getId(), 0);
1854 currentCoreLock.readLock().unlock();
1870 public String
getSolrContent(
final Content content,
int chunkID)
throws NoOpenCoreException {
1871 currentCoreLock.readLock().lock();
1873 if (null == currentCollection) {
1874 throw new NoOpenCoreException();
1876 return currentCollection.getSolrContent(content.getId(), chunkID);
1878 currentCoreLock.readLock().unlock();
1892 currentCoreLock.readLock().lock();
1894 if (null == currentCollection) {
1895 throw new NoOpenCoreException();
1897 return currentCollection.getSolrContent(objectID, 0);
1899 currentCoreLock.readLock().unlock();
1913 public String
getSolrContent(
final long objectID,
final int chunkID)
throws NoOpenCoreException {
1914 currentCoreLock.readLock().lock();
1916 if (null == currentCollection) {
1917 throw new NoOpenCoreException();
1919 return currentCollection.getSolrContent(objectID, chunkID);
1921 currentCoreLock.readLock().unlock();
1946 CoreAdminRequest.getStatus(null, localSolrServer);
1961 void connectToSolrServer(String host, String port)
throws SolrServerException, IOException {
1962 try (HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr")) {
1963 connectToSolrServer(solrServer);
1978 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1979 CollectionAdminResponse statusResponse = statusRequest.process(solrServer);
1980 int statusCode = Integer.valueOf(((NamedList) statusResponse.getResponse().get(
"responseHeader")).
get(
"status").toString());
1981 if (statusCode != 0) {
1982 logger.log(Level.WARNING,
"Could not connect to Solr server ");
1984 logger.log(Level.INFO,
"Connected to Solr server ");
1989 private List<String>
getSolrServerList(String host, String port)
throws KeywordSearchModuleException {
1990 HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr");
1994 private List<String>
getSolrServerList(HttpSolrClient solrServer)
throws KeywordSearchModuleException {
1997 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1998 CollectionAdminResponse statusResponse;
2000 statusResponse = statusRequest.process(solrServer);
2001 }
catch (RemoteSolrException ex) {
2003 return Collections.emptyList();
2006 if (statusResponse == null) {
2007 return Collections.emptyList();
2010 NamedList<?> error = (NamedList) statusResponse.getResponse().get(
"error");
2011 if (error != null) {
2012 return Collections.emptyList();
2015 NamedList<?> cluster = (NamedList) statusResponse.getResponse().get(
"cluster");
2016 @SuppressWarnings(
"unchecked")
2017 List<String> liveNodes = (ArrayList) cluster.get(
"live_nodes");
2019 if (liveNodes != null) {
2020 liveNodes = liveNodes.stream()
2021 .map(serverStr -> serverStr.endsWith(
"_solr")
2022 ? serverStr.substring(0, serverStr.length() -
"_solr".length())
2024 .collect(Collectors.toList());
2027 }
catch (Exception ex) {
2029 throw new KeywordSearchModuleException(
2030 NbBundle.getMessage(
this.getClass(),
"Server.serverList.exception.msg", solrServer.getBaseURL()));
2037 private final String name;
2041 private final Index textIndex;
2047 private HttpSolrClient queryClient;
2048 private SolrClient indexingClient;
2050 private final int maxBufferSize;
2051 private final List<SolrInputDocument> buffer;
2052 private final Object bufferLock;
2057 private static final int MAX_NUM_CONSECUTIVE_FAILURES = 5;
2058 private AtomicInteger numConsecutiveFailures =
new AtomicInteger(0);
2059 private AtomicBoolean skipIndexing =
new AtomicBoolean(
false);
2061 private final ScheduledThreadPoolExecutor periodicTasksExecutor;
2062 private static final long PERIODIC_BATCH_SEND_INTERVAL_MINUTES = 10;
2063 private static final int NUM_BATCH_UPDATE_RETRIES = 10;
2064 private static final long SLEEP_BETWEEN_RETRIES_MS = 10000;
2066 private Collection(String name,
Case theCase, Index index)
throws TimeoutException, InterruptedException, KeywordSearchModuleException {
2069 this.textIndex = index;
2070 bufferLock =
new Object();
2074 queryClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2075 indexingClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2081 if (IndexFinder.getCurrentSolrVersion().equals(index.getSolrVersion())) {
2083 indexingClient =
getCloudSolrClient(properties.getHost(), properties.getPort(), name);
2091 logger.log(Level.INFO,
"Using Solr document queue size = {0}", maxBufferSize);
2092 buffer =
new ArrayList<>(maxBufferSize);
2093 periodicTasksExecutor =
new ScheduledThreadPoolExecutor(1,
new ThreadFactoryBuilder().setNameFormat(
"periodic-batched-document-task-%d").build());
2094 periodicTasksExecutor.scheduleWithFixedDelay(
new SendBatchedDocumentsTask(), PERIODIC_BATCH_SEND_INTERVAL_MINUTES, PERIODIC_BATCH_SEND_INTERVAL_MINUTES, TimeUnit.MINUTES);
2108 if (skipIndexing.get()) {
2112 List<SolrInputDocument> clone;
2113 synchronized (bufferLock) {
2115 if (buffer.isEmpty()) {
2121 clone = buffer.stream().collect(toList());
2127 sendBufferedDocs(clone);
2128 }
catch (KeywordSearchModuleException ex) {
2129 logger.log(Level.SEVERE,
"Periodic batched document update failed", ex);
2143 private Index getIndexInfo() {
2144 return this.textIndex;
2147 private QueryResponse
query(SolrQuery sq)
throws SolrServerException, IOException {
2148 return queryClient.query(sq);
2151 private NamedList<Object> request(SolrRequest<?> request)
throws SolrServerException, RemoteSolrException {
2153 return queryClient.request(request);
2154 }
catch (Exception e) {
2156 logger.log(Level.WARNING,
"Could not issue Solr request. ", e);
2157 throw new SolrServerException(
2158 NbBundle.getMessage(
this.getClass(),
"Server.request.exception.exception.msg"), e);
2163 private QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws SolrServerException, IOException {
2164 return queryClient.query(sq, method);
2167 private TermsResponse
queryTerms(SolrQuery sq)
throws SolrServerException, IOException {
2168 QueryResponse qres = queryClient.query(sq);
2169 return qres.getTermsResponse();
2172 private void commit() throws SolrServerException {
2173 List<SolrInputDocument> clone;
2174 synchronized (bufferLock) {
2177 clone = buffer.stream().collect(toList());
2182 sendBufferedDocs(clone);
2183 }
catch (KeywordSearchModuleException ex) {
2184 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), ex);
2189 indexingClient.commit(
true,
true);
2190 }
catch (Exception e) {
2192 logger.log(Level.WARNING,
"Could not commit index. ", e);
2193 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), e);
2197 private void deleteDataSource(Long dsObjId)
throws IOException, SolrServerException {
2198 String dataSourceId = Long.toString(dsObjId);
2199 String deleteQuery =
"image_id:" + dataSourceId;
2201 queryClient.deleteByQuery(deleteQuery);
2215 @NbBundle.Messages({
2216 "# {0} - Number of extracted terms",
2217 "ExtractAllTermsReport.numberExtractedTerms=Extracted {0} terms..."
2219 private void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws IOException, SolrServerException, NoCurrentCaseException, KeywordSearchModuleException {
2221 Files.deleteIfExists(outputFile);
2222 OpenOption[] options =
new OpenOption[] { java.nio.file.StandardOpenOption.CREATE, java.nio.file.StandardOpenOption.APPEND };
2225 int termStep = 1000;
2226 long numExtractedTerms = 0;
2227 String firstTerm =
"";
2229 SolrQuery
query =
new SolrQuery();
2230 query.setRequestHandler(
"/terms");
2231 query.setTerms(
true);
2232 query.setTermsLimit(termStep);
2233 query.setTermsLower(firstTerm);
2234 query.setTermsLowerInclusive(
false);
2239 query.setTermsSortString(
"index");
2242 query.addTermsField(Server.Schema.TEXT.toString());
2243 query.setTermsMinCount(0);
2248 QueryRequest request =
new QueryRequest(query);
2249 TermsResponse response = request.process(queryClient).getTermsResponse();
2250 List<Term> terms = response.getTerms(Server.Schema.TEXT.toString());
2252 if (terms == null || terms.isEmpty()) {
2253 numExtractedTerms += terms.size();
2254 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2259 firstTerm = terms.get(terms.size()-1).getTerm();
2261 List<String> listTerms = terms.stream().map(Term::getTerm).collect(Collectors.toList());
2262 Files.write(outputFile, listTerms, options);
2264 numExtractedTerms += termStep;
2265 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2277 void addDocument(SolrInputDocument doc)
throws KeywordSearchModuleException {
2279 if (skipIndexing.get()) {
2283 List<SolrInputDocument> clone;
2284 synchronized (bufferLock) {
2287 if (buffer.size() < maxBufferSize) {
2293 clone = buffer.stream().collect(toList());
2298 sendBufferedDocs(clone);
2308 @NbBundle.Messages({
2309 "Collection.unableToIndexData.error=Unable to add data to text index. All future text indexing for the current case will be skipped.",
2312 private void sendBufferedDocs(List<SolrInputDocument> docBuffer)
throws KeywordSearchModuleException {
2314 if (docBuffer.isEmpty()) {
2319 boolean success =
true;
2320 for (
int reTryAttempt = 0; reTryAttempt < NUM_BATCH_UPDATE_RETRIES; reTryAttempt++) {
2323 indexingClient.add(docBuffer);
2324 }
catch (Exception ex) {
2326 if (reTryAttempt < NUM_BATCH_UPDATE_RETRIES - 1) {
2327 logger.log(Level.WARNING,
"Unable to send document batch to Solr. Re-trying...", ex);
2329 Thread.sleep(SLEEP_BETWEEN_RETRIES_MS);
2330 }
catch (InterruptedException ignore) {
2331 throw new KeywordSearchModuleException(
2332 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2337 numConsecutiveFailures.set(0);
2338 if (reTryAttempt > 0) {
2339 logger.log(Level.INFO,
"Batch update suceeded after {0} re-try", reTryAttempt);
2345 logger.log(Level.SEVERE,
"Unable to send document batch to Solr. All re-try attempts failed!");
2346 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2347 }
catch (Exception ex) {
2349 numConsecutiveFailures.incrementAndGet();
2350 logger.log(Level.SEVERE,
"Could not add batched documents to index", ex);
2353 MessageNotifyUtil.Notify.error(
2354 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2355 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2356 throw new KeywordSearchModuleException(
2357 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2359 if (numConsecutiveFailures.get() >= MAX_NUM_CONSECUTIVE_FAILURES) {
2361 skipIndexing.set(
true);
2362 logger.log(Level.SEVERE,
"Unable to add data to text index. All future text indexing for the current case will be skipped!");
2365 MessageNotifyUtil.Notify.error(
2366 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2367 Bundle.Collection_unableToIndexData_error());
2368 if (RuntimeProperties.runningWithGUI()) {
2369 MessageNotifyUtil.Message.error(Bundle.Collection_unableToIndexData_error());
2387 final SolrQuery q =
new SolrQuery();
2389 String filterQuery = Schema.ID.toString() +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2391 filterQuery = filterQuery + Server.CHUNK_ID_SEPARATOR + chunkID;
2393 q.addFilterQuery(filterQuery);
2394 q.setFields(Schema.TEXT.toString());
2397 SolrDocumentList solrDocuments = queryClient.query(q).getResults();
2399 if (!solrDocuments.isEmpty()) {
2400 SolrDocument solrDocument = solrDocuments.get(0);
2401 if (solrDocument != null) {
2402 java.util.Collection<Object> fieldValues = solrDocument.getFieldValues(Schema.TEXT.toString());
2403 if (fieldValues.size() == 1)
2405 return fieldValues.toArray(
new String[0])[0];
2409 return fieldValues.toArray(
new String[0])[1];
2413 }
catch (Exception ex) {
2415 logger.log(Level.SEVERE,
"Error getting content from Solr. Solr document id " + contentID +
", chunk id " + chunkID +
", query: " + filterQuery, ex);
2422 synchronized void close() throws KeywordSearchModuleException {
2427 ThreadUtils.shutDownTaskExecutor(periodicTasksExecutor);
2434 CoreAdminRequest.unloadCore(this.name, localSolrServer);
2435 }
catch (Exception ex) {
2437 throw new KeywordSearchModuleException(
2438 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg"), ex);
2441 queryClient.close();
2443 indexingClient.close();
2444 indexingClient = null;
2445 }
catch (IOException ex) {
2446 throw new KeywordSearchModuleException(
2447 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg2"), ex);
2475 SolrQuery q =
new SolrQuery(Server.Schema.ID +
":*" + Server.CHUNK_ID_SEPARATOR +
"*");
2477 int numChunks = (int)
query(q).getResults().getNumFound();
2492 SolrQuery q =
new SolrQuery(
"*:*");
2494 return (
int)
query(q).getResults().getNumFound();
2506 private boolean queryIsIndexed(
long contentID)
throws SolrServerException, IOException {
2507 String
id = KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2508 SolrQuery q =
new SolrQuery(
"*:*");
2509 q.addFilterQuery(Server.Schema.ID.toString() +
":" + id);
2512 return (
int)
query(q).getResults().getNumFound() != 0;
2529 private int queryTotalNumFileChunks(
long contentID)
throws SolrServerException, IOException {
2530 final SolrQuery q =
new SolrQuery();
2532 String filterQuery = Schema.ID.toString() +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2533 q.addFilterQuery(filterQuery);
2534 q.setFields(Schema.NUM_CHUNKS.toString());
2536 SolrDocumentList solrDocuments =
query(q).getResults();
2537 if (!solrDocuments.isEmpty()) {
2538 SolrDocument solrDocument = solrDocuments.get(0);
2539 if (solrDocument != null && !solrDocument.isEmpty()) {
2540 Object fieldValue = solrDocument.getFieldValue(Schema.NUM_CHUNKS.toString());
2541 return (Integer)fieldValue;
2544 }
catch (Exception ex) {
2546 logger.log(Level.SEVERE,
"Error getting content from Solr. Solr document id " + contentID +
", query: " + filterQuery, ex);
2565 SolrQuery q =
new SolrQuery(Server.Schema.ID +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID)) + Server.CHUNK_ID_SEPARATOR +
"*");
2567 int numChunks = (int)
query(q).getResults().getNumFound();
2572 class ServerAction
extends AbstractAction {
2574 private static final long serialVersionUID = 1L;
2577 public void actionPerformed(ActionEvent e) {
2578 logger.log(Level.INFO, e.paramString().trim());
2585 class SolrServerNoPortException
extends SocketException {
2587 private static final long serialVersionUID = 1L;
2592 private final int port;
2594 SolrServerNoPortException(
int port) {
2595 super(NbBundle.getMessage(Server.class,
"Server.solrServerNoPortException.msg", port,
2596 Server.PROPERTIES_CURRENT_SERVER_PORT));
2600 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)