/**
* 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.base;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.roda.core.data.common.RodaConstants;
import org.roda.core.data.common.RodaConstants.PreservationEventType;
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.RequestNotValidException;
import org.roda.core.data.v2.LiteOptionalWithCause;
import org.roda.core.data.v2.Void;
import org.roda.core.data.v2.index.filter.Filter;
import org.roda.core.data.v2.index.filter.SimpleFilterParameter;
import org.roda.core.data.v2.ip.IndexedAIP;
import org.roda.core.data.v2.jobs.Job;
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.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;
// FIXME 20161202 hsilva: expose params PLUGIN_PARAMS_PARENT_ID & PLUGIN_PARAMS_OTHER_JOB_ID
public class FixAncestorsPlugin extends AbstractPlugin<Void> {
private String originalJobId;
@Override
public void init() throws PluginException {
// do nothing
}
@Override
public void shutdown() {
// do nothing
}
public static String getStaticName() {
return "AIP ancestor hierarchy fix";
}
@Override
public String getName() {
return getStaticName();
}
public static String getStaticDescription() {
return "Attempts to fix the ancestor hierarchy of the AIPs in the catalogue by removing ghosts (i.e. AIPs with nonexistent ancestors in the catalogue) "
+ "and merging AIPs with the same Ingest SIP identifier.\nThis task aims to fix problems that may occur when SIPs are ingested but not all the "
+ "necessary items to construct the catalogue hierarchy have been received or properly ingested.";
}
@Override
public String getDescription() {
return getStaticDescription();
}
@Override
public String getVersionImpl() {
return "1.0";
}
@Override
public void setParameterValues(Map<String, String> parameters) throws InvalidParameterException {
super.setParameterValues(parameters);
if (getParameterValues().containsKey(RodaConstants.PLUGIN_PARAMS_OTHER_JOB_ID)) {
originalJobId = getParameterValues().get(RodaConstants.PLUGIN_PARAMS_OTHER_JOB_ID);
}
}
@Override
public Report execute(IndexService index, ModelService model, StorageService storage,
List<LiteOptionalWithCause> list) throws PluginException {
final int counter = calculateSourceObjectsCount(index);
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) {
fixAncestors(index, model, report, jobPluginInfo, jobPluginInfo.getSourceObjectsCount());
}
}, index, model, storage, counter);
}
private int calculateSourceObjectsCount(IndexService index) {
int count;
try {
count = index.count(IndexedAIP.class,
new Filter(new SimpleFilterParameter(RodaConstants.AIP_GHOST, Boolean.TRUE.toString()))).intValue();
// XXX 20160929 Is it really needed? (it is there to be possible to get
// 100% done reports)
if (count == 0) {
count = index.count(IndexedAIP.class, Filter.ALL).intValue();
}
} catch (RequestNotValidException | GenericException e) {
count = 0;
}
return count;
}
private void fixAncestors(IndexService index, ModelService model, Report report, SimpleJobPluginInfo jobPluginInfo,
int counter) {
try {
Optional<String> computedSearchScope = PluginHelper.getSearchScopeFromParameters(this, model);
Job originalJob = PluginHelper.getJob(originalJobId, model);
PluginHelper.fixParents(index, model, Optional.ofNullable(originalJob.getId()), computedSearchScope);
jobPluginInfo.incrementObjectsProcessedWithSuccess(counter);
report.setPluginState(PluginState.SUCCESS);
} catch (NotFoundException | GenericException | RequestNotValidException | AuthorizationDeniedException e) {
jobPluginInfo.incrementObjectsProcessedWithFailure(counter);
report.setPluginState(PluginState.FAILURE);
}
}
@Override
public Plugin<Void> cloneMe() {
return new FixAncestorsPlugin();
}
@Override
public PluginType getType() {
return PluginType.AIP_TO_AIP;
}
@Override
public boolean areParameterValuesValid() {
return true;
}
@Override
public PreservationEventType getPreservationEventType() {
return PreservationEventType.UPDATE;
}
@Override
public String getPreservationEventDescription() {
return "Fixed the ancestor hierarchy";
}
@Override
public String getPreservationEventSuccessMessage() {
return "Fixed the ancestor hierarchy successfully";
}
@Override
public String getPreservationEventFailureMessage() {
return "Fix of the ancestor hierarchy failed";
}
@Override
public Report beforeAllExecute(IndexService index, ModelService model, StorageService storage)
throws PluginException {
// do nothing
return null;
}
@Override
public Report afterAllExecute(IndexService index, ModelService model, StorageService storage) throws PluginException {
// do nothing
return null;
}
@Override
public List<String> getCategories() {
return Arrays.asList(RodaConstants.PLUGIN_CATEGORY_MISC);
}
@Override
public List<Class<Void>> getObjectClasses() {
return Arrays.asList(Void.class);
}
}