package org.drooms.impl.util;
import org.drooms.impl.logic.PathTracker;
import org.kie.api.KieBase;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.builder.ReleaseId;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.runtime.KieContainer;
import org.slf4j.Logger;
import java.util.*;
import java.util.concurrent.*;
/**
* A class to validate strategy's feasibility.
*
*/
public class DroomsStrategyValidator implements Callable<DroomsStrategyValidator> {
private final ReleaseId releaseId;
private final List<String> errors = new LinkedList<>();
private final List<String> warnings = new LinkedList<>();
private static final Map<String, Future<DroomsStrategyValidator>> validators = new HashMap<>();
private static final ExecutorService E = Executors.newCachedThreadPool();
private static String getInternalId(final ReleaseId strategyReleaseId) {
return strategyReleaseId.getGroupId().trim() + ":" + strategyReleaseId.getArtifactId().trim() + ":" +
strategyReleaseId.getVersion().trim();
}
public static DroomsStrategyValidator getInstance(final ReleaseId strategyReleaseId) {
final String internalId = DroomsStrategyValidator.getInternalId(strategyReleaseId);
synchronized (DroomsStrategyValidator.class) {
if (!DroomsStrategyValidator.validators.containsKey(internalId)) {
DroomsStrategyValidator.validators.put(internalId, DroomsStrategyValidator.E.submit(new
DroomsStrategyValidator(strategyReleaseId)));
}
}
try {
System.out.println(validators);
return DroomsStrategyValidator.validators.get(internalId).get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("This should not have happened.", e);
}
}
private DroomsStrategyValidator(ReleaseId releaseId) {
this.releaseId = releaseId;
}
/**
* Retrieve problems that are critical to the strategy and will result in
* the strategy not being accepted for the game.
*
* @return An unmodifiable collection of error messages.
*/
public List<String> getErrors() {
return Collections.unmodifiableList(this.errors);
}
/**
* Retrieve problems that aren't critical to the strategy. The strategy may
* be sub-optimal, but it will be allowed into the game.
*
* @return An unmodifiable collection of warnings.
*/
public List<String> getWarnings() {
return Collections.unmodifiableList(this.warnings);
}
/**
* Whether or not the strategy is both valid and leverages all the available
* options.
*
* @return True if clean.
*/
public boolean isClean() {
return this.isValid() && this.warnings.isEmpty();
}
/**
* Whether or not the strategy is valid. Invalid strategies may not be
* accepted into the game.
*
* @return True if valid.
*/
public boolean isValid() {
return this.errors.isEmpty();
}
public DroomsStrategyValidator call() {
final KieServices ks = KieServices.Factory.get();
try {
final KieContainer container = ks.newKieContainer(this.releaseId);
final KieBaseConfiguration config = ks.newKieBaseConfiguration();
config.setOption(EventProcessingOption.STREAM);
final KieBase kbase = container.newKieBase(config);
final KnowledgeSessionValidationHelper helper = new KnowledgeSessionValidationHelper(kbase);
this.validateGlobal(helper, "logger", Logger.class, false);
this.validateGlobal(helper, "tracker", PathTracker.class, false);
this.validateEntryPoint(helper, "rewardEvents", true);
this.validateEntryPoint(helper, "playerEvents", true);
this.validateEntryPoint(helper, "gameEvents", true);
} catch (RuntimeException ex) {
// KieServices throw RuntimeException when KieModule or default KieBase is not found
report(ex.getMessage(), true);
}
return this;
}
private void report(final String report, final boolean isError) {
if (isError) {
this.errors.add(report);
} else {
this.warnings.add(report);
}
}
private void validateEntryPoint(final KnowledgeSessionValidationHelper helper, final String name, final boolean isError) {
if (!helper.hasEntryPoint(name)) {
this.report("Entry point '" + name + "' not declared.", isError);
}
}
private void validateGlobal(final KnowledgeSessionValidationHelper helper, final String name, final Class<?> cls,
final boolean isError) {
if (!helper.hasGlobal(name, cls)) {
this.report("Global '" + name + "' of type '" + cls.getCanonicalName() + "' not declared.", isError);
}
}
@Override
public String toString() {
return "DroomsStrategyValidator [releaseId=" + releaseId + ", errors=" + errors.size() + ", warnings=" +
warnings.size() + ']';
}
}