001package org.kuali.ole.deliver.drools; 002 003import org.apache.commons.io.FileUtils; 004import org.apache.commons.io.FilenameUtils; 005import org.apache.lucene.util.CollectionUtil; 006import org.drools.core.definitions.rule.impl.RuleImpl; 007import org.kie.api.KieServices; 008import org.kie.api.builder.KieBuilder; 009import org.kie.api.builder.KieFileSystem; 010import org.kie.api.builder.Message; 011import org.kie.api.builder.Results; 012import org.kie.api.definition.KiePackage; 013import org.kie.api.definition.rule.Rule; 014import org.kie.api.event.rule.DebugAgendaEventListener; 015import org.kie.api.runtime.KieContainer; 016import org.kie.api.runtime.KieSession; 017import org.kie.internal.io.ResourceFactory; 018import org.kuali.ole.OLEConstants; 019import org.kuali.ole.deliver.service.ParameterValueResolver; 020import org.kuali.ole.sys.context.SpringContext; 021import org.kuali.rice.core.api.config.property.ConfigContext; 022import org.kuali.rice.coreservice.api.parameter.Parameter; 023import org.kuali.rice.coreservice.api.parameter.ParameterType; 024import org.kuali.rice.coreservice.framework.parameter.ParameterService; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028import java.io.File; 029import java.util.*; 030 031/** 032 * Created by pvsubrah on 3/23/15. 033 */ 034public class DroolsKieEngine { 035 private Logger LOG = LoggerFactory.getLogger(DroolsKieEngine.class); 036 private KieContainer kieContainer; 037 private ParameterService parameterService; 038 039 private static Boolean forceLoadPolicies = true; 040 private static final String LOAD_POLICIES_IND = "LOAD_CIRC_POLICIES_IND"; 041 042 private static DroolsKieEngine droolsEngine = new DroolsKieEngine(); 043 044 protected DroolsKieEngine() { 045 046 } 047 048 public static DroolsKieEngine getInstance() { 049 return droolsEngine; 050 } 051 052 /* 053 This method should be called first to load the rules repository. 054 */ 055 public void initKnowledgeBase() { 056 long startTime = System.currentTimeMillis(); 057 populateKnowledgeBase(); 058 long endTime = System.currentTimeMillis(); 059 System.out.println("Time taken to populate drools knowledgebase: " + (endTime - startTime) + " ms"); 060 } 061 062 private void populateKnowledgeBase() { 063 Boolean parameterValueAsBoolean = getParameterAsBoolean(); 064 if (forceLoadPolicies || parameterValueAsBoolean) { 065 readRules(); 066 updateParameter(); 067 } 068 } 069 070 private Boolean getParameterAsBoolean() { 071 return ParameterValueResolver.getInstance().getParameterAsBoolean(OLEConstants 072 .APPL_ID, OLEConstants 073 .DLVR_NMSPC, 074 OLEConstants 075 .DLVR_CMPNT, LOAD_POLICIES_IND); 076 } 077 078 private void updateParameter() { 079 Parameter existingParameter = getParameterService().getParameter(OLEConstants.DLVR_NMSPC, OLEConstants 080 .DLVR_CMPNT, LOAD_POLICIES_IND); 081 if (existingParameter != null) { 082 Parameter.Builder updatedParameter = Parameter.Builder.create(existingParameter); 083 updatedParameter.setValue("N"); 084 forceLoadPolicies = false; 085 getParameterService().updateParameter(updatedParameter.build()); 086 } else { 087 Parameter.Builder newParameter = Parameter.Builder.create(OLEConstants.APPL_ID, OLEConstants.DLVR_NMSPC, OLEConstants.DLVR_CMPNT, LOAD_POLICIES_IND, ParameterType.Builder.create("CONFG")); 088 newParameter.setDescription("Set to 'Y' to have the application ingest the default circulation policies " + 089 "upon next policy evaluation."); 090 newParameter.setValue("Y"); 091 getParameterService().createParameter(newParameter.build()); 092 forceLoadPolicies = false; 093 } 094 } 095 096 private void readRules() { 097 098 File rulesDirectory = FileUtils.getFile(getRulesDirectory()); 099 if (null != rulesDirectory && rulesDirectory.isDirectory() && FileUtils.sizeOfDirectory(rulesDirectory) > 0) { 100 File[] files = rulesDirectory.listFiles(); 101 102 KieServices kieServices = KieServices.Factory.get(); 103 KieFileSystem kfs = kieServices.newKieFileSystem(); 104 105 loadRules(kfs, files); 106 107 KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll(); 108 Results results = kieBuilder.getResults(); 109 110 if (results.hasMessages(Message.Level.ERROR)) { 111 //TODO: Populate the DroolResponse object with the appropriate message. 112 } 113 114 long startTime = System.currentTimeMillis(); 115 kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()); 116 long endTime = System.currentTimeMillis(); 117 System.out.println("Time taken to initiallize KieContainer: " + (endTime - startTime) + "ms"); 118 119 120 } else { 121 LOG.error("Could not load Circulation Rules as directory doest not exist or is unreadable."); 122 } 123 } 124 125 private void loadRules(KieFileSystem kfs, File[] files) { 126 for (int i = 0; i < files.length; i++) { 127 File file = files[i]; 128 if (!file.isDirectory()) { 129 if (FilenameUtils.getExtension(file.getName()).equals("drl")) { 130 kfs.write(ResourceFactory.newFileResource(file)); 131 } 132 } else { 133 File[] subDirFiles = file.listFiles(); 134 loadRules(kfs, subDirFiles); 135 } 136 } 137 } 138 139 public synchronized void disposeSession(KieSession kieSession) { 140 kieSession.dispose(); 141 } 142 143 public String getRulesDirectory() { 144 String rulesDirectory = ConfigContext.getCurrentContextConfig().getProperty("rules.directory"); 145 return rulesDirectory; 146 } 147 148 public synchronized KieSession getSession() { 149 populateKnowledgeBase(); 150 long startTime1 = System.currentTimeMillis(); 151 KieSession kieSession = kieContainer.newKieSession(); 152 kieSession.addEventListener(new CustomAgendaEventListener()); 153 kieSession.addEventListener(new DebugAgendaEventListener()); 154 long endTime1 = System.currentTimeMillis(); 155 156 System.out.println("Time taken to initialize KieSession: " + (endTime1 - startTime1) + "ms"); 157 158 return kieSession; 159 160 } 161 162 public ParameterService getParameterService() { 163 if (null == parameterService) { 164 parameterService = SpringContext.getBean(ParameterService.class); 165 } 166 return parameterService; 167 } 168 169 public void setParameterService(ParameterService parameterService) { 170 this.parameterService = parameterService; 171 } 172 173 174 public List<String> getRulesByAgendaGroup(List<String>agendaGroups){ 175 List<String> ruleNames = new ArrayList<>(); 176 177 for (Iterator iterator = kieContainer.getKieBase().getKiePackages().iterator(); iterator.hasNext(); ) { 178 KiePackage kiePackage = (KiePackage) iterator.next(); 179 Collection<Rule> rules = kiePackage.getRules(); 180 for (Iterator<Rule> ruleIterator = rules.iterator(); ruleIterator.hasNext(); ) { 181 Rule rule = ruleIterator.next(); 182 if(agendaGroups.contains(((RuleImpl)rule).getAgendaGroup())){ 183 ruleNames.add(rule.getName()); 184 } 185 } 186 } 187 Collections.sort(ruleNames); 188 return ruleNames; 189 } 190 191 192 public List<String> getAllLoadedRules(){ 193 List<String> ruleNames = new ArrayList<>(); 194 195 for (Iterator iterator = kieContainer.getKieBase().getKiePackages().iterator(); iterator.hasNext(); ) { 196 KiePackage kiePackage = (KiePackage) iterator.next(); 197 Collection<Rule> rules = kiePackage.getRules(); 198 for (Iterator<Rule> ruleIterator = rules.iterator(); ruleIterator.hasNext(); ) { 199 Rule rule = ruleIterator.next(); 200 ruleNames.add(rule.getName()); 201 } 202 } 203 204 return ruleNames; 205 } 206}