I want to create an Audit logger for the rules i have in my OptaPlanner project
and i need to get access to KieSession and KieServices from Drools to do that.
The problem here is i don't have access to them.
In the documentation in section 5.3.4.2.3. A ksessionName in a Kjar from a Maven repository, i can define a KieSessionName from the solverConfig and create the SolverFactory using the createFromKieContainerXmlResource. The problem here is that i can't find the META-INF/kmodule.xml file. Even if i find the folder, can i use the KieSessionName to get a KieSession.
I'm asking this because with the current way of creating the SolverFactory, using createFromXmlResource, i can get to the KieSessionName with using:
SolverConfig solverConfig = solverFactory.getSolverConfig();
ScoreDirectorFactoryConfig scoreDirectorFactoryConfig = solverConfig.getScoreDirectorFactoryConfig();
String kieSessionName = scoreDirectorFactoryConfig.getKsessionName();
After getting the session name i can't find a way to get the KieSession.
So my questions here are:
Where can i locate META-INF/kmodule.xml?
How can i use kSessionName to get use as a KieSession object?
Is there a way to access the KieSession object without chaging the core files?
Related
Is there any quick way to check programmatically if DRL file is loaded successfully by the drools library within our web application? BTW, I am developing soap based web service using drools. For ex: listing out all the rule names present in the knowledge base at a certain time etc.
Please help.
This is what I am doing to load the drl file from centOS filesystem:
String drlFile = "/tmp/conf/object.drl";
ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
FileInputStream fis = new FileInputStream( drlFile );
kfs.write("/Drools/Object.drl",ks.getResources().newInputStreamResource( fis ));
KieBuilder kieBuilder = ks.newKieBuilder( kfs ).buildAll();
The simplest way to detect errors on a build all is to pull up the messages on the results from the buildAll().
kieBuilder.getResults().hasMessages(Message.Level.ERROR)
or
kieBuilder.getResults().getMessages()
as a side note*
I had a similar issue where buildAll() was not reading the file I wrote inside the kfs. The symptoms were the same where no packages were in the collection.
To fix that issue I had to add a specific resource type to the inputStream.
e.g.
kfs.write("/Drools/Object.drl",ks.getResources().newInputStreamResource( fis ).setResourceType(ResourceType.DRL));
For determining the packages inside the ksession I always have used.
ksession.getKieBase().getKiePackages()
For detecting the files my builder knew about and loaded I used this
((MemoryKieModule)kb.getKieModule()).getFileNames()
How can I get fact definied by user in GUI and insert it to DRL?
For example: The user has chosen black car in GUI (JavaFX), and now I want to use that fact in DRL code. How to send that info about black car to DRL? Should i use POJO?
If you want to execute rules that you have written in DRL file you have to create a POJO and using KieSession you can execute your rules. For example,
val pojo = new POJO('POJO arguments')
val kieServices = KieServices.Factory.get()
val kieContainer = kieServices.newKieClasspathContainer()
val kieSession = kContainer.newKieSession()
kieSession.insert(pojo)
kieSession.fireAllRules()
Read this documentation. You can get all the drool-API examples here
I just set up a kie-workbench (6.1.0 Final) on tomcat and created an example demo-project which contains a drl file and a big flat POJO created with the data modeller.
I built and deployed the demo-project and managed to fire the rules from a client application using the code below:
String url = "http://yytomcat7kie.domain.com:8080/kie/maven2/gro/up/demoproject/0.0.3/demoproject-0.0.3.jar";
ReleaseIdImpl releaseId = new ReleaseIdImpl("gro.up", "demoproject", "0.0.3");
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
UrlResource urlResource = (UrlResource) ResourceFactory.newUrlResource(url);
kfs.write(urlResource);
KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
KieContainer kContainer = ks.newKieContainer(releaseId);
KieSession kSession = kContainer.newKieSession();
SessionConfiguration sConf = (SessionConfiguration)kSession.getSessionConfiguration();
MyKiePojo kiePojo = new MyKiePojo();
kiePojo.setField01("blah");
kiePojo.setField02("blahblah");
kiePojo.setField03("blahblahblah");
kSession.insert(kiePojo);
kSession.fireAllRules();
System.out.println(" ALL RULES FIRED ");
System.out.println(kiePojo.getField04());
System.out.println(kiePojo.getField05());
It works fine but the question I have now is:
Is it possible to get a handle of the MyKiePojo class which is in the demoproject.jar without having it in the client app's classpath? Ideally I would like to keep all my models in the workbench without having to mirror them in the client app and be able to instantiate them and populate them with values received from rest requests. Is this possible?
A KieContainer when used with dynamic modules keeps all the jars it loads in an isolated ClassLoader. So you can put your models into their own jar and specify them as a maven dependency on the project being deployed. If you are using kie-ci it will resolve the transitive dependencies and build a ClassLoader from them.
Externally you can use reflection to access the pojos in that CassLoader, or you can have an initialisation rule that calls out to a static initialisation method. Where that static initializer method is any class in the jar or one of the dependant jars.
What we don't have yet is a life cycle for KieContainers and KieSession to automate certain things via callbacks. This is definitely something we need to look into, and I expect it to be in the next (after 6.2) release.
See the documentation chapter "Rule Language Reference", section "Type Declaration". A quick example taken from there:
declare Address
number : int
streetName : String
city : String
end
You can create objects using new and use getters and setters etc.
You'll have to code the transformation from the request to this object.
In my project, there are additional (non-wicket) applications, which need to know the URL representation of some domain objects (e.g. in order to write a link like http://mydomain.com/user/someUserName/ into a notification email).
Now I'd like to create a spring bean in my wicket module, exposing the URLs I need without having a running wicket context, in order to make the other application depend on the wicket module, e.g. offering a method public String getUrlForUser(User u) returning "/user/someUserName/".
I've been stalking around the web and through the wicket source for a complete workday now, and did not find a way to retrieve the URL for a given PageClass and PageParameters without a current RequestCycle.
Any ideas how I could achieve this? Actually, all the information I need is somehow stored by my WebApplication, in which I define mount points and page classes.
Update: Because the code below caused problems under certain circumstances (in our case, being executed subsequently by a quarz scheduled job), I dived a bit deeper and finally found a more light-weight solution.
Pros:
No need to construct and run an instance of the WebApplication
No need to mock a ServletContext
Works completely independent of web application container
Contra (or not, depends on how you look at it):
Need to extract the actual mounting from your WebApplication class and encapsulate it in another class, which can then be used by standalone processes. You can no longer use WebApplication's convenient mountPage() method then, but you can easily build your own convenience implementation, just have a look at the wicket sources.
(Personally, I have never been happy with all the mount configuration making up 95% of my WebApplication class, so it felt good to finally extract it somewhere else.)
I cannot post the actual code, but having a look at this piece of code will give you an idea how you should mount your pages and how to get hold of the URL afterwards:
CompoundRequestMapper rm = new CompoundRequestMapper();
// mounting the pages
rm.add(new MountedMapper("mypage",MyPage.class));
// ... mount other pages ...
// create URL from page class and parameters
Class<? extends IRequestablePage> pageClass = MyPage.class;
PageParameters pp = new PageParameters();
pp.add("param1","value1");
IRequestHandler handler = new BookmarkablePageRequestHandler(new PageProvider(MyPage.class, pp));
Url url = rm.mapHandler(handler);
Original solution below:
After deep-diving into the intestines of the wicket sources, I was able to glue together this piece of code
IRequestMapper rm = MyWebApplication.get().getRootRequestMapper();
IRequestHandler handler = new BookmarkablePageRequestHandler(new PageProvider(pageClass, parameters));
Url url = rm.mapHandler(handler);
It works without a current RequestCycle, but still needs to have MyWebApplication running.
However, from Wicket's internal test classes, I have put the following together to construct a dummy instance of MyWebApplication:
MyWebApplication dummy = new MyWebApplication();
dummy.setName("test-app");
dummy.setServletContext(new MockServletContext(dummy, ""));
ThreadContext.setApplication(dummy);
dummy.initApplication();
I am using Eclipse with the Drools plugin to create rules.
I want to create business rules and main aim is to try and provide the user a set of options which he can use to create rules.
For eg:If an Apple can have only 3 colors: I want to provide an option like a drop down so that the user can know before hand which are the options he can use in his rules.
Is it possible?
I am creating a dsl but unable to still provide the above functionality for a business rule.
I am having an error implementing a basic dsl also.
The code to add the dsl is as follows in my RuleRunner class()
InputStream ruleSource = RuleRunner.class.getClassLoader().getResourceAsStream("/Rule1.dslr");
InputStream dslSource = RuleRunner.class.getClassLoader().getResourceAsStream("/sample-dsl.dsl");
//Load the rules , using DSL
addRulesToThisPackage.addPackageFromDrl(
new InputStreamReader(ruleSource),new InputStreamReader(dslSource));
I have both the sample-dsl .dsl and Rule1.dslr in my working directory.
Error encountered at adding the dsl to the package (last line)
Error stack:
Exception in thread "main" java.lang.NullPointerException
at java.io.Reader.<init>(Unknown Source)
at java.io.InputStreamReader.<init>(Unknown Source)
at com.org.RuleRunner.loadRuleFile(RuleRunner.java:96)
at com.org.RuleRunner.loadRules(RuleRunner.java:48)
at com.org.RuleRunner.runStatelessRules(RuleRunner.java:109)
at com.org.RulesTest.main(RulesTest.java:41)
my dsl file has basic mapping as per the online documentations.
The dsl rule I created is:
expander sample-dsl.dsl
rule "A status changes B status"
when
There is an A
- has an address
There is a B
- has name
then
- print updated A and Aaddress
End
I have created DSL in eclipse.
Is the code I added for it to be loaded to my package correct?? Or am I missing something????
It seems like my program is unable to find the dsl?
Please help. Can you point me towards the right direction to create a user friendly business rule ??
Thanks.
J
I am not quite familiar with the method you are trying to use to create a knowledge session, but I will show a example of what's used in my applications.
KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase(<KnowledgeBaseConfiguration>);
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClassPathResource( "rules/myRuleFile.drl", getClass() ),
ResourceType.DRL );
kbuilder.add( ResourceFactory.newClassPathResource( "rules/myDslFile.dsl", getClass() ),
ResourceType.DSL );
if ( kbuilder.hasErrors() ) {
System.err.println( builder.getErrors().toString() );
}
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
Now as far as giving your users the ability to author rule files, with built in constraints, have you looked at Drools Guvnor?(http://downloads.jboss.com/drools/docs/5.0.1.26597.FINAL/drools-guvnor/html_single/index.html) I have not incorporated it into my project yet, but have researched it a bit. I think it may provide the functionality your seeking for allowing your users to create and edit rule files. Good luck!