diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml
index 60fcc44060..a5bfd61bfb 100644
--- a/dspace-api/pom.xml
+++ b/dspace-api/pom.xml
@@ -759,6 +759,13 @@
20180130
+
+
+ com.opencsv
+ opencsv
+ 4.5
+
+
org.apache.velocity
velocity-engine-core
diff --git a/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java b/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java
index acb5bd754d..10a608bb76 100644
--- a/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java
+++ b/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java
@@ -8,6 +8,7 @@
package org.dspace.authority;
import java.sql.SQLException;
+import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -23,6 +24,7 @@ import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.core.Context;
+import org.dspace.util.SolrUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
@@ -34,8 +36,6 @@ import org.joda.time.format.ISODateTimeFormat;
* @author Mark Diggory (markd at atmire dot com)
*/
public class AuthorityValue {
-
-
/**
* The id of the record in solr
*/
@@ -150,12 +150,13 @@ public class AuthorityValue {
public SolrInputDocument getSolrInputDocument() {
SolrInputDocument doc = new SolrInputDocument();
+ DateFormat solrDateFormatter = SolrUtils.getDateFormatter();
doc.addField("id", getId());
doc.addField("field", getField());
doc.addField("value", getValue());
doc.addField("deleted", isDeleted());
- doc.addField("creation_date", getCreationDate());
- doc.addField("last_modified_date", getLastModified());
+ doc.addField("creation_date", solrDateFormatter.format(getCreationDate()));
+ doc.addField("last_modified_date", solrDateFormatter.format(getLastModified()));
doc.addField("authority_type", getAuthorityType());
return doc;
}
@@ -196,12 +197,12 @@ public class AuthorityValue {
* @return map
*/
public Map choiceSelectMap() {
- return new HashMap();
+ return new HashMap<>();
}
public List getDateFormatters() {
- List list = new ArrayList();
+ List list = new ArrayList<>();
list.add(ISODateTimeFormat.dateTime());
list.add(ISODateTimeFormat.dateTimeNoMillis());
return list;
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java
index acb259f99d..6de698d0ed 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java
@@ -14,6 +14,7 @@ import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.sql.SQLException;
+import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -105,6 +106,7 @@ import org.dspace.handle.service.HandleService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.storage.rdbms.DatabaseUtils;
import org.dspace.util.MultiFormatDateParser;
+import org.dspace.util.SolrUtils;
import org.dspace.workflow.WorkflowItem;
import org.dspace.xmlworkflow.WorkflowConfigurationException;
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
@@ -1038,6 +1040,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
*/
protected void buildDocument(Context context, Item item)
throws SQLException, IOException {
+ final DateFormat solrDateFormatter = SolrUtils.getDateFormatter();
+
String handle = item.getHandle();
if (handle == null) {
@@ -1055,7 +1059,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
doc.addField("archived", item.isArchived());
doc.addField("withdrawn", item.isWithdrawn());
doc.addField("discoverable", item.isDiscoverable());
- doc.addField("lastModified", item.getLastModified());
+ doc.addField("lastModified", solrDateFormatter.format(item.getLastModified()));
EPerson submitter = item.getSubmitter();
if (submitter != null) {
@@ -1476,7 +1480,9 @@ public class SolrServiceImpl implements SearchService, IndexingService {
if (type.equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
Date date = MultiFormatDateParser.parse(value);
if (date != null) {
- doc.addField(field + "_dt", date);
+ final DateFormat solrDateFormatter = SolrUtils.getDateFormatter();
+ String stringDate = solrDateFormatter.format(date);
+ doc.addField(field + "_dt", stringDate);
} else {
log.warn("Error while indexing sort date field, item: " + item
.getHandle() + " metadata field: " + field + " date value: " + date);
@@ -1741,7 +1747,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
List locations) {
// want to be able to check when last updated
// (not tokenized, but it is indexed)
- doc.addField(LAST_INDEXED_FIELD, new Date());
+ doc.addField(LAST_INDEXED_FIELD,
+ SolrUtils.getDateFormatter().format(new Date()));
// New fields to weaken the dependence on handles, and allow for faster
// list display
diff --git a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
index f34dca7d20..e1ff0c69b8 100644
--- a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
@@ -8,7 +8,6 @@
package org.dspace.statistics;
import java.io.File;
-import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
@@ -17,7 +16,10 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
+import java.net.URI;
import java.net.URLEncoder;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
@@ -45,14 +47,18 @@ import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.HttpSolrClient.RemoteSolrException;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.apache.solr.client.solrj.request.LukeRequest;
+import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.LukeResponse;
import org.apache.solr.client.solrj.response.QueryResponse;
@@ -64,10 +70,12 @@ import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.luke.FieldFlag;
import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.ShardParams;
+import org.apache.solr.common.util.NamedList;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
@@ -103,8 +111,7 @@ import org.springframework.beans.factory.annotation.Autowired;
*/
public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBean {
- private static final org.apache.logging.log4j.Logger log =
- org.apache.logging.log4j.LogManager.getLogger(SolrLoggerServiceImpl.class);
+ private static final Logger log = LogManager.getLogger();
private static final String MULTIPLE_VALUES_SPLITTER = "|";
protected SolrClient solr;
@@ -129,6 +136,12 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
@Autowired(required = true)
private ClientInfoService clientInfoService;
+ /** URL to the current-year statistics core. Prior-year shards will have a year suffixed. */
+ private String statisticsCoreURL;
+
+ /** Name of the current-year statistics core. Prior-year shards will have a year suffixed. */
+ private String statisticsCoreBase;
+
public static enum StatisticsType {
VIEW("view"),
SEARCH("search"),
@@ -153,14 +166,26 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
@Override
public void afterPropertiesSet() throws Exception {
- log.info("solr-statistics.server:" + configurationService.getProperty("solr-statistics.server"));
- log.info("usage-statistics.dbfile:" + configurationService.getProperty("usage-statistics.dbfile"));
+ statisticsCoreURL = configurationService.getProperty("solr-statistics.server");
+
+ if (null != statisticsCoreURL) {
+ Path statisticsPath = Paths.get(new URI(statisticsCoreURL).getPath());
+ statisticsCoreBase = statisticsPath
+ .getName(statisticsPath.getNameCount() - 1)
+ .toString();
+ } else {
+ statisticsCoreBase = null;
+ }
+
+ log.info("solr-statistics.server: {}", statisticsCoreURL);
+ log.info("usage-statistics.dbfile: {}",
+ configurationService.getProperty("usage-statistics.dbfile"));
HttpSolrClient server = null;
- if (configurationService.getProperty("solr-statistics.server") != null) {
+ if (statisticsCoreURL != null) {
try {
- server = new HttpSolrClient.Builder(configurationService.getProperty("solr-statistics.server")).build();
+ server = new HttpSolrClient.Builder(statisticsCoreURL).build();
} catch (Exception e) {
log.error("Error accessing Solr server configured in 'solr-statistics.server'", e);
}
@@ -1159,7 +1184,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
filterQuery.append(")");
- Map yearQueryParams = new HashMap();
+ Map yearQueryParams = new HashMap<>();
yearQueryParams.put(CommonParams.Q, "*:*");
yearQueryParams.put(CommonParams.ROWS, String.valueOf(10000));
yearQueryParams.put(CommonParams.FQ, filterQuery.toString());
@@ -1170,7 +1195,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
yearQueryParams.put("csv.mv.separator", MULTIPLE_VALUES_SPLITTER);
//Start by creating a new core
- String coreName = "statistics-" + dcStart.getYearUTC();
+ String coreName = statisticsCoreBase + "-" + dcStart.getYearUTC();
HttpSolrClient statisticsYearServer = createCore((HttpSolrClient) solr, coreName);
System.out.println("Moving: " + totalRecords + " into core " + coreName);
@@ -1198,12 +1223,12 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
for (File tempCsv : filesToUpload) {
//Upload the data in the csv files to our new solr core
- ContentStreamUpdateRequest contentStreamUpdateRequest = new ContentStreamUpdateRequest("/update/csv");
- contentStreamUpdateRequest.setParam("stream.contentType", "text/plain;charset=utf-8");
+ ContentStreamUpdateRequest contentStreamUpdateRequest = new ContentStreamUpdateRequest("/update");
+ contentStreamUpdateRequest.setParam("stream.contentType", "text/csv;charset=utf-8");
contentStreamUpdateRequest.setParam("escape", "\\");
contentStreamUpdateRequest.setParam("skip", "_version_");
contentStreamUpdateRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
- contentStreamUpdateRequest.addFile(tempCsv, "text/plain;charset=utf-8");
+ contentStreamUpdateRequest.addFile(tempCsv, "text/csv;charset=utf-8");
//Add parsing directives for the multivalued fields so that they are stored as separate values
// instead of one value
@@ -1223,39 +1248,42 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
solr.deleteByQuery(filterQuery.toString());
solr.commit(true, true);
- log.info("Moved " + totalRecords + " records into core: " + coreName);
+ log.info("Moved {} records into core: {}", totalRecords, coreName);
}
FileUtils.deleteDirectory(tempDirectory);
}
- protected HttpSolrClient createCore(HttpSolrClient solr, String coreName) throws IOException, SolrServerException {
- String solrDir = configurationService.getProperty("dspace.dir") + File.separator + "solr" + File.separator;
- String baseSolrUrl = solr.getBaseURL().replace("statistics", "");
+ protected HttpSolrClient createCore(HttpSolrClient solr, String coreName)
+ throws IOException, SolrServerException {
+ String baseSolrUrl = solr.getBaseURL().replace(statisticsCoreBase, ""); // Has trailing slash
- //DS-3458: Test to see if a solr core already exists. If it exists, return that server. Otherwise create a
- // new one.
- HttpSolrClient returnServer = new HttpSolrClient.Builder(baseSolrUrl + "/" + coreName).build();
+ //DS-3458: Test to see if a solr core already exists. If it exists,
+ // return a connection to that core. Otherwise create a new core and
+ // return a connection to it.
+ HttpSolrClient returnServer = new HttpSolrClient.Builder(baseSolrUrl + coreName).build();
try {
SolrPingResponse ping = returnServer.ping();
- log.debug(String.format("Ping of Solr Core [%s] Returned with Status [%d]", coreName, ping.getStatus()));
+ log.debug("Ping of Solr Core {} returned with Status {}",
+ coreName, ping.getStatus());
return returnServer;
- } catch (Exception e) {
- log.debug(String.format("Ping of Solr Core [%s] Failed with [%s]. New Core Will be Created", coreName,
- e.getClass().getName()));
+ } catch (IOException | RemoteSolrException | SolrServerException e) {
+ log.debug("Ping of Solr Core {} failed with {}. New Core Will be Created",
+ coreName, e.getClass().getName());
}
//Unfortunately, this class is documented as "experimental and subject to change" on the Lucene website.
//http://lucene.apache.org/solr/4_4_0/solr-solrj/org/apache/solr/client/solrj/request/CoreAdminRequest.html
CoreAdminRequest.Create create = new CoreAdminRequest.Create();
create.setCoreName(coreName);
+ String configSetName = configurationService
+ .getProperty("solr-statistics.configset", "statistics");
+ create.setConfigSet(configSetName);
+ create.setInstanceDir(coreName);
- //The config files for a statistics shard reside wihtin the statistics repository
- create.setInstanceDir("statistics");
- create.setDataDir(solrDir + coreName + File.separator + "data");
HttpSolrClient solrServer = new HttpSolrClient.Builder(baseSolrUrl).build();
create.process(solrServer);
- log.info("Created core with name: " + coreName);
+ log.info("Created core with name: {} from configset {}", coreName, configSetName);
return returnServer;
}
@@ -1390,10 +1418,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
//Add all the separate csv files
for (File tempCsv : tempCsvFiles) {
- ContentStreamUpdateRequest contentStreamUpdateRequest = new ContentStreamUpdateRequest("/update/csv");
- contentStreamUpdateRequest.setParam("stream.contentType", "text/plain;charset=utf-8");
+ ContentStreamUpdateRequest contentStreamUpdateRequest = new ContentStreamUpdateRequest("/update");
+ contentStreamUpdateRequest.setParam("stream.contentType", "text/csv;charset=utf-8");
contentStreamUpdateRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
- contentStreamUpdateRequest.addFile(tempCsv, "text/plain;charset=utf-8");
+ contentStreamUpdateRequest.addFile(tempCsv, "text/csv;charset=utf-8");
solr.request(contentStreamUpdateRequest);
}
@@ -1520,43 +1548,49 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
}
/*
- * The statistics shards should not be initialized until all tomcat webapps are fully initialized.
- * DS-3457 uncovered an issue in DSpace 6x in which this code triggered tomcat to hang when statistics shards are
- * present.
- * This code is synchonized in the event that 2 threads trigger the initialization at the same time.
+ * The statistics shards should not be initialized until all tomcat webapps
+ * are fully initialized. DS-3457 uncovered an issue in DSpace 6x in which
+ * this code triggered Tomcat to hang when statistics shards are present.
+ * This code is synchonized in the event that 2 threads trigger the
+ * initialization at the same time.
*/
protected synchronized void initSolrYearCores() {
if (statisticYearCoresInit || !(solr instanceof HttpSolrClient)) {
return;
}
- try {
+
+ //Base url should like : http://localhost:{port.number}/solr
+ String baseSolrUrl = ((HttpSolrClient) solr).getBaseURL().replace(statisticsCoreBase, "");
+
+ try (HttpSolrClient enumClient = new HttpSolrClient.Builder(baseSolrUrl).build();) {
//Attempt to retrieve all the statistic year cores
- File solrDir = new File(
- configurationService.getProperty("dspace.dir") + File.separator + "solr" + File.separator);
- File[] solrCoreFiles = solrDir.listFiles(new FileFilter() {
-
- @Override
- public boolean accept(File file) {
- //Core name example: statistics-2008
- return file.getName().matches("statistics-\\d\\d\\d\\d");
+ CoreAdminRequest coresRequest = new CoreAdminRequest();
+ coresRequest.setAction(CoreAdminAction.STATUS);
+ CoreAdminResponse coresResponse = coresRequest.process(enumClient);
+ NamedList