I need help for implementing Drool Fluent ApI for dynamically generated DRL file usi ng Kie file system - drools

I was successfully able to generate drool file dynamically using drool fluent api.But my issue is I am not able to write this file in memory area using KieFileSystem API.That is resulting in runtime exception can not find kie module.Below is the same
package com.nagarro;
global fact.OutputData output;
rule "rule1"
when
GenericEvent( cost>500 )
then
output.setDiscount(10)
end
Exception in thread "main" java.lang.RuntimeException: Cannot find KieModule: org.default:artifact:1.0.0-SNAPSHOT
at org.drools.compiler.kie.builder.impl.KieServicesImpl.newKieContainer(KieServicesImpl.java:97)
at main.Launcher.evaluate(Launcher.java:67)
at main.Launcher.main(Launcher.java:58)
I have already validate the structure of drl file using drool verifier.
Below is code I am using for the same.
public class Launcher {
public static void main(final String[] args) throws Exception {
/* PackageDescr pkg = DescrFactory.newPackage()
.name("org.drools.example").newImport().target("java.util.ArrayList").end()
.newImport().target("java.util.ArrayList").end()
.newImport().target("java.util.Vector").end()
.newRule().name("alert")
.lhs()
.and()
.pattern("Foo").id( "$foo", false ).constraint("bar==baz").constraint("x>y").end()
.not().pattern("Bar").constraint("a+b==c").end().end()
.end()
.end()
.rhs("System.out.println;"+"/n"+"System.out.println;").end()
.getDescr();*/
PackageDescr desc2 = DescrFactory
.newPackage()
.name("com.nagarro;")
.newGlobal().type("fact.OutputData").identifier("output;")
.end()
.newRule().name("rule1")
.lhs()
.pattern("GenericEvent").constraint("cost>500")
.end()
.end()
.rhs(" output.setDiscount(10)")
.end()
.getDescr();
DrlDumper dumper=new DrlDumper();
String drl=dumper.dump(desc2);
System.out.print(drl);
// verify(drl);
evaluate(drl, new OrderEvent());
}
static private void evaluate(final String drl, final Event event) throws Exception {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.write("src/main/resources/rule.drl", drl);
kieServices.newKieBuilder(kieFileSystem).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
StatelessKieSession statelessKieSession = kieContainer.getKieBase().newStatelessKieSession();
//HashMap<String,Object> outputMap = new HashMap<>();
OutputData outData = new OutputData();
statelessKieSession.getGlobals().set("output", outData);
HashMap<String, Object> inputMap = new HashMap<>();
inputMap.put("price", 1000);
GenericEvent evt = new GenericEvent();
evt.setInputmap(inputMap);
evt.setCost(1000);
statelessKieSession.execute(evt);
System.out.println(outData.getDiscount());
}
public static void verify(final String drl) {
// Create verifier builder [1]
VerifierBuilder vBuilder = VerifierBuilderFactory.newVerifierBuilder();
// Create verifier [2]
Verifier verifier = vBuilder.newVerifier();
// Add Resources you want to verify [3]
verifier.addResourcesToVerify(new ClassPathResource("generic.drl",Launcher.class),
ResourceType.DRL );
// Run the verification rules [4]
verifier.fireAnalysis();
// Get the result object [5]
VerifierReport result = verifier.getResult();
System.out.println(result);
// Print the the errors [6]
for(VerifierMessageBase base: result.getBySeverity( Severity.ERROR ) ){
System.out.println( base );
}
}
}

For writing the drl as file use:
kieFileSystem.write("src/main/resources/rule2.drl", kieServices.getResources().newReaderResource(
new StringReader(drl)));
For validating the drl
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
// check there have been no errors for rule setup
Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
System.out.println(results.getMessages());
throw new IllegalStateException("### errors ###");
}
KieContainer kieContainer = kieServices.newKieContainer( kieBuilder.getKieModule().getReleaseId());
KieSession kieSession = kieContainer.newKieSession();
For evaluating rules:
kieSession.insert(inputData);
kieSession.setGlobal("output", outData);
kieSession.fireAllRules();
kieSession.dispose();

Related

Pass filenames dynamically to FlatFileItemWriter through StepBuilderFactory stream() when using ClassifierCompositeItemProcessor in SpringBatch

I'm processing multiple input files with multi-format lines using ClassifierCompositeItemProcessor. But when using StepBuilderFactory stream to write the files, I'm unable to pass the Resource filename dynamically. Filename should be the respective input file name. Any help would be much appreciated.
Input File 1 (data-111111-12323.txt)
1#9999999#00001#2#RecordType1
2#00002#June#Statement#2020#9#RecordType2
3#7777777#RecordType3
Input File 2 (data-22222-23244.txt)
1#435435#00002#2#RecordType1
2#345435#July#Statement#2021#9#RecordType2
3#645456#RecordType3
Expected output file 1 (data-111111-12323.txt)
1#9999999#00001#2#RecordType1#mobilenumber1
2#00002#June#Statement#2020#9#RecordType2#mobilenumber2
3#7777777#RecordType3#mobilenumber3
Expected output file 2 (data-22222-23244.txt)
1#9999999#00001#2#RecordType1#mobilenumber1
2#00002#June#Statement#2020#9#RecordType2#mobilenumber2
3#7777777#RecordType3#mobilenumber3
Step
public Step partitionStep() throws Exception {
ItemReader reader = context.getBean(FlatFileItemReader.class);
ClassifierCompositeItemWriter writer = context.getBean(ClassifierCompositeItemWriter.class);
return stepBuilderFactory.get("statementProcessingStep.slave").<String, String>chunk(12).reader(reader).processor(processor()).writer(writer)
.stream(recordType0FlatFileItemWriter())
.stream(recordType1FlatFileItemWriter())
.build();
}
Processor
#Bean
#StepScope
public ItemProcessor processor() {
ClassifierCompositeItemProcessor<? extends RecordType, ? extends RecordType> processor = new ClassifierCompositeItemProcessor<>();
SubclassClassifier classifier = new SubclassClassifier();
Map typeMap = new HashMap();
typeMap.put(RecordType0.class, recordType0Processor);
typeMap.put(RecordType1.class, recordType1Processor);
classifier.setTypeMap(typeMap);
processor.setClassifier(classifier);
return processor;
}
Writer
#Bean
public FlatFileItemWriter<RecordType1> recordType1FlatFileItemWriter() throws Exception{
FlatFileItemWriter<RecordType1> writer = new FlatFileItemWriter<>();
writer.setResource( new FileSystemResource("record1.txt")); //This filename should be dynamic
writer.setAppendAllowed(true);
writer.setLineAggregator(new DelimitedLineAggregator<RecordType1>() {{
setDelimiter("#");
setFieldExtractor(new BeanWrapperFieldExtractor<RecordType1>() {
{
setNames(new String[] { "RecordType", "ID1", "ID2", "ID3"});
}
});
}});
return writer;
}
You can make your item reader/writer step-scoped and inject values from job parameters or step/job execution context using late-binding. For example:
#StepScope
#Bean
public FlatFileItemReader flatFileItemReader(#Value("#{jobParameters['input.file.name']}") String name) {
return new FlatFileItemReaderBuilder<Foo>()
.name("flatFileItemReader")
.resource(new FileSystemResource(name))
.build();
}
You can find more details in the Late Binding of Job and Step Attributes section of the reference documentation.

Drools - Kie Spring Integration - Interfaces

I am a newbie to Drools, Need some clarificatoins on Drools - Spring Integration.
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
for (Resource file : getRuleFiles()) {
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
}
return kieFileSystem;
}
public KieContainer kieContainer() throws IOException {
final KieRepository kieRepository = getKieServices().getRepository();
kieRepository.addKieModule(new KieModule() {
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
});
KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
kieBuilder.buildAll();
return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
}
My understaing as per the documentation & few examples
We need to define rules in a file
KieFileSystem loads the rules into KieBuilder
KieBuilder holds the knowledge base
Based on KieBuilder we can prepare KieContainer & new KieSession
On KieSessoin we include the facts and fire the rules.
Question 1: What is the importance of KieModule, KieRepository, ReleaseId?
Question 2: I have seperate directories for different flows. How can I load specific rules based on flow?

How to import Drools Decision table present in multiple sheets of same excel file, using Drools 6?

I am not getting any specific way to do it using Drools 6.
I had tried to do it using the following sample code :
`
private static KieBase readBase(String strFilePath) throws IOException, BiffException {
DecisionTableConfiguration dtconf = KnowledgeBuilderFactory.newDecisionTableConfiguration();
dtconf.setInputType(DecisionTableInputType.XLS);
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
File xls = new File(strFilePath);
SpreadsheetCompiler compiler = new SpreadsheetCompiler();
Workbook w;
String sheetName = "";
FileInputStream in = null;
try {
w = Workbook.getWorkbook(xls);
for (Sheet sheet : w.getSheets()) {
sheetName = sheet.getName();
in = new FileInputStream(xls);
System.out.println("The sheet name is : " + sheetName);
compileSheet(kbuilder, xls, compiler, sheetName, in);
}
} catch (DecisionTableParseException e) {
System.out.println("Failed to parse spreadsheet " + sheetName + " "
+ e);
}
KieBase k = KnowledgeBaseFactory.newKnowledgeBase();
// kContainer.
KnowledgeBase kb = KnowledgeBaseFactory.newKnowledgeBase();
kb.addKnowledgePackages(kbuilder.getKnowledgePackages());
return kb;
}
private static KnowledgeBuilder compileSheet(KnowledgeBuilder kbuilder, File xls, SpreadsheetCompiler compiler, String sheetName, FileInputStream in) {
try {
String compiled = compiler.compile(in, sheetName);
kbuilder.add(ResourceFactory.newReaderResource(new StringReader(compiled)), ResourceType.DRL);
System.out.println("***************************************drl**************************************");
System.out.println(compiled);
} catch (DecisionTableParseException dtpe) {
if (dtpe.getMessage().equals("No RuleTable's were found in spreadsheet.")) {
System.out.println("No rule tables found in sheet {}" + sheetName);
} else {
throw dtpe;
}
}
return kbuilder;
}
`
Problem here is Drools 6 uses KIEBase not KnowledgeBase, so I am not getting appropriate way for to load compiled sheets in KieBase. Is there any other way to do it in Drools 6?
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
FileInputStream fis = new FileInputStream( "dir/some.drl" );
kfs.write( "src/main/resources/simple.drl",
kieServices.getResources().newInputStreamResource( fis ) );
KieBuilder kieBuilder = kieServices.newKieBuilder( kfs ).buildAll();
Results results = kieBuilder.getResults();
if( results.hasMessages( Message.Level.ERROR ) ){
System.out.println( results.getMessages() );
throw new IllegalStateException( "### errors ###" );
}
KieContainer kieContainer =
kieServices.newKieContainer( kieServices.getRepository().getDefaultReleaseId() );
KieBase kieBase = kieContainer.getKieBase();
You can use this with dsl, dslr and xls files as well.

How to access an arraylist from one rule to another in DROOLS

This is the java file that is the rule engine
RuleRunner.java
public class RuleRunner {
KieSession kSession = null;
public RuleRunner() {
}
/**
* Method that executes all the rules specified in rule file
*
* #param rules
* #param facts
*/
public void runRules(String[] rules, String[] values) {
KieServices kieServices = KieServices.Factory.get();
KieResources kieResources = kieServices.getResources();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
KieRepository kieRepository = kieServices.getRepository();
for (String ruleFile : rules) {
Resource resource = kieResources.newClassPathResource(ruleFile);
kieFileSystem.write(
"src/main/resources/com/skills421/examples/drools6_0/"
+ ruleFile, resource);
}
KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
kb.buildAll();
if (kb.getResults().hasMessages(Level.ERROR)) {
throw new RuntimeException("Build Errors:\n"
+ kb.getResults().toString());
}
KieContainer kContainer = kieServices.newKieContainer(kieRepository
.getDefaultReleaseId());
kSession = kContainer.newKieSession();
for (String value : values){
kSession.insert(value);
}
kSession.fireAllRules();
}
}
This is Main.java which integrates the drl file and rule engine
public class Main
{
public static void main(String[] args)
{
long startTime = System.currentTimeMillis();
//Creating the rule and specifying the rule file
RuleRunner runner = new RuleRunner();
String[] rules = { "test1.drl"};
String[] values={"creditcard","personal_status","male single"};
//Object[] facts = { new CreditCard("male single",25,">=7")};
runner.runRules(rules,values);
long endTime = System.currentTimeMillis();
System.out.println("Took "+(endTime - startTime) + " ms");
}
}
I am new to DROOLS.This is my .drl file
dialect "mvel"
/*
*This rule picks people with good credit record and an employment history
of more than 7 years
*/
rule "Credit Card employment and class check"
when
passList : ArrayList()
$creditCard : CreditCard() from passList
eval($creditCard.get_class() == "good" && $creditCard.getEmployment() ==
">=7")
then
passList = new ArrayList();
passList.add($creditCard);
end
dialect "java"
rule "passList check"
when
eval( true )
then
System.out.println("passList size2....");
end
I want to pass the calculated value of passList from rule1 to rule2.Any help would be appreciated.

Getting NPE when getting started with Drools 6.0.0 Final in Eclipse

Getting started (Without Maven) I first Installed GEF and Drools 6.0.0 final plugin in eclipse.
and then I created a Drools project which generated the two files below.
DroolsTest.java
package com.sample;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
/**
* This is a sample class to launch a rule.
*/
public class DroolsTest {
public static final void main(String[] args) {
try {
// load up the knowledge base
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession("ksession-rules");
// go !
Message message = new Message();
message.setMessage("Hello World");
message.setStatus(Message.HELLO);
kSession.insert(message);
kSession.fireAllRules();
} catch (Throwable t) {
t.printStackTrace();
}
}
public static class Message {
public static final int HELLO = 0;
public static final int GOODBYE = 1;
private String message;
private int status;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
}
}
Sample.drl
package com.sample
import com.sample.DroolsTest.Message;
rule "Hello World"
when
m : Message( status == Message.HELLO, myMessage : message )
then
System.out.println( myMessage );
m.setMessage( "Goodbye cruel world" );
m.setStatus( Message.GOODBYE );
update( m );
end
rule "GoodBye"
when
Message( status == Message.GOODBYE, myMessage : message )
then
System.out.println( myMessage );
end
I get NPE at kSession.insert(message); obviously due to missing ksession-rules here
KieSession kSession = kContainer.newKieSession("ksession-rules");
I get the same thing when I mavenize this project and run it as a maven test.
I notice some ppl already experienced this and are point to classpath issue, I am still not clear with the solution though.
mvn eclipse:eclipse did not help either.
Links I went thru already
Getting null pointer exception while running helloworld in drools
Unknown KieSession name in drools 6.0 (while trying to add drools to existing maven/eclipse project)
After going thru Drools 6.0.0 in github, I see a file kModule.xml should be present with session name "ksession-rules" tied to a rule. This file did not get generated (bug??)
I am however downgrading to 5.6.0 to get better community support and good documentation.