/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.start.common.validation.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.core.start.common.validation.api.InstanceValidationResult;
import de.rcenvironment.core.start.common.validation.api.InstanceValidationResult.InstanceValidationResultType;
import de.rcenvironment.core.start.common.validation.api.InstanceValidationResultFactory;
import de.rcenvironment.core.start.common.validation.api.InstanceValidationService;
import de.rcenvironment.core.start.common.validation.spi.InstanceValidator;
import de.rcenvironment.core.utils.common.StringUtils;
/**
* Implementation of {@link InstanceValidationService}.
*
* @author Christian Weiss
* @author Doreen Seider
* @author Tobias Rodehutskors
*/
public class InstanceValidationServiceImpl implements InstanceValidationService {
protected Map<Class<? extends InstanceValidator>, InstanceValidationResult> executedValidators =
new HashMap<Class<? extends InstanceValidator>, InstanceValidationResult>();
private final Log log = LogFactory.getLog(InstanceValidationServiceImpl.class);
private List<InstanceValidator> validators = new LinkedList<InstanceValidator>();
protected void bindInstanceValidator(final InstanceValidator newValidation) {
validators.add(newValidation);
}
/**
* Checks for a given InstanceValidator if all required predecessors of this InstanceValidator have been executed and passed.
*
* @param validator The InstanceValidator whose predecessors should be checked.
* @return True, if all required predecessors have already been executed; false otherwise.
*/
protected boolean necessaryValidatorsExecuted(InstanceValidator validator) {
List<Class<? extends InstanceValidator>> necessaryPredecessors = validator.getNecessaryPredecessors();
if (necessaryPredecessors == null) {
return true;
}
for (Class<? extends InstanceValidator> necessaryPredecessor : necessaryPredecessors) {
if (!executedValidators.containsKey(necessaryPredecessor)) {
return false;
}
InstanceValidationResult instanceValidationResult = executedValidators.get(necessaryPredecessor);
if (!InstanceValidationResultType.PASSED.equals(instanceValidationResult.getType())) {
return false;
}
}
return true;
}
/**
* Validates the RCE instance. All InstanceValidators need to be present before the validation starts.
*
* @return map with {@link InstanceValidationResult}s. For each validator one result exists. It is guaranteed that all of the possible
* {@link InstanceValidationResultType}s are provided as keys of the map.
*/
@Override
public Map<InstanceValidationResultType, List<InstanceValidationResult>> validateInstance() {
final Map<InstanceValidationResultType, List<InstanceValidationResult>> results = new HashMap<>();
results.put(InstanceValidationResultType.PASSED, new ArrayList<InstanceValidationResult>());
results.put(InstanceValidationResultType.FAILED_PROCEEDING_ALLOWED, new ArrayList<InstanceValidationResult>());
results.put(InstanceValidationResultType.FAILED_SHUTDOWN_REQUIRED, new ArrayList<InstanceValidationResult>());
// list of all validators which need to be executed in order to validate the instance
List<InstanceValidator> pendingValidators = new LinkedList<InstanceValidator>(validators);
int pendingValidatorsBeforeIteration;
do {
pendingValidatorsBeforeIteration = pendingValidators.size();
// helper list, since we cannot safely remove items from a list while iterating over it
List<InstanceValidator> currentValidators = new LinkedList<InstanceValidator>(pendingValidators);
for (InstanceValidator validator : currentValidators) {
// skip a validator if its required predecessors have not been executed yet
if (!necessaryValidatorsExecuted(validator)) {
continue;
}
InstanceValidationResult result;
try {
result = validator.validate();
} catch (RuntimeException e) {
log.error(StringUtils.format("Unexpected exception from instance validator '%s'", validator.getClass().getName()), e);
result = InstanceValidationResultFactory.createResultForFailureWhichRequiresInstanceShutdown(
"Instance validator", "An unexpected excetion occurred during instance validation. See log for more details.");
}
results.get(result.getType()).add(result);
executedValidators.put(validator.getClass(), result);
pendingValidators.remove(validator);
}
// if the list of pending validators does not decrease we have an unresolveable dependency
} while (!pendingValidators.isEmpty() && pendingValidators.size() < pendingValidatorsBeforeIteration);
// shutdown the instance if not all validators have been executed
if (!pendingValidators.isEmpty()) {
log.error(StringUtils.format("%d instance validator have not been executed, as there have missing predecessors: ",
pendingValidators.size()));
for (InstanceValidator validator : pendingValidators) {
log.error(StringUtils.format("%s has not been executed.", validator.getClass().getName()));
}
InstanceValidationResult result = InstanceValidationResultFactory.createResultForFailureWhichRequiresInstanceShutdown(
"Instance validator", "Not all necessary validators have been executed. See log for more details.");
results.get(result.getType()).add(result);
}
return results;
}
}