/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.core.plugins.plugins.reindex;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.roda.core.RodaCoreFactory;
import org.roda.core.data.common.RodaConstants;
import org.roda.core.data.common.RodaConstants.PreservationEventType;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.exceptions.InvalidParameterException;
import org.roda.core.data.exceptions.RODAException;
import org.roda.core.data.v2.LiteOptionalWithCause;
import org.roda.core.data.v2.Void;
import org.roda.core.data.v2.common.OptionalWithCause;
import org.roda.core.data.v2.jobs.Job;
import org.roda.core.data.v2.jobs.PluginParameter;
import org.roda.core.data.v2.jobs.PluginParameter.PluginParameterType;
import org.roda.core.data.v2.jobs.PluginType;
import org.roda.core.data.v2.jobs.Report;
import org.roda.core.data.v2.jobs.Report.PluginState;
import org.roda.core.data.v2.log.LogEntry;
import org.roda.core.index.IndexService;
import org.roda.core.model.ModelService;
import org.roda.core.plugins.AbstractPlugin;
import org.roda.core.plugins.Plugin;
import org.roda.core.plugins.PluginException;
import org.roda.core.plugins.RODAProcessingLogic;
import org.roda.core.plugins.orchestrate.SimpleJobPluginInfo;
import org.roda.core.plugins.plugins.PluginHelper;
import org.roda.core.storage.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReindexActionLogPlugin extends AbstractPlugin<Void> {
private static final int DEFAULT_DELETE_OLDER_THAN_X_DAYS = RodaCoreFactory.getRodaConfigurationAsInt(0, "core",
"actionlogs", "delete_older_than_x_days");
private static final Logger LOGGER = LoggerFactory.getLogger(ReindexActionLogPlugin.class);
private boolean clearIndexes = false;
private boolean optimizeIndexes = true;
private int dontReindexOlderThanXDays = DEFAULT_DELETE_OLDER_THAN_X_DAYS;
private static Map<String, PluginParameter> pluginParameters = new HashMap<>();
static {
pluginParameters.put(RodaConstants.PLUGIN_PARAMS_INT_VALUE,
new PluginParameter(RodaConstants.PLUGIN_PARAMS_INT_VALUE, "Delete older logs", PluginParameterType.INTEGER,
Integer.toString(DEFAULT_DELETE_OLDER_THAN_X_DAYS), false, false, "Delete logs older than x days."));
pluginParameters.put(RodaConstants.PLUGIN_PARAMS_CLEAR_INDEXES,
new PluginParameter(RodaConstants.PLUGIN_PARAMS_CLEAR_INDEXES, "Clear indexes", PluginParameterType.BOOLEAN,
"false", false, false, "Clear all indexes before reindexing them."));
pluginParameters.put(RodaConstants.PLUGIN_PARAMS_OPTIMIZE_INDEXES,
new PluginParameter(RodaConstants.PLUGIN_PARAMS_OPTIMIZE_INDEXES, "Optimize indexes", PluginParameterType.BOOLEAN,
"true", false, false, "Optimize indexes after reindexing them."));
}
@Override
public void init() throws PluginException {
// do nothing
}
@Override
public void shutdown() {
// do nothing
}
@Override
public String getName() {
return "Rebuild log index";
}
@Override
public String getDescription() {
return "Clears the index and recreates it from actual physical data that exists on the storage. This task aims to fix inconsistencies between"
+ " what is shown in the graphical user interface of the repository and what is actually kept at the storage layer. Such inconsistencies may"
+ " occur for various reasons, e.g. index corruption, ungraceful shutdown of the repository, etc.";
}
@Override
public String getVersionImpl() {
return "1.0";
}
@Override
public List<PluginParameter> getParameters() {
ArrayList<PluginParameter> parameters = new ArrayList<>();
parameters.add(pluginParameters.get(RodaConstants.PLUGIN_PARAMS_INT_VALUE));
parameters.add(pluginParameters.get(RodaConstants.PLUGIN_PARAMS_CLEAR_INDEXES));
parameters.add(pluginParameters.get(RodaConstants.PLUGIN_PARAMS_OPTIMIZE_INDEXES));
return parameters;
}
@Override
public void setParameterValues(Map<String, String> parameters) throws InvalidParameterException {
super.setParameterValues(parameters);
if (parameters != null && parameters.containsKey(RodaConstants.PLUGIN_PARAMS_CLEAR_INDEXES)) {
clearIndexes = Boolean.parseBoolean(parameters.get(RodaConstants.PLUGIN_PARAMS_CLEAR_INDEXES));
}
if (parameters != null && parameters.containsKey(RodaConstants.PLUGIN_PARAMS_OPTIMIZE_INDEXES)) {
optimizeIndexes = Boolean.parseBoolean(parameters.get(RodaConstants.PLUGIN_PARAMS_OPTIMIZE_INDEXES));
}
if (parameters != null && parameters.containsKey(RodaConstants.PLUGIN_PARAMS_INT_VALUE)) {
try {
int dontReindexOlderThan = Integer.parseInt(parameters.get(RodaConstants.PLUGIN_PARAMS_INT_VALUE));
if (dontReindexOlderThan >= 0) {
dontReindexOlderThanXDays = dontReindexOlderThan;
} else {
dontReindexOlderThanXDays = 0;
}
} catch (NumberFormatException e) {
dontReindexOlderThanXDays = 0;
}
}
}
@Override
public Report execute(IndexService index, ModelService model, StorageService storage,
List<LiteOptionalWithCause> list) throws PluginException {
return PluginHelper.processVoids(this, new RODAProcessingLogic<Void>() {
@Override
public void process(IndexService index, ModelService model, StorageService storage, Report report, Job cachedJob,
SimpleJobPluginInfo jobPluginInfo, Plugin<Void> plugin) {
reindexActionLogs(index, model, report, cachedJob, jobPluginInfo);
}
}, index, model, storage);
}
private void reindexActionLogs(IndexService index, ModelService model, Report report, Job job,
SimpleJobPluginInfo jobPluginInfo) {
report.setPluginState(PluginState.SUCCESS);
int i = 0;
for (OptionalWithCause<LogEntry> logEntry : model.listLogEntries(dontReindexOlderThanXDays)) {
jobPluginInfo.incrementObjectsCount();
i++;
if (logEntry.isPresent()) {
index.reindexActionLog(logEntry.get());
jobPluginInfo.incrementObjectsProcessedWithSuccess();
} else {
jobPluginInfo.incrementObjectsProcessedWithFailure();
Report reportItem = PluginHelper.initPluginReportItem(this, "log #" + i, LogEntry.class);
RODAException cause = logEntry.getCause();
StringBuilder message = new StringBuilder("Could not parse log entry: ");
message.append("[" + cause.getClass().getSimpleName() + "] " + cause.getMessage());
if (cause.getCause() != null) {
message
.append("\n cause: [" + cause.getCause().getClass().getSimpleName() + "] " + cause.getCause().getMessage());
}
reportItem.setPluginState(PluginState.FAILURE).setPluginDetails(message.toString());
report.addReport(reportItem);
PluginHelper.updatePartialJobReport(this, model, reportItem, false, job);
}
}
}
@Override
public Report beforeAllExecute(IndexService index, ModelService model, StorageService storage)
throws PluginException {
if (clearIndexes) {
LOGGER.debug("Clearing indexes");
try {
index.clearIndex(RodaConstants.INDEX_ACTION_LOG);
} catch (GenericException e) {
throw new PluginException("Error clearing index", e);
}
} else {
LOGGER.debug("Skipping clear indexes");
}
return new Report();
}
@Override
public Report afterAllExecute(IndexService index, ModelService model, StorageService storage) throws PluginException {
if (optimizeIndexes) {
LOGGER.debug("Optimizing indexes");
try {
index.optimizeIndex(RodaConstants.INDEX_ACTION_LOG);
} catch (GenericException e) {
throw new PluginException("Error optimizing index", e);
}
}
return new Report();
}
@Override
public Plugin<Void> cloneMe() {
return new ReindexActionLogPlugin();
}
@Override
public PluginType getType() {
return PluginType.MISC;
}
@Override
public boolean areParameterValuesValid() {
return true;
}
@Override
public PreservationEventType getPreservationEventType() {
return PreservationEventType.NONE;
}
@Override
public String getPreservationEventDescription() {
return "Reindexed action logs";
}
@Override
public String getPreservationEventSuccessMessage() {
return "Reindexed action logs successfully";
}
@Override
public String getPreservationEventFailureMessage() {
return "Reindex of action logs failed";
}
@Override
public List<String> getCategories() {
return Arrays.asList(RodaConstants.PLUGIN_CATEGORY_REINDEX);
}
@Override
public List<Class<Void>> getObjectClasses() {
return Arrays.asList(Void.class);
}
}