简体   繁体   中英

Can we set fact type and fact field dynamically in Drools

How do I set fact type and fact field dynamically in drl file?I am reading a json file which having the records.that records I am mapping to pojo class which is generating dynamically from json schema I used json2pojo maven plugin ! .now I want to fire some rules on that class. but I am not able to fech that class in drl file as a fact.same for fields. below is drl rule.

rule "not null"

when 

  obj:Class(fieldName==null)
then
  //take action
end

this Class and fieldName is generating dynamically. please suggest me solution regarding this. Thanks.

I have successfully implemented a similar kind of problem statement. Have a quick look at it. I was supposed to dynamically generate rules on a sql table selected by the user on runtime in a web application. Point to be noted here is that the pojo class too should be generated at runtime. Drools 6 has an inbuilt API (similar to JAVA reflection API) where you can dynamically generate a class and hence the factTypes too. So first the .drl file :-

declare {insert tablename as chosen by the user}
{columnname} : {columntype}  
{columnname} : {columntype}  
end

This generates a pojo class alongwith the getters and setters of the attributes which can be directly accessed in the rules. Now, the java file :-

The generated class can be accessed in java application like this:

//get the declared FactType

FactType  tableType = kbase.getFactType({packagename},{tablename});

//create instances:

Object obj = tableType.newInstance();

Now, facts were inserted from sql corresponding to the selected table was implemented via hibernate. This also kept the table updated if any modifications were made by the rules.

Feel free to ask any questions. Happy to help..:)

我根据我的要求找到了一个解决方案。这是我动态删除生成的 POJO 的另一种方法。我创建了一个 POJO 作为“参数”,它将用作事实类型。因为我的字段为 fieldName(Json field path),rulesToFire (规则)和 json 记录列表。所以在 drl 文件中我可以获取这些值。使用 com.jayway.jsonpath.JsonPath 我可以读取受尊重的值。

JSON is good for sending data over the line, etc. But then you should convert it to a POJO and write your validation rules in terms of Java object. I see no good reason why you shouldn't be able to do so.

However... If you want to spend a lot of time and effort...

What you might do has been done using XML, which is another (textual) representation for data sets ("records"). Looking at the JSON structure definition, you can see that you have "objects" and "arrays". These will be your fact types. A (JS-)Object can be represented by a POJO containing a Map, a (JS-)Array might be implemented by a POJO with a java.util.List field.

You can write rules that select a JS-Object and perform field checks.

There is an option in FactType interface as setFromMap . If you are able to provide your input in a Map collection (may be JSON, or JSON to Map ) then you can set all of the properties of your declared type from this Map . Below is a test case for this approach. I hope it is gonna be helpful.

   @Test
    void test_StatelessKieSession_DynamicRuleNestedObjects_DeclaredVariables_Standalone() throws Exception{
        Map<String,Object> fields =
                Stream.of(new Object[][] {
                        {"name","server001"},
                        {"processors",4},
                        {"memory",8192},
                        {"diskSpace",128},
                        {"cpuUsage",3},
                        {"virtualizations"
                                ,Stream.of(
                                new HashMap<String,Object>(){{
                                    put("name","virtualization - 1");
                                    put("diskSpace",4);
                                    put("memory",1024);}},
                                new HashMap<String,Object>(){{
                                    put("name","virtualization - 2");
                                    put("diskSpace",8);
                                    put("memory",2048);}}
                        ).collect(Collectors.toList())}
                }).collect(Collectors.toMap(key -> (String)key[0], val -> val[1]));

        String packageName = "com.genericrule";
        String mainObjectName = "Server";

        String ruleStr = "package com.genericrule import java.util.List; declare Server name : String processors : int memory : int diskSpace : int virtualizations : List cpuUsage : int ruleMessage : String end; declare Virtualization name : String diskSpace : int memory : int end; rule \"check minimum server configuration\" dialect \"mvel\" when $server : Server(processors < 2 || memory <= 1024 || diskSpace <= 250 ) then $server.ruleMessage = $server.name + \" was rejected by don't apply the minimum configuration.\"; end;";

        KieServices kieServices = KieServices.Factory.get();

        KieRepository kr = kieServices.getRepository();
        KieFileSystem kfs = kieServices.newKieFileSystem();

        kfs.write("src/main/resources/genericRule.drl", ruleStr);

        KieBuilder kb = kieServices.newKieBuilder(kfs);
        kb.buildAll();

        KieContainer kContainer = kieServices.newKieContainer(kr.getDefaultReleaseId());

        StatelessKieSession sks = kContainer.newStatelessKieSession();

        FactType mainObjectFact = sks.getKieBase().getFactType(packageName,mainObjectName);

        Object mainObject = mainObjectFact.newInstance();

        mainObjectFact.setFromMap(mainObject,fields);
        sks.execute(mainObject);

        assertThat((String) mainObjectFact.get(mainObject,"ruleMessage")).contains("rejected");
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM