package net.techreadiness.service;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.jws.WebService;
import net.techreadiness.persistence.dao.EntityDAO.EntityTypeCode;
import net.techreadiness.persistence.dao.EntityRuleDAO;
import net.techreadiness.persistence.domain.EntityRuleDO;
import net.techreadiness.rules.EndsWithEvaluatorDefinition;
import net.techreadiness.rules.StartsWithEvaluatorDefinition;
import net.techreadiness.service.common.ValidationError;
import net.techreadiness.service.exception.ServiceException;
import net.techreadiness.service.exception.ValidationServiceException;
import net.techreadiness.service.object.BaseObject;
import net.techreadiness.service.object.Permission;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderConfiguration;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.builder.conf.EvaluatorOption;
import org.drools.io.ResourceFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
@WebService
@Service
@Transactional
public class RuleServiceImpl extends BaseServiceImpl implements RuleService {
@Inject
private EntityRuleDAO entityRuleDAO;
@Inject
private UserService userService;
@Override
public StatefulKnowledgeSession getRuleSessionForScopePath(ServiceContext context, Long scopeId,
EntityTypeCode entityType) {
List<EntityRuleDO> entityRuleDOs = entityRuleDAO.findValidationRules(scopeId, entityType);
return getRuleSessionForEntityRules(context, entityRuleDOs);
}
private StatefulKnowledgeSession getRuleSessionForEntityRules(ServiceContext context, List<EntityRuleDO> entityRuleDOs) {
KnowledgeBase kbase = getKnowlegeBase(entityRuleDOs);
if (kbase != null) {
StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession();
for (Permission permission : userService.findAvailablePermissions(context)) {
session.insert(permission);
}
return session;
}
return null;
}
private static KnowledgeBase getKnowlegeBase(List<EntityRuleDO> rules) {
if (rules == null || rules.size() == 0) {
return null;
}
StringBuilder sb = new StringBuilder();
for (EntityRuleDO entityRuleDO : rules) {
sb.append(entityRuleDO.getRule()).append("\n");
}
KnowledgeBuilderConfiguration config = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration();
config.setOption(EvaluatorOption.get("startsWith", new StartsWithEvaluatorDefinition()));
config.setOption(EvaluatorOption.get("endsWith", new EndsWithEvaluatorDefinition()));
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(config);
kbuilder.add(ResourceFactory.newByteArrayResource(sb.toString().getBytes()), ResourceType.DRL);
if (kbuilder.hasErrors()) {
throw new ServiceException("Problem building cross field validation rules: " + kbuilder.getErrors());
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
return kbase;
}
@Override
public void clearAllCached(ServiceContext context) {
throw new UnsupportedOperationException("caching is not yet implemented for rules");
}
/**
* Execute a given entity rule
*
* @throws ValidationServiceException
* if the rule does not pass validations
*/
@Override
public void executeEntityRule(ServiceContext context, Long entityRuleId, Map<String, String> entity)
throws ValidationServiceException {
EntityRuleDO entityRule = entityRuleDAO.getById(entityRuleId);
List<EntityRuleDO> asList = Arrays.asList(entityRule);
StatefulKnowledgeSession ruleSession = getRuleSessionForEntityRules(context, asList);
List<ValidationError> errorList = Lists.newArrayList();
ruleSession.setGlobal("errorList", errorList);
ruleSession.insert(entity);
ruleSession.fireAllRules();
ruleSession.dispose();
}
@Override
public boolean executeViewRule(ServiceContext context, Long ruleId, BaseObject<?> baseObject) {
EntityRuleDO rule = entityRuleDAO.getById(ruleId);
if (rule != null) {
KnowledgeBase knowlegeBase = getKnowlegeBase(Lists.newArrayList(rule));
StatefulKnowledgeSession session = knowlegeBase.newStatefulKnowledgeSession();
for (Permission permission : userService.findAvailablePermissions(context)) {
session.insert(permission);
}
List<ValidationError> errorList = Lists.newArrayList();
session.setGlobal("errorList", errorList);
session.insert(baseObject);
session.fireAllRules();
session.dispose();
return errorList.isEmpty();
}
return true;
}
}