VIVO-869 Improve the display

Show exclusions count as separate from deletions count.
When there is an error on the Ajax call, display the error status and stop asking for refreshes.
When a rebuild is requested, redirect to just status, so refreshing the page would not request another rebuild.
This commit is contained in:
Jim Blake 2015-01-20 14:06:11 -05:00
parent 78491234db
commit 83a5523ace
7 changed files with 62 additions and 16 deletions

View file

@ -102,19 +102,25 @@ public class SearchIndexerStatus {
} }
public static class UriCounts extends Counts { public static class UriCounts extends Counts {
private final int excluded;
private final int deleted; private final int deleted;
private final int updated; private final int updated;
private final int remaining; private final int remaining;
private final int total; private final int total;
public UriCounts(int deleted, int updated, int remaining, int total) { public UriCounts(int excluded, int deleted, int updated, int remaining, int total) {
super(Type.URI_COUNTS); super(Type.URI_COUNTS);
this.excluded = excluded;
this.deleted = deleted; this.deleted = deleted;
this.updated = updated; this.updated = updated;
this.remaining = remaining; this.remaining = remaining;
this.total = total; this.total = total;
} }
public int getExcluded() {
return excluded;
}
public int getDeleted() { public int getDeleted() {
return deleted; return deleted;
} }
@ -133,7 +139,7 @@ public class SearchIndexerStatus {
@Override @Override
public String toString() { public String toString() {
return "[deleted=" + deleted + ", updated=" + updated return "[excluded=" + excluded + ", deleted=" + deleted + ", updated=" + updated
+ ", remaining=" + remaining + ", total=" + total + "]"; + ", remaining=" + remaining + ", total=" + total + "]";
} }
} }

View file

@ -16,10 +16,13 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexer; import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexer;
@ -99,10 +102,6 @@ public class IndexController extends FreemarkerHttpServlet {
@Override @Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException { throws IOException, ServletException {
if (!isAuthorizedToDisplayPage(req, resp, REQUIRED_ACTIONS)) {
return;
}
switch (RequestType.fromRequest(req)) { switch (RequestType.fromRequest(req)) {
case STATUS: case STATUS:
showStatus(req, resp); showStatus(req, resp);
@ -118,12 +117,17 @@ public class IndexController extends FreemarkerHttpServlet {
return "Rebuild Search Index"; return "Rebuild Search Index";
} }
@Override
protected AuthorizationRequest requiredActions(VitroRequest vreq) {
return REQUIRED_ACTIONS;
}
@Override @Override
protected ResponseValues processRequest(VitroRequest vreq) { protected ResponseValues processRequest(VitroRequest vreq) {
switch (RequestType.fromRequest(vreq)) { switch (RequestType.fromRequest(vreq)) {
case REBUILD: case REBUILD:
requestRebuild(); requestRebuild();
return showDisplay(); return new RedirectResponseValues(PAGE_URL);
default: default:
return showDisplay(); return showDisplay();
} }
@ -138,6 +142,12 @@ public class IndexController extends FreemarkerHttpServlet {
private void showStatus(HttpServletRequest req, HttpServletResponse resp) private void showStatus(HttpServletRequest req, HttpServletResponse resp)
throws IOException { throws IOException {
if (!PolicyHelper.isAuthorizedForActions(req, REQUIRED_ACTIONS)) {
resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
resp.getWriter().write("You are not authorized to access this page.");
return;
}
try { try {
Map<String, Object> body = new HashMap<>(); Map<String, Object> body = new HashMap<>();
body.put("statusUrl", UrlBuilder.getUrl(PAGE_URL, "status", "true")); body.put("statusUrl", UrlBuilder.getUrl(PAGE_URL, "status", "true"));

View file

@ -28,7 +28,7 @@ import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexerStatu
public class IndexHistory implements SearchIndexer.Listener { public class IndexHistory implements SearchIndexer.Listener {
private static final Log log = LogFactory.getLog(IndexHistory.class); private static final Log log = LogFactory.getLog(IndexHistory.class);
private final static int MAX_EVENTS = 10; private final static int MAX_EVENTS = 20;
private final Deque<Event> events = new LinkedList<>(); private final Deque<Event> events = new LinkedList<>();
@ -84,6 +84,7 @@ public class IndexHistory implements SearchIndexer.Listener {
} }
private void addCounts(UriCounts counts, Map<String, Object> map) { private void addCounts(UriCounts counts, Map<String, Object> map) {
map.put("excluded", counts.getExcluded());
map.put("updated", counts.getUpdated()); map.put("updated", counts.getUpdated());
map.put("deleted", counts.getDeleted()); map.put("deleted", counts.getDeleted());
map.put("remaining", counts.getRemaining()); map.put("remaining", counts.getRemaining());

View file

@ -69,8 +69,7 @@ public class UpdateUrisTask implements Task {
this.status = new Status(uris.size(), 500, listeners); this.status = new Status(uris.size(), 500, listeners);
this.searchEngine = ApplicationUtils.instance().getSearchEngine(); this.searchEngine = ApplicationUtils.instance().getSearchEngine();
} }
@Override @Override
@ -86,8 +85,10 @@ public class UpdateUrisTask implements Task {
break; break;
} else { } else {
Individual ind = getIndividual(uri); Individual ind = getIndividual(uri);
if (ind == null || isExcluded(ind)) { if (ind == null) {
deleteDocument(uri); deleteDocument(uri);
} else if (isExcluded(ind)) {
excludeDocument(uri);
} else { } else {
updateDocument(ind); updateDocument(ind);
} }
@ -133,6 +134,17 @@ public class UpdateUrisTask implements Task {
} }
} }
/** An exclusion is just a delete for different reasons. */
private void excludeDocument(String uri) {
try {
searchEngine.deleteById(SearchIndexerUtils.getIdForUri(uri));
status.incrementExclusions();
log.debug("excluded '" + uri + "' from search index.");
} catch (Exception e) {
log.warn("Failed to exclude '" + uri + "' from search index", e);
}
}
private void updateDocument(Individual ind) { private void updateDocument(Individual ind) {
Runnable workUnit = new UpdateDocumentWorkUnit(ind, modifiers); Runnable workUnit = new UpdateDocumentWorkUnit(ind, modifiers);
pool.submit(workUnit, this); pool.submit(workUnit, this);
@ -165,6 +177,7 @@ public class UpdateUrisTask implements Task {
private final ListenerList listeners; private final ListenerList listeners;
private int updated = 0; private int updated = 0;
private int deleted = 0; private int deleted = 0;
private int excluded = 0;
private Date since = new Date(); private Date since = new Date();
public Status(int total, int progressInterval, ListenerList listeners) { public Status(int total, int progressInterval, ListenerList listeners) {
@ -184,6 +197,11 @@ public class UpdateUrisTask implements Task {
since = new Date(); since = new Date();
} }
public synchronized void incrementExclusions() {
excluded++;
since = new Date();
}
private void maybeFireProgressEvent() { private void maybeFireProgressEvent() {
if (updated > 0 && updated % progressInterval == 0) { if (updated > 0 && updated % progressInterval == 0) {
listeners.fireEvent(new Event(PROGRESS, listeners.fireEvent(new Event(PROGRESS,
@ -192,9 +210,9 @@ public class UpdateUrisTask implements Task {
} }
public synchronized SearchIndexerStatus getSearchIndexerStatus() { public synchronized SearchIndexerStatus getSearchIndexerStatus() {
int remaining = total - updated - deleted; int remaining = total - updated - deleted - excluded;
return new SearchIndexerStatus(PROCESSING_URIS, since, return new SearchIndexerStatus(PROCESSING_URIS, since,
new UriCounts(deleted, updated, remaining, total)); new UriCounts(excluded, deleted, updated, remaining, total));
} }
} }

View file

@ -9,8 +9,12 @@ function updateSearchIndexerStatus() {
url: searchIndexerStatusUrl, url: searchIndexerStatusUrl,
dataType: "html", dataType: "html",
complete: function(xhr, status) { complete: function(xhr, status) {
updatePanelContents(xhr.responseText); if (xhr.status == 200) {
setTimeout(updateSearchIndexerStatus,5000); updatePanelContents(xhr.responseText);
setTimeout(updateSearchIndexerStatus,5000);
} else {
displayErrorMessage(xhr.status + " " + xhr.statusText);
}
} }
}); });
} }
@ -19,4 +23,9 @@ function updatePanelContents(contents) {
document.getElementById("searchIndexerStatus").innerHTML = contents; document.getElementById("searchIndexerStatus").innerHTML = contents;
} }
function displayErrorMessage(message) {
document.getElementById("searchIndexerError").innerHTML = "<h3>" + message + "</h3>";
}
$(document).ready(updateSearchIndexerStatus()); $(document).ready(updateSearchIndexerStatus());

View file

@ -7,6 +7,8 @@
<h2>${i18n().search_index_status}</h2> <h2>${i18n().search_index_status}</h2>
<div id="searchIndexerError" />
<div id="searchIndexerStatus"> <div id="searchIndexerStatus">
Search Indexer Status Search Indexer Status
</div> </div>

View file

@ -64,7 +64,7 @@
<#macro showIndexerCounts countsType, counts> <#macro showIndexerCounts countsType, counts>
<#if countsType == "URI_COUNTS"> <#if countsType == "URI_COUNTS">
Updated: ${counts.updated}, deleted: ${counts.deleted}, remaining: ${counts.remaining}, total: ${counts.total} Updated: ${counts.updated}, excluded: ${counts.excluded}, deleted: ${counts.deleted}, remaining: ${counts.remaining}, total: ${counts.total}
<#elseif countsType == "STATEMENT_COUNTS"> <#elseif countsType == "STATEMENT_COUNTS">
Processed: ${counts.processed}, remaining: ${counts.remaining}, total: ${counts.total} Processed: ${counts.processed}, remaining: ${counts.remaining}, total: ${counts.total}
<#elseif countsType == "REBUILD_COUNTS"> <#elseif countsType == "REBUILD_COUNTS">