Added support for BASIC authentication to Solr.
diff --git a/norconex-committer-solr/src/main/java/com/norconex/committer/solr/SolrCommitter.java b/norconex-committer-solr/src/main/java/com/norconex/committer/solr/SolrCommitter.java
index ec509b1..6730caa 100644
--- a/norconex-committer-solr/src/main/java/com/norconex/committer/solr/SolrCommitter.java
+++ b/norconex-committer-solr/src/main/java/com/norconex/committer/solr/SolrCommitter.java
@@ -14,6 +14,7 @@
*/
package com.norconex.committer.solr;
+import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -33,6 +34,7 @@
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.common.SolrInputDocument;
@@ -51,19 +53,19 @@
*
* Commits documents to Apache Solr.
*
- *
+ *
* Solr Client:
*
- * As of 2.4.0, it is possible to specify which type of
+ * As of 2.4.0, it is possible to specify which type of
*
* Solr Client to use.
* The expected configuration value of "solrURL" is influenced
- * by the client type chosen. Default client type is
+ * by the client type chosen. Default client type is
* HttpSolrClient
. The clients are:
*
*
* - HttpSolrClient
- * - For direct access to a single Solr node. Ideal for
+ *
- For direct access to a single Solr node. Ideal for
* local development. Needs a Solr URL. Default client.
* - LBHttpSolrClient
* - Simple load-balancing as an alternative to an external load balancer.
@@ -72,7 +74,7 @@
*
- Optimized for mass upload on a single node. Not best for queries.
* Needs a Solr URL.
* - CloudSolrClient
- * - For use with a SolrCloud cluster. Needs a comma-separated list
+ *
- For use with a SolrCloud cluster. Needs a comma-separated list
* of Zookeeper hosts.
* - Http2SolrClient
* - Same as HttpSolrClient but for HTTP/2 support. Marked as
@@ -84,10 +86,10 @@
*
- Same as LBHttpSolrClient but for HTTP/2 support. Marked as
* experimental by Apache.
*
- *
+ *
* Authentication
*
- * Since 2.4.0, BASIC authentication is supported for password-protected
+ * Since 2.4.0, BASIC authentication is supported for password-protected
* Solr installations.
* The password
can optionally be
* encrypted using {@link EncryptionUtil} (or command-line "encrypt.bat"
@@ -121,15 +123,15 @@
*
Name of a JVM system property containing the key. |
*
*
- *
+ *
*
* As of 2.2.1, XML configuration entries expecting millisecond durations
- * can be provided in human-readable format (English only), as per
+ * can be provided in human-readable format (English only), as per
* {@link DurationParser} (e.g., "5 minutes and 30 seconds" or "5m30s").
*
- *
+ *
* XML configuration usage:
- *
+ *
*
* <committer class="com.norconex.committer.solr.SolrCommitter">
* <solrClientType>
@@ -141,29 +143,29 @@
* <-- multiple param tags allowed -->
* </solrUpdateURLParams>
* <solrCommitDisabled>[false|true]</solrCommitDisabled>
- *
+ *
* <!-- Use the following if BASIC authentication is required. -->
* <username>(Optional user name)</username>
* <password>(Optional user password)</password>
* <!-- Use the following if password is encrypted. -->
* <passwordKey>(the encryption key or a reference to it)</passwordKey>
* <passwordKeySource>[key|file|environment|property]</passwordKeySource>
- *
+ *
* <sourceReferenceField keep="[false|true]">
- * (Optional name of field that contains the document reference, when
+ * (Optional name of field that contains the document reference, when
* the default document reference is not used. The reference value
- * will be mapped to Solr "id" field, or the "targetReferenceField"
+ * will be mapped to Solr "id" field, or the "targetReferenceField"
* specified.
- * Once re-mapped, this metadata source field is
+ * Once re-mapped, this metadata source field is
* deleted, unless "keep" is set to true
.)
* </sourceReferenceField>
* <targetReferenceField>
- * (Name of Solr target field where the store a document unique
- * identifier (idSourceField). If not specified, default is "id".)
+ * (Name of Solr target field where the store a document unique
+ * identifier (idSourceField). If not specified, default is "id".)
* </targetReferenceField>
* <sourceContentField keep="[false|true]">
- * (If you wish to use a metadata field to act as the document
- * "content", you can specify that field here. Default
+ * (If you wish to use a metadata field to act as the document
+ * "content", you can specify that field here. Default
* does not take a metadata field but rather the document content.
* Once re-mapped, the metadata source field is deleted,
* unless "keep" is set to true
.)
@@ -173,7 +175,7 @@
* Default is: content)
* </targetContentField>
* <commitBatchSize>
- * (Maximum number of docs to send Solr at once. Will issue a Solr
+ * (Maximum number of docs to send Solr at once. Will issue a Solr
* commit unless "solrCommitDisabled" is true)
* </commitBatchSize>
* <queueDir>(optional path where to queue files)</queueDir>
@@ -182,7 +184,7 @@
* <maxRetryWait>(max delay in milliseconds between retries)</maxRetryWait>
* </committer>
*
- *
+ *
* @author Pascal Essiembre
*/
public class SolrCommitter extends AbstractMappedCommitter {
@@ -195,16 +197,16 @@ public class SolrCommitter extends AbstractMappedCommitter {
public static final String DEFAULT_SOLR_CONTENT_FIELD = "content";
- private SolrClientType solrClientType;
+ private SolrClientType solrClientType;
private String solrURL;
private boolean solrCommitDisabled;
private final Map updateUrlParams = new HashMap<>();
private String username;
private String password;
private EncryptionKey passwordKey;
-
+
private SolrClient solrClient;
-
+
/**
* Constructor.
*/
@@ -280,7 +282,7 @@ public Set getUpdateUrlParamNames() {
/**
* Sets whether to send an explicit commit request at the end of every
* batch, or let the server auto-commit.
- * @param solrCommitDisabled true
if sending Solr commit is
+ * @param solrCommitDisabled true
if sending Solr commit is
* disabled
* @since 2.2.0
*/
@@ -351,20 +353,20 @@ public EncryptionKey getPasswordKey() {
public void setPasswordKey(EncryptionKey passwordKey) {
this.passwordKey = passwordKey;
}
-
+
@Override
protected void commitBatch(List batch) {
- LOG.info("Sending " + batch.size()
+ LOG.info("Sending " + batch.size()
+ " documents to Solr for update/deletion.");
try {
SolrClient solrClient = ensureSolrClient();
-
+
// Add to request all operations in batch, and force a commit
// whenever we do a "delete" after an "add" to eliminate the
- // risk of the delete being a no-op since added documents are
+ // risk of the delete being a no-op since added documents are
// not visible until committed (thus nothing to delete).
-
+
//TODO before a delete, check if the same reference was previously
//added before forcing a commit if any additions occurred.
boolean previousWasAddition = false;
@@ -375,34 +377,44 @@ protected void commitBatch(List batch) {
previousWasAddition = true;
} else if (op instanceof IDeleteOperation) {
if (previousWasAddition && !isSolrCommitDisabled()) {
- solrClient.commit();
+ solrCommit();
}
req = solrDeleteRequest((IDeleteOperation) op);
previousWasAddition = false;
} else {
throw new CommitterException("Unsupported operation:" + op);
}
-
- if (StringUtils.isNotBlank(getUsername())) {
- req.setBasicAuthCredentials(
- getUsername(), EncryptionUtil.decrypt(
- getPassword(), getPasswordKey()));
- }
+
+ setCredentials(req);
+
for (Entry entry : updateUrlParams.entrySet()) {
req.setParam(entry.getKey(), entry.getValue());
}
- solrClient.request(req);
+ req.process(solrClient);
}
if (!isSolrCommitDisabled()) {
- solrClient.commit();
+ solrCommit();
}
} catch (Exception e) {
throw new CommitterException(
"Cannot index document batch to Solr.", e);
}
- LOG.info("Done sending documents to Solr for update/deletion.");
+ LOG.info("Done sending documents to Solr for update/deletion.");
+ }
+
+ private void setCredentials(UpdateRequest req) {
+ if (StringUtils.isNotBlank(getUsername())) {
+ req.setBasicAuthCredentials(getUsername(), EncryptionUtil.decrypt(
+ getPassword(), getPasswordKey()));
+ }
+ }
+
+ private void solrCommit() throws IOException, SolrServerException {
+ UpdateRequest req = new UpdateRequest();
+ setCredentials(req);
+ req.commit(solrClient, null);
}
-
+
protected UpdateRequest solrAddRequest(IAddOperation op) {
UpdateRequest req = new UpdateRequest();
req.add(buildSolrDocument(op.getMetadata()));
@@ -413,15 +425,15 @@ protected UpdateRequest solrDeleteRequest(IDeleteOperation op) {
req.deleteById(op.getReference());
return req;
}
-
+
private synchronized SolrClient ensureSolrClient() {
if (solrClient == null) {
- solrClient = ObjectUtils.defaultIfNull(solrClientType,
+ solrClient = ObjectUtils.defaultIfNull(solrClientType,
SolrClientType.HTTP).create(solrURL);
}
return solrClient;
}
-
+
private SolrInputDocument buildSolrDocument(Properties fields) {
SolrInputDocument doc = new SolrInputDocument();
for (String key : fields.keySet()) {
@@ -436,7 +448,7 @@ private SolrInputDocument buildSolrDocument(Properties fields) {
@Override
protected void saveToXML(XMLStreamWriter writer) throws XMLStreamException {
EnhancedXMLStreamWriter w = new EnhancedXMLStreamWriter(writer);
-
+
if (solrClientType != null) {
w.writeElementString("solrClientType", solrClientType.toString());
}
@@ -462,13 +474,13 @@ protected void saveToXML(XMLStreamWriter writer) throws XMLStreamException {
key.getSource().name().toLowerCase());
}
}
-
+
w.writeEndElement();
}
@Override
protected void loadFromXml(XMLConfiguration xml) {
-
+
String xmlSolrClientType = xml.getString("solrClientType", null);
if (StringUtils.isNotBlank(xmlSolrClientType)) {
setSolrClientType(SolrClientType.of(xmlSolrClientType));
@@ -476,7 +488,7 @@ protected void loadFromXml(XMLConfiguration xml) {
setSolrURL(xml.getString("solrURL", getSolrURL()));
setSolrCommitDisabled(xml.getBoolean(
"solrCommitDisabled", isSolrCommitDisabled()));
- List uparams =
+ List uparams =
xml.configurationsAt("solrUpdateURLParams.param");
for (HierarchicalConfiguration param : uparams) {
setUpdateUrlParam(param.getString("[@name]"), param.getString(""));
@@ -532,7 +544,7 @@ public boolean equals(Object obj) {
.append(passwordKey, other.passwordKey)
.isEquals();
}
-
+
@Override
public String toString() {
return new ToStringBuilder(this)