/*
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.optaplanner.core.impl.score.director.drools;
import org.kie.api.KieBase;
import org.kie.api.builder.model.KieSessionModel;
import org.kie.api.definition.KiePackage;
import org.kie.api.definition.rule.Global;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor;
import org.optaplanner.core.impl.score.director.AbstractScoreDirectorFactory;
import org.optaplanner.core.impl.score.director.ScoreDirectorFactory;
/**
* Drools implementation of {@link ScoreDirectorFactory}.
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
* @see DroolsScoreDirector
* @see ScoreDirectorFactory
*/
public class DroolsScoreDirectorFactory<Solution_> extends AbstractScoreDirectorFactory<Solution_> {
protected final KieContainer kieContainer;
protected final String ksessionName;
/**
* For {@link LegacyDroolsScoreDirectorFactory} only. Do not use.
* @param kieBase never null
*/
protected DroolsScoreDirectorFactory(KieBase kieBase) {
kieContainer = null;
ksessionName = null;
}
/**
* @param kieContainer never null
* @param ksessionName null if the default ksession should be used
*/
public DroolsScoreDirectorFactory(KieContainer kieContainer, String ksessionName) {
this.kieContainer = kieContainer;
this.ksessionName = ksessionName;
// if ksessionName is null, then the default kieSession is used
KieSessionModel kieSessionModel = kieContainer.getKieSessionModel(ksessionName);
if (kieSessionModel == null) {
if (ksessionName == null) {
throw new IllegalArgumentException("The kieContainer does not have a default ksession"
+ " and the ksessionName (" + ksessionName + ") is not specified.");
} else {
throw new IllegalArgumentException("The kieContainer does not contain a ksessionName ("
+ ksessionName + ") with that name.");
}
}
if (kieSessionModel.getType() != KieSessionModel.KieSessionType.STATEFUL) {
throw new IllegalStateException("The ksessionName (" + ksessionName
+ ") with type (" + kieSessionModel.getType() + ") is not stateful.\n"
+ "Stateless sessions are not allowed because they don't support incremental score calculation"
+ " and are therefore exponentially slower.");
}
String kbaseName = kieSessionModel.getKieBaseModel().getName();
KieBase kieBase = kieContainer.newKieBase(kbaseName, null);
checkIfGlobalScoreHolderExists(kieBase);
}
protected void checkIfGlobalScoreHolderExists(KieBase kieBase) {
boolean hasGlobalScoreHolder = false;
for (KiePackage kiePackage : kieBase.getKiePackages()) {
for (Global global : kiePackage.getGlobalVariables()) {
if (DroolsScoreDirector.GLOBAL_SCORE_HOLDER_KEY.equals(global.getName())) {
hasGlobalScoreHolder = true;
// TODO Fail fast once global.getType() can be turned into a Class instead of a String
// if (!ScoreHolder.class.isAssignableFrom(global.getType())) {
// throw new IllegalStateException("The global with name (" + global.getName()
// + ") has a type (" + global.getType()
// + ") that does not implement " + ScoreHolder.class.getSimpleName() + ".");
// }
break;
}
}
}
if (!hasGlobalScoreHolder) {
throw new IllegalArgumentException("The kieBase with kiePackages (" + kieBase.getKiePackages()
+ ") has no global field called " + DroolsScoreDirector.GLOBAL_SCORE_HOLDER_KEY + ".\n"
+ "Check if the rule files are found and if the global field is spelled correctly.");
}
}
@Override
public void setSolutionDescriptor(SolutionDescriptor<Solution_> solutionDescriptor) {
super.setSolutionDescriptor(solutionDescriptor);
solutionDescriptor.checkIfProblemFactsExist();
}
public KieContainer getKieContainer() {
return kieContainer;
}
/**
* @return null if the default ksession should be used
*/
public String getKsessionName() {
return ksessionName;
}
// ************************************************************************
// Complex methods
// ************************************************************************
@Override
public DroolsScoreDirector<Solution_> buildScoreDirector(
boolean lookUpEnabled, boolean constraintMatchEnabledPreference) {
return new DroolsScoreDirector<>(this, lookUpEnabled, constraintMatchEnabledPreference);
}
public KieSession newKieSession() {
return kieContainer.newKieSession(ksessionName);
}
}