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)
399 if (!defaultCollectionName.isEmpty()) {
400 client.setDefaultCollection(defaultCollectionName);
407 public void finalize() throws java.lang.Throwable {
413 serverAction.addPropertyChangeListener(l);
416 int getLocalSolrServerPort() {
420 int getLocalSolrStopPort() {
431 volatile boolean doRun =
true;
434 this.stream = stream;
436 final String log = Places.getUserDirectory().getAbsolutePath()
437 +
File.separator +
"var" +
File.separator +
"log"
438 +
File.separator +
"solr.log." + type;
439 File outputFile =
new File(log.concat(
".0"));
440 File first =
new File(log.concat(
".1"));
441 File second =
new File(log.concat(
".2"));
442 if (second.exists()) {
445 if (first.exists()) {
446 first.renameTo(second);
448 if (outputFile.
exists()) {
449 outputFile.renameTo(first);
451 outputFile.createNewFile();
453 out =
new FileOutputStream(outputFile);
455 }
catch (Exception ex) {
456 logger.log(Level.WARNING,
"Failed to create solr log file", ex);
467 try (InputStreamReader isr =
new InputStreamReader(stream);
468 BufferedReader br =
new BufferedReader(isr);
470 BufferedWriter bw =
new BufferedWriter(osw);) {
473 while (doRun && (line = br.readLine()) != null) {
482 }
catch (IOException ex) {
483 logger.log(Level.SEVERE,
"Error redirecting Solr output stream", ex);
501 File solr8Folder = InstalledFileLocator.getDefault().locate(
"solr",
Server.class.getPackage().getName(),
false);
504 solr8CmdPath = Paths.get(solr8Folder.getAbsolutePath(),
"bin",
"autopsy-solr.cmd");
506 solr8CmdPath = Paths.get(solr8Folder.getAbsolutePath(),
"bin",
"autopsy-solr");
510 List<String> commandLine =
new ArrayList<>();
511 commandLine.add(solr8CmdPath.toString());
512 commandLine.addAll(solrArguments);
514 ProcessBuilder solrProcessBuilder =
new ProcessBuilder(commandLine);
515 solrProcessBuilder.directory(solr8Folder);
518 Path solrStdoutPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stdout");
519 solrProcessBuilder.redirectOutput(solrStdoutPath.toFile());
521 Path solrStderrPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stderr");
522 solrProcessBuilder.redirectError(solrStderrPath.toFile());
525 String jreFolderPath =
new File(javaPath).getParentFile().getParentFile().getAbsolutePath();
527 solrProcessBuilder.environment().put(
"SOLR_JAVA_HOME", jreFolderPath);
528 solrProcessBuilder.environment().put(
"SOLR_HOME", solr8Home.toString());
529 solrProcessBuilder.environment().put(
"STOP_KEY", KEY);
530 solrProcessBuilder.environment().put(
"SOLR_JAVA_MEM", MAX_SOLR_MEM_MB_PAR);
531 logger.log(Level.INFO,
"Setting Solr 8 directory: {0}", solr8Folder.
toString());
532 logger.log(Level.INFO,
"Running Solr 8 command: {0} from {1}",
new Object[]{solrProcessBuilder.command(), solr8Folder.toString()});
533 Process process = solrProcessBuilder.start();
534 logger.log(Level.INFO,
"Finished running Solr 8 command");
549 File solr4Folder = InstalledFileLocator.getDefault().locate(
"solr4",
Server.class.getPackage().getName(),
false);
551 List<String> commandLine =
new ArrayList<>();
552 commandLine.add(javaPath);
553 commandLine.add(MAX_SOLR_MEM_MB_PAR);
554 commandLine.add(
"-DSTOP.PORT=" + localSolrStopPort);
555 commandLine.add(
"-Djetty.port=" + localSolrServerPort);
556 commandLine.add(
"-DSTOP.KEY=" + KEY);
557 commandLine.add(
"-jar");
558 commandLine.add(
"start.jar");
560 commandLine.addAll(solrArguments);
562 ProcessBuilder solrProcessBuilder =
new ProcessBuilder(commandLine);
563 solrProcessBuilder.directory(solr4Folder);
566 Path solrStdoutPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stdout");
567 solrProcessBuilder.redirectOutput(solrStdoutPath.toFile());
569 Path solrStderrPath = Paths.get(Places.getUserDirectory().getAbsolutePath(),
"var",
"log",
"solr.log.stderr");
570 solrProcessBuilder.redirectError(solrStderrPath.toFile());
572 logger.log(Level.INFO,
"Running Solr 4 command: {0}", solrProcessBuilder.command());
573 Process process = solrProcessBuilder.start();
574 logger.log(Level.INFO,
"Finished running Solr 4 command");
583 List<Long> getSolrPIDs() {
584 List<Long> pids =
new ArrayList<>();
587 final String pidsQuery =
"-DSTOP.KEY=" + KEY +
"%start.jar";
590 if (pidsArr != null) {
591 for (
int i = 0; i < pidsArr.length; ++i) {
592 pids.add(pidsArr[i]);
604 List<Long> solrPids = getSolrPIDs();
605 for (
long pid : solrPids) {
606 logger.log(Level.INFO,
"Trying to kill old Solr process, PID: {0}", pid);
607 PlatformUtil.killProcess(pid);
611 void start() throws KeywordSearchModuleException, SolrServerNoPortException, SolrServerException {
612 startLocalSolr(SOLR_VERSION.SOLR8);
616 "# {0} - indexVersion",
617 "Server_configureSolrConnection_illegalSolrVersion=The solr version in the case: {0}, is not supported."
625 if (!IndexFinder.getCurrentSolrVersion().equals(index.getSolrVersion())) {
632 if (!this.isLocalSolrRunning()) {
633 logger.log(Level.SEVERE,
"Local Solr server is not running");
641 connectToSolrServer(remoteSolrServer);
643 }
catch (SolrServerException | IOException ex) {
666 if (properties.
host.isEmpty() || properties.
port.isEmpty()) {
667 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.connectionInfoMissing.exception.msg", index.getSolrVersion()));
669 String solrUrl =
"http://" + properties.
host +
":" + properties.
port +
"/solr";
671 if (!name.isEmpty()) {
672 solrUrl = solrUrl +
"/" + name;
685 "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.",})
686 synchronized void startLocalSolr(SOLR_VERSION version)
throws KeywordSearchModuleException, SolrServerNoPortException, SolrServerException {
688 logger.log(Level.INFO,
"Starting local Solr " + version +
" server");
689 if (version == SOLR_VERSION.SOLR8) {
690 localSolrFolder = InstalledFileLocator.getDefault().locate(
"solr", Server.class.getPackage().getName(),
false);
692 throw new KeywordSearchModuleException(Bundle.Server_configureSolrConnection_illegalSolrVersion(version.name()));
695 if (isLocalSolrRunning()) {
696 if (localServerVersion.equals(version)) {
698 logger.log(Level.INFO,
"Local Solr " + version +
" server is already running");
707 localServerVersion = version;
709 if (!isPortAvailable(localSolrServerPort)) {
713 final List<Long> pids = this.getSolrPIDs();
717 if (pids.isEmpty()) {
718 throw new SolrServerNoPortException(localSolrServerPort);
727 if (!isPortAvailable(localSolrServerPort)) {
728 throw new SolrServerNoPortException(localSolrServerPort);
730 if (!isPortAvailable(localSolrStopPort)) {
731 throw new SolrServerNoPortException(localSolrStopPort);
735 if (isPortAvailable(localSolrServerPort)) {
736 logger.log(Level.INFO,
"Port [{0}] available, starting Solr", localSolrServerPort);
738 if (version == SOLR_VERSION.SOLR8) {
739 logger.log(Level.INFO,
"Starting Solr 8 server");
741 Integer.toString(localSolrServerPort))));
744 logger.log(Level.INFO,
"Starting Solr 4 server");
746 Arrays.asList(
"-Dbootstrap_confdir=../solr/configsets/AutopsyConfig/conf",
747 "-Dcollection.configName=AutopsyConfig")));
752 if (isLocalSolrRunning()) {
753 final List<Long> pids = this.getSolrPIDs();
754 logger.log(Level.INFO,
"New Solr process PID: {0}", pids);
761 TimeUnit.SECONDS.sleep(EMBEDDED_SERVER_RETRY_WAIT_SEC);
762 }
catch (InterruptedException ex) {
763 logger.log(Level.WARNING,
"Timer interrupted");
769 logger.log(Level.WARNING,
"Local Solr server failed to respond to status requests.");
770 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
773 MessageNotifyUtil.Notify.error(
774 NbBundle.getMessage(
this.getClass(),
"Installer.errorInitKsmMsg"),
775 Bundle.Server_status_failed_msg());
778 }
catch (SecurityException ex) {
779 throw new KeywordSearchModuleException(
780 NbBundle.getMessage(
this.getClass(),
"Server.start.exception.cantStartSolr.msg"), ex);
781 }
catch (IOException ex) {
782 throw new KeywordSearchModuleException(
783 NbBundle.getMessage(
this.getClass(),
"Server.start.exception.cantStartSolr.msg2"), ex);
794 static boolean isPortAvailable(
int port) {
796 if (port < 1 || port > 65535) {
797 throw new IllegalArgumentException(
"Invalid start port: " + port);
800 ServerSocket ss = null;
801 DatagramSocket ds = null;
803 ss =
new ServerSocket(port);
804 ss.setReuseAddress(
true);
805 ds =
new DatagramSocket(port);
806 ds.setReuseAddress(
true);
808 }
catch (IOException e) {
817 }
catch (IOException e) {
832 void changeSolrServerPort(
int port) {
833 localSolrServerPort = port;
834 ModuleSettings.setConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_SERVER_PORT, String.valueOf(port));
842 void changeSolrStopPort(
int port) {
843 localSolrStopPort = port;
844 ModuleSettings.setConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_STOP_PORT, String.valueOf(port));
852 synchronized void stop() {
857 }
catch (KeywordSearchModuleException e) {
858 logger.log(Level.WARNING,
"Failed to close core: ", e);
872 logger.log(Level.INFO,
"Stopping Solr 8 server");
873 process =
runLocalSolr8ControlCommand(
new ArrayList<>(Arrays.asList(
"stop",
"-k", KEY,
"-p", Integer.toString(localSolrServerPort))));
876 logger.log(Level.INFO,
"Stopping Solr 4 server");
880 logger.log(Level.INFO,
"Waiting for Solr server to stop");
884 if (curSolrProcess != null) {
885 curSolrProcess.destroy();
886 curSolrProcess = null;
889 }
catch (IOException | InterruptedException ex) {
890 logger.log(Level.WARNING,
"Error while attempting to stop Solr server", ex);
894 if (errorRedirectThread != null) {
895 errorRedirectThread.stopRun();
896 errorRedirectThread = null;
903 logger.log(Level.INFO,
"Finished stopping Solr server");
917 if (isPortAvailable(localSolrServerPort)) {
926 logger.log(Level.INFO,
"Solr server is running");
927 }
catch (SolrServerException ex) {
929 Throwable cause = ex.getRootCause();
934 if (cause instanceof ConnectException || cause instanceof SocketException) {
935 logger.log(Level.INFO,
"Solr server is not running, cause: {0}", cause.getMessage());
938 throw new KeywordSearchModuleException(
939 NbBundle.getMessage(
this.getClass(),
"Server.isRunning.exception.errCheckSolrRunning.msg"), ex);
941 }
catch (SolrException ex) {
943 logger.log(Level.INFO,
"Solr server is not running", ex);
945 }
catch (IOException ex) {
946 throw new KeywordSearchModuleException(
947 NbBundle.getMessage(
this.getClass(),
"Server.isRunning.exception.errCheckSolrRunning.msg2"), ex);
965 void openCoreForCase(Case theCase, Index index)
throws KeywordSearchModuleException {
966 currentCoreLock.writeLock().lock();
968 currentCollection =
openCore(theCase, index);
973 }
catch (NoOpenCoreException ex) {
974 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
977 serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STARTED);
979 currentCoreLock.writeLock().unlock();
988 boolean coreIsOpen() {
989 currentCoreLock.readLock().lock();
991 return (null != currentCollection);
993 currentCoreLock.readLock().unlock();
997 Index getIndexInfo() throws NoOpenCoreException {
998 currentCoreLock.readLock().lock();
1000 if (null == currentCollection) {
1001 throw new NoOpenCoreException();
1003 return currentCollection.getIndexInfo();
1005 currentCoreLock.readLock().unlock();
1009 void closeCore() throws KeywordSearchModuleException {
1010 currentCoreLock.writeLock().lock();
1012 if (null != currentCollection) {
1013 currentCollection.close();
1014 serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STOPPED);
1017 currentCollection = null;
1018 currentCoreLock.writeLock().unlock();
1022 void addDocument(SolrInputDocument doc)
throws KeywordSearchModuleException, NoOpenCoreException {
1023 currentCoreLock.readLock().lock();
1025 if (null == currentCollection) {
1026 throw new NoOpenCoreException();
1028 TimingMetric metric = HealthMonitor.getTimingMetric(
"Solr: Index chunk");
1029 currentCollection.addDocument(doc);
1030 HealthMonitor.submitTimingMetric(metric);
1032 currentCoreLock.readLock().unlock();
1044 @NbBundle.Messages({
1045 "# {0} - colelction name",
"Server.deleteCore.exception.msg=Failed to delete Solr colelction {0}",})
1046 void deleteCollection(String coreName, CaseMetadata metadata)
throws KeywordSearchServiceException, KeywordSearchModuleException {
1048 HttpSolrClient solrServer;
1049 if (metadata.getCaseType() == CaseType.SINGLE_USER_CASE) {
1050 solrServer =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr");
1051 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, solrServer);
1052 if (null != response.getCoreStatus(coreName).get(
"instanceDir")) {
1062 org.apache.solr.client.solrj.request.CoreAdminRequest.unloadCore(coreName,
true,
true, solrServer);
1066 solrServer =
getSolrClient(
"http://" + properties.getHost() +
":" + properties.getPort() +
"/solr");
1067 connectToSolrServer(solrServer);
1069 CollectionAdminRequest.Delete deleteCollectionRequest = CollectionAdminRequest.deleteCollection(coreName);
1070 CollectionAdminResponse response = deleteCollectionRequest.process(solrServer);
1071 if (response.isSuccess()) {
1072 logger.log(Level.INFO,
"Deleted collection {0}", coreName);
1074 logger.log(Level.WARNING,
"Unable to delete collection {0}", coreName);
1077 }
catch (SolrServerException | IOException ex) {
1080 if (!ex.getMessage().equals(
"Already closed")) {
1081 throw new KeywordSearchServiceException(Bundle.Server_deleteCore_exception_msg(coreName), ex);
1097 @NbBundle.Messages({
1098 "Server.exceptionMessage.unableToCreateCollection=Unable to create Solr collection",
1099 "Server.exceptionMessage.unableToBackupCollection=Unable to backup Solr collection",
1100 "Server.exceptionMessage.unableToRestoreCollection=Unable to restore Solr collection",
1102 private Collection
openCore(
Case theCase, Index index)
throws KeywordSearchModuleException {
1104 int numShardsToUse = 1;
1113 }
catch (Exception ex) {
1115 throw new KeywordSearchModuleException(NbBundle.getMessage(
Server.class,
"Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
1119 String collectionName = index.getIndexName();
1126 boolean doRetry =
false;
1131 }
catch (Exception ex) {
1132 if (reTryAttempt >= NUM_COLLECTION_CREATION_RETRIES) {
1133 logger.log(Level.SEVERE,
"Unable to create Solr collection " + collectionName, ex);
1134 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
1136 logger.log(Level.SEVERE,
"Unable to create Solr collection " + collectionName +
". Re-trying...", ex);
1137 Thread.sleep(1000L);
1149 File dataDir =
new File(
new File(index.getIndexPath()).getParent());
1158 if (corePropertiesFile.toFile().exists()) {
1160 corePropertiesFile.toFile().delete();
1161 }
catch (Exception ex) {
1162 logger.log(Level.INFO,
"Could not delete pre-existing core.properties prior to opening the core.");
1168 CoreAdminRequest.Create createCoreRequest =
new CoreAdminRequest.Create();
1169 createCoreRequest.setDataDir(dataDir.getAbsolutePath());
1170 createCoreRequest.setCoreName(collectionName);
1171 createCoreRequest.setConfigSet(
"AutopsyConfig");
1172 createCoreRequest.setIsLoadOnStartup(
false);
1173 createCoreRequest.setIsTransient(
true);
1174 localSolrServer.request(createCoreRequest);
1177 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.noIndexDir.msg"));
1182 return new Collection(collectionName, theCase, index);
1184 }
catch (Exception ex) {
1185 logger.log(Level.SEVERE,
"Exception during Solr collection creation.", ex);
1186 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.cantOpen.msg"), ex);
1200 return solrServerList.size();
1216 private boolean collectionExists(String collectionName)
throws SolrServerException, IOException {
1217 CollectionAdminRequest.List req =
new CollectionAdminRequest.List();
1218 CollectionAdminResponse response = req.process(remoteSolrServer);
1219 List<?> existingCollections = (List<?>) response.getResponse().get(
"collections");
1220 if (existingCollections == null) {
1221 existingCollections =
new ArrayList<>();
1223 return existingCollections.contains(collectionName);
1261 private void createMultiUserCollection(String collectionName,
int numShardsToUse)
throws KeywordSearchModuleException, SolrServerException, IOException {
1268 Integer numShards = numShardsToUse;
1269 logger.log(Level.INFO,
"numShardsToUse: {0}", numShardsToUse);
1270 Integer numNrtReplicas = 1;
1271 Integer numTlogReplicas = 0;
1272 Integer numPullReplicas = 0;
1273 CollectionAdminRequest.Create createCollectionRequest = CollectionAdminRequest.createCollection(collectionName,
"AutopsyConfig", numShards, numNrtReplicas, numTlogReplicas, numPullReplicas);
1275 CollectionAdminResponse createResponse = createCollectionRequest.process(remoteSolrServer);
1276 if (createResponse.isSuccess()) {
1277 logger.log(Level.INFO,
"Collection {0} successfully created.", collectionName);
1279 logger.log(Level.SEVERE,
"Unable to create Solr collection {0}", collectionName);
1280 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToCreateCollection());
1287 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.openCore.exception.noIndexDir.msg"));
1291 private void backupCollection(String collectionName, String backupName, String pathToBackupLocation)
throws SolrServerException, IOException, KeywordSearchModuleException {
1292 CollectionAdminRequest.Backup backup = CollectionAdminRequest.backupCollection(collectionName, backupName)
1293 .setLocation(pathToBackupLocation);
1295 CollectionAdminResponse backupResponse = backup.process(remoteSolrServer);
1296 if (backupResponse.isSuccess()) {
1297 logger.log(Level.INFO,
"Collection {0} successfully backep up.", collectionName);
1299 logger.log(Level.SEVERE,
"Unable to back up Solr collection {0}", collectionName);
1300 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToBackupCollection());
1304 private void restoreCollection(String backupName, String restoreCollectionName, String pathToBackupLocation)
throws SolrServerException, IOException, KeywordSearchModuleException {
1306 CollectionAdminRequest.Restore restore = CollectionAdminRequest.restoreCollection(restoreCollectionName, backupName)
1307 .setLocation(pathToBackupLocation);
1309 CollectionAdminResponse restoreResponse = restore.process(remoteSolrServer);
1310 if (restoreResponse.isSuccess()) {
1311 logger.log(Level.INFO,
"Collection {0} successfully resored.", restoreCollectionName);
1313 logger.log(Level.SEVERE,
"Unable to restore Solr collection {0}", restoreCollectionName);
1314 throw new KeywordSearchModuleException(Bundle.Server_exceptionMessage_unableToRestoreCollection());
1332 private boolean coreIsLoaded(String coreName)
throws SolrServerException, IOException {
1333 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, localSolrServer);
1334 return response.getCoreStatus(coreName).get(
"instanceDir") != null;
1350 CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, localSolrServer);
1351 Object dataDirPath = response.getCoreStatus(coreName).get(
"dataDir");
1352 if (null != dataDirPath) {
1353 File indexDir = Paths.get((String) dataDirPath,
"index").toFile();
1354 return indexDir.
exists();
1374 Path serverFilePath = Paths.get(caseDirectory,
"solrserver.txt");
1375 if (serverFilePath.toFile().exists()) {
1377 List<String> lines = Files.readAllLines(serverFilePath);
1378 if (lines.isEmpty()) {
1379 logger.log(Level.SEVERE,
"solrserver.txt file does not contain any data");
1380 }
else if (!lines.get(0).contains(
",")) {
1381 logger.log(Level.SEVERE,
"solrserver.txt file is corrupt - could not read host/port from " + lines.get(0));
1383 String[] parts = lines.get(0).split(
",");
1384 if (parts.length != 2) {
1385 logger.log(Level.SEVERE,
"solrserver.txt file is corrupt - could not read host/port from " + lines.get(0));
1390 }
catch (IOException ex) {
1391 logger.log(Level.SEVERE,
"solrserver.txt file could not be read", ex);
1396 List<Index> indexes =
new ArrayList<>();
1398 IndexMetadata indexMetadata =
new IndexMetadata(caseDirectory);
1399 indexes = indexMetadata.getIndexes();
1400 }
catch (IndexMetadata.TextIndexMetadataException ex) {
1401 logger.log(Level.SEVERE,
"Unable to read text index metadata file: " + caseDirectory, ex);
1411 Index indexToUse = IndexFinder.identifyIndexToUse(indexes);
1412 if (indexToUse == null) {
1414 logger.log(Level.SEVERE,
"Unable to find index that can be used for case: {0}", caseDirectory);
1423 if (IndexFinder.getCurrentSolrVersion().equals(indexToUse.getSolrVersion())) {
1447 public static void selectSolrServerForCase(Path rootOutputDirectory, Path caseDirectoryPath)
throws KeywordSearchModuleException {
1449 String serverListName =
"solrServerList.txt";
1450 Path serverListPath = Paths.get(rootOutputDirectory.toString(), serverListName);
1451 if (serverListPath.toFile().exists()) {
1456 lines = Files.readAllLines(serverListPath);
1457 }
catch (IOException ex) {
1458 throw new KeywordSearchModuleException(serverListName +
" could not be read", ex);
1462 for (Iterator<String> iterator = lines.iterator(); iterator.hasNext();) {
1463 String line = iterator.next();
1464 if (!line.contains(
",")) {
1469 if (lines.isEmpty()) {
1470 throw new KeywordSearchModuleException(serverListName +
" had no valid server information");
1474 int rnd =
new Random().nextInt(lines.size());
1475 String[] parts = lines.get(rnd).split(
",");
1476 if (parts.length != 2) {
1477 throw new KeywordSearchModuleException(
"Invalid server data: " + lines.get(rnd));
1481 String host = parts[0];
1482 String port = parts[1];
1483 if (host.isEmpty() || port.isEmpty()) {
1484 throw new KeywordSearchModuleException(
"Invalid server data: " + lines.get(rnd));
1488 Path serverFile = Paths.get(caseDirectoryPath.toString(),
"solrserver.txt");
1490 caseDirectoryPath.toFile().mkdirs();
1491 if (!caseDirectoryPath.toFile().exists()) {
1492 throw new KeywordSearchModuleException(
"Case directory " + caseDirectoryPath.toString() +
" does not exist");
1494 Files.write(serverFile, lines.get(rnd).getBytes());
1495 }
catch (IOException ex) {
1496 throw new KeywordSearchModuleException(serverFile.toString() +
" could not be written", ex);
1538 void commit() throws SolrServerException, NoOpenCoreException {
1539 currentCoreLock.readLock().lock();
1541 if (null == currentCollection) {
1542 throw new NoOpenCoreException();
1544 currentCollection.commit();
1546 currentCoreLock.readLock().unlock();
1550 NamedList<Object> request(SolrRequest<?> request)
throws SolrServerException, RemoteSolrException, NoOpenCoreException {
1551 currentCoreLock.readLock().lock();
1553 if (null == currentCollection) {
1554 throw new NoOpenCoreException();
1556 return currentCollection.request(request);
1558 currentCoreLock.readLock().unlock();
1573 currentCoreLock.readLock().lock();
1575 if (null == currentCollection) {
1576 throw new NoOpenCoreException();
1579 return currentCollection.queryNumIndexedFiles();
1580 }
catch (Exception ex) {
1582 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxFiles.exception.msg"), ex);
1585 currentCoreLock.readLock().unlock();
1599 currentCoreLock.readLock().lock();
1601 if (null == currentCollection) {
1602 throw new NoOpenCoreException();
1605 return currentCollection.queryNumIndexedChunks();
1606 }
catch (Exception ex) {
1608 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxChunks.exception.msg"), ex);
1611 currentCoreLock.readLock().unlock();
1625 currentCoreLock.readLock().lock();
1627 if (null == currentCollection) {
1628 throw new NoOpenCoreException();
1631 return currentCollection.queryNumIndexedDocuments();
1632 }
catch (Exception ex) {
1634 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumIdxDocs.exception.msg"), ex);
1637 currentCoreLock.readLock().unlock();
1652 currentCoreLock.readLock().lock();
1654 if (null == currentCollection) {
1655 throw new NoOpenCoreException();
1658 int totalNumChunks = currentCollection.queryTotalNumFileChunks(contentID);
1659 if (totalNumChunks == 0) {
1663 int numIndexedChunks = currentCollection.queryNumIndexedChunks(contentID);
1664 return numIndexedChunks == totalNumChunks;
1665 }
catch (Exception ex) {
1667 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryIsIdxd.exception.msg"), ex);
1671 currentCoreLock.readLock().unlock();
1687 currentCoreLock.readLock().lock();
1689 if (null == currentCollection) {
1690 throw new NoOpenCoreException();
1693 return currentCollection.queryTotalNumFileChunks(fileID);
1694 }
catch (Exception ex) {
1696 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryNumFileChunks.exception.msg"), ex);
1699 currentCoreLock.readLock().unlock();
1713 public QueryResponse
query(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException, IOException {
1714 currentCoreLock.readLock().lock();
1716 if (null == currentCollection) {
1717 throw new NoOpenCoreException();
1720 return currentCollection.query(sq);
1721 }
catch (Exception ex) {
1723 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1724 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query.exception.msg", sq.getQuery()), ex);
1727 currentCoreLock.readLock().unlock();
1742 public QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws KeywordSearchModuleException, NoOpenCoreException {
1743 currentCoreLock.readLock().lock();
1745 if (null == currentCollection) {
1746 throw new NoOpenCoreException();
1749 return currentCollection.query(sq, method);
1750 }
catch (Exception ex) {
1752 logger.log(Level.SEVERE,
"Solr query failed: " + sq.getQuery(), ex);
1753 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.query2.exception.msg", sq.getQuery()), ex);
1756 currentCoreLock.readLock().unlock();
1770 public TermsResponse
queryTerms(SolrQuery sq)
throws KeywordSearchModuleException, NoOpenCoreException {
1771 currentCoreLock.readLock().lock();
1773 if (null == currentCollection) {
1774 throw new NoOpenCoreException();
1777 return currentCollection.queryTerms(sq);
1778 }
catch (Exception ex) {
1780 logger.log(Level.SEVERE,
"Solr terms query failed: " + sq.getQuery(), ex);
1781 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.queryTerms.exception.msg", sq.getQuery()), ex);
1784 currentCoreLock.readLock().unlock();
1795 void deleteDataSource(Long dataSourceId)
throws IOException, KeywordSearchModuleException, NoOpenCoreException, SolrServerException {
1797 currentCoreLock.writeLock().lock();
1798 if (null == currentCollection) {
1799 throw new NoOpenCoreException();
1801 currentCollection.deleteDataSource(dataSourceId);
1802 currentCollection.commit();
1804 currentCoreLock.writeLock().unlock();
1816 @NbBundle.Messages({
1817 "Server.getAllTerms.error=Extraction of all unique Solr terms failed:"})
1818 void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws KeywordSearchModuleException, NoOpenCoreException {
1820 currentCoreLock.writeLock().lock();
1821 if (null == currentCollection) {
1822 throw new NoOpenCoreException();
1825 currentCollection.extractAllTermsForDataSource(outputFile, progressPanel);
1826 }
catch (Exception ex) {
1828 logger.log(Level.SEVERE,
"Extraction of all unique Solr terms failed: ", ex);
1829 throw new KeywordSearchModuleException(Bundle.Server_getAllTerms_error(), ex);
1832 currentCoreLock.writeLock().unlock();
1846 currentCoreLock.readLock().lock();
1848 if (null == currentCollection) {
1849 throw new NoOpenCoreException();
1851 return currentCollection.getSolrContent(content.getId(), 0);
1853 currentCoreLock.readLock().unlock();
1870 currentCoreLock.readLock().lock();
1872 if (null == currentCollection) {
1873 throw new NoOpenCoreException();
1875 return currentCollection.getSolrContent(content.getId(), chunkID);
1877 currentCoreLock.readLock().unlock();
1891 currentCoreLock.readLock().lock();
1893 if (null == currentCollection) {
1894 throw new NoOpenCoreException();
1896 return currentCollection.getSolrContent(objectID, 0);
1898 currentCoreLock.readLock().unlock();
1912 public String
getSolrContent(
final long objectID,
final int chunkID)
throws NoOpenCoreException {
1913 currentCoreLock.readLock().lock();
1915 if (null == currentCollection) {
1916 throw new NoOpenCoreException();
1918 return currentCollection.getSolrContent(objectID, chunkID);
1920 currentCoreLock.readLock().unlock();
1945 CoreAdminRequest.getStatus(null, localSolrServer);
1960 void connectToSolrServer(String host, String port)
throws SolrServerException, IOException {
1961 try (HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr")) {
1962 connectToSolrServer(solrServer);
1977 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1978 CollectionAdminResponse statusResponse = statusRequest.process(solrServer);
1979 int statusCode = Integer.valueOf(((NamedList) statusResponse.getResponse().get(
"responseHeader")).
get(
"status").toString());
1980 if (statusCode != 0) {
1981 logger.log(Level.WARNING,
"Could not connect to Solr server ");
1983 logger.log(Level.INFO,
"Connected to Solr server ");
1988 private List<String>
getSolrServerList(String host, String port)
throws KeywordSearchModuleException {
1989 HttpSolrClient solrServer =
getSolrClient(
"http://" + host +
":" + port +
"/solr");
1993 private List<String>
getSolrServerList(HttpSolrClient solrServer)
throws KeywordSearchModuleException {
1996 CollectionAdminRequest.ClusterStatus statusRequest = CollectionAdminRequest.getClusterStatus();
1997 CollectionAdminResponse statusResponse;
1999 statusResponse = statusRequest.process(solrServer);
2000 }
catch (RemoteSolrException ex) {
2002 return Collections.emptyList();
2005 if (statusResponse == null) {
2006 return Collections.emptyList();
2009 NamedList<?> error = (NamedList) statusResponse.getResponse().get(
"error");
2010 if (error != null) {
2011 return Collections.emptyList();
2014 NamedList<?> cluster = (NamedList) statusResponse.getResponse().get(
"cluster");
2015 @SuppressWarnings(
"unchecked")
2016 List<String> liveNodes = (ArrayList) cluster.get(
"live_nodes");
2018 if (liveNodes != null) {
2019 liveNodes = liveNodes.stream()
2020 .map(serverStr -> serverStr.endsWith(
"_solr")
2021 ? serverStr.substring(0, serverStr.length() -
"_solr".length())
2023 .collect(Collectors.toList());
2026 }
catch (Exception ex) {
2028 throw new KeywordSearchModuleException(
2029 NbBundle.getMessage(
this.getClass(),
"Server.serverList.exception.msg", solrServer.getBaseURL()));
2036 private final String name;
2040 private final Index textIndex;
2046 private HttpSolrClient queryClient;
2047 private SolrClient indexingClient;
2049 private final int maxBufferSize;
2050 private final List<SolrInputDocument> buffer;
2051 private final Object bufferLock;
2056 private static final int MAX_NUM_CONSECUTIVE_FAILURES = 5;
2057 private AtomicInteger numConsecutiveFailures =
new AtomicInteger(0);
2058 private AtomicBoolean skipIndexing =
new AtomicBoolean(
false);
2060 private final ScheduledThreadPoolExecutor periodicTasksExecutor;
2061 private static final long PERIODIC_BATCH_SEND_INTERVAL_MINUTES = 10;
2062 private static final int NUM_BATCH_UPDATE_RETRIES = 10;
2063 private static final long SLEEP_BETWEEN_RETRIES_MS = 10000;
2065 private Collection(String name,
Case theCase, Index index)
throws TimeoutException, InterruptedException, KeywordSearchModuleException {
2068 this.textIndex = index;
2069 bufferLock =
new Object();
2073 queryClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2074 indexingClient =
getSolrClient(
"http://localhost:" + localSolrServerPort +
"/solr/" + name);
2080 if (IndexFinder.getCurrentSolrVersion().equals(index.getSolrVersion())) {
2082 indexingClient =
getCloudSolrClient(properties.getHost(), properties.getPort(), name);
2090 logger.log(Level.INFO,
"Using Solr document queue size = {0}", maxBufferSize);
2091 buffer =
new ArrayList<>(maxBufferSize);
2092 periodicTasksExecutor =
new ScheduledThreadPoolExecutor(1,
new ThreadFactoryBuilder().setNameFormat(
"periodic-batched-document-task-%d").build());
2093 periodicTasksExecutor.scheduleWithFixedDelay(
new SendBatchedDocumentsTask(), PERIODIC_BATCH_SEND_INTERVAL_MINUTES, PERIODIC_BATCH_SEND_INTERVAL_MINUTES, TimeUnit.MINUTES);
2107 if (skipIndexing.get()) {
2111 List<SolrInputDocument> clone;
2112 synchronized (bufferLock) {
2114 if (buffer.isEmpty()) {
2120 clone = buffer.stream().collect(toList());
2126 sendBufferedDocs(clone);
2127 }
catch (KeywordSearchModuleException ex) {
2128 logger.log(Level.SEVERE,
"Periodic batched document update failed", ex);
2142 private Index getIndexInfo() {
2143 return this.textIndex;
2146 private QueryResponse
query(SolrQuery sq)
throws SolrServerException, IOException {
2147 return queryClient.query(sq);
2150 private NamedList<Object> request(SolrRequest<?> request)
throws SolrServerException, RemoteSolrException {
2152 return queryClient.request(request);
2153 }
catch (Exception e) {
2155 logger.log(Level.WARNING,
"Could not issue Solr request. ", e);
2156 throw new SolrServerException(
2157 NbBundle.getMessage(
this.getClass(),
"Server.request.exception.exception.msg"), e);
2162 private QueryResponse
query(SolrQuery sq, SolrRequest.METHOD method) throws SolrServerException, IOException {
2163 return queryClient.query(sq, method);
2166 private TermsResponse
queryTerms(SolrQuery sq)
throws SolrServerException, IOException {
2167 QueryResponse qres = queryClient.query(sq);
2168 return qres.getTermsResponse();
2171 private void commit() throws SolrServerException {
2172 List<SolrInputDocument> clone;
2173 synchronized (bufferLock) {
2176 clone = buffer.stream().collect(toList());
2181 sendBufferedDocs(clone);
2182 }
catch (KeywordSearchModuleException ex) {
2183 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), ex);
2188 indexingClient.commit(
true,
true);
2189 }
catch (Exception e) {
2191 logger.log(Level.WARNING,
"Could not commit index. ", e);
2192 throw new SolrServerException(NbBundle.getMessage(
this.getClass(),
"Server.commit.exception.msg"), e);
2196 private void deleteDataSource(Long dsObjId)
throws IOException, SolrServerException {
2197 String dataSourceId = Long.toString(dsObjId);
2198 String deleteQuery =
"image_id:" + dataSourceId;
2200 queryClient.deleteByQuery(deleteQuery);
2214 @NbBundle.Messages({
2215 "# {0} - Number of extracted terms",
2216 "ExtractAllTermsReport.numberExtractedTerms=Extracted {0} terms..."
2218 private void extractAllTermsForDataSource(Path outputFile, ReportProgressPanel progressPanel)
throws IOException, SolrServerException, NoCurrentCaseException, KeywordSearchModuleException {
2220 Files.deleteIfExists(outputFile);
2221 OpenOption[] options =
new OpenOption[] { java.nio.file.StandardOpenOption.CREATE, java.nio.file.StandardOpenOption.APPEND };
2224 int termStep = 1000;
2225 long numExtractedTerms = 0;
2226 String firstTerm =
"";
2228 SolrQuery
query =
new SolrQuery();
2229 query.setRequestHandler(
"/terms");
2230 query.setTerms(
true);
2231 query.setTermsLimit(termStep);
2232 query.setTermsLower(firstTerm);
2233 query.setTermsLowerInclusive(
false);
2238 query.setTermsSortString(
"index");
2241 query.addTermsField(Server.Schema.TEXT.toString());
2242 query.setTermsMinCount(0);
2247 QueryRequest request =
new QueryRequest(query);
2248 TermsResponse response = request.process(queryClient).getTermsResponse();
2249 List<Term> terms = response.getTerms(Server.Schema.TEXT.toString());
2251 if (terms == null || terms.isEmpty()) {
2252 numExtractedTerms += terms.size();
2253 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2258 firstTerm = terms.get(terms.size()-1).getTerm();
2260 List<String> listTerms = terms.stream().map(Term::getTerm).collect(Collectors.toList());
2261 Files.write(outputFile, listTerms, options);
2263 numExtractedTerms += termStep;
2264 progressPanel.updateStatusLabel(Bundle.ExtractAllTermsReport_numberExtractedTerms(numExtractedTerms));
2276 void addDocument(SolrInputDocument doc)
throws KeywordSearchModuleException {
2278 if (skipIndexing.get()) {
2282 List<SolrInputDocument> clone;
2283 synchronized (bufferLock) {
2286 if (buffer.size() < maxBufferSize) {
2292 clone = buffer.stream().collect(toList());
2297 sendBufferedDocs(clone);
2307 @NbBundle.Messages({
2308 "Collection.unableToIndexData.error=Unable to add data to text index. All future text indexing for the current case will be skipped.",
2311 private void sendBufferedDocs(List<SolrInputDocument> docBuffer)
throws KeywordSearchModuleException {
2313 if (docBuffer.isEmpty()) {
2318 boolean success =
true;
2319 for (
int reTryAttempt = 0; reTryAttempt < NUM_BATCH_UPDATE_RETRIES; reTryAttempt++) {
2322 indexingClient.add(docBuffer);
2323 }
catch (Exception ex) {
2325 if (reTryAttempt < NUM_BATCH_UPDATE_RETRIES - 1) {
2326 logger.log(Level.WARNING,
"Unable to send document batch to Solr. Re-trying...", ex);
2328 Thread.sleep(SLEEP_BETWEEN_RETRIES_MS);
2329 }
catch (InterruptedException ignore) {
2330 throw new KeywordSearchModuleException(
2331 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2336 numConsecutiveFailures.set(0);
2337 if (reTryAttempt > 0) {
2338 logger.log(Level.INFO,
"Batch update suceeded after {0} re-try", reTryAttempt);
2344 logger.log(Level.SEVERE,
"Unable to send document batch to Solr. All re-try attempts failed!");
2345 throw new KeywordSearchModuleException(NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2346 }
catch (Exception ex) {
2348 numConsecutiveFailures.incrementAndGet();
2349 logger.log(Level.SEVERE,
"Could not add batched documents to index", ex);
2352 MessageNotifyUtil.Notify.error(
2353 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2354 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"));
2355 throw new KeywordSearchModuleException(
2356 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"), ex);
2358 if (numConsecutiveFailures.get() >= MAX_NUM_CONSECUTIVE_FAILURES) {
2360 skipIndexing.set(
true);
2361 logger.log(Level.SEVERE,
"Unable to add data to text index. All future text indexing for the current case will be skipped!");
2364 MessageNotifyUtil.Notify.error(
2365 NbBundle.getMessage(
this.getClass(),
"Server.addDocBatch.exception.msg"),
2366 Bundle.Collection_unableToIndexData_error());
2367 if (RuntimeProperties.runningWithGUI()) {
2368 MessageNotifyUtil.Message.error(Bundle.Collection_unableToIndexData_error());
2386 final SolrQuery q =
new SolrQuery();
2388 String filterQuery = Schema.ID.toString() +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2390 filterQuery = filterQuery + Server.CHUNK_ID_SEPARATOR + chunkID;
2392 q.addFilterQuery(filterQuery);
2393 q.setFields(Schema.TEXT.toString());
2396 SolrDocumentList solrDocuments = queryClient.query(q).getResults();
2398 if (!solrDocuments.isEmpty()) {
2399 SolrDocument solrDocument = solrDocuments.get(0);
2400 if (solrDocument != null) {
2401 java.util.Collection<Object> fieldValues = solrDocument.getFieldValues(Schema.TEXT.toString());
2402 if (fieldValues.size() == 1)
2404 return fieldValues.toArray(
new String[0])[0];
2408 return fieldValues.toArray(
new String[0])[1];
2412 }
catch (Exception ex) {
2414 logger.log(Level.SEVERE,
"Error getting content from Solr. Solr document id " + contentID +
", chunk id " + chunkID +
", query: " + filterQuery, ex);
2421 synchronized void close() throws KeywordSearchModuleException {
2426 ThreadUtils.shutDownTaskExecutor(periodicTasksExecutor);
2433 CoreAdminRequest.unloadCore(this.name, localSolrServer);
2434 }
catch (Exception ex) {
2436 throw new KeywordSearchModuleException(
2437 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg"), ex);
2440 queryClient.close();
2442 indexingClient.close();
2443 indexingClient = null;
2444 }
catch (IOException ex) {
2445 throw new KeywordSearchModuleException(
2446 NbBundle.getMessage(
this.getClass(),
"Server.close.exception.msg2"), ex);
2474 SolrQuery q =
new SolrQuery(Server.Schema.ID +
":*" + Server.CHUNK_ID_SEPARATOR +
"*");
2476 int numChunks = (int)
query(q).getResults().getNumFound();
2491 SolrQuery q =
new SolrQuery(
"*:*");
2493 return (
int)
query(q).getResults().getNumFound();
2505 private boolean queryIsIndexed(
long contentID)
throws SolrServerException, IOException {
2506 String
id = KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2507 SolrQuery q =
new SolrQuery(
"*:*");
2508 q.addFilterQuery(Server.Schema.ID.toString() +
":" + id);
2511 return (
int)
query(q).getResults().getNumFound() != 0;
2528 private int queryTotalNumFileChunks(
long contentID)
throws SolrServerException, IOException {
2529 final SolrQuery q =
new SolrQuery();
2531 String filterQuery = Schema.ID.toString() +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID));
2532 q.addFilterQuery(filterQuery);
2533 q.setFields(Schema.NUM_CHUNKS.toString());
2535 SolrDocumentList solrDocuments =
query(q).getResults();
2536 if (!solrDocuments.isEmpty()) {
2537 SolrDocument solrDocument = solrDocuments.get(0);
2538 if (solrDocument != null && !solrDocument.isEmpty()) {
2539 Object fieldValue = solrDocument.getFieldValue(Schema.NUM_CHUNKS.toString());
2540 return (Integer)fieldValue;
2543 }
catch (Exception ex) {
2545 logger.log(Level.SEVERE,
"Error getting content from Solr. Solr document id " + contentID +
", query: " + filterQuery, ex);
2564 SolrQuery q =
new SolrQuery(Server.Schema.ID +
":" + KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID)) + Server.CHUNK_ID_SEPARATOR +
"*");
2566 int numChunks = (int)
query(q).getResults().getNumFound();
2571 class ServerAction
extends AbstractAction {
2573 private static final long serialVersionUID = 1L;
2576 public void actionPerformed(ActionEvent e) {
2577 logger.log(Level.INFO, e.paramString().trim());
2584 class SolrServerNoPortException
extends SocketException {
2586 private static final long serialVersionUID = 1L;
2591 private final int port;
2593 SolrServerNoPortException(
int port) {
2594 super(NbBundle.getMessage(Server.class,
"Server.solrServerNoPortException.msg", port,
2595 Server.PROPERTIES_CURRENT_SERVER_PORT));
2599 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)
String toString(boolean preserveState)
static final boolean DEBUG
QueryResponse query(SolrQuery sq, SolrRequest.METHOD method)