diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 6ee83a3dfb..ffe67c43be 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -141,20 +141,20 @@ public class Case implements SleuthkitCase.ErrorObserver { SINGLE_USER_CASE("Single-user case"), MULTI_USER_CASE("Multi-user case"); - private final String caseName; + private final String caseType; private CaseType(String s) { - caseName = s; + caseType = s; } - public boolean equalsName(String otherName) { - return (otherName == null) ? false : caseName.equals(otherName); + public boolean equalsName(String otherType) { + return (otherType == null) ? false : caseType.equals(otherType); } - public static CaseType fromString(String text) { - if (text != null) { + public static CaseType fromString(String typeName) { + if (typeName != null) { for (CaseType c : CaseType.values()) { - if (text.equalsIgnoreCase(c.caseName)) { + if (typeName.equalsIgnoreCase(c.caseType)) { return c; } } @@ -164,7 +164,7 @@ public class Case implements SleuthkitCase.ErrorObserver { @Override public String toString() { - return caseName; + return caseType; } }; @@ -176,6 +176,7 @@ public class Case implements SleuthkitCase.ErrorObserver { private final SleuthkitCase db; // Track the current case (only set with changeCase() method) private static Case currentCase = null; + private CaseType caseType; private final Services services; private static final Logger logger = Logger.getLogger(Case.class.getName()); static final String CASE_EXTENSION = "aut"; //NON-NLS @@ -189,12 +190,13 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Constructor for the Case class */ - private Case(String name, String number, String examiner, String configFilePath, XMLCaseManagement xmlcm, SleuthkitCase db) { + private Case(String name, String number, String examiner, String configFilePath, XMLCaseManagement xmlcm, SleuthkitCase db, CaseType type) { this.name = name; this.number = number; this.examiner = examiner; this.configFilePath = configFilePath; this.xmlcm = xmlcm; + this.caseType = type; this.db = db; this.services = new Services(db); // messenger = new Messenger(this.name); @@ -344,16 +346,20 @@ public class Case implements SleuthkitCase.ErrorObserver { XMLCaseManagement xmlcm = new XMLCaseManagement(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); + Date date = new Date(); + String indexName = caseName + "_" + dateFormat.format(date); + String dbName = null; - // figure out the database name + + // figure out the database name and index name for text extraction if (caseType == CaseType.SINGLE_USER_CASE) { dbName = caseDir + File.separator + "autopsy.db"; //NON-NLS } else if (caseType == CaseType.MULTI_USER_CASE) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); - dbName = caseName + "_" + dateFormat.format(new Date()); + dbName = caseName + "_" + dateFormat.format(date); } - xmlcm.create(caseDir, caseName, examiner, caseNumber, caseType, dbName); // create a new XML config file + xmlcm.create(caseDir, caseName, examiner, caseNumber, caseType, dbName, indexName); // create a new XML config file xmlcm.writeFile(); SleuthkitCase db = null; @@ -373,7 +379,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Two-stage initialization to avoid leaking reference to "this" in * constructor. */ - Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db); + Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType); newCase.init(); // newCase.messenger.start(); @@ -403,7 +409,7 @@ public class Case implements SleuthkitCase.ErrorObserver { SleuthkitCase db; if (caseType == CaseType.SINGLE_USER_CASE) { - // if the caseName is "", case / config file can't be opened + // if the caseType is "", case / config file can't be opened if (caseName.equals("")) { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.blankCase.msg")); } @@ -434,7 +440,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Two-stage initialization to avoid leaking reference to "this" in * constructor. */ - Case openedCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db); + Case openedCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType); openedCase.init(); // openedCase.messenger.start(); @@ -789,6 +795,14 @@ public class Case implements SleuthkitCase.ErrorObserver { } } + /** + * Get the case type. + * @return + */ + public CaseType getCaseType() { + return this.caseType; + } + /** * Gets the full path to the temp directory of this case * @@ -854,6 +868,19 @@ public class Case implements SleuthkitCase.ErrorObserver { } } + /** + * Get the name of the index where extracted text is stored for the case. + * + * @return Index name. + */ + public String getTextIndexName() { + if (xmlcm == null) { + return ""; + } else { + return xmlcm.getTextIndexName(); + } + } + /** * Get absolute module output directory path where modules should save their * permanent data The directory is a subdirectory of this case dir. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd b/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd index 442eae823f..63c9aa49df 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd @@ -16,6 +16,8 @@ + + @@ -99,6 +101,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java index f1ad541b5e..86b9ddc770 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java @@ -60,6 +60,7 @@ import org.xml.sax.SAXException; final static String SCHEMA_VERSION_NAME = "SchemaVersion"; //NON-NLS final static String AUTOPSY_CRVERSION_NAME = "AutopsyCreatedVersion"; //NON-NLS final static String AUTOPSY_MVERSION_NAME = "AutopsySavedVersion"; //NON-NLS + final static String CASE_TEXT_INDEX_NAME = "TextIndexName"; //NON-NLS // folders inside case directory final static String LOG_FOLDER_NAME = "LogFolder"; //NON-NLS final static String LOG_FOLDER_RELPATH = "Log"; //NON-NLS @@ -88,6 +89,7 @@ import org.xml.sax.SAXException; private String autopsySavedVersion; private CaseType caseType; // The type of case: local or shared private String dbName; // The name of the database + private String textIndexName; // The name of the index where extracted text is stored. // for error handling private JPanel caller; @@ -247,6 +249,34 @@ import org.xml.sax.SAXException; } /** + * Sets the text index name internally (on local variable in this class) + * + * @param textIndexName the new name for the index where extracted text + * is stored for the case. + */ + private void setTextIndexName(String textIndexName) { + this.textIndexName= textIndexName; // change this to change the xml file if needed + } + + /** + * Gets the name of the index where extracted text is stored. + * + * @return the index name + */ + public String getTextIndexName() { + if (doc == null) { + return ""; + } else { + if (getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).getLength() > 0) { + Element nameElement = (Element) getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).item(0); + return nameElement.getTextContent(); + } else { + return ""; /// couldn't find one, so return a blank index name + } + } + } + + /** * Sets the examiner name internally (on local variable in this class) * * @param givenExaminer the new examiner @@ -503,8 +533,9 @@ import org.xml.sax.SAXException; * @param caseNumber case number (optional), can be empty * @param dbName the name of the database. Could be a local path, could be * a Postgre db name. + * @param textIndexName The name of the index where extracted text is stored. */ - protected void create(String dirPath, String caseName, String examiner, String caseNumber, CaseType caseType, String dbName) throws CaseActionException { + protected void create(String dirPath, String caseName, String examiner, String caseNumber, CaseType caseType, String dbName, String textIndexName) throws CaseActionException { clear(); // clear the previous data // set the case Name and Directory and the parent directory @@ -514,6 +545,7 @@ import org.xml.sax.SAXException; setNumber(caseNumber); setCaseType(caseType); setDatabaseName(dbName); + setTextIndexName(textIndexName); DocumentBuilder docBuilder; DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); @@ -593,6 +625,10 @@ import org.xml.sax.SAXException; dbNameElement.appendChild(doc.createTextNode(dbName)); caseElement.appendChild(dbNameElement); + Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... + indexNameElement.appendChild(doc.createTextNode(textIndexName)); + caseElement.appendChild(indexNameElement); + // write more code if needed ... } @@ -761,5 +797,6 @@ import org.xml.sax.SAXException; examiner = ""; caseType = CaseType.SINGLE_USER_CASE; dbName = ""; + textIndexName = ""; } } diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 3f3365d4fe..92385abf1a 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -45,6 +45,8 @@ public final class UserPreferences { public static final String EXTERNAL_DATABASE_PASSWORD = "ExternalDatabasePassword"; //NON-NLS public static final String EXTERNAL_DATABASE_TYPE = "ExternalDatabaseType"; //NON-NLS public static final String NEW_CASE_TYPE = "NewCaseType"; //NON-NLS + public static final String INDEXING_SERVER_HOST = "IndexingServerHost"; //NON-NLS + public static final String INDEXING_SERVER_PORT = "IndexingServerPort"; //NON-NLS private static final String MESSAGE_SERVICE_PASSWORD = "MessageServicePassword"; //NON-NLS private static final String MESSAGE_SERVICE_USER = "MessageServiceUser"; //NON-NLS private static final String MESSAGE_SERVICE_HOST = "MessageServiceHost"; //NON-NLS @@ -132,6 +134,22 @@ public final class UserPreferences { public static void setNewCaseType(int value) { preferences.putInt(NEW_CASE_TYPE, value); } + + public static String getIndexingServerHost() { + return preferences.get(INDEXING_SERVER_HOST, ""); + } + + public static void setIndexingServerHost(String hostName) { + preferences.put(INDEXING_SERVER_HOST, hostName); + } + + public static String getIndexingServerPort() { + return preferences.get(INDEXING_SERVER_PORT, ""); + } + + public static void setIndexingServerPort(int port) { + preferences.putInt(INDEXING_SERVER_PORT, port); + } /** * Persists message service connection info. diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index c2a7d818e4..c5089ca52c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -165,6 +165,7 @@ MultiUserSettingsPanel.lbDatabaseSettings.text=Database Settings MultiUserSettingsPanel.validationErrMsg.incomplete=Fill in all values MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number MultiUserSettingsPanel.validationErrMsg.invalidMessageServicePort=Invalid message service port number +MultiUserSettingsPanel.validationErrMsg.invalidIndexingServerPort=Invalid Solr server port number MultiUserSettingsPanel.validationErrMsg.invalidMessgeServiceURI=Message service host and/or port not valid MultiUserSettingsPanel.msgHostTextField.text= MultiUserSettingsPanel.msgHostTextField.toolTipText=Hostname or IP Address @@ -174,3 +175,7 @@ MultiUserSettingsPanel.msgPasswordField.toolTipText=Password MultiUserSettingsPanel.msgPasswordField.text= MultiUserSettingsPanel.msgPortTextField.toolTipText=Hostname or IP Address MultiUserSettingsPanel.msgPortTextField.text= +MultiUserSettingsPanel.tbIndexingServerHost.text=localhost +MultiUserSettingsPanel.tbIndexingServerPort.text=23232 +MultiUserSettingsPanel.tbIndexingServerHost.toolTipText=Hostname or IP Address +MultiUserSettingsPanel.tbIndexingServerPort.toolTipText=Port Number diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.form index 89d75fd3df..723f7b999b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.form @@ -16,7 +16,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -126,6 +126,9 @@ + + + @@ -191,10 +194,17 @@ - + + + + + + + + + + - - @@ -203,7 +213,11 @@ - + + + + + @@ -219,6 +233,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.java index 32d3cdaade..b5bc13392f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanel.java @@ -27,6 +27,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { private static final String INCOMPLETE_SETTINGS_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.incomplete"); private static final String INVALID_DB_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort"); private static final String INVALID_MESSAGE_SERVICE_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidMessageServicePort"); + private static final String INVALID_INDEXING_SERVER_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidIndexingServerPort"); private final MultiUserSettingsPanelController controller; private final Collection textBoxes = new ArrayList<>(); private final TextBoxChangedListener textBoxChangedListener; @@ -51,6 +52,8 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { textPrompts.add(new TextPrompt(PORT_PROMPT, msgPortTextField)); textPrompts.add(new TextPrompt(USER_NAME_PROMPT, msgUserNameTextField)); textPrompts.add(new TextPrompt(PASSWORD_PROMPT, msgPasswordField)); + textPrompts.add(new TextPrompt(HOST_NAME_OR_IP_PROMPT, tbIndexingServerHost)); + textPrompts.add(new TextPrompt(PORT_PROMPT, tbIndexingServerPort)); configureTextPrompts(textPrompts); /// Register for notifications when the text boxes get updated. @@ -63,6 +66,8 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { textBoxes.add(msgPortTextField); textBoxes.add(msgUserNameTextField); textBoxes.add(msgPasswordField); + textBoxes.add(tbIndexingServerHost); + textBoxes.add(tbIndexingServerPort); addDocumentListeners(textBoxes, textBoxChangedListener); enableMultiUserComponents(textBoxes, cbEnableMultiUser.isSelected()); @@ -112,6 +117,8 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { lbDatabaseSettings = new javax.swing.JLabel(); pnSolrSettings = new javax.swing.JPanel(); lbSolrSettings = new javax.swing.JLabel(); + tbIndexingServerHost = new javax.swing.JTextField(); + tbIndexingServerPort = new javax.swing.JTextField(); lbOops = new javax.swing.JLabel(); pnMessagingSettings = new javax.swing.JPanel(); lbMessagingSettings = new javax.swing.JLabel(); @@ -126,6 +133,11 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { tbHostnameOrIp.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N tbHostnameOrIp.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbHostnameOrIp.text")); // NOI18N tbHostnameOrIp.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbHostnameOrIp.toolTipText")); // NOI18N + tbHostnameOrIp.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + tbHostnameOrIpActionPerformed(evt); + } + }); tbPortNumber.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N tbPortNumber.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbPortNumber.text")); // NOI18N @@ -180,21 +192,48 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { lbSolrSettings.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(lbSolrSettings, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbSolrSettings.text")); // NOI18N + tbIndexingServerHost.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N + tbIndexingServerHost.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbIndexingServerHost.text")); // NOI18N + tbIndexingServerHost.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbIndexingServerHost.toolTipText")); // NOI18N + tbIndexingServerHost.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + tbIndexingServerHostActionPerformed(evt); + } + }); + + tbIndexingServerPort.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N + tbIndexingServerPort.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbIndexingServerPort.text")); // NOI18N + tbIndexingServerPort.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbIndexingServerPort.toolTipText")); // NOI18N + tbIndexingServerPort.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + tbIndexingServerPortActionPerformed(evt); + } + }); + javax.swing.GroupLayout pnSolrSettingsLayout = new javax.swing.GroupLayout(pnSolrSettings); pnSolrSettings.setLayout(pnSolrSettingsLayout); pnSolrSettingsLayout.setHorizontalGroup( pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(pnSolrSettingsLayout.createSequentialGroup() .addContainerGap() - .addComponent(lbSolrSettings) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnSolrSettingsLayout.createSequentialGroup() + .addComponent(lbSolrSettings) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(tbIndexingServerHost, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(tbIndexingServerPort, javax.swing.GroupLayout.Alignment.TRAILING)) + .addContainerGap()) ); pnSolrSettingsLayout.setVerticalGroup( pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(pnSolrSettingsLayout.createSequentialGroup() .addContainerGap() .addComponent(lbSolrSettings) - .addContainerGap(75, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tbIndexingServerHost, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(tbIndexingServerPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(45, 45, 45)) ); lbOops.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N @@ -285,7 +324,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { .addGroup(pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbEnableMultiUser) .addComponent(lbOops)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 6, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnDatabaseSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(pnSolrSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -298,7 +337,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pnOverallPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 511, Short.MAX_VALUE) + .addComponent(pnOverallPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -325,6 +364,18 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { controller.changed(); }//GEN-LAST:event_cbEnableMultiUserItemStateChanged + private void tbHostnameOrIpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbHostnameOrIpActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_tbHostnameOrIpActionPerformed + + private void tbIndexingServerHostActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbIndexingServerHostActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_tbIndexingServerHostActionPerformed + + private void tbIndexingServerPortActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbIndexingServerPortActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_tbIndexingServerPortActionPerformed + void load() { CaseDbConnectionInfo dbInfo = UserPreferences.getDatabaseConnectionInfo(); tbHostnameOrIp.setText(dbInfo.getHost()); @@ -338,6 +389,15 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { msgUserNameTextField.setText(msgServiceInfo.getUserName()); msgPasswordField.setText(msgServiceInfo.getPassword()); + String indexingServerHost = UserPreferences.getIndexingServerHost(); + if (!indexingServerHost.isEmpty()) { + tbIndexingServerHost.setText(indexingServerHost); + } + String indexingServerPort = UserPreferences.getIndexingServerPort(); + if (portNumberIsValid(indexingServerPort)) { + tbIndexingServerPort.setText(indexingServerPort); + } + if (dbInfo.getDbType() == DbType.UNKNOWN) { cbEnableMultiUser.setSelected(false); } else { @@ -381,6 +441,10 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { msgHostTextField.getText(), msgPortTextField.getText()); UserPreferences.setMessageServiceConnectionInfo(msgServiceInfo); + + UserPreferences.setIndexingServerHost(tbIndexingServerHost.getText()); + UserPreferences.setIndexingServerPort(Integer.parseInt(tbIndexingServerPort.getText())); + } /** @@ -391,7 +455,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { boolean valid() { lbOops.setText(""); if (cbEnableMultiUser.isSelected()) { - return settingsAreComplete() && databaseSettingsAreValid() && messageServiceSettingsAreValid(); + return settingsAreComplete() && databaseSettingsAreValid() && indexingServerSettingsAreValid() && messageServiceSettingsAreValid(); } else { return true; } @@ -444,6 +508,20 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { return true; } + /** + * Tests whether or not the indexing server settings are valid. + * + * @return True or false. + */ + boolean indexingServerSettingsAreValid() { + if (!portNumberIsValid(tbIndexingServerPort.getText())) { + lbOops.setText(INVALID_INDEXING_SERVER_PORT_MSG); + return false; + } + + return true; + } + /** * Determines whether or not a port number is within the range of valid port * numbers. @@ -478,6 +556,8 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { private javax.swing.JPanel pnOverallPanel; private javax.swing.JPanel pnSolrSettings; private javax.swing.JTextField tbHostnameOrIp; + private javax.swing.JTextField tbIndexingServerHost; + private javax.swing.JTextField tbIndexingServerPort; private javax.swing.JPasswordField tbPassword; private javax.swing.JTextField tbPortNumber; private javax.swing.JTextField tbUsername; @@ -503,6 +583,6 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel { public void removeUpdate(DocumentEvent e) { controller.changed(); - } + } } } diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index f07f7894a0..0f823bd9be 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -169,58 +169,14 @@ ext/bcmail-jdk15-1.45.jar release/modules/ext/bcmail-jdk15-1.45.jar - - ext/bcprov-jdk15-1.45.jar - release/modules/ext/bcprov-jdk15-1.45.jar - - - ext/commons-logging-api-1.1.jar - release/modules/ext/commons-logging-api-1.1.jar - - - ext/commons-logging-1.1.1.jar - release/modules/ext/commons-logging-1.1.1.jar - - - ext/commons-compress-1.5.jar - release/modules/ext/commons-compress-1.5.jar - - - ext/commons-lang-2.4.jar - release/modules/ext/commons-lang-2.4.jar - - - ext/commons-lang-2.4-javadoc.jar - release/modules/ext/commons-lang-2.4-javadoc.jar - - - ext/commons-lang-2.4-sources.jar - release/modules/ext/commons-lang-2.4-sources.jar - ext/tika-parsers-1.5.jar release/modules/ext/tika-parsers-1.5.jar - - ext/tika-core-1.5.jar - release/modules/ext/tika-core-1.5.jar - - - ext/metadata-extractor-2.7.2.jar - release/modules/ext/metadata-extractor-2.7.2.jar - - - ext/xmpcore-5.1.2.jar - release/modules/ext/xmpcore-5.1.2.jar - ext/jericho-html-3.3.jar release/modules/ext/jericho-html-3.3.jar - - ext/jericho-html-3.3-sources.jar - release/modules/ext/jericho-html-3.3-sources.jar - ext/org.osgi.compendium-4.0.0.jar release/modules/ext/org.osgi.compendium-4.0.0.jar @@ -234,33 +190,57 @@ release/modules/ext/xmlbeans-2.3.0.jar - ext/asm-all-3.1.jar - release/modules/ext/asm-all-3.1.jar - - - ext/poi-3.10-beta2.jar - release/modules/ext/poi-3.10-beta2.jar + ext/jempbox-1.8.4.jar + release/modules/ext/jempbox-1.8.4.jar ext/poi-ooxml-3.10-beta2.jar release/modules/ext/poi-ooxml-3.10-beta2.jar - ext/poi-ooxml-schemas-3.10-beta2.jar - release/modules/ext/poi-ooxml-schemas-3.10-beta2.jar + ext/commons-logging-api-1.1.jar + release/modules/ext/commons-logging-api-1.1.jar - ext/poi-scratchpad-3.10-beta2.jar - release/modules/ext/poi-scratchpad-3.10-beta2.jar + ext/asm-all-3.1.jar + release/modules/ext/asm-all-3.1.jar + + + ext/solr-solrj-4.9.1-javadoc.jar + release/modules/ext/solr-solrj-4.9.1-javadoc.jar + + + ext/poi-3.10-beta2.jar + release/modules/ext/poi-3.10-beta2.jar ext/icu4j-3.8.jar release/modules/ext/icu4j-3.8.jar + + ext/fontbox-1.8.4.jar + release/modules/ext/fontbox-1.8.4.jar + + + ext/xmpcore-5.1.2.jar + release/modules/ext/xmpcore-5.1.2.jar + + + ext/metadata-extractor-2.7.2.jar + release/modules/ext/metadata-extractor-2.7.2.jar + ext/tagsoup-1.2.1.jar release/modules/ext/tagsoup-1.2.1.jar + + ext/commons-compress-1.5.jar + release/modules/ext/commons-compress-1.5.jar + + + ext/commons-lang-2.4-javadoc.jar + release/modules/ext/commons-lang-2.4-javadoc.jar + ext/org.osgi.core-4.0.0.jar release/modules/ext/org.osgi.core-4.0.0.jar @@ -269,14 +249,6 @@ ext/httpclient-4.3.1.jar release/modules/ext/httpclient-4.3.1.jar - - ext/httpcore-4.3.jar - release/modules/ext/httpcore-4.3.jar - - - ext/httpmime-4.3.1.jar - release/modules/ext/httpmime-4.3.1.jar - ext/isoparser-1.0-RC-1.jar release/modules/ext/isoparser-1.0-RC-1.jar @@ -285,6 +257,14 @@ ext/log4j-1.2.17.jar release/modules/ext/log4j-1.2.17.jar + + ext/commons-lang-2.4-sources.jar + release/modules/ext/commons-lang-2.4-sources.jar + + + ext/tika-core-1.5.jar + release/modules/ext/tika-core-1.5.jar + ext/jericho-html-3.3-javadoc.jar release/modules/ext/jericho-html-3.3-javadoc.jar @@ -302,12 +282,12 @@ release/modules/ext/solr-solrj-4.9.1.jar - ext/solr-solrj-4.9.1-javadoc.jar - release/modules/ext/solr-solrj-4.9.1-javadoc.jar + ext/poi-scratchpad-3.10-beta2.jar + release/modules/ext/poi-scratchpad-3.10-beta2.jar - ext/solr-solrj-4.9.1-sources.jar - release/modules/ext/solr-solrj-4.9.1-sources.jar + ext/commons-logging-1.1.1.jar + release/modules/ext/commons-logging-1.1.1.jar ext/netcdf-4.2-min.jar @@ -317,6 +297,18 @@ ext/vorbis-java-core-0.1-tests.jar release/modules/ext/vorbis-java-core-0.1-tests.jar + + ext/commons-io-2.3.jar + release/modules/ext/commons-io-2.3.jar + + + ext/jericho-html-3.3-sources.jar + release/modules/ext/jericho-html-3.3-sources.jar + + + ext/solr-solrj-4.9.1-sources.jar + release/modules/ext/solr-solrj-4.9.1-sources.jar + ext/juniversalchardet-1.0.3.jar release/modules/ext/juniversalchardet-1.0.3.jar @@ -333,10 +325,22 @@ ext/apache-mime4j-core-0.7.2.jar release/modules/ext/apache-mime4j-core-0.7.2.jar + + ext/httpmime-4.3.1.jar + release/modules/ext/httpmime-4.3.1.jar + ext/qdox-1.12.jar release/modules/ext/qdox-1.12.jar + + ext/httpcore-4.3.jar + release/modules/ext/httpcore-4.3.jar + + + ext/commons-lang-2.4.jar + release/modules/ext/commons-lang-2.4.jar + ext/rome-0.9.jar release/modules/ext/rome-0.9.jar @@ -353,18 +357,14 @@ ext/jdom-1.0.jar release/modules/ext/jdom-1.0.jar + + ext/poi-ooxml-schemas-3.10-beta2.jar + release/modules/ext/poi-ooxml-schemas-3.10-beta2.jar + ext/pdfbox-1.8.4.jar release/modules/ext/pdfbox-1.8.4.jar - - ext/fontbox-1.8.4.jar - release/modules/ext/fontbox-1.8.4.jar - - - ext/jempbox-1.8.4.jar - release/modules/ext/jempbox-1.8.4.jar - ext/wstx-asl-3.2.7.jar release/modules/ext/wstx-asl-3.2.7.jar @@ -377,6 +377,10 @@ ext/dom4j-1.6.1.jar release/modules/ext/dom4j-1.6.1.jar + + ext/bcprov-jdk15-1.45.jar + release/modules/ext/bcprov-jdk15-1.45.jar + diff --git a/KeywordSearch/release/solr/solr/solr.xml b/KeywordSearch/release/solr/solr/solr.xml index f2d49d693e..94d60b6a29 100644 --- a/KeywordSearch/release/solr/solr/solr.xml +++ b/KeywordSearch/release/solr/solr/solr.xml @@ -17,17 +17,29 @@ --> - + This is an example of a simple "solr.xml" file for configuring one or + more Solr Cores, as well as allowing Cores to be added, removed, and + reloaded via HTTP requests. + + More information about options available in this configuration file, + and Solr Core administration can be found online: + http://wiki.apache.org/solr/CoreAdmin +--> + + + + + ${host:} + ${jetty.port:8983} + ${hostContext:solr} + ${zkClientTimeout:30000} + ${genericCoreNodeNames:true} + + + + ${socketTimeout:0} + ${connTimeout:0} + - - - diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java index 99f4f288d4..677ad0e4c4 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Installer.java @@ -38,7 +38,6 @@ import org.sleuthkit.autopsy.coreutils.Version; class Installer extends ModuleInstall { private static final Logger logger = Logger.getLogger(Installer.class.getName()); - private final static int SERVER_START_RETRIES = 5; @Override public void restored() { @@ -48,138 +47,19 @@ class Installer extends ModuleInstall { Case.addPropertyChangeListener(new KeywordSearch.CaseChangeListener()); final Server server = KeywordSearch.getServer(); - int retries = SERVER_START_RETRIES; - - //TODO revise this logic, handle other server types, move some logic to Server class try { - //check if running from previous application instance and try to shut down - logger.log(Level.INFO, "Checking if server is running"); //NON-NLS - if (server.isRunning()) { - //TODO this could hang if other type of server is running - logger.log(Level.WARNING, "Already a server running on " + server.getCurrentSolrServerPort() //NON-NLS - + " port, maybe leftover from a previous run. Trying to shut it down."); //NON-NLS - //stop gracefully - server.stop(); - logger.log(Level.INFO, "Re-checking if server is running"); //NON-NLS - if (server.isRunning()) { - int serverPort = server.getCurrentSolrServerPort(); - int serverStopPort = server.getCurrentSolrStopPort(); - logger.log(Level.SEVERE, "There's already a server running on " //NON-NLS - + serverPort + " port that can't be shutdown."); //NON-NLS - if (!Server.isPortAvailable(serverPort)) { - reportPortError(serverPort); - } else if (!Server.isPortAvailable(serverStopPort)) { - reportStopPortError(serverStopPort); - } else { - //some other reason - reportInitError(); - } - - //in this case give up - - } else { - logger.log(Level.INFO, "Old Solr server shutdown successfully."); //NON-NLS - //make sure there really isn't a hang Solr process, in case isRunning() reported false - server.killSolr(); - } - } - } catch (KeywordSearchModuleException e) { - logger.log(Level.SEVERE, "Starting server failed, will try to kill. ", e); //NON-NLS - server.killSolr(); + server.start(); + } catch (SolrServerNoPortException ex) { + logger.log(Level.SEVERE, "Failed to start Keyword Search server: ", ex); //NON-NLS + if (ex.getPortNumber() == server.getCurrentSolrServerPort()) + reportPortError(ex.getPortNumber()); + else + reportStopPortError(ex.getPortNumber()); } - - - try { - //Ensure no other process is still bound to that port, even if we think solr is not running - //Try to bind to the port 4 times at 1 second intervals. - //TODO move some of this logic to Server class - for (int i = 0; i <= 3; i++) { - logger.log(Level.INFO, "Checking if port available."); //NON-NLS - if (Server.isPortAvailable(server.getCurrentSolrServerPort())) { - logger.log(Level.INFO, "Port available, trying to start server."); //NON-NLS - server.start(); - break; - } else if (i == 3) { - logger.log(Level.INFO, "No port available, done retrying."); //NON-NLS - reportPortError(server.getCurrentSolrServerPort()); - retries = 0; - break; - } else { - try { - Thread.sleep(1000); - } catch (InterruptedException iex) { - logger.log(Level.WARNING, "Timer interrupted"); //NON-NLS - } - } - } - } catch (SolrServerNoPortException npe) { - logger.log(Level.SEVERE, "Starting server failed due to no port available. ", npe); //NON-NLS - //try to kill it - - } catch (KeywordSearchModuleException e) { - logger.log(Level.SEVERE, "Starting server failed. ", e); //NON-NLS - } - - - //retry if needed - //TODO this loop may be now redundant - while (retries-- > 0) { - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - logger.log(Level.WARNING, "Timer interrupted."); //NON-NLS - } - - try { - logger.log(Level.INFO, "Ensuring the server is running, retries remaining: " + retries); //NON-NLS - if (!server.isRunning()) { - logger.log(Level.WARNING, "Server still not running"); //NON-NLS - try { - logger.log(Level.WARNING, "Trying to start the server. "); //NON-NLS - server.start(); - } catch (SolrServerNoPortException npe) { - logger.log(Level.SEVERE, "Starting server failed due to no port available. ", npe); //NON-NLS - } - } else { - logger.log(Level.INFO, "Server appears now running. "); //NON-NLS - break; - } - } catch (KeywordSearchModuleException ex) { - logger.log(Level.SEVERE, "Starting server failed. ", ex); //NON-NLS - //retry if has retries - } - - } //end of retry while loop - - - //last check if still not running to report errors - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - logger.log(Level.WARNING, "Timer interrupted."); //NON-NLS - } - try { - logger.log(Level.INFO, "Last check if server is running. "); //NON-NLS - if (!server.isRunning()) { - logger.log(Level.SEVERE, "Server is still not running. "); //NON-NLS - //check if port is taken or some other reason - int serverPort = server.getCurrentSolrServerPort(); - int serverStopPort = server.getCurrentSolrStopPort(); - if (!Server.isPortAvailable(serverPort)) { - reportPortError(serverPort); - } else if (!Server.isPortAvailable(serverStopPort)) { - reportStopPortError(serverStopPort); - } else { - //some other reason - reportInitError(); - } - } - } catch (KeywordSearchModuleException ex) { - logger.log(Level.SEVERE, "Starting server failed. ", ex); //NON-NLS - reportInitError(); - } - - + catch (KeywordSearchModuleException ex) { + logger.log(Level.SEVERE, "Failed to start Keyword Search server: ", ex); //NON-NLS + reportInitError(ex.getMessage()); + } } @Override @@ -218,13 +98,10 @@ class Installer extends ModuleInstall { }); } - private void reportInitError() { + private void reportInitError(final String msg) { WindowManager.getDefault().invokeWhenUIReady(new Runnable() { @Override public void run() { - final String msg = NbBundle.getMessage(this.getClass(), "Installer.reportInitError", KeywordSearch.getServer().getCurrentSolrServerPort(), Version.getName(), Server.PROPERTIES_CURRENT_SERVER_PORT, Server.PROPERTIES_FILE); - MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "Installer.errorInitKsmMsg"), msg); - MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "Installer.errorInitKsmMsg"), msg); } }); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index de6871788c..ac80816888 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -45,7 +45,6 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.AbstractAction; import org.apache.solr.client.solrj.SolrQuery; -import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.request.CoreAdminRequest; import org.apache.solr.client.solrj.response.QueryResponse; @@ -63,6 +62,8 @@ import org.apache.solr.common.SolrInputDocument; import org.apache.solr.client.solrj.impl.XMLResponseParser; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; +import org.sleuthkit.autopsy.casemodule.Case.CaseType; +import org.sleuthkit.autopsy.core.UserPreferences; /** * Handles for keeping track of a Solr server and its cores @@ -148,7 +149,6 @@ public class Server { public static final long MAX_CONTENT_SIZE = 1L * 1024 * 1024 * 1024; private static final Logger logger = Logger.getLogger(Server.class.getName()); private static final String DEFAULT_CORE_NAME = "coreCase"; //NON-NLS - // TODO: DEFAULT_CORE_NAME needs to be replaced with unique names to support multiple open cases public static final String CORE_EVT = "CORE_EVT"; //NON-NLS public static final char ID_CHUNK_SEP = '_'; private String javaPath = "java"; //NON-NLS @@ -160,6 +160,7 @@ public class Server { static final String PROPERTIES_CURRENT_SERVER_PORT = "IndexingServerPort"; //NON-NLS static final String PROPERTIES_CURRENT_STOP_PORT = "IndexingServerStopPort"; //NON-NLS private static final String KEY = "jjk#09s"; //NON-NLS + static final String DEFAULT_SOLR_SERVER_HOST = "localhost"; //NON-NLS static final int DEFAULT_SOLR_SERVER_PORT = 23232; static final int DEFAULT_SOLR_STOP_PORT = 34343; private int currentSolrServerPort = 0; @@ -170,23 +171,27 @@ public class Server { STOPPED, STARTED }; - private SolrServer solrServer; - private String instanceDir; - private File solrFolder; - private ServerAction serverAction; + + // A reference to the locally running Solr instance. + private final HttpSolrServer localSolrServer; + + // A reference to the Solr server we are currently connected to for the Case. + // This could be a local or remote server. + private HttpSolrServer currentSolrServer; + + private final String instanceDir; + private final File solrFolder; + private final ServerAction serverAction; private InputStreamPrinterThread errorRedirectThread; - private String solrUrl; /** * New instance for the server at the given URL * - * @param url should be something like "http://localhost:23232/solr/" */ Server() { initSettings(); - this.solrUrl = "http://localhost:" + currentSolrServerPort + "/solr"; //NON-NLS - this.solrServer = new HttpSolrServer(solrUrl); + this.localSolrServer = new HttpSolrServer("http://localhost:" + currentSolrServerPort + "/solr"); //NON-NLS serverAction = new ServerAction(); solrFolder = InstalledFileLocator.getDefault().locate("solr", Server.class.getPackage().getName(), false); //NON-NLS instanceDir = solrFolder.getAbsolutePath() + File.separator + "solr"; //NON-NLS @@ -196,6 +201,7 @@ public class Server { } private void initSettings() { + if (ModuleSettings.settingExists(PROPERTIES_FILE, PROPERTIES_CURRENT_SERVER_PORT)) { try { currentSolrServerPort = Integer.decode(ModuleSettings.getConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_SERVER_PORT)); @@ -207,7 +213,7 @@ public class Server { currentSolrServerPort = DEFAULT_SOLR_SERVER_PORT; ModuleSettings.setConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_SERVER_PORT, String.valueOf(currentSolrServerPort)); } - + if (ModuleSettings.settingExists(PROPERTIES_FILE, PROPERTIES_CURRENT_STOP_PORT)) { try { currentSolrStopPort = Integer.decode(ModuleSettings.getConfigSetting(PROPERTIES_FILE, PROPERTIES_CURRENT_STOP_PORT)); @@ -325,10 +331,10 @@ public class Server { * @return */ List getSolrPIDs() { - List pids = new ArrayList(); + List pids = new ArrayList<>(); //NOTE: these needs to be in sync with process start string in start() - final String pidsQuery = "Args.4.eq=-DSTOP.KEY=" + KEY + ",Args.7.eq=start.jar"; //NON-NLS + final String pidsQuery = "Args.4.eq=-DSTOP.KEY=" + KEY + ",Args.6.eq=start.jar"; //NON-NLS long[] pidsArr = PlatformUtil.getJavaPIDs(pidsQuery); if (pidsArr != null) { @@ -353,12 +359,44 @@ public class Server { } /** - * Tries to start a Solr instance in a separate process. Returns immediately + * Tries to start a local Solr instance in a separate process. Returns immediately * (probably before the server is ready) and doesn't check whether it was * successful. */ void start() throws KeywordSearchModuleException, SolrServerNoPortException { + if (isRunning()) { + // If a Solr server is running we stop it. + stop(); + } + + if (!isPortAvailable(currentSolrServerPort)){ + // There is something already listening on our port. Let's see if + // this is from an earlier run that didn't successfully shut down + // and if so kill it. + final List pids = this.getSolrPIDs(); + + // If the culprit listening on the port is not a Solr process + // we refuse to start. + if (pids.isEmpty()) { + throw new SolrServerNoPortException(currentSolrServerPort); + } + + // Ok, we've tried to stop it above but there still appears to be + // a Solr process listening on our port so we forcefully kill it. + killSolr(); + + // If either of the ports are still in use after our attempt to kill + // previously running processes we give up and throw an exception. + if (!isPortAvailable(currentSolrServerPort)) { + throw new SolrServerNoPortException(currentSolrServerPort); + } + if (!isPortAvailable(currentSolrStopPort)) { + throw new SolrServerNoPortException(currentSolrStopPort); + } + } + logger.log(Level.INFO, "Starting Solr server from: " + solrFolder.getAbsolutePath()); //NON-NLS + if (isPortAvailable(currentSolrServerPort)) { logger.log(Level.INFO, "Port [" + currentSolrServerPort + "] available, starting Solr"); //NON-NLS try { @@ -405,6 +443,7 @@ public class Server { } catch (InterruptedException ex) { logger.log(Level.WARNING, "Timer interrupted"); //NON-NLS } + final List pids = this.getSolrPIDs(); logger.log(Level.INFO, "New Solr process PID: " + pids); //NON-NLS } catch (SecurityException ex) { @@ -416,10 +455,7 @@ public class Server { throw new KeywordSearchModuleException( NbBundle.getMessage(this.getClass(), "Server.start.exception.cantStartSolr.msg2"), ex); } - } else { - logger.log(Level.SEVERE, "Could not start Solr server process, port [" + currentSolrServerPort + "] not available!"); //NON-NLS - throw new SolrServerNoPortException(currentSolrServerPort); - } + } } /** @@ -472,11 +508,12 @@ public class Server { } /** - * Tries to stop a Solr instance. + * Tries to stop the local Solr instance. * * Waits for the stop command to finish before returning. */ synchronized void stop() { + try { logger.log(Level.INFO, "Stopping Solr server from: " + solrFolder.getAbsolutePath()); //NON-NLS //try graceful shutdown @@ -498,8 +535,7 @@ public class Server { curSolrProcess = null; } - } catch (InterruptedException ex) { - } catch (IOException ex) { + } catch (InterruptedException | IOException ex) { } finally { //stop Solr stream -> log redirect threads try { @@ -517,7 +553,7 @@ public class Server { } /** - * Tests if there's a Solr server running by sending it a core-status + * Tests if there's a local Solr server running by sending it a core-status * request. * * @return false if the request failed with a connection error, otherwise @@ -525,13 +561,20 @@ public class Server { */ synchronized boolean isRunning() throws KeywordSearchModuleException { try { + + if (isPortAvailable(currentSolrServerPort)) { + return false; + } + + if (curSolrProcess != null && !curSolrProcess.isAlive()) { + return false; + } + // making a status request here instead of just doing solrServer.ping(), because // that doesn't work when there are no cores - //TODO check if port avail and return false if it is - //TODO handle timeout in cases when some other type of server on that port - CoreAdminRequest.getStatus(null, solrServer); + CoreAdminRequest.getStatus(null, localSolrServer); logger.log(Level.INFO, "Solr server is running"); //NON-NLS } catch (SolrServerException ex) { @@ -642,7 +685,8 @@ public class Server { */ private synchronized Core openCore(Case theCase) throws KeywordSearchModuleException { String dataDir = getIndexDirPath(theCase); - return this.openCore(DEFAULT_CORE_NAME, new File(dataDir)); + String coreName = theCase.getTextIndexName(); + return this.openCore(coreName.isEmpty() ? DEFAULT_CORE_NAME : coreName, new File(dataDir), theCase.getCaseType()); } /** @@ -914,7 +958,7 @@ public class Server { * @param dataDir directory to load/store the core data from/to * @return new core */ - private Core openCore(String coreName, File dataDir) throws KeywordSearchModuleException { + private Core openCore(String coreName, File dataDir, CaseType caseType) throws KeywordSearchModuleException { try { if (!dataDir.exists()) { dataDir.mkdirs(); @@ -929,17 +973,24 @@ public class Server { CoreAdminRequest.Create createCore = new CoreAdminRequest.Create(); createCore.setDataDir(dataDir.getAbsolutePath()); - createCore.setInstanceDir(instanceDir); createCore.setCoreName(coreName); createCore.setConfigSet("AutopsyConfig"); - this.solrServer.request(createCore); + if (caseType == CaseType.SINGLE_USER_CASE) { + currentSolrServer = this.localSolrServer; + //createCore.setInstanceDir(instanceDir); + } + else { + currentSolrServer = connectToRemoteSolrServer(); + } + + currentSolrServer.request(createCore); final Core newCore = new Core(coreName); return newCore; - } catch (SolrServerException ex) { + } catch (SolrServerException | SolrException ex) { throw new KeywordSearchModuleException( NbBundle.getMessage(this.getClass(), "Server.openCore.exception.cantOpen.msg"), ex); } catch (IOException ex) { @@ -948,6 +999,13 @@ public class Server { } } + private HttpSolrServer connectToRemoteSolrServer() { + String host = UserPreferences.getIndexingServerHost(); + String port = UserPreferences.getIndexingServerPort(); + + return new HttpSolrServer("http://" + host + ":" + port + "/solr"); + } + class Core { // handle to the core in Solr @@ -959,7 +1017,7 @@ public class Server { private Core(String name) { this.name = name; - this.solrCore = new HttpSolrServer(solrUrl + "/" + name); + this.solrCore = new HttpSolrServer(currentSolrServer.getBaseURL() + "/" + name); //TODO test these settings //solrCore.setSoTimeout(1000 * 60); // socket read timeout, make large enough so can index larger files @@ -1062,7 +1120,7 @@ public class Server { synchronized void close() throws KeywordSearchModuleException { try { - CoreAdminRequest.unloadCore(this.name, solrServer); + CoreAdminRequest.unloadCore(this.name, currentSolrServer); } catch (SolrServerException ex) { throw new KeywordSearchModuleException( NbBundle.getMessage(this.getClass(), "Server.close.exception.msg"), ex);