Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* $This file is distributed under the terms of the license in LICENSE$ */
package edu.cornell.mannlib.vitro.webapp.search.controller;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
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.controller.VitroRequest;
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.responsevalues.RedirectResponseValues;
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.modules.searchIndexer.SearchIndexer;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexerStatus;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexerStatus.RebuildCounts;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexerStatus.State;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexerStatus.StatementCounts;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexerStatus.UriCounts;
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingServiceSetup;
/**
* Accepts requests to display the current status of the search index, or to
* initiate a rebuild.
*
* A DISPLAY or REBUILD request is handled like any other FreemarkerHttpServlet.
* A STATUS is an AJAX request, we override doGet() so we can format the
* template without enclosing it in a body template.
*
* When initialized, this servlet adds a listener to the SearchIndexer, so it
* can maintain a history of activity. This will provide the contents of the
* display.
*/
@WebServlet(name = "IndexController", urlPatterns = {"/SearchIndex"} )
public class IndexController extends FreemarkerHttpServlet {
private static final Log log = LogFactory.getLog(IndexController.class);
/**
*
* This request might be:
* DISPLAY (default) -- Send the template that will contain the status display.
* STATUS -- Send the current status and history.
* REBUILD -- Initiate a rebuild. Then act like DISPLAY.
*
*/
private enum RequestType {
DISPLAY, STATUS, REBUILD;
/** What type of request is this? */
static RequestType fromRequest(HttpServletRequest req) {
if (hasParameter(req, "rebuild")) {
return REBUILD;
} else if (hasParameter(req, "status")) {
return STATUS;
} else {
return DISPLAY;
}
}
private static boolean hasParameter(HttpServletRequest req, String key) {
String value = req.getParameter(key);
return (value != null) && (!value.isEmpty());
}
}
private static final String PAGE_URL = "/SearchIndex";
private static final String PAGE_TEMPLATE_NAME = "searchIndex.ftl";
private static final String STATUS_TEMPLATE_NAME = "searchIndexStatus.ftl";
public static final RequestedAction REQUIRED_ACTIONS = SimplePermission.MANAGE_SEARCH_INDEX.ACTION;
private SearchIndexer indexer;
private static IndexHistory history;
@Override
public void init() throws ServletException {
this.indexer = ApplicationUtils.instance().getSearchIndexer();
super.init();
}
/**
* Called by SearchIndexerSetup to provide a history that dates from
* startup, not just from servlet load time.
*/
public static void setHistory(IndexHistory history) {
IndexController.history = history;
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
switch (RequestType.fromRequest(req)) {
case STATUS:
showStatus(req, resp);
break;
default:
super.doGet(req, resp);
break;
}
}
@Override
protected String getTitle(String siteName, VitroRequest vreq) {
return "Rebuild Search Index";
}
@Override
protected AuthorizationRequest requiredActions(VitroRequest vreq) {
return REQUIRED_ACTIONS;
}
@Override
protected ResponseValues processRequest(VitroRequest vreq) {
switch (RequestType.fromRequest(vreq)) {
case REBUILD:
requestRebuild();
try {
// Pause, giving a chance to start the task queue.
Thread.sleep(1000);
} catch (InterruptedException e) {
// Don't care, so pass it along.
Thread.currentThread().interrupt();
}
return new RedirectResponseValues(PAGE_URL);
default:
return showDisplay();
}
}
private ResponseValues showDisplay() {
HashMap body = new HashMap<>();
body.put("statusUrl", UrlBuilder.getUrl(PAGE_URL, "status", "true"));
body.put("rebuildUrl", UrlBuilder.getUrl(PAGE_URL, "rebuild", "true"));
return new TemplateResponseValues(PAGE_TEMPLATE_NAME, body);
}
private void showStatus(HttpServletRequest req, HttpServletResponse resp)
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 {
Map body = new HashMap<>();
body.put("statusUrl", UrlBuilder.getUrl(PAGE_URL, "status", "true"));
body.put("rebuildUrl",
UrlBuilder.getUrl(PAGE_URL, "rebuild", "true"));
body.put("status", buildStatusMap(indexer.getStatus()));
if (history != null) {
body.put("history", history.toMaps());
}
String rendered = FreemarkerProcessingServiceSetup.getService(
getServletContext()).renderTemplate(STATUS_TEMPLATE_NAME,
body, req);
resp.getWriter().write(rendered);
} catch (Exception e) {
resp.setStatus(500);
resp.getWriter().write(e.toString());
log.error(e, e);
}
}
private void requestRebuild() {
indexer.rebuildIndex();
}
private Map buildStatusMap(SearchIndexerStatus status) {
Map map = new HashMap<>();
State state = status.getState();
map.put("statusType", state);
map.put("since", status.getSince());
if (state == State.PROCESSING_URIS) {
UriCounts counts = status.getCounts().asUriCounts();
map.put("updated", counts.getUpdated());
map.put("deleted", counts.getDeleted());
map.put("remaining", counts.getRemaining());
map.put("total", counts.getTotal());
map.put("elapsed", breakDownElapsedTime(status.getSince()));
map.put("expectedCompletion",
figureExpectedCompletion(status.getSince(),
counts.getTotal(),
counts.getTotal() - counts.getRemaining()));
} else if (state == State.PROCESSING_STMTS) {
StatementCounts counts = status.getCounts().asStatementCounts();
map.put("processed", counts.getProcessed());
map.put("remaining", counts.getRemaining());
map.put("total", counts.getTotal());
map.put("elapsed", breakDownElapsedTime(status.getSince()));
map.put("expectedCompletion",
figureExpectedCompletion(status.getSince(),
counts.getTotal(), counts.getProcessed()));
} else if (state == State.REBUILDING) {
RebuildCounts counts = status.getCounts().asRebuildCounts();
map.put("documentsBefore", counts.getDocumentsBefore());
map.put("documentsAfter", counts.getDocumentsAfter());
} else {
// nothing for IDLE or SHUTDOWN, except what's already there.
}
return map;
}
private Date figureExpectedCompletion(Date startTime, long totalToDo,
long completedCount) {
Date now = new Date();
long elapsedMillis = now.getTime() - startTime.getTime();
if (elapsedMillis <= 0) {
return now;
}
if (completedCount <= 0) {
return now;
}
if (totalToDo <= completedCount) {
return now;
}
long millisPerRecord = elapsedMillis / completedCount;
long expectedDuration = totalToDo * millisPerRecord;
return new Date(expectedDuration + startTime.getTime());
}
private int[] breakDownElapsedTime(Date since) {
long elapsedMillis = new Date().getTime() - since.getTime();
long seconds = (elapsedMillis / 1000L) % 60L;
long minutes = (elapsedMillis / 60000L) % 60L;
long hours = elapsedMillis / 3600000L;
return new int[] { (int) hours, (int) minutes, (int) seconds };
}
}