Add contributed solr repository connector
git-svn-id: https://svn.apache.org/repos/asf/manifoldcf/branches/CONNECTORS-1653@1883685 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/connectors/pom.xml b/connectors/pom.xml
index d55762f..640c3e2 100644
--- a/connectors/pom.xml
+++ b/connectors/pom.xml
@@ -78,6 +78,7 @@
<module>html-extractor</module>
<module>mongodb</module>
<module>csws</module>
+ <module>solringester</module>
</modules>
</project>
diff --git a/connectors/solringester/README.md b/connectors/solringester/README.md
new file mode 100644
index 0000000..bc43cb0
--- /dev/null
+++ b/connectors/solringester/README.md
@@ -0,0 +1 @@
+# mcf-solringester-connector
\ No newline at end of file
diff --git a/connectors/solringester/build.xml b/connectors/solringester/build.xml
new file mode 100644
index 0000000..d2ffb51
--- /dev/null
+++ b/connectors/solringester/build.xml
@@ -0,0 +1,68 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project name="solringester" default="all">
+
+ <property environment="env"/>
+ <condition property="mcf-dist" value="${env.MCFDISTPATH}">
+ <isset property="env.MCFDISTPATH"/>
+ </condition>
+ <property name="abs-dist" location="../../dist"/>
+ <condition property="mcf-dist" value="${abs-dist}">
+ <not>
+ <isset property="env.MCFDISTPATH"/>
+ </not>
+ </condition>
+
+ <import file="${mcf-dist}/connector-build.xml"/>
+
+ <path id="connector-classpath">
+ <path refid="mcf-connector-build.connector-classpath"/>
+ <fileset dir="../../lib">
+ <include name="solr-solrj*.jar"/>
+ </fileset>
+ </path>
+
+ <target name="lib" depends="mcf-connector-build.lib,precompile-check" if="canBuild">
+ <mkdir dir="dist/lib"/>
+ <copy todir="dist/lib">
+ <fileset dir="../../lib">
+ <include name="solr-solrj*.jar"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="integration">
+
+ <mkdir dir="dist/integration/solr-7.x"/>
+ <copy todir="dist/integration/solr-7.x">
+ <fileset dir="../../lib/solr-7.x"/>
+ </copy>
+ <mkdir dir="dist/integration/solr-8.x"/>
+ <copy todir="dist/integration/solr-8.x">
+ <fileset dir="../../lib/solr-8.x"/>
+ </copy>
+ </target>
+
+ <target name="deliver-connector" depends="mcf-connector-build.deliver-connector">
+ <antcall target="general-add-repository-connector">
+ <param name="connector-label" value="SolrIngester"/>
+ <param name="connector-class" value="org.apache.manifoldcf.crawler.connectors.solringester.SolrIngesterConnector"/>
+ </antcall>
+ </target>
+
+</project>
diff --git a/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/Messages.java b/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/Messages.java
new file mode 100644
index 0000000..88b49ce
--- /dev/null
+++ b/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/Messages.java
@@ -0,0 +1,121 @@
+/* $Id: Messages.java 1295926 2012-03-01 21:56:27Z kwright $ */
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+* http://www.apache.org/licenses/LICENSE-2.0
+ *
+* Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.manifoldcf.crawler.connectors.solringester;
+
+import java.util.Locale;
+import java.util.Map;
+import org.apache.manifoldcf.core.interfaces.IHTTPOutput;
+import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
+
+public class Messages extends org.apache.manifoldcf.ui.i18n.Messages {
+
+ public static final String DEFAULT_BUNDLE_NAME = "org.apache.manifoldcf.crawler.connectors.solringester.common";
+
+ public static final String DEFAULT_PATH_NAME = "org.apache.manifoldcf.crawler.connectors.solringester";
+
+ /**
+ * Constructor - do no instantiate
+ */
+ protected Messages() {
+ }
+
+ public static String getString(Locale locale, String messageKey) {
+ return getString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+ }
+
+ public static String getAttributeString(Locale locale, String messageKey) {
+ return getAttributeString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+ }
+
+ public static String getBodyString(Locale locale, String messageKey) {
+ return getBodyString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+ }
+
+ public static String getAttributeJavascriptString(Locale locale, String messageKey) {
+ return getAttributeJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+ }
+
+ public static String getBodyJavascriptString(Locale locale, String messageKey) {
+ return getBodyJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, null);
+ }
+
+ public static String getString(Locale locale, String messageKey, Object[] args) {
+ return getString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+ }
+
+ public static String getAttributeString(Locale locale, String messageKey, Object[] args) {
+ return getAttributeString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+ }
+
+ public static String getBodyString(Locale locale, String messageKey, Object[] args) {
+ return getBodyString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+ }
+
+ public static String getAttributeJavascriptString(Locale locale, String messageKey, Object[] args) {
+ return getAttributeJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+ }
+
+ public static String getBodyJavascriptString(Locale locale, String messageKey, Object[] args) {
+ return getBodyJavascriptString(DEFAULT_BUNDLE_NAME, locale, messageKey, args);
+ }
+
+ // More general methods which allow bundlenames and class loaders to be specified.
+ public static String getString(String bundleName, Locale locale, String messageKey, Object[] args) {
+ return getString(Messages.class, bundleName, locale, messageKey, args);
+ }
+
+ public static String getAttributeString(String bundleName, Locale locale, String messageKey, Object[] args) {
+ return getAttributeString(Messages.class, bundleName, locale, messageKey, args);
+ }
+
+ public static String getBodyString(String bundleName, Locale locale, String messageKey, Object[] args) {
+ return getBodyString(Messages.class, bundleName, locale, messageKey, args);
+ }
+
+ public static String getAttributeJavascriptString(String bundleName, Locale locale, String messageKey, Object[] args) {
+ return getAttributeJavascriptString(Messages.class, bundleName, locale, messageKey, args);
+ }
+
+ public static String getBodyJavascriptString(String bundleName, Locale locale, String messageKey, Object[] args) {
+ return getBodyJavascriptString(Messages.class, bundleName, locale, messageKey, args);
+ }
+
+ // Resource output
+ public static void outputResource(IHTTPOutput output, Locale locale, String resourceKey,
+ Map<String, String> substitutionParameters, boolean mapToUpperCase)
+ throws ManifoldCFException {
+ outputResource(output, Messages.class, DEFAULT_PATH_NAME, locale, resourceKey,
+ substitutionParameters, mapToUpperCase);
+ }
+
+ public static void outputResourceWithVelocity(IHTTPOutput output, Locale locale, String resourceKey,
+ Map<String, String> substitutionParameters, boolean mapToUpperCase)
+ throws ManifoldCFException {
+ outputResourceWithVelocity(output, Messages.class, DEFAULT_BUNDLE_NAME, DEFAULT_PATH_NAME, locale, resourceKey,
+ substitutionParameters, mapToUpperCase);
+ }
+
+ public static void outputResourceWithVelocity(IHTTPOutput output, Locale locale, String resourceKey,
+ Map<String, Object> contextObjects)
+ throws ManifoldCFException {
+ outputResourceWithVelocity(output, Messages.class, DEFAULT_BUNDLE_NAME, DEFAULT_PATH_NAME, locale, resourceKey,
+ contextObjects);
+ }
+
+
+}
diff --git a/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/SolrIngesterConfig.java b/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/SolrIngesterConfig.java
new file mode 100644
index 0000000..62e92a5
--- /dev/null
+++ b/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/SolrIngesterConfig.java
@@ -0,0 +1,34 @@
+package org.apache.manifoldcf.crawler.connectors.solringester;
+
+public class SolrIngesterConfig {
+
+ // Repository connection Configuration parameters
+ public static final String PARAM_SOLRADDRESS = "solrAddress";
+ public static final String PARAM_SOLRUSERNAME = "solrUsername";
+ public static final String PARAM_SOLRPASSWORD = "solrPassword";
+// public static final String PARAM_SOLRPORT = "solrPort";
+ //public static final String SOLRPORTPORT_DEFAULT = "8983";
+ public static final String PARAM_CONNECTIONTIMEOUT = "connectionTimeout";
+ public static final String SOLRUSERNAME_DEFAULT = "";
+ public static final String SOLRPASSWORD_DEFAULT = "";
+ public static final String PARAM_SOCKETTIMEOUT = "socketTimeout";
+ public static final String SOLRADDRESS_DEFAULT = "http://localhost:8983/solr";
+ public static final String CONNECTIONTIMEOUT_DEFAULT = "60000";
+ public static final String SOCKETTIMEOUT_DEFAULT = "180000";
+
+ // Specification nodes and values
+ public static final String NODE_FIELDMAP = "fieldmap";
+ public static final String ATTRIBUTE_SOURCE = "source";
+ public static final String ATTRIBUTE_TARGET = "target";
+ public static final String ATTRIBUTE_VALUE = "value";
+ public static final String SECURITY_ACTIVATED = "securityactivated";
+ public static final String SECURITY_FIELD = "securityfield";
+ public static final String SECURITY_FIELD2 = "securityfield2";
+ public static final String ID_FIELD = "fieldid";
+ public static final String ROWS_NUMBER = "rowsnumber";
+ public static final String DATE_FIELD = "fielddate";
+ public static final String CONTENT_FIELD = "fieldcontent";
+ public static final String FILTER_CONDITION = "filter";
+ public static final String COLLECTION_NAME = "collection";
+
+}
diff --git a/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/SolrIngesterConnector.java b/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/SolrIngesterConnector.java
new file mode 100644
index 0000000..5306ce3
--- /dev/null
+++ b/connectors/solringester/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/solringester/SolrIngesterConnector.java
@@ -0,0 +1,1279 @@
+/* $Id: SvnConnector.java 994959 2010-09-08 10:04:42Z krycek $ */
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.manifoldcf.crawler.connectors.solringester;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLContext;
+
+import org.apache.http.Header;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultRedirectStrategy;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.ssl.TrustStrategy;
+import org.apache.http.util.EntityUtils;
+import org.apache.manifoldcf.agents.interfaces.RepositoryDocument;
+import org.apache.manifoldcf.agents.interfaces.ServiceInterruption;
+import org.apache.manifoldcf.connectorcommon.common.XThreadStringBuffer;
+import org.apache.manifoldcf.core.interfaces.ConfigParams;
+import org.apache.manifoldcf.core.interfaces.IHTTPOutput;
+import org.apache.manifoldcf.core.interfaces.IPostParameters;
+import org.apache.manifoldcf.core.interfaces.IThreadContext;
+import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
+import org.apache.manifoldcf.core.interfaces.Specification;
+import org.apache.manifoldcf.core.interfaces.SpecificationNode;
+import org.apache.manifoldcf.core.system.ManifoldCF;
+import org.apache.manifoldcf.core.util.URLEncoder;
+import org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector;
+import org.apache.manifoldcf.crawler.interfaces.IExistingVersions;
+import org.apache.manifoldcf.crawler.interfaces.IProcessActivity;
+import org.apache.manifoldcf.crawler.interfaces.ISeedingActivity;
+import org.apache.manifoldcf.crawler.system.Logging;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpClientUtil;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.params.CursorMarkParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+
+public class SolrIngesterConnector extends BaseRepositoryConnector {
+
+ public static final String _rcsid = "@(#)$Id: solringesterConnector.java 994959 2010-09-08 10:04:42Z redguy $";
+
+ /**
+ * Deny access token for default authority
+ */
+ private final static String defaultAuthorityDenyToken = "__nosecurity__";
+
+ private final static String ACTION_PARAM_NAME = "action";
+
+ private final static String ACTION_CHECK = "check";
+
+ private final static String ACTION_SEED = "seed";
+
+ private final static String ACTION_ITEMS = "items";
+
+ private final static String ACTION_ITEM = "item";
+
+ /** Connection timeout */
+ private int connectionTimeout = -1;
+
+ /** Socket timeout */
+ private int socketTimeout = -1;
+
+ /** Session timeout */
+ private long sessionTimeout = -1L;
+
+ protected final static long sessionExpirationInterval = 300000L;
+
+ private String solringesterLogin = null;
+
+ private String solringesterPassword = null;
+
+ /** Connection manager */
+ private HttpClientConnectionManager connectionManager = null;
+
+ /** HttpClientBuilder */
+ private HttpClientBuilder builder = null;
+
+ /** Httpclient instance */
+ private CloseableHttpClient httpClient = null;
+
+ private HttpSolrClient httpSolrClient = null;
+
+ /** Connection timeout */
+ private String connectionTimeoutString = null;
+
+ /** Socket timeout */
+ private String socketTimeoutString = null;
+
+ private String solringesterEntryPoint = null;
+
+ private static final String date_target_field = "last_modified";
+
+ private final static String versionField = "_version_";
+
+ protected static final String RELATIONSHIP_RELATED = "related";
+
+ private static final String EDIT_CONFIGURATION_CONNECTOR_JS = "editConfiguration_connector.js";
+ private static final String EDIT_CONFIGURATION_CONNECTOR_HTML = "editConfiguration_connector.html";
+ private static final String VIEW_CONFIGURATION_CONNECTOR_HTML = "viewConfiguration_connector.html";
+
+ private static final String EDIT_SPECIFICATION_JOB_PARAMETERS_JS = "editSpecification_job_parameters.js";
+ private static final String EDIT_SPECIFICATION_JOB_PARAMETERS_HTML = "editSpecification_job_parameters.html";
+ private static final String VIEW_SPECIFICATION_JOB_PARAMETERS_HTML = "viewSpecification_job_parameters.html";
+
+ private static final String EDIT_SPECIFICATION_JOB_SECURITY_JS = "editSpecification_job_security.js";
+ private static final String EDIT_SPECIFICATION_JOB_SECURITY_HTML = "editSpecification_job_security.html";
+ private static final String VIEW_SPECIFICATION_JOB_SECURITY_HTML = "viewSpecification_job_security.html";
+
+ protected final static String ACTIVITY_GET = "get document";
+
+ /**
+ * Constructor.
+ */
+ public SolrIngesterConnector() {
+ }
+
+ @Override
+ public int getMaxDocumentRequest() {
+ return 100;
+ }
+
+ @Override
+ public String[] getRelationshipTypes() {
+ return new String[] { RELATIONSHIP_RELATED };
+ }
+
+ @Override
+ public int getConnectorModel() {
+ return SolrIngesterConnector.MODEL_ADD_CHANGE;
+ }
+
+ @Override
+ public String[] getActivitiesList() {
+ return new String[] { ACTIVITY_GET };
+ }
+
+ /**
+ * For any given document, list the bins that it is a member of.
+ */
+ @Override
+ public String[] getBinNames(final String documentIdentifier) {
+ // Return the host name
+ return new String[] { solringesterEntryPoint };
+ }
+
+ // All methods below this line will ONLY be called if a connect() call succeeded
+ // on this instance!
+ /**
+ * Connect. The configuration parameters are included.
+ *
+ * @param configParams
+ * are the configuration parameters for this connection. Note well: There are no exceptions allowed from this call, since it is
+ * expected to mainly establish connection parameters.
+ */
+ @Override
+ public void connect(final ConfigParams configParams) {
+ super.connect(configParams);
+ solringesterEntryPoint = configParams.getParameter(SolrIngesterConfig.PARAM_SOLRADDRESS);
+ solringesterLogin = configParams.getParameter(SolrIngesterConfig.PARAM_SOLRUSERNAME);
+ solringesterPassword = "";
+ try {
+ solringesterPassword = ManifoldCF.deobfuscate(configParams.getParameter(SolrIngesterConfig.PARAM_SOLRPASSWORD));
+ } catch (final ManifoldCFException ignore) {
+ }
+ connectionTimeoutString = configParams.getParameter(SolrIngesterConfig.PARAM_CONNECTIONTIMEOUT);
+ socketTimeoutString = configParams.getParameter(SolrIngesterConfig.PARAM_SOCKETTIMEOUT);
+
+ if (Logging.connectors.isDebugEnabled()) {
+ Logging.connectors.debug("SolrIngester: Connection to '" + solringesterEntryPoint + "'");
+ }
+
+ }
+
+ @Override
+ public void disconnect() throws ManifoldCFException {
+ socketTimeoutString = null;
+ connectionTimeoutString = null;
+ sessionTimeout = -1L;
+ httpClient = null;
+ httpSolrClient = null;
+ if (connectionManager != null) {
+ connectionManager.shutdown();
+ }
+ connectionManager = null;
+ solringesterLogin = null;
+ solringesterPassword = null;
+ solringesterEntryPoint = null;
+ super.disconnect();
+ }
+
+ protected void expireSession() throws ManifoldCFException {
+ httpClient = null;
+ httpSolrClient = null;
+ if (connectionManager != null) {
+ connectionManager.shutdown();
+ }
+ connectionManager = null;
+ sessionTimeout = -1L;
+ }
+
+ @Override
+ public void poll() throws ManifoldCFException {
+ if (System.currentTimeMillis() >= sessionTimeout) {
+ expireSession();
+ }
+ if (connectionManager != null) {
+ connectionManager.closeIdleConnections(60000L, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ protected void getSession() throws ManifoldCFException {
+ if (sessionTimeout == -1L) {
+
+ try {
+ this.connectionTimeout = Integer.parseInt(connectionTimeoutString);
+ } catch (final NumberFormatException e) {
+ throw new ManifoldCFException("Bad connection timeout number: " + connectionTimeoutString);
+ }
+ try {
+ this.socketTimeout = Integer.parseInt(socketTimeoutString);
+ } catch (final NumberFormatException e) {
+ throw new ManifoldCFException("Bad socket timeout number: " + socketTimeoutString);
+ }
+
+ final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true;
+ SSLConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
+ try {
+ final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
+ sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
+ } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
+ throw new ManifoldCFException("SSL context initialization failure", e);
+ }
+
+ final PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(
+ RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build());
+ poolingConnectionManager.setDefaultMaxPerRoute(1);
+ poolingConnectionManager.setValidateAfterInactivity(2000);
+ poolingConnectionManager.setDefaultSocketConfig(SocketConfig.custom().setTcpNoDelay(true).setSoTimeout(socketTimeout).build());
+
+ this.connectionManager = poolingConnectionManager;
+
+ final RequestConfig.Builder requestBuilder = RequestConfig.custom().setCircularRedirectsAllowed(true).setSocketTimeout(socketTimeout).setExpectContinueEnabled(false)
+ .setConnectTimeout(connectionTimeout).setConnectionRequestTimeout(socketTimeout);
+
+ final List<Header> headers = new ArrayList<>();
+ if (solringesterLogin != null && !solringesterLogin.isEmpty() && solringesterPassword != null) {
+ final String auth = solringesterLogin + ":" + solringesterPassword;
+ final String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.ISO_8859_1));
+ final String authHeader = "Basic " + new String(encodedAuth);
+ final Header basicAuthheader = new BasicHeader(HttpHeaders.AUTHORIZATION, authHeader);
+ headers.add(basicAuthheader);
+ }
+
+ this.builder = HttpClients.custom().setDefaultHeaders(headers).setConnectionManager(connectionManager).disableAutomaticRetries().setDefaultRequestConfig(requestBuilder.build());
+ builder.setRequestExecutor(new HttpRequestExecutor(socketTimeout)).setRedirectStrategy(new DefaultRedirectStrategy());
+ this.httpClient = builder.build();
+ this.httpSolrClient = new HttpSolrClient.Builder(solringesterEntryPoint).withHttpClient(httpClient).withConnectionTimeout(connectionTimeout).withSocketTimeout(socketTimeout).build();
+ }
+ sessionTimeout = System.currentTimeMillis() + sessionExpirationInterval;
+
+ }
+
+ @Override
+ public String check() throws ManifoldCFException {
+ getSession();
+
+ final HttpGet httpGet = new HttpGet(solringesterEntryPoint);
+ CloseableHttpResponse response = null;
+ try {
+ try {
+ response = this.httpClient.execute(httpGet);
+ } catch (final IOException e) {
+ return "Connection error: " + e.getMessage();
+ }
+ final int responseCode = response.getStatusLine().getStatusCode();
+ if (responseCode != 200) {
+ return "Bad response: " + response.getStatusLine();
+ }
+ return super.check();
+ } finally {
+ if (response != null) {
+ try {
+ response.close();
+ } catch (final IOException e) {
+ return "Connection error: " + e.getMessage();
+ }
+ }
+ }
+ }
+
+ @Override
+ public String addSeedDocuments(final ISeedingActivity activities, final Specification spec, final String lastSeedVersion, final long seedTime, final int jobMode)
+ throws ManifoldCFException, ServiceInterruption {
+
+ long startTime;
+
+ String idFieldName = null;
+ String collection = null;
+ final String dateField = null;
+ final String contentField = null;
+ String rowsNumberString = null;
+ String filter = null;
+
+ if (Logging.connectors.isDebugEnabled()) {
+ Logging.connectors.debug("SolrIngester: Connection to '" + solringesterEntryPoint + "'");
+ }
+
+ // Retrieve configuration parameters
+ for (int l = 0; l < spec.getChildCount(); l++) {
+ final SpecificationNode sn = spec.getChild(l);
+ if (sn.getType() == SolrIngesterConfig.COLLECTION_NAME) {
+ collection = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ if (sn.getType() == SolrIngesterConfig.ID_FIELD) {
+ idFieldName = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+
+ if (sn.getType() == SolrIngesterConfig.ROWS_NUMBER) {
+ rowsNumberString = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+
+ if (sn.getType() == SolrIngesterConfig.FILTER_CONDITION) {
+ filter = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ }
+
+ if (lastSeedVersion == null) {
+ startTime = 0L;
+ } else {
+ // Unpack seed time from seed version string
+ startTime = new Long(lastSeedVersion).longValue();
+ }
+
+ getSession();
+
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ROOT);
+
+ final StringBuilder url = new StringBuilder(solringesterEntryPoint);
+ url.append("?").append(ACTION_PARAM_NAME).append("=").append(ACTION_SEED);
+ if (startTime > 0) {
+ url.append("&startTime=").append(sdf.format(new Date(startTime)));
+ }
+ url.append("&endTime=").append(sdf.format(new Date(seedTime)));
+
+ // ExecuteSeedingThread t = new ExecuteSeedingThread(client, url.toString());
+
+ long dateSolr;
+ if (lastSeedVersion != null) {
+ dateSolr = new Long(lastSeedVersion).longValue();
+ } else {
+ dateSolr = 0L;
+ }
+
+ // String dateSolr = sdf.format(dateSolr);
+
+ final int rowsNumber = Integer.valueOf(rowsNumberString);
+ try {
+ SolrQuery query;
+ if (filter == null || filter == "*:*") {
+ query = new SolrQuery("*:*").setRows(rowsNumber).setSort(idFieldName, SolrQuery.ORDER.asc);
+ } else {
+ query = new SolrQuery("*:*").addFilterQuery(filter).setRows(rowsNumber).setSort(idFieldName, SolrQuery.ORDER.asc);
+ }
+ query.setFields(idFieldName);
+ String cursorMark = CursorMarkParams.CURSOR_MARK_START;
+ boolean done = false;
+ while (!done) {
+ query.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark);
+ QueryResponse response;
+
+ response = httpSolrClient.query(collection, query);
+ final String nextCursorMark = response.getNextCursorMark();
+ final SolrDocumentList documents = response.getResults();
+ for (final SolrDocument document : documents) {
+ activities.addSeedDocument((String) document.getFieldValue(idFieldName));
+ }
+ if (cursorMark.equals(nextCursorMark)) {
+ done = true;
+ }
+ cursorMark = nextCursorMark;
+ }
+ } catch (final SolrServerException | IOException e) {
+ Logging.connectors.error("Unable to perform Solr requests", e);
+ throw new ManifoldCFException("Unable to perform Solr requests", e);
+ }
+
+ return new Long(seedTime).toString();
+
+ }
+
+ @Override
+ public void processDocuments(final String[] documentIdentifiers, final IExistingVersions statuses, final Specification spec, final IProcessActivity activities, final int jobMode,
+ final boolean usesDefaultAuthority) throws ManifoldCFException, ServiceInterruption {
+
+ getSession();
+
+ if (Logging.connectors.isDebugEnabled()) {
+ Logging.connectors.debug("SolrIngester: ProcessDocuments method");
+ }
+ // Get parameters configuration
+ String collection = null;
+ String idFieldName = null;
+ boolean securityActivated = false;
+ String dateField = null;
+ String contentField = null;
+ String securityField = null;
+ String securityField2 = null;
+ String rowsNumberString = null;
+
+ String errorCode = null;
+ String description = "";
+
+ final long startFetchTime = System.currentTimeMillis();
+
+
+ // Hashmap
+ final Map<String, String> mapFields = new HashMap<String, String>();
+
+ for (int l = 0; l < spec.getChildCount(); l++) {
+ final SpecificationNode sn = spec.getChild(l);
+ if (sn.getType() == SolrIngesterConfig.COLLECTION_NAME) {
+ collection = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ if (sn.getType() == SolrIngesterConfig.SECURITY_ACTIVATED) {
+ securityActivated = Boolean.parseBoolean(sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE));
+ }
+ if (sn.getType() == SolrIngesterConfig.ID_FIELD) {
+ idFieldName = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ if (sn.getType() == SolrIngesterConfig.DATE_FIELD) {
+ dateField = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ if (sn.getType() == SolrIngesterConfig.CONTENT_FIELD) {
+ contentField = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ if (sn.getType() == SolrIngesterConfig.SECURITY_FIELD) {
+ securityField = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ if (sn.getType() == SolrIngesterConfig.SECURITY_FIELD2) {
+ securityField2 = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ if (sn.getType().equals(SolrIngesterConfig.NODE_FIELDMAP)) {
+ final String source = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_SOURCE);
+ final String target = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_TARGET);
+ mapFields.put(source, target);
+ }
+ if (sn.getType() == SolrIngesterConfig.ROWS_NUMBER) {
+ rowsNumberString = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+ }
+ }
+
+ final String versionString = null;
+
+ final StringBuilder url = new StringBuilder(solringesterEntryPoint);
+
+ url.append("?").append(ACTION_PARAM_NAME).append("=").append(ACTION_ITEMS);
+ for (int i = 0; i < documentIdentifiers.length; i++) {
+ url.append("&id[]=").append(URLEncoder.encode(documentIdentifiers[i]));
+ }
+
+ /*
+ * Step 1 query that gets idFieldName and versionFieldName
+ *
+ */
+ final String documentIdentifiersString = "\"" + String.join("\" OR \"", documentIdentifiers) + "\"";
+ final int rowsNumber = Integer.valueOf(rowsNumberString);
+ final HashMap<String, String> existingIds = new HashMap<String, String>();
+ if (Logging.connectors.isDebugEnabled()) {
+ Logging.connectors.debug("SolrIngester: docidentifiers size '" + documentIdentifiers.length);
+
+ }
+ if (documentIdentifiers.length > 0) {
+ try {
+ SolrQuery query;
+ query = new SolrQuery("*:*").setRows(rowsNumber).setSort(idFieldName, SolrQuery.ORDER.asc);
+ query.setFields(idFieldName, versionField);
+ query.addFilterQuery(idFieldName + ":(" + documentIdentifiersString + ")");
+
+ String cursorMark = CursorMarkParams.CURSOR_MARK_START;
+ boolean done = false;
+ while (!done) {
+ query.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark);
+ QueryResponse response;
+ response = httpSolrClient.query(collection, query);
+
+ final String nextCursorMark = response.getNextCursorMark();
+ final SolrDocumentList documents = response.getResults();
+ for (final SolrDocument document : documents) {
+ existingIds.put((String) document.getFieldValue(idFieldName), String.valueOf(document.getFieldValue(versionField)));
+ }
+ if (cursorMark.equals(nextCursorMark)) {
+ done = true;
+ }
+ cursorMark = nextCursorMark;
+ }
+
+ /*
+ * End step 1
+ */
+
+ /*
+ * Step 2 Compare the version stored in MCF and store id without version or with different version
+ *
+ */
+ final Set<String> toProcess = new HashSet<String>();
+ final Iterator it = existingIds.entrySet().iterator();
+
+ while (it.hasNext()) {
+
+ final Map.Entry pair = (Map.Entry) it.next();
+
+ final String idStringBis = (String) pair.getKey();
+ final String versionStringBis = (String) pair.getValue();
+
+ if (versionStringBis.length() == 0 || activities.checkDocumentNeedsReindexing(idStringBis, versionStringBis)) {
+ toProcess.add("\"" + (String) pair.getKey() + "\"");
+
+ }
+ // it.remove(); // avoids a ConcurrentModificationException
+ }
+
+ /*
+ * Step 3 : Build query from toProcess list and index all the content
+ */
+
+ if (toProcess.size() > 0) {
+ final List<String> listToProcess = new ArrayList<String>(toProcess);
+ final String listToProcessString = String.join(" OR ", listToProcess);
+
+ // Process the document
+ final RepositoryDocument doc = new RepositoryDocument();
+
+ query = new SolrQuery("*:*").setRows(rowsNumber).setSort(idFieldName, SolrQuery.ORDER.asc);
+ query.setFields("*");
+ query.addFilterQuery(idFieldName + ":(" + listToProcessString + ")");
+
+ cursorMark = CursorMarkParams.CURSOR_MARK_START;
+ done = false;
+ while (!done) {
+ query.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark);
+ QueryResponse response;
+
+ SolrDocumentList documents = null;
+
+ response = httpSolrClient.query(collection, query);
+
+ final String nextCursorMark = response.getNextCursorMark();
+ documents = response.getResults();
+ InputStream is = null;
+ for (final SolrDocument document : documents) {
+ for (final Map.Entry<String, String> entry : mapFields.entrySet()) {
+ ArrayList<Object> listFieldValues = null;
+ if (document.getFieldValues(entry.getKey()) != null) {
+ listFieldValues = (ArrayList<Object>) document.getFieldValues(entry.getKey());
+ if (listFieldValues != null) {
+
+ // TODO
+ // For now only supports String fields (not int, long, date etc...)
+ final String[] tablistFieldValues = listFieldValues.toArray(new String[0]);
+ doc.addField(entry.getValue(), tablistFieldValues);
+
+ }
+ }
+ }
+
+ // TODO
+ // For now you can indicate the date field of the source. But the date field of the target is hardcoded and its value is last_modified
+ doc.addField(date_target_field, (Date) document.getFieldValue(dateField));
+ doc.setFileName((String) document.getFieldValue(idFieldName));
+
+ if (Logging.connectors.isDebugEnabled()) {
+ Logging.connectors.debug("doc '" + (String) document.getFieldValue(idFieldName));
+ }
+
+ // Content part
+ ArrayList<Object> contentFieldValues = null;
+ String contentFieldValuesString = "";
+
+ if (document.getFieldValues(contentField) != null) {
+ contentFieldValues = (ArrayList<Object>) document.getFieldValues(contentField);
+ if (contentFieldValues != null) {
+ final String[] tabContentFieldValues = contentFieldValues.toArray(new String[0]);
+ for (final String s : tabContentFieldValues) {
+ contentFieldValuesString = contentFieldValuesString + " " + s;
+ }
+ }
+ } else if (document.getFieldValue(contentField) != null) {
+
+ contentFieldValuesString = (String) document.getFieldValue(contentField);
+ } else {
+ contentFieldValuesString = "";
+ }
+
+ is = new ByteArrayInputStream(contentFieldValuesString.getBytes());
+
+ // security part
+
+ if (securityActivated = true) {
+
+
+ if (Logging.connectors.isDebugEnabled()) {
+ Logging.connectors.debug("Security part");
+ }
+
+ if (document.getFieldValues(securityField) != null && document.getFieldValues(securityField2) != null) {
+ ArrayList<Object> securityFieldValues = null;
+ ArrayList<Object> securityFieldValues2 = null;
+
+ securityFieldValues = (ArrayList<Object>) document.getFieldValues(securityField);
+ securityFieldValues2 = (ArrayList<Object>) document.getFieldValues(securityField2);
+ if (Logging.connectors.isDebugEnabled()) {
+ Logging.connectors.debug("Security field 1 : " + securityFieldValues.toString());
+ Logging.connectors.debug("Security field 2 : " + securityFieldValues2.toString());
+ }
+
+ String[] securityValues = null;
+ final ArrayList<Object> all = new ArrayList<Object>();
+ all.addAll(securityFieldValues);
+ all.addAll(securityFieldValues2);
+
+ final HashSet hs = new HashSet();
+ hs.addAll(all);
+ all.clear();
+ all.addAll(hs);
+ securityValues = all.toArray(new String[0]);
+ doc.setSecurity(RepositoryDocument.SECURITY_TYPE_DOCUMENT, securityValues, new String[] { defaultAuthorityDenyToken });
+ securityFieldValues = null;
+ securityFieldValues2 = null;
+ } else if (document.getFieldValues(securityField) != null) {
+ ArrayList<Object> securityFieldValues = null;
+ securityFieldValues = (ArrayList<Object>) document.getFieldValues(securityField);
+ String[] tabsecurityFieldValues = securityFieldValues.toArray(new String[0]);
+ doc.setSecurity(RepositoryDocument.SECURITY_TYPE_DOCUMENT, tabsecurityFieldValues, new String[] { defaultAuthorityDenyToken });
+ securityFieldValues = null;
+ tabsecurityFieldValues = null;
+ } else if (document.getFieldValues(securityField2) != null) {
+ ArrayList<Object> securityFieldValues2 = null;
+ securityFieldValues2 = (ArrayList<Object>) document.getFieldValues(securityField2);
+ String[] tabsecurityFieldValues2 = securityFieldValues2.toArray(new String[0]);
+ doc.setSecurity(RepositoryDocument.SECURITY_TYPE_DOCUMENT, tabsecurityFieldValues2, new String[] { defaultAuthorityDenyToken });
+ securityFieldValues2 = null;
+ tabsecurityFieldValues2 = null;
+ } else {
+ doc.setSecurity(RepositoryDocument.SECURITY_TYPE_DOCUMENT, new String[] { "__nosecurity__" }, new String[] { "__nosecurity__" });
+ }
+
+ }
+
+ // Can only index while background thread is running!
+ try {
+ doc.setBinary(is, is.available());
+ // doc.setFileName(documentIdentifier);
+ activities.ingestDocumentWithException(String.valueOf(document.getFieldValue(idFieldName)), String.valueOf(document.getFieldValue(versionField)),
+ String.valueOf(document.getFieldValue(idFieldName)), doc);
+ activities.recordActivity(new Long(startFetchTime), ACTIVITY_GET, doc.getBinaryLength(), document.getFieldValue(idFieldName).toString(), "OK", "", null);
+ is.close();
+ } catch (final IOException e) {
+ errorCode = "ERROR";
+ description = "Unable to perform Solr requests";
+ Logging.connectors.error("Unable to perform Solr requests", e);
+ }
+
+ }
+ if (cursorMark.equals(nextCursorMark)) {
+ done = true;
+ }
+ cursorMark = nextCursorMark;
+ }
+
+ }
+ } catch (final SolrServerException | IOException e) {
+ errorCode = "ERROR";
+ description = "Unable to perform Solr requests";
+ Logging.connectors.error("Unable to perform Solr requests", e);
+ }
+
+ /*
+ * Etape 4 Iterate into documentIdentifiers and check if each id is present into existingIds. If not, delete the doc */
+
+ for (int i = 0; i < documentIdentifiers.length; i++) {
+ if (!existingIds.containsKey(documentIdentifiers[i])) {
+ activities.deleteDocument(documentIdentifiers[i]);
+ activities.recordActivity(new Long(startFetchTime), ACTIVITY_GET, 0L, documentIdentifiers[i], "NOTFOUND", "Document not found in Solr", null);
+ } else if (errorCode != null) {
+ activities.recordActivity(new Long(startFetchTime), ACTIVITY_GET, 0L, documentIdentifiers[i], errorCode, description, null);
+ }
+
+ }
+ }
+
+
+
+ }
+
+ @Override
+ public String processSpecificationPost(final IPostParameters variableContext, final Locale locale, final Specification os, final int connectionSequenceNumber) throws ManifoldCFException {
+ final String seqPrefix = "s" + connectionSequenceNumber + "_";
+
+ String x;
+
+ x = variableContext.getParameter(seqPrefix + "fieldmapping_count");
+ if (x != null && x.length() > 0) {
+ // About to gather the fieldmapping nodes, so get rid of the old ones.
+ int i = 0;
+ while (i < os.getChildCount()) {
+ final SpecificationNode node = os.getChild(i);
+ if (node.getType().equals(SolrIngesterConfig.NODE_FIELDMAP)) {
+ os.removeChild(i);
+ } else {
+ i++;
+ }
+ }
+ final int count = Integer.parseInt(x);
+ i = 0;
+ while (i < count) {
+ final String prefix = seqPrefix + "fieldmapping_";
+ final String suffix = "_" + Integer.toString(i);
+ final String op = variableContext.getParameter(prefix + "op" + suffix);
+ if (op == null || !op.equals("Delete")) {
+ // Gather the fieldmap etc.
+ final String source = variableContext.getParameter(prefix + "source" + suffix);
+ String target = variableContext.getParameter(prefix + "target" + suffix);
+ if (target == null) {
+ target = "";
+ }
+ final SpecificationNode node = new SpecificationNode(SolrIngesterConfig.NODE_FIELDMAP);
+ node.setAttribute(SolrIngesterConfig.ATTRIBUTE_SOURCE, source);
+ node.setAttribute(SolrIngesterConfig.ATTRIBUTE_TARGET, target);
+ os.addChild(os.getChildCount(), node);
+ }
+ i++;
+ }
+
+ final String addop = variableContext.getParameter(seqPrefix + "fieldmapping_op");
+ if (addop != null && addop.equals("Add")) {
+ final String source = variableContext.getParameter(seqPrefix + "fieldmapping_source");
+ String target = variableContext.getParameter(seqPrefix + "fieldmapping_target");
+ if (target == null) {
+ target = "";
+ }
+ final SpecificationNode node = new SpecificationNode(SolrIngesterConfig.NODE_FIELDMAP);
+ node.setAttribute(SolrIngesterConfig.ATTRIBUTE_SOURCE, source);
+ node.setAttribute(SolrIngesterConfig.ATTRIBUTE_TARGET, target);
+ os.addChild(os.getChildCount(), node);
+ }
+
+ final SpecificationNode node2 = new SpecificationNode(SolrIngesterConfig.SECURITY_ACTIVATED);
+ final String securityActivated = variableContext.getParameter(seqPrefix + "securityactivated");
+
+ if (securityActivated != null) {
+ node2.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, securityActivated);
+ } else {
+ node2.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, "false");
+ }
+ os.addChild(os.getChildCount(), node2);
+
+ final SpecificationNode node3 = new SpecificationNode(SolrIngesterConfig.SECURITY_FIELD);
+ final String securityField = variableContext.getParameter(seqPrefix + "securityfield");
+
+ node3.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, securityField);
+
+ os.addChild(os.getChildCount(), node3);
+
+ final SpecificationNode node4 = new SpecificationNode(SolrIngesterConfig.ID_FIELD);
+ final String fieldId = variableContext.getParameter(seqPrefix + "fieldid");
+
+ node4.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, fieldId);
+
+ os.addChild(os.getChildCount(), node4);
+
+ final SpecificationNode node5 = new SpecificationNode(SolrIngesterConfig.DATE_FIELD);
+ final String fieldDate = variableContext.getParameter(seqPrefix + "fielddate");
+
+ node5.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, fieldDate);
+
+ os.addChild(os.getChildCount(), node5);
+
+ final SpecificationNode node6 = new SpecificationNode(SolrIngesterConfig.CONTENT_FIELD);
+ final String fieldContent = variableContext.getParameter(seqPrefix + "fieldcontent");
+
+ node6.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, fieldContent);
+
+ os.addChild(os.getChildCount(), node6);
+
+ final SpecificationNode node7 = new SpecificationNode(SolrIngesterConfig.COLLECTION_NAME);
+ final String collectionName = variableContext.getParameter(seqPrefix + "collection");
+
+ node7.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, collectionName);
+
+ os.addChild(os.getChildCount(), node7);
+
+ final SpecificationNode node8 = new SpecificationNode(SolrIngesterConfig.FILTER_CONDITION);
+ final String filter = variableContext.getParameter(seqPrefix + "filter");
+
+ node8.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, filter);
+
+ os.addChild(os.getChildCount(), node8);
+
+ final SpecificationNode node9 = new SpecificationNode(SolrIngesterConfig.ROWS_NUMBER);
+ final String rowsNumber = variableContext.getParameter(seqPrefix + "rowsnumber");
+
+ node9.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, rowsNumber);
+
+ os.addChild(os.getChildCount(), node9);
+
+ final SpecificationNode node10 = new SpecificationNode(SolrIngesterConfig.SECURITY_FIELD2);
+ final String securityField2 = variableContext.getParameter(seqPrefix + "securityfield2");
+
+ node10.setAttribute(SolrIngesterConfig.ATTRIBUTE_VALUE, securityField2);
+
+ os.addChild(os.getChildCount(), node10);
+ }
+
+ return null;
+ }
+
+ /**
+ * Output the configuration header section. This method is called in the head section of the connector's configuration page. Its purpose is
+ * to add the required tabs to the list, and to output any javascript methods that might be needed by the configuration editing HTML.
+ *
+ * @param threadContext
+ * is the local thread context.
+ * @param out
+ * is the output to which any HTML should be sent.
+ * @param parameters
+ * are the configuration parameters, as they currently exist, for this connection being configured.
+ * @param tabsArray
+ * is an array of tab names. Add to this array any tab names that are specific to the connector.
+ */
+ @Override
+ public void outputConfigurationHeader(final IThreadContext threadContext, final IHTTPOutput out, final Locale locale, final ConfigParams parameters, final List<String> tabsArray)
+ throws ManifoldCFException, IOException {
+ tabsArray.add(Messages.getString(locale, "SolrIngester.SolrIngesterTabName"));
+ Messages.outputResourceWithVelocity(out, locale, EDIT_CONFIGURATION_CONNECTOR_JS, null);
+ }
+
+ /**
+ * Output the configuration body section. This method is called in the body section of the connector's configuration page. Its purpose is to
+ * present the required form elements for editing. The coder can presume that the HTML that is output from this configuration will be within
+ * appropriate <html>, <body>, and <form> tags. The name of the form is "editconnection".
+ *
+ * @param threadContext
+ * is the local thread context.
+ * @param out
+ * is the output to which any HTML should be sent.
+ * @param parameters
+ * are the configuration parameters, as they currently exist, for this connection being configured.
+ * @param tabName
+ * is the current tab name.
+ */
+ @Override
+ public void outputConfigurationBody(final IThreadContext threadContext, final IHTTPOutput out, final Locale locale, final ConfigParams parameters, final String tabName)
+ throws ManifoldCFException, IOException {
+ final Map<String, Object> velocityContext = new HashMap<>();
+ velocityContext.put("TabName", tabName);
+ fillInServerTab(velocityContext, out, parameters);
+ Messages.outputResourceWithVelocity(out, locale, EDIT_CONFIGURATION_CONNECTOR_HTML, velocityContext);
+ }
+
+ /**
+ * Process a configuration post. This method is called at the start of the connector's configuration page, whenever there is a possibility
+ * that form data for a connection has been posted. Its purpose is to gather form information and modify the configuration parameters
+ * accordingly. The name of the posted form is "editconnection".
+ *
+ * @param threadContext
+ * is the local thread context.
+ * @param variableContext
+ * is the set of variables available from the post, including binary file post information.
+ * @param parameters
+ * are the configuration parameters, as they currently exist, for this connection being configured.
+ * @return null if all is well, or a string error message if there is an error that should prevent saving of the connection (and cause a
+ * redirection to an error page).
+ */
+ @Override
+ public String processConfigurationPost(final IThreadContext threadContext, final IPostParameters variableContext, final Locale locale, final ConfigParams parameters) throws ManifoldCFException {
+ final String solrAddress = variableContext.getParameter("solrAddress");
+ if (solrAddress != null) {
+ parameters.setParameter(SolrIngesterConfig.PARAM_SOLRADDRESS, solrAddress);
+ }
+
+ final String solrUsername = variableContext.getParameter("solrUsername");
+ if (solrUsername != null) {
+ parameters.setParameter(SolrIngesterConfig.PARAM_SOLRUSERNAME, solrUsername);
+ }
+
+ final String solrPassword = variableContext.getParameter("solrPassword");
+ if (solrPassword != null) {
+ parameters.setParameter(SolrIngesterConfig.PARAM_SOLRPASSWORD, ManifoldCF.obfuscate(variableContext.mapKeyToPassword(solrPassword)));
+ }
+
+ final String connectionTimeout = variableContext.getParameter(SolrIngesterConfig.PARAM_CONNECTIONTIMEOUT);
+ if (connectionTimeout != null) {
+ parameters.setParameter(SolrIngesterConfig.PARAM_CONNECTIONTIMEOUT, connectionTimeout);
+ }
+
+ final String socketTimeout = variableContext.getParameter(SolrIngesterConfig.PARAM_SOCKETTIMEOUT);
+ if (socketTimeout != null) {
+ parameters.setParameter(SolrIngesterConfig.PARAM_SOCKETTIMEOUT, socketTimeout);
+ }
+
+ return null;
+ }
+
+ /**
+ * View configuration. This method is called in the body section of the connector's view configuration page. Its purpose is to present the
+ * connection information to the user. The coder can presume that the HTML that is output from this configuration will be within appropriate
+ * <html> and <body> tags.
+ *
+ * @param threadContext
+ * is the local thread context.
+ * @param out
+ * is the output to which any HTML should be sent.
+ * @param parameters
+ * are the configuration parameters, as they currently exist, for this connection being configured.
+ */
+ @Override
+ public void viewConfiguration(final IThreadContext threadContext, final IHTTPOutput out, final Locale locale, final ConfigParams parameters) throws ManifoldCFException, IOException {
+ final Map<String, Object> velocityContext = new HashMap<>();
+ fillInServerTab(velocityContext, out, parameters);
+ Messages.outputResourceWithVelocity(out, locale, VIEW_CONFIGURATION_CONNECTOR_HTML, velocityContext);
+ }
+
+ protected static void fillInServerTab(final Map<String, Object> velocityContext, final IHTTPOutput out, final ConfigParams parameters) throws ManifoldCFException {
+
+ String solrAddress = parameters.getParameter(SolrIngesterConfig.PARAM_SOLRADDRESS);
+
+ if (solrAddress == null) {
+ solrAddress = SolrIngesterConfig.SOLRADDRESS_DEFAULT;
+ }
+
+ String solrUsername = parameters.getParameter(SolrIngesterConfig.PARAM_SOLRUSERNAME);
+
+ if (solrUsername == null) {
+ solrUsername = SolrIngesterConfig.SOLRUSERNAME_DEFAULT;
+ }
+
+ String solrPassword = parameters.getParameter(SolrIngesterConfig.PARAM_SOLRPASSWORD);
+
+ if (solrPassword == null) {
+ solrPassword = SolrIngesterConfig.SOLRPASSWORD_DEFAULT;
+ }
+
+ String connectionTimeout = parameters.getParameter(SolrIngesterConfig.PARAM_CONNECTIONTIMEOUT);
+ if (connectionTimeout == null) {
+ connectionTimeout = SolrIngesterConfig.CONNECTIONTIMEOUT_DEFAULT;
+ }
+
+ String socketTimeout = parameters.getParameter(SolrIngesterConfig.PARAM_SOCKETTIMEOUT);
+ if (socketTimeout == null) {
+ socketTimeout = SolrIngesterConfig.SOCKETTIMEOUT_DEFAULT;
+ }
+ // Fill in context
+
+ velocityContext.put("SOLRADDRESS", solrAddress);
+ velocityContext.put("SOLRUSERNAME", solrUsername);
+ velocityContext.put("SOLRPASSWORD", solrPassword);
+ velocityContext.put("CONNECTIONTIMEOUT", connectionTimeout);
+ velocityContext.put("SOCKETTIMEOUT", socketTimeout);
+
+ }
+
+ /**
+ * Output the specification header section. This method is called in the head section of a job page which has selected a pipeline connection
+ * of the current type. Its purpose is to add the required tabs to the list, and to output any javascript methods that might be needed by
+ * the job editing HTML.
+ *
+ * @param out
+ * is the output to which any HTML should be sent.
+ * @param locale
+ * is the preferred local of the output.
+ * @param os
+ * is the current pipeline specification for this connection.
+ * @param connectionSequenceNumber
+ * is the unique number of this connection within the job.
+ * @param tabsArray
+ * is an array of tab names. Add to this array any tab names that are specific to the connector.
+ */
+ @Override
+ public void outputSpecificationHeader(final IHTTPOutput out, final Locale locale, final Specification os, final int connectionSequenceNumber, final List<String> tabsArray)
+ throws ManifoldCFException, IOException {
+ final Map<String, Object> paramMap = new HashMap<>();
+ paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
+
+ tabsArray.add(Messages.getString(locale, "SolrIngester.SecurityTabName"));
+ tabsArray.add(Messages.getString(locale, "SolrIngester.ParametersTabName"));
+
+ // Fill in the specification header map, using data from all tabs.
+
+ Messages.outputResourceWithVelocity(out, locale, EDIT_SPECIFICATION_JOB_PARAMETERS_JS, paramMap);
+ Messages.outputResourceWithVelocity(out, locale, EDIT_SPECIFICATION_JOB_SECURITY_JS, paramMap);
+ }
+
+ /**
+ * Output the specification body section. This method is called in the body section of a job page which has selected a pipeline connection
+ * of the current type. Its purpose is to present the required form elements for editing. The coder can presume that the HTML that is output
+ * from this configuration will be within appropriate <html>, <body>, and <form> tags. The name of the form is "editjob".
+ *
+ * @param out
+ * is the output to which any HTML should be sent.
+ * @param locale
+ * is the preferred local of the output.
+ * @param os
+ * is the current pipeline specification for this job.
+ * @param connectionSequenceNumber
+ * is the unique number of this connection within the job.
+ * @param actualSequenceNumber
+ * is the connection within the job that has currently been selected.
+ * @param tabName
+ * is the current tab name.
+ */
+ @Override
+ public void outputSpecificationBody(final IHTTPOutput out, final Locale locale, final Specification os, final int connectionSequenceNumber, final int actualSequenceNumber, final String tabName)
+ throws ManifoldCFException, IOException {
+ final Map<String, Object> paramMap = new HashMap<>();
+
+ // Set the tab name
+ paramMap.put("TABNAME", tabName);
+ paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
+ paramMap.put("SELECTEDNUM", Integer.toString(actualSequenceNumber));
+
+ // Fill in the field mapping tab data
+ fillInFieldMappingSpecificationMap(paramMap, os);
+ // fillInSecuritySpecificationMap(paramMap, os);
+
+ Messages.outputResourceWithVelocity(out, locale, EDIT_SPECIFICATION_JOB_PARAMETERS_HTML, paramMap);
+ Messages.outputResourceWithVelocity(out, locale, EDIT_SPECIFICATION_JOB_SECURITY_HTML, paramMap);
+ }
+
+ /**
+ * View specification. This method is called in the body section of a job's view page. Its purpose is to present the pipeline specification
+ * information to the user. The coder can presume that the HTML that is output from this configuration will be within appropriate <html> and
+ * <body> tags.
+ *
+ * @param out
+ * is the output to which any HTML should be sent.
+ * @param locale
+ * is the preferred local of the output.
+ * @param connectionSequenceNumber
+ * is the unique number of this connection within the job.
+ * @param os
+ * is the current pipeline specification for this job.
+ */
+
+ @Override
+ public void viewSpecification(final IHTTPOutput out, final Locale locale, final Specification os, final int connectionSequenceNumber) throws ManifoldCFException, IOException {
+ final Map<String, Object> paramMap = new HashMap<>();
+ paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
+
+ // Fill in the map with data from all tabs
+ fillInFieldMappingSpecificationMap(paramMap, os);
+
+ Messages.outputResourceWithVelocity(out, locale, VIEW_SPECIFICATION_JOB_PARAMETERS_HTML, paramMap);
+ Messages.outputResourceWithVelocity(out, locale, VIEW_SPECIFICATION_JOB_SECURITY_HTML, paramMap);
+
+ }
+
+ protected static void fillInFieldMappingSpecificationMap(final Map<String, Object> paramMap, final Specification os) {
+
+ String securityActivated = "false";
+ String securityField = "";
+ String securityField2 = "";
+ String idField = "id";
+ String dateField = "last_modified";
+ String contentField = "content";
+ String filterCondition = "*:*";
+ String collection = "techproducts";
+ String rowsNumber = "50";
+
+ final List<Map<String, String>> fieldMappings = new ArrayList<>();
+
+ for (int i = 0; i < os.getChildCount(); i++) {
+ final SpecificationNode sn = os.getChild(i);
+
+ if (sn.getType().equals(SolrIngesterConfig.NODE_FIELDMAP)) {
+ final String source = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_SOURCE);
+ String target = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_TARGET);
+ String targetDisplay;
+ if (target == null) {
+ target = "";
+ targetDisplay = "(remove)";
+ } else {
+ targetDisplay = target;
+ }
+ final Map<String, String> fieldMapping = new HashMap<>();
+ fieldMapping.put("SOURCE", source);
+ fieldMapping.put("TARGET", target);
+ fieldMapping.put("TARGETDISPLAY", targetDisplay);
+
+ fieldMappings.add(fieldMapping);
+ } else if (sn.getType().equals(SolrIngesterConfig.SECURITY_ACTIVATED)) {
+ securityActivated = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.SECURITY_FIELD)) {
+ securityField = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.SECURITY_FIELD2)) {
+ securityField2 = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.ID_FIELD)) {
+ idField = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.DATE_FIELD)) {
+ dateField = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.CONTENT_FIELD)) {
+ contentField = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.FILTER_CONDITION)) {
+ filterCondition = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.COLLECTION_NAME)) {
+ collection = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ } else if (sn.getType().equals(SolrIngesterConfig.ROWS_NUMBER)) {
+ rowsNumber = sn.getAttributeValue(SolrIngesterConfig.ATTRIBUTE_VALUE);
+
+ }
+ }
+ // Prep for field mappings
+
+ paramMap.put("FIELDMAPPINGS", fieldMappings);
+ paramMap.put("SECURITYACTIVATION", securityActivated);
+ paramMap.put("SECURITYFIELD", securityField);
+ paramMap.put("SECURITYFIELD2", securityField2);
+ paramMap.put("FIELDID", idField);
+ paramMap.put("FIELDDATE", dateField);
+ paramMap.put("FIELDCONTENT", contentField);
+ paramMap.put("FILTERCONDITION", filterCondition);
+ paramMap.put("COLLECTION", collection);
+ paramMap.put("ROWSNUMBER", rowsNumber);
+
+ }
+
+ static class PreemptiveAuth implements HttpRequestInterceptor {
+
+ private final Credentials credentials;
+
+ public PreemptiveAuth(final Credentials creds) {
+ this.credentials = creds;
+ }
+
+ @Override
+ public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
+ request.addHeader(new BasicScheme(StandardCharsets.US_ASCII).authenticate(credentials, request, context));
+ }
+ }
+
+ protected static class CheckThread extends Thread {
+
+ protected HttpClient client;
+
+ protected String url;
+
+ protected Throwable exception = null;
+
+ protected String result = "Unknown";
+
+ public CheckThread(final HttpClient client, final String url) {
+ super();
+ setDaemon(true);
+ this.client = client;
+ this.url = url;
+ }
+
+ @Override
+ public void run() {
+ final HttpGet method = new HttpGet(url);
+ try {
+ final HttpResponse response = client.execute(method);
+ try {
+ if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ result = "Connection failed: " + response.getStatusLine().getReasonPhrase();
+ return;
+ }
+ EntityUtils.consume(response.getEntity());
+ result = "Connection OK";
+ } finally {
+ EntityUtils.consume(response.getEntity());
+ method.releaseConnection();
+ }
+ } catch (final IOException ex) {
+ exception = ex;
+ }
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+
+ public String getResult() {
+ return result;
+ }
+ }
+
+ protected static class ExecuteSeedingThread extends Thread {
+
+ protected final HttpClient client;
+
+ protected final String url;
+
+ protected final XThreadStringBuffer seedBuffer;
+
+ protected Throwable exception = null;
+
+ public ExecuteSeedingThread(final HttpClient client, final String url) {
+ super();
+ setDaemon(true);
+ this.client = client;
+ this.url = url;
+ seedBuffer = new XThreadStringBuffer();
+ }
+
+ public XThreadStringBuffer getBuffer() {
+ return seedBuffer;
+ }
+ }
+}
diff --git a/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_en_US.properties b/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_en_US.properties
new file mode 100644
index 0000000..5ef0de9
--- /dev/null
+++ b/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_en_US.properties
@@ -0,0 +1,52 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+SolrIngester.SolrIngesterTabName=Solr Ingester
+SolrIngester.SecurityTabName=Security
+SolrIngester.ParametersTabName=Parameters
+SolrIngester.SolrAddress=Solr Address
+SolrIngester.SolrUsername=Login
+SolrIngester.SolrPassword=Password
+SolrIngester.ConnectionTimeout=Connection timeout:
+SolrIngester.SocketTimeout=Socket timeout:
+SolrIngester.SecurityActivation=Security activated
+SolrIngester.SecurityField=Security Field
+SolrIngester.SecurityField2=Security Field 2
+SolrIngester.FieldMappingTabName=Field mapping
+SolrIngester.FieldMappings=Field mappings:
+SolrIngester.MetadataFieldName=Metadata field name
+SolrIngester.FinalFieldName=Final field name
+SolrIngester.NoFieldMappingSpecified=No field mapping specified
+SolrIngester.Add=Add
+SolrIngester.AddFieldMapping=Add field mapping
+SolrIngester.Delete=Delete
+SolrIngester.DeleteFieldMapping=Delete field mapping
+SolrIngester.NoFieldNameSpecified=Please specify a field name
+SolrIngester.FieldId=ID Field
+SolrIngester.RowsNumber=Solr rows number
+SolrIngester.FieldDate=Date Field
+SolrIngester.FieldContent=Content Field
+SolrIngester.FilterCondition=Filter Condition
+SolrIngester.CollectionName=Collection Name
+SolrIngester.Parameters=Parameters
+SolrIngester.Security=Security
+SolrIngester.Delete=Delete
+SolrIngester.Add=Add
+SolrIngester.NoValueSecurityField=No value entered for Security field
+SolrIngester.NoValueCollection=No value entered for collection
+SolrIngester.NoValueIdField=No value entered for field Id
+SolrIngester.NoValueDateField=No value entered for field Date
+SolrIngester.NoValueSolrAddress=No value entered for Solr address
+SolrIngester.NoValueConnectionTimeOut= No value entered for connection timeout
+SolrIngester.NoValueSocketTimeOut=No value entered for socket timeout
\ No newline at end of file
diff --git a/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_es_ES.properties b/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_es_ES.properties
new file mode 100644
index 0000000..0eff91a
--- /dev/null
+++ b/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_es_ES.properties
@@ -0,0 +1,52 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+SolrIngester.SolrIngesterTabName=Solr Ingester
+SolrIngester.SecurityTabName=Security
+SolrIngester.ParametersTabName=Parameters
+SolrIngester.SolrUsername=Login
+SolrIngester.SolrPassword=Password
+SolrIngester.SolrAddress=Solr Address
+SolrIngester.ConnectionTimeout=Connection timeout:
+SolrIngester.SocketTimeout=Socket timeout:
+SolrIngester.SecurityActivation=Security activated
+SolrIngester.SecurityField=Security Field
+SolrIngester.SecurityField2=Security Field 2
+SolrIngester.FieldMappingTabName=Field mapping
+SolrIngester.FieldMappings=Field mappings:
+SolrIngester.MetadataFieldName=Metadata field name
+SolrIngester.FinalFieldName=Final field name
+SolrIngester.NoFieldMappingSpecified=No field mapping specified
+SolrIngester.Add=Add
+SolrIngester.AddFieldMapping=Add field mapping
+SolrIngester.Delete=Delete
+SolrIngester.DeleteFieldMapping=Delete field mapping
+SolrIngester.NoFieldNameSpecified=Please specify a field name
+SolrIngester.FieldId=ID Field
+SolrIngester.RowsNumber=Solr rows number
+SolrIngester.FieldDate=Date Field
+SolrIngester.FieldContent=Content Field
+SolrIngester.FilterCondition=Filter Condition
+SolrIngester.CollectionName=Collection Name
+SolrIngester.Parameters=Parameters
+SolrIngester.Security=Security
+SolrIngester.Delete=Delete
+SolrIngester.Add=Add
+SolrIngester.NoValueSecurityField=No value entered for Security field
+SolrIngester.NoValueCollection=No value entered for collection
+SolrIngester.NoValueIdField=No value entered for field Id
+SolrIngester.NoValueDateField=No value entered for field Date
+SolrIngester.NoValueSolrAddress=No value entered for Solr address
+SolrIngester.NoValueConnectionTimeOut= No value entered for connection timeout
+SolrIngester.NoValueSocketTimeOut=No value entered for socket timeout
\ No newline at end of file
diff --git a/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_fr_FR.properties b/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_fr_FR.properties
new file mode 100644
index 0000000..1a39922
--- /dev/null
+++ b/connectors/solringester/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/connectors/solringester/common_fr_FR.properties
@@ -0,0 +1,54 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+SolrIngester.SolrIngesterTabName=Solr Ingester
+SolrIngester.SecurityTabName=Securité
+SolrIngester.ParametersTabName=Paramètres
+SolrIngester.SolrAddress=URL Solr
+SolrIngester.SolrUsername=Login
+SolrIngester.SolrPassword=Password
+SolrIngester.ConnectionTimeout=Connection timeout:
+SolrIngester.SocketTimeout=Socket timeout:
+SolrIngester.SecurityActivation=Securité activée
+SolrIngester.SecurityField=Champ de sécurité
+SolrIngester.SecurityField2=Champ de sécurité 2
+SolrIngester.FieldMappingTabName=Correspondance des champs
+SolrIngester.FieldMappings=Correspondance des champs:
+SolrIngester.MetadataFieldName=Nom du champ de métadonnées
+SolrIngester.FinalFieldName=Champ final
+SolrIngester.NoFieldMappingSpecified=Pas de correspondance de champ spécifiée
+SolrIngester.Add=Ajouter
+SolrIngester.AddFieldMapping=Ajouter correspondance de champs
+SolrIngester.Delete=Supprimer
+SolrIngester.DeleteFieldMapping=Supprimer correspondance de champ
+SolrIngester.NoFieldNameSpecified=Spécifier un champ svp
+SolrIngester.Parameters=Paramètres
+SolrIngester.Security=Security
+SolrIngester.Delete=Delete
+SolrIngester.Add=Add
+SolrIngester.FieldId=Champ ID
+SolrIngester.RowsNumber=Solr rows number
+SolrIngester.FieldDate=Champ Date
+SolrIngester.FieldContent=Champ Contenu
+SolrIngester.FilterCondition=Condition de Filtre
+SolrIngester.CollectionName=Nom de la Collection
+SolrIngester.ParameterName=Parameter name
+SolrIngester.ParameterValue=Parameter value
+SolrIngester.NoValueSecurityField=Pas de valeur entrée pour le champ Sécurité
+SolrIngester.NoValueCollection==Pas de valeur entrée pour la collection
+SolrIngester.NoValueIdField==Pas de valeur entrée pour le champ Id
+SolrIngester.NoValueDateField==Pas de valeur entrée pour le champ Date
+SolrIngester.NoValueSolrAddress==Pas de valeur entrée pour l'adresse Solr
+SolrIngester.NoValueConnectionTimeOut= Pas de valeur entrée pour connection timeout
+SolrIngester.NoValueSocketTimeOut=Pas de valeur entrée pour socket timeout
\ No newline at end of file
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editConfiguration_connector.html b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editConfiguration_connector.html
new file mode 100644
index 0000000..40f9b59
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editConfiguration_connector.html
@@ -0,0 +1,61 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+#if($TabName == $ResourceBundle.getString('SolrIngester.SolrIngesterTabName'))
+
+<table class="displaytable">
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SolrAddress'))</nobr></td>
+ <td class="value"><input name="solrAddress" type="text"
+ value="$Encoder.attributeEscape($SOLRADDRESS)" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SolrUsername'))</nobr></td>
+ <td class="value"><input name="solrUsername" type="text"
+ value="$Encoder.attributeEscape($SOLRUSERNAME)" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SolrPassword'))</nobr></td>
+ <td class="value"><input name="solrPassword" type="password"
+ value="$Encoder.attributeEscape($SOLRPASSWORD)" size="40" />
+ </td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.ConnectionTimeout'))</nobr></td>
+ <td class="value"><input name="connectionTimeout" type="text"
+ value="$Encoder.attributeEscape($CONNECTIONTIMEOUT)" size="20" />
+ </td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SocketTimeout'))</nobr></td>
+ <td class="value"><input name="socketTimeout" type="text"
+ value="$Encoder.attributeEscape($SOCKETTIMEOUT)" size="20" />
+ </td>
+ </tr>
+
+</table>
+#else
+<input type="hidden" name="solrAddress" value="$SOLRADDRESS"/>
+<input type="hidden" name="solrUsername" value="$SOLRUSERNAME"/>
+<input type="hidden" name="solrPassword" value="$SOLRPASSWORD"/>
+<input type="hidden" name="connectionTimeout" value="$CONNECTIONTIMEOUT"/>
+<input type="hidden" name="socketTimeout" value="$SOCKETTIMEOUT"/>
+
+#end
\ No newline at end of file
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editConfiguration_connector.js b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editConfiguration_connector.js
new file mode 100644
index 0000000..a263f1a
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editConfiguration_connector.js
@@ -0,0 +1,48 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<script type="text/javascript">
+<!--
+
+function checkConfigForSave()
+{
+ if (editconnection.solrAddress.value == "")
+ {
+ alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.NoValueSolrAddress'))");
+ SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.SolrIngesterTabName'))");
+ eval("editconnection.solrAddress.focus()");
+ return false;
+ }
+ if (editconnection.connectionTimeout.value == "")
+ {
+ alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.NoValueConnectionTimeOut'))");
+ SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.SolrIngesterTabName'))");
+ eval("editconnection.connectionTimeout.focus()");
+ return false;
+ }
+ if (editconnection.socketTimeout.value == "")
+ {
+ alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.NoValueSocketTimeOut'))");
+ SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.SolrIngesterTabName'))");
+ eval("editconnection.socketTimeout.focus()");
+ return false;
+ }
+ return true;
+}
+
+//-->
+</script>
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_parameters.html b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_parameters.html
new file mode 100644
index 0000000..a5bc958
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_parameters.html
@@ -0,0 +1,149 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+#if($TABNAME == $ResourceBundle.getString('SolrIngester.ParametersTabName') && ${SEQNUM} == ${SELECTEDNUM})
+
+
+<table class="displaytable">
+
+<tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.CollectionName'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_collection" type="text"
+ value="$Encoder.attributeEscape($COLLECTION)" size="16" />
+ </td>
+ </tr>
+
+<tr>
+
+
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FieldMappings'))</nobr></td>
+ <td class="boxcell">
+ <table class="formtable">
+ <tr class="formheaderrow">
+ <td class="formcolumnheader"></td>
+ <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.MetadataFieldName'))</nobr></td>
+ <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FinalFieldName'))</nobr></td>
+ </tr>
+
+ #set($fieldcounter = 0)
+ #foreach($fieldmapping in $FIELDMAPPINGS)
+ #set($fieldcounterdisplay = $fieldcounter + 1)
+ #if(($fieldcounter % 2) == 0)
+ <tr class="evenformrow">
+ #else
+ <tr class="oddformrow">
+ #end
+ <td class="formcolumncell">
+ <a name="s${SEQNUM}_fieldmapping_$fieldcounter">
+ <input type="button" value="$Encoder.attributeEscape($ResourceBundle.getString('SolrIngester.Delete'))" alt="$Encoder.attributeEscape($ResourceBundle.getString('SolrIngester.DeleteFieldMapping'))$fieldcounterdisplay" onclick='javascript:s${SEQNUM}_deleteFieldMapping("$fieldcounter");'/>
+ <input type="hidden" name="s${SEQNUM}_fieldmapping_op_$fieldcounter" value="Continue"/>
+ <input type="hidden" name="s${SEQNUM}_fieldmapping_source_$fieldcounter" value="$Encoder.attributeEscape($fieldmapping.get('SOURCE'))"/>
+ <input type="hidden" name="s${SEQNUM}_fieldmapping_target_$fieldcounter" value="$Encoder.attributeEscape($fieldmapping.get('TARGET'))"/>
+ </a>
+ </td>
+ <td class="formcolumncell">
+ <nobr>$Encoder.bodyEscape($fieldmapping.get('SOURCE'))</nobr>
+ </td>
+ <td class="formcolumncell">
+ <nobr>$Encoder.bodyEscape($fieldmapping.get('TARGETDISPLAY'))</nobr>
+ </td>
+ </tr>
+ #set($fieldcounter = $fieldcounter + 1)
+ #end
+
+ #if($fieldcounter == 0)
+ <tr class="formrow"><td class="formmessage" colspan="3">$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.NoFieldMappingSpecified'))</td></tr>
+ #end
+
+ <tr class="formrow"><td class="formseparator" colspan="3"><hr/></td></tr>
+ <tr class="formrow">
+ <td class="formcolumncell">
+ <a name="fieldmapping">
+ <input type="button" value="$Encoder.attributeEscape($ResourceBundle.getString('SolrIngester.Add'))" alt="$Encoder.attributeEscape($ResourceBundle.getString('SolrIngester.AddFieldMapping'))" onclick="javascript:s${SEQNUM}_addFieldMapping();"/>
+ </a>
+ <input type="hidden" name="s${SEQNUM}_fieldmapping_count" value="$fieldcounter"/>
+ <input type="hidden" name="s${SEQNUM}_fieldmapping_op" value="Continue"/>
+ </td>
+ <td class="formcolumncell">
+ <nobr><input type="text" size="15" name="s${SEQNUM}_fieldmapping_source" value=""/></nobr>
+ </td>
+ <td class="formcolumncell">
+ <nobr><input type="text" size="15" name="s${SEQNUM}_fieldmapping_target" value=""/></nobr>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FieldId'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_fieldid" type="text"
+ value="$Encoder.attributeEscape($FIELDID)" size="16" />
+ </td>
+ </tr>
+
+<tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FieldDate'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_fielddate" type="text"
+ value="$Encoder.attributeEscape($FIELDDATE)" size="16" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FieldContent'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_fieldcontent" type="text"
+ value="$Encoder.attributeEscape($FIELDCONTENT)" size="16" />
+ </td>
+ </tr>
+
+
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FilterCondition'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_filter" type="text"
+ value="$Encoder.attributeEscape($FILTERCONDITION)" size="16" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.RowsNumber'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_rowsnumber" type="text"
+ value="$Encoder.attributeEscape($ROWSNUMBER)" size="16" />
+ </td>
+ </tr>
+
+
+</table>
+#else
+
+ #set($fieldcounter = 0)
+ #foreach($fieldmapping in $FIELDMAPPINGS)
+<input type="hidden" name="s${SEQNUM}_fieldmapping_source_$fieldcounter" value="$Encoder.attributeEscape($fieldmapping.get('SOURCE'))"/>
+<input type="hidden" name="s${SEQNUM}_fieldmapping_target_$fieldcounter" value="$Encoder.attributeEscape($fieldmapping.get('TARGET'))"/>
+ #set($fieldcounter = $fieldcounter + 1)
+ #end
+<input type="hidden" name="s${SEQNUM}_fieldmapping_count" value="$fieldcounter"/>
+<input type="hidden" name="s${SEQNUM}_collection" value="$Encoder.bodyEscape($COLLECTION)" />
+<input type="hidden" name="s${SEQNUM}_fieldid" value="$Encoder.bodyEscape($FIELDID)" />
+<input type="hidden" name="s${SEQNUM}_fielddate" value="$Encoder.bodyEscape($FIELDDATE)" />
+<input type="hidden" name="s${SEQNUM}_fieldcontent" value="$Encoder.bodyEscape($FIELDCONTENT)" />
+<input type="hidden" name="s${SEQNUM}_filter" value="$Encoder.bodyEscape($FILTERCONDITION)" />
+<input type="hidden" name="s${SEQNUM}_rowsnumber" value="$Encoder.bodyEscape($ROWSNUMBER)" />
+
+
+#end
\ No newline at end of file
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_parameters.js b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_parameters.js
new file mode 100644
index 0000000..c25dfd4
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_parameters.js
@@ -0,0 +1,48 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<script type="text/javascript">
+<!--
+function s${SEQNUM}_addFieldMapping()
+{
+ if (editjob.s${SEQNUM}_fieldmapping_source.value == "")
+ {
+ alert("$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.NoFieldNameSpecified'))");
+ editjob.s${SEQNUM}_fieldmapping_source.focus();
+ return;
+ }
+ editjob.s${SEQNUM}_fieldmapping_op.value="Add";
+ postFormSetAnchor("s${SEQNUM}_fieldmapping");
+}
+
+function s${SEQNUM}_deleteFieldMapping(i)
+{
+ // Set the operation
+ eval("editjob.s${SEQNUM}_fieldmapping_op_"+i+".value=\"Delete\"");
+ // Submit
+ if (editjob.s${SEQNUM}_fieldmapping_count.value==i)
+ postFormSetAnchor("s${SEQNUM}_fieldmapping");
+ else
+ postFormSetAnchor("s${SEQNUM}_fieldmapping_"+i)
+ // Undo, so we won't get two deletes next time
+ eval("editjob.s${SEQNUM}_fieldmapping_op_"+i+".value=\"Continue\"");
+}
+
+
+
+//-->
+</script>
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_security.html b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_security.html
new file mode 100644
index 0000000..eff3c94
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_security.html
@@ -0,0 +1,57 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+#if($TABNAME == $ResourceBundle.getString('SolrIngester.SecurityTabName') && ${SEQNUM} == ${SELECTEDNUM})
+
+<table class="displaytable">
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SecurityActivation'))</nobr></td>
+ <td class="value">
+ #if($SECURITYACTIVATION == 'true')
+ <input type="checkbox" checked="true" name="s${SEQNUM}_securityactivated" value="true"/>
+ #else
+ <input type="checkbox" name="s${SEQNUM}_securityactivated" value="true"/>
+ #end
+ </td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SecurityField'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_securityfield" type="text"
+ value="$Encoder.attributeEscape($SECURITYFIELD)" size="20" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SecurityField2'))</nobr></td>
+ <td class="value"><input name="s${SEQNUM}_securityfield2" type="text"
+ value="$Encoder.attributeEscape($SECURITYFIELD2)" size="20" />
+ </td>
+ </tr>
+</table>
+
+#else
+
+
+
+<input type="hidden" name="s${SEQNUM}_securityactivated" value="$Encoder.bodyEscape($SECURITYACTIVATION)"/>
+<input type="hidden" name="s${SEQNUM}_securityfield" value="$Encoder.bodyEscape($SECURITYFIELD)"/>
+<input type="hidden" name="s${SEQNUM}_securityfield2" value="$Encoder.bodyEscape($SECURITYFIELD2)"/>
+
+
+#end
\ No newline at end of file
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_security.js b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_security.js
new file mode 100644
index 0000000..ddef4d7
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/editSpecification_job_security.js
@@ -0,0 +1,53 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<script type="text/javascript">
+function s${SEQNUM}_checkSpecification()
+{
+ if (editjob.s${SEQNUM}_securityactivated.checked && editjob.s${SEQNUM}_securityfield.value == "")
+ {
+ alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.NoValueSecurityField'))");
+ editjob.s${SEQNUM}_securityfield.focus();
+ return false;
+ }
+
+ if (editjob.s${SEQNUM}_collection.value == "")
+ {
+ alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.NoValueCollection'))");
+ editjob.s${SEQNUM}_collection.focus();
+ return false;
+ }
+
+ if (editjob.s${SEQNUM}_fieldid.value == "")
+ {
+ alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.NoValueIdField'))");
+ editjob.s${SEQNUM}_fieldid.focus();
+ return false;
+ }
+
+ if (editjob.s${SEQNUM}_fielddate.value == "")
+ {
+ alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SolrIngester.NoValueDateField'))");
+ editjob.s${SEQNUM}_fielddate.focus();
+ return false;
+ }
+
+
+ return true;
+}
+//-->
+</script>
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewConfiguration_connector.html b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewConfiguration_connector.html
new file mode 100644
index 0000000..3118bf4
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewConfiguration_connector.html
@@ -0,0 +1,39 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<table class="displaytable">
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SolrAddress'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($SOLRADDRESS)</nobr></td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SolrUsername'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($SOLRUSERNAME)</nobr></td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SolrPassword'))</nobr></td>
+ <td class="value"><nobr>**********</nobr></td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.ConnectionTimeout'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($CONNECTIONTIMEOUT)</nobr></td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SocketTimeout'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($SOCKETTIMEOUT)</nobr></td>
+ </tr>
+</table>
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewSpecification_job_parameters.html b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewSpecification_job_parameters.html
new file mode 100644
index 0000000..132b676
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewSpecification_job_parameters.html
@@ -0,0 +1,87 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<table class="displaytable">
+
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.CollectionName'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($COLLECTION)</nobr></td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FieldMappings'))</nobr></td>
+ <td class="boxcell">
+ <table class="formtable">
+ <tr class="formheaderrow">
+ <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.MetadataFieldName'))</nobr></td>
+ <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FinalFieldName'))</nobr></td>
+ </tr>
+#set($fieldcounter = 0)
+#foreach($fieldmapping in $FIELDMAPPINGS)
+ #if(($fieldcounter % 2) == 0)
+ <tr class="evenformrow">
+ #else
+ <tr class="oddformrow">
+ #end
+ <td class="formcolumncell">
+ <nobr>$Encoder.bodyEscape($fieldmapping.get('SOURCE'))</nobr>
+ </td>
+ <td class="formcolumncell">
+ <nobr>$Encoder.bodyEscape($fieldmapping.get('TARGETDISPLAY'))</nobr>
+ </td>
+ </tr>
+ #set($fieldcounter = $fieldcounter + 1)
+#end
+#if($fieldcounter == 0)
+ <tr class="formrow"><td class="formmessage" colspan="2">$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.NoFieldMappingSpecified'))</td></tr>
+#end
+ </table>
+ </td>
+ </tr>
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.IdField'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($FIELDID)</nobr></td>
+ </tr>
+
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.DateField'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($FIELDDATE)</nobr></td>
+ </tr>
+
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.ContentField'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($FIELDCONTENT)</nobr></td>
+ </tr>
+
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.FilterCondition'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($FILTERCONDITION)</nobr></td>
+ </tr>
+
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.RowsNumber'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($ROWSNUMBER)</nobr></td>
+ </tr>
+
+
+
+</table>
diff --git a/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewSpecification_job_security.html b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewSpecification_job_security.html
new file mode 100644
index 0000000..6384935
--- /dev/null
+++ b/connectors/solringester/connector/src/main/resources/org/apache/manifoldcf/crawler/connectors/solringester/viewSpecification_job_security.html
@@ -0,0 +1,38 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<table class="displaytable">
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SecurityActivation'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($SECURITYACTIVATION)</nobr></td>
+ </tr>
+ <tr><td class="separator" colspan="2"><hr/></td></tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SecurityField'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($SECURITYFIELD)</nobr></td>
+ </tr>
+ <tr>
+ <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SolrIngester.SecurityField2'))</nobr></td>
+ <td class="value"><nobr>$Encoder.bodyEscape($SECURITYFIELD2)</nobr></td>
+ </tr>
+
+
+
+</table>
diff --git a/connectors/solringester/pom.xml b/connectors/solringester/pom.xml
new file mode 100644
index 0000000..9cd6194
--- /dev/null
+++ b/connectors/solringester/pom.xml
@@ -0,0 +1,393 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.manifoldcf</groupId>
+ <artifactId>mcf-connectors</artifactId>
+ <version>2.13</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ </properties>
+
+ <artifactId>mcf-solringester-connector</artifactId>
+ <name>ManifoldCF - Connectors - SolrIngester</name>
+
+ <build>
+ <defaultGoal>integration-test</defaultGoal>
+ <sourceDirectory>${basedir}/connector/src/main/java</sourceDirectory>
+ <testSourceDirectory>${basedir}/connector/src/test/java</testSourceDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/connector/src/main/native2ascii</directory>
+ <includes>
+ <include>**/*.properties</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>${basedir}/connector/src/main/resources</directory>
+ <includes>
+ <include>**/*.html</include>
+ <include>**/*.js</include>
+ </includes>
+ </resource>
+ </resources>
+ <testResources>
+ <testResource>
+ <directory>${basedir}/connector/src/test/resources</directory>
+ </testResource>
+ </testResources>
+
+ <plugins>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>native2ascii-maven-plugin</artifactId>
+ <version>1.0-beta-1</version>
+ <configuration>
+ <dest>target/classes</dest>
+ <src>connector/src/main/native2ascii</src>
+ </configuration>
+ <executions>
+ <execution>
+ <id>native2ascii-utf8</id>
+ <goals>
+ <goal>native2ascii</goal>
+ </goals>
+ <configuration>
+ <encoding>UTF8</encoding>
+ <includes>
+ <include>**/*.properties</include>
+ </includes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Test plugin configuration -->
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-war</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>target/dependency</outputDirectory>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-api-service</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ <overWrite>false</overWrite>
+ <destFileName>mcf-api-service.war</destFileName>
+ </artifactItem>
+ <artifactItem>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-authority-service</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ <overWrite>false</overWrite>
+ <destFileName>mcf-authority-service.war</destFileName>
+ </artifactItem>
+ <artifactItem>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-crawler-ui</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ <overWrite>false</overWrite>
+ <destFileName>mcf-crawler-ui.war</destFileName>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>**/*Postgresql*.java</exclude>
+ <exclude>**/*MySQL*.java</exclude>
+ </excludes>
+ <forkCount>1</forkCount>
+ <reuseForks>false</reuseForks>
+ <workingDirectory>target/test-output</workingDirectory>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <skipTests>${skipITs}</skipTests>
+ <systemPropertyVariables>
+ <crawlerWarPath>../dependency/mcf-crawler-ui.war</crawlerWarPath>
+ <authorityserviceWarPath>../dependency/mcf-authority-service.war</authorityserviceWarPath>
+ <apiWarPath>../dependency/mcf-api-service.war</apiWarPath>
+ </systemPropertyVariables>
+ <excludes>
+ <exclude>**/*Postgresql*.java</exclude>
+ <exclude>**/*MySQL*.java</exclude>
+ </excludes>
+ <forkCount>1</forkCount>
+ <reuseForks>false</reuseForks>
+ <workingDirectory>target/test-output</workingDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>integration-test</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>verify</id>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-connector-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-agents</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-pull-agent</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-ui-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>${commons-logging.version}</version>
+ </dependency>
+
+ <!-- Testing dependencies -->
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-agents</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-pull-agent</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.postgresql</groupId>
+ <artifactId>postgresql</artifactId>
+ <version>${postgresql.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hsqldb</groupId>
+ <artifactId>hsqldb</artifactId>
+ <version>${hsqldb.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>${mysql.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-api-service</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-authority-service</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mcf-crawler-ui</artifactId>
+ <version>${project.version}</version>
+ <type>war</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-webapp</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-servlet</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-http</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-security</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-continuation</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-xml</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jsp-api-2.1-glassfish</artifactId>
+ <version>${glassfish.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jsp-2.1-glassfish</artifactId>
+ <version>${glassfish.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>${xerces.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xml.bind</groupId>
+ <artifactId>jaxb-impl</artifactId>
+ <version>${jaxb.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>${httpcomponent.httpclient.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.solr</groupId>
+ <artifactId>solr-solrj</artifactId>
+ <version>7.5.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.solr</groupId>
+ <artifactId>solr-core</artifactId>
+ <version>7.5.0</version>
+ </dependency>
+ </dependencies>
+</project>
+