Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Flores <[email protected]>
  • Loading branch information
SugaryLump committed Oct 29, 2024
1 parent e60d1ec commit 81e1733
Show file tree
Hide file tree
Showing 21 changed files with 1,298 additions and 206 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ protected <I extends IsIndexed> Class<I> getIndexClass() {
return (Class<I>) IndexedAIP.class;
}

@Override
protected String getObjectId(AIP object) {
return object.getId();
}

@Override
public Plugin<AIP> cloneMe() {
return new GenerateAIPBackfillPlugin();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,272 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE.md file at the root of the source
* tree and available online at
* <p>
* https://github.com/keeps/roda
*/
package org.roda.core.plugins.base.maintenance.backfill;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.roda.core.data.v2.index.IsIndexed;
import org.roda.core.common.iterables.CloseableIterable;
import org.roda.core.data.common.RodaConstants;
import org.roda.core.data.common.RodaConstants.PreservationEventType;
import org.roda.core.data.exceptions.AlreadyExistsException;
import org.roda.core.data.exceptions.AuthorizationDeniedException;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.exceptions.InvalidParameterException;
import org.roda.core.data.exceptions.NotFoundException;
import org.roda.core.data.exceptions.NotSupportedException;
import org.roda.core.data.exceptions.RequestNotValidException;
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.ip.StoragePath;
import org.roda.core.data.v2.jobs.Job;
import org.roda.core.data.v2.jobs.PluginParameter;
import org.roda.core.data.v2.jobs.PluginType;
import org.roda.core.data.v2.jobs.Report;
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.PluginHelper;
import org.roda.core.plugins.RODAProcessingLogic;
import org.roda.core.plugins.base.maintenance.backfill.beans.Add;
import org.roda.core.plugins.base.maintenance.backfill.beans.DocType;
import org.roda.core.plugins.orchestrate.JobPluginInfo;
import org.roda.core.storage.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Alexandre Flores <[email protected]>
*/
public class GenerateActionLogBackfillPlugin extends GenerateRODAEntityBackfillPlugin<LogEntry> {
public class GenerateActionLogBackfillPlugin extends AbstractPlugin<Void> {

private static final Logger LOGGER = LoggerFactory.getLogger(GenerateActionLogBackfillPlugin.class);
private String outputDirectory = ".";
private boolean onlyGenerateInventory = false;
private Date startDate = null;

private static final Map<String, PluginParameter> pluginParameters = new HashMap<>();

static {
pluginParameters.put(RodaConstants.PLUGIN_PARAMS_OUTPUT_DIRECTORY,
PluginParameter
.getBuilder(RodaConstants.PLUGIN_PARAMS_OUTPUT_DIRECTORY, "Output directory",
PluginParameter.PluginParameterType.STRING)
.withDefaultValue(".").isMandatory(true).withDescription("This job's output directory path").build());
pluginParameters.put(RodaConstants.PLUGIN_PARAMS_ONLY_GENERATE_INVENTORY,
PluginParameter
.getBuilder(RodaConstants.PLUGIN_PARAMS_ONLY_GENERATE_INVENTORY, "Only generate inventory",
PluginParameter.PluginParameterType.BOOLEAN)
.withDefaultValue("false").isMandatory(true)
.withDescription(
"Whether this job should only generate the inventory of RODA objects and not the index backfill files")
.build());
pluginParameters.put(RodaConstants.PLUGIN_PARAMS_START_DATE,
PluginParameter
.getBuilder(RodaConstants.PLUGIN_PARAMS_START_DATE, "Object starting date",
PluginParameter.PluginParameterType.STRING)
.isMandatory(false).withDescription(
"The last modified data for source objects to process. If not set, all objects will be processed.")
.build());
}

@Override
public void init() throws PluginException {
// do nothing
}

@Override
public List<Class<Void>> getObjectClasses() {
return List.of(Void.class);
}

@Override
public void shutdown() {
// do nothing
}

@Override
public String getName() {
return "Generate complete log entry index backfill";
}

@Override
public String getDescription() {
return "Description of example plugin";
}

@Override
public String getVersionImpl() {
// Get from pom.xml <version>
return getClass().getPackage().getImplementationVersion();
}

@Override
public List<PluginParameter> getParameters() {
ArrayList<PluginParameter> parameters = new ArrayList<>();
parameters.add(pluginParameters.get(RodaConstants.PLUGIN_PARAMS_OUTPUT_DIRECTORY));
parameters.add(pluginParameters.get(RodaConstants.PLUGIN_PARAMS_ONLY_GENERATE_INVENTORY));
parameters.add(pluginParameters.get(RodaConstants.PLUGIN_PARAMS_START_DATE));
return parameters;
}

@Override
protected <I extends IsIndexed> Class<I> getIndexClass() {
return (Class<I>) LogEntry.class;
@Override
public void setParameterValues(Map<String, String> parameters) throws InvalidParameterException {
super.setParameterValues(parameters);
if (parameters != null && parameters.containsKey(RodaConstants.PLUGIN_PARAMS_OUTPUT_DIRECTORY)) {
outputDirectory = parameters.get(RodaConstants.PLUGIN_PARAMS_OUTPUT_DIRECTORY);
}
if (parameters != null && parameters.containsKey(RodaConstants.PLUGIN_PARAMS_ONLY_GENERATE_INVENTORY)) {
onlyGenerateInventory = Boolean.parseBoolean(parameters.get(RodaConstants.PLUGIN_PARAMS_ONLY_GENERATE_INVENTORY));
}
if (parameters != null && parameters.containsKey(RodaConstants.PLUGIN_PARAMS_START_DATE)) {
String dateString = parameters.get(RodaConstants.PLUGIN_PARAMS_START_DATE);
if (!dateString.isEmpty()) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
try {
startDate = formatter.parse(parameters.get(RodaConstants.PLUGIN_PARAMS_START_DATE));
} catch (ParseException e) {
throw new InvalidParameterException(e);
}
}
}
}

@Override
public Report execute(IndexService index, ModelService model, StorageService storage,
List<LiteOptionalWithCause> liteList) throws PluginException {
return PluginHelper
.processVoids(this,
(index1, model1, storage1, report, cachedJob, jobPluginInfo,
plugin) -> generateBackfill(model1, index1, storage1, report, jobPluginInfo, cachedJob),
index, model, storage);
}

protected void generateBackfill(ModelService model, IndexService index, StorageService storage, Report report,
JobPluginInfo jobPluginInfo, Job cachedJob) {
List<String> processedIds = new LinkedList<>();

CloseableIterable<OptionalWithCause<LogEntry>> objects = model.listLogEntries();
// TODO: Get this from config
int batchSize = 100;
int blockSize = 10;
Add addBean = new Add();
int docCount = 0;
int addCount = 0;
for (OptionalWithCause<LogEntry> object : objects) {
if (object.isPresent() && (startDate == null || object.get().getDatetime().after(startDate))) {
// TODO Handle exceptions
try {
DocType docBean = GenerateBackfillPluginUtils.toDocBean(object.get(), LogEntry.class);
addBean.getDoc().add(docBean);
processedIds.addLast(object.get().getId());

@Override
public Plugin<LogEntry> cloneMe() {
return new GenerateActionLogBackfillPlugin();
docCount++;
if (docCount >= blockSize * batchSize) {
StoragePath addPath = GenerateBackfillPluginUtils.constructAddOutputPath(outputDirectory, LogEntry.class,
Integer.toString(addCount));
GenerateBackfillPluginUtils.writeAddBean(storage, addPath, addBean);
addBean = new Add();
addCount++;
docCount = 0;
}
} catch (AuthorizationDeniedException e) {
throw new RuntimeException(e);
} catch (RequestNotValidException e) {
throw new RuntimeException(e);
} catch (NotFoundException e) {
throw new RuntimeException(e);
} catch (NotSupportedException e) {
throw new RuntimeException(e);
} catch (GenericException e) {
throw new RuntimeException(e);
} catch (AlreadyExistsException e) {
throw new RuntimeException(e);
}
}
}
// TODO Handle exceptions
try {
objects.close();
if (docCount > 0) {
StoragePath addPath = GenerateBackfillPluginUtils.constructAddOutputPath(outputDirectory, LogEntry.class,
Integer.toString(addCount));
GenerateBackfillPluginUtils.writeAddBean(storage, addPath, addBean);
}
StoragePath inventoryPath = GenerateBackfillPluginUtils.constructInventoryOutputPath(outputDirectory,
LogEntry.class);
GenerateBackfillPluginUtils.writeInventoryPartial(storage, inventoryPath, processedIds);
} catch (AlreadyExistsException | RequestNotValidException | GenericException | AuthorizationDeniedException
| NotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
public PluginType getType() {
return PluginType.MISC;
}

@Override
public boolean areParameterValuesValid() {
return true;
}

@Override
public PreservationEventType getPreservationEventType() {
return PreservationEventType.MIGRATION;
}

@Override
public String getPreservationEventDescription() {
return "Checked if ...";
}

@Override
public String getPreservationEventSuccessMessage() {
return "... with success.";
}

@Override
public String getPreservationEventFailureMessage() {
return "Failed to ...";
}

@Override
public Report beforeAllExecute(IndexService index, ModelService model, StorageService storage) {
// do nothing
return null;
}

@Override
public Report afterAllExecute(IndexService index, ModelService model, StorageService storage) {
// do nothing
return null;
}

@Override
public List<String> getCategories() {
return Collections.singletonList(RodaConstants.PLUGIN_CATEGORY_EXPERIMENTAL);
}

@Override
public List<Class<LogEntry>> getObjectClasses() {
return List.of(LogEntry.class);
@Override
public Plugin<Void> cloneMe() {
return new GenerateActionLogBackfillPlugin();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
import org.roda.core.data.v2.index.select.SelectedItems;
import org.roda.core.data.v2.index.select.SelectedItemsAll;
import org.roda.core.data.v2.index.select.SelectedItemsFilter;
import org.roda.core.data.v2.ip.DIPFile;
import org.roda.core.data.v2.ip.File;
import org.roda.core.data.v2.ip.Representation;
import org.roda.core.data.v2.ip.metadata.PreservationMetadata;
import org.roda.core.data.v2.jobs.Job;
import org.roda.core.data.v2.jobs.PluginParameter;
import org.roda.core.data.v2.jobs.PluginState;
Expand Down Expand Up @@ -130,19 +134,22 @@ public void setParameterValues(Map<String, String> parameters) throws InvalidPar
onlyGenerateInventory = Boolean.parseBoolean(parameters.get(RodaConstants.PLUGIN_PARAMS_ONLY_GENERATE_INVENTORY));
}
if (parameters != null && parameters.containsKey(RodaConstants.PLUGIN_PARAMS_START_DATE)) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
try {
startDate = formatter.parse(parameters.get(RodaConstants.PLUGIN_PARAMS_START_DATE));
} catch (ParseException e) {
throw new InvalidParameterException(e);
String dateString = parameters.get(RodaConstants.PLUGIN_PARAMS_START_DATE);
if (!dateString.isEmpty()) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
try {
startDate = formatter.parse(parameters.get(RodaConstants.PLUGIN_PARAMS_START_DATE));
} catch (ParseException e) {
throw new InvalidParameterException(e);
}
}
}
}

@Override
public Report execute(IndexService index, ModelService model, StorageService storage,
List<LiteOptionalWithCause> liteList) throws PluginException {
List<Class<? extends IsRODAObject>> classes = PluginHelper.getReindexObjectClasses();
List<Class<? extends IsRODAObject>> classes = GenerateBackfillPluginUtils.getBackfillObjectClasses();
return PluginHelper.processVoids(this,
(RODAProcessingLogic<Void>) (index1, model1, storage1, report, cachedJob, jobPluginInfo,
plugin) -> generateBackfill(model1, index1, storage1, report, jobPluginInfo, cachedJob, classes),
Expand All @@ -166,7 +173,8 @@ protected Report generateRODAObjectBackfill(ModelService model, Class<? extends
JobPluginInfo jobPluginInfo) {
Report report = null;

if (model.hasObjects(clazz)) {
if (model.hasObjects(clazz) || (clazz.equals(DIPFile.class) || clazz.equals(Representation.class)
|| clazz.equals(File.class) || clazz.equals(PreservationMetadata.class))) {
String jobId = IdUtils.createUUID();
String jobName = "Generate index backfill for RODA entity (" + clazz.getSimpleName() + ")";
report = PluginHelper.initPluginReportItem(this, jobId, Job.class);
Expand Down Expand Up @@ -197,6 +205,10 @@ protected <T extends IsRODAObject> Job initGenerateBackfillJob(Class<T> clazz, S
localPluginParameters.put(RodaConstants.PLUGIN_PARAMS_OUTPUT_DIRECTORY, outputDirectory);
localPluginParameters.put(RodaConstants.PLUGIN_PARAMS_ONLY_GENERATE_INVENTORY,
String.valueOf(onlyGenerateInventory));
if (startDate != null) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
localPluginParameters.put(RodaConstants.PLUGIN_PARAMS_START_DATE, dateFormat.format(startDate));
}
job.setPluginParameters(localPluginParameters);
job.setPluginType(PluginType.MISC);
job.setUsername(username);
Expand Down
Loading

0 comments on commit 81e1733

Please sign in to comment.