How to edit and update the Drools rule file? - drools

My project uses drools expert means (DRL) file. In the rules file, if the user wants to delete and update the rules, what should be done?
Rule file:
package com.sample;
import com.sample.Tuplebean;
import com.sample.DroolsBolt;
dialect "mvel"
rule "SafetyAlert-Critical"
when
t:Tuplebean(t.getSmoke() == true && t.getSmoke_density() == true && t.getTemperature() > 25.0)
then
DroolsBolt.insertToAlertLog("alert generated");
end
For example, the user wants to change the value of temperature to 30.0.

In my application i gone through same problem i fixed those problem by fallowing way , i am maintaining the all the rule file database.
I am keeping all the rule file in tables and i am loading every rule file based on the IMEI number(in my case i am generating one rule for one adaptor ie adaptor having unique IMEI number).
In below code first load the rule file from datbase and convert that string to the Resource beacuse Resource Factory accept only Resource as constructor argument. and store that in to the ksession and fire the rules.
For edit and delete operation i make one flag in database , if that flag is true again update the rule file to the database table.
if it is false load the same old rule file.
Here your generating the rule file and save to the database table and if flag is true and again your re-generate the rule file.
public void generateDrrols(String macAddress) throws SQLException, ClassNotFoundException, IOException{
logger.error("++++Generate drools file started++++");
Class.forName("org.postgresql.Driver");
Connection conn = DriverManager.getConnection("jdbc:postgresql://10.0.0.5:5432/iotdb",
"postgres", "track#123");
//String sql="SELECT alert_playload FROM iot.alert_configuration WHERE drools_boolean=true and alert_configuration_id=94 && 95";
String sql = ""
+ "select drools_condtion , iot.alert_configuration.alert_status , iot.alert_configuration.websocket_key , device_id , iot.alert_configuration.device_configuration_id , "
+ "email , iot.alert_configuration.mac_address , phone , sensor_id , iot.alert_configuration.sensor_configuration_id , alert_configuration_id , site_id , "
+ "startdatetime , enddatetime , exludedays , timetoexclude , log_update_time ,iot.sensor_configuration.sensor_name "
+ "from iot.alert_configuration "
+ "join iot.sensor_configuration on iot.sensor_configuration.sensor_configuration_id=iot.alert_configuration.sensor_configuration_id "
+ "where iot.alert_configuration.mac_address=? and soft_delete_flag=false";
PreparedStatement prepareStatement = conn.prepareStatement(sql);
prepareStatement.setString(1, macAddress);
ResultSet rs = prepareStatement.executeQuery();
//ResultSet rs = sta.executeQuery(sql);
final ResultSetGenerator converter = new ResultSetGenerator();
InputStream in = getClass().getResourceAsStream("/alert.drt");
final String drl = converter.compile(rs, in);
System.out.println(drl);
rs.close();
KnowledgeBuilder kbuilder =
KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newByteArrayResource(drl.getBytes()),
ResourceType.DRL);
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
StatefulKnowledgeSession kSession =
kbase.newStatefulKnowledgeSession();
logger.error("++++Reading rule file ie., rule.drl started++++");
logger.error("++++Making drool table status false++++");
String sql2="update iot.drool_rules set drool_rules=? where mac_address=?";
PreparedStatement prepareStatement2 = conn.prepareStatement(sql2);
prepareStatement2.setString(1, drl.toString());
prepareStatement2.setString(2, macAddress);
boolean execute2 = prepareStatement2.execute();
String sql1="update iot.alert_configuration set storm_drool_status=false where mac_address=?";
//Statement createStatement = conn.createStatement();
PreparedStatement prepareStatement3 = conn.prepareStatement(sql1);
prepareStatement3.setString(1, macAddress);
boolean execute = prepareStatement3.execute();
}
Here your loaing the rule file from database and fire all the rules.
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
try{
String sql="select drool_rules from iot.drool_rules where mac_address=?";
PreparedStatement prepareStatement = connectPostgres.prepareStatement(hql);
prepareStatement.setString(1, topicId);
ResultSet executeQuery1 = prepareStatement.executeQuery();
String rules=null;
while(executeQuery1.next()){
rules=executeQuery1.getString(1);
}
String i=null;
String replace = rules.replace('"', '\"');
System.out.println(replace);
Reader reader=(Reader)new StringReader(replace);
Resource myResource = ResourceFactory.newReaderResource(reader);
kbuilder.add(myResource, ResourceType.DRL);
}
catch(Exception e)
{
e.printStackTrace();
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
ksession = kbase.newStatefulKnowledgeSession();

Related

Android SQLite not returning data for given search term

I am trying to build a search interface but the SQLite database returns nothing here is the code for search function
public List<DiaryModel> searchData(String srchTerm){
List<DiaryModel> data2=new ArrayList<>();
SQLiteDatabase db1 = this.getWritableDatabase();
String sql="SELECT * FROM "+DB_TABLE+" WHERE "+KEY_HEADING+" LIKE '"+srchTerm+"%'";
Cursor cursor2 =db1.rawQuery(sql,null);
cursor2.moveToFirst();
StringBuilder stringBuffer2;
stringBuffer2 = new StringBuilder();
DiaryModel diaryModel2;
while (cursor2.moveToNext()){
diaryModel2 = new DiaryModel();
String heading = cursor2.getString(cursor2.getColumnIndexOrThrow("heading"));
String desc = cursor2.getString(cursor2.getColumnIndexOrThrow("desc_"));
diaryModel2.setHeading(heading);
diaryModel2.setDesc(desc);
stringBuffer2.append(diaryModel2);
data2.add(diaryModel2);
}
return data2;
}
but when I print everything the Database returns data, here is the code for get Data used for printing data present in Database
public List<DiaryModel> getdata(){
List<DiaryModel> data=new ArrayList<>();
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor =db.rawQuery("SELECT * FROM diary_db", null);
cursor.moveToFirst();
StringBuilder stringBuffer = new StringBuilder();
DiaryModel diaryModel;
while (cursor.moveToNext()){
diaryModel = new DiaryModel();
String heading = cursor.getString(cursor.getColumnIndexOrThrow(KEY_HEADING));
String desc = cursor.getString(cursor.getColumnIndexOrThrow(KEY_DESC));
diaryModel.setHeading(heading);
diaryModel.setDesc(desc);
stringBuffer.append(diaryModel);
data.add(diaryModel);
}
return data
}
The thing is only this SQL statement is working
SELECT * FROM diary_db
and if any condition is put nothing returns.
There is something that you are doing wrong in both methods:
cursor.moveToFirst();
and then:
while (cursor.moveToNext()){
.................
}
This way you miss the 1st row of the results, because after you move the cursor to the 1st row, you move once again to the next row.
So delete this:
cursor.moveToFirst();
from both methods.

Custom procedure fails to collect properties of a class parameter; why?

OK, first of all, I'm a rookie with Caché, so the code will probably be poor, but...
I need to be able to query the Caché database in Java in order to rebuild source files out of the Studio.
I can dump methods etc without trouble, however there is one thing which escapes me... For some reason, I cannot dump the properties of parameter EXTENTQUERYSPEC from class Samples.Person (namespace: SAMPLES).
The class reads like this in Studio:
Class Sample.Person Extends (%Persistent, %Populate, %XML.Adaptor)
{
Parameter EXTENTQUERYSPEC = "Name,SSN,Home.City,Home.State";
// etc etc
}
Here is the code of the procedure:
CREATE PROCEDURE CacheQc.getParamDesc(
IN className VARCHAR(50),
IN methodName VARCHAR(50),
OUT description VARCHAR(8192),
OUT type VARCHAR(50),
OUT defaultValue VARCHAR(1024)
) RETURNS NUMBER LANGUAGE COS {
set ref = className _ "||" _ methodName
set row = ##class(%Dictionary.ParameterDefinition).%OpenId(ref)
if (row = "") {
quit 1
}
set description = row.Description
set type = row.Type
set defaultValue = row.Default
quit 0
}
And the Java code:
private void getParamDetail(final String className, final String paramName)
throws SQLException
{
final String call
= "{ ? = call CacheQc.getParamDesc(?, ?, ?, ?, ?) }";
try (
final CallableStatement statement = connection.prepareCall(call);
) {
statement.registerOutParameter(1, Types.INTEGER);
statement.setString(2, className);
statement.setString(3, paramName);
statement.registerOutParameter(4, Types.VARCHAR);
statement.registerOutParameter(5, Types.VARCHAR);
statement.registerOutParameter(6, Types.VARCHAR);
statement.executeUpdate();
final int ret = statement.getInt(1);
// HERE
if (ret != 0)
throw new SQLException("failed to read parameter");
System.out.println(" description: " + statement.getString(4));
System.out.println(" type : " + statement.getString(5));
System.out.println(" default : " + statement.getString(6));
}
}
Now, for the aforementioned class/parameter pair the condition marked // HERE is always triggered and therefore the exception thrown... If I comment the whole line then I see that all three of OUT parameters are null, even defaultValue!
I'd have expected the latter to have the value mentioned in Studio...
So, why does this happen? Is my procedure broken somewhat?
In first you should check that you send right value for className and paramName, full name and in right case and. Why you choose storage procedures, when you can use select? And you can call your procedure in System Management Portal to see about probable errors.
select description, type,_Default "Default" from %Dictionary.ParameterDefinition where id='Sample.Person||EXTENTQUERYSPEC'
Your example, works well for me.
package javaapplication3;
import com.intersys.jdbc.CacheDataSource;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
public class JavaApplication3 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws SQLException {
CacheDataSource ds = new CacheDataSource();
ds.setURL("jdbc:Cache://127.0.0.1:56775/Samples");
ds.setUser("_system");
ds.setPassword("SYS");
Connection dbconnection = ds.getConnection();
String call = "{ ? = call CacheQc.getParamDesc(?, ?, ?, ?, ?)}";
CallableStatement statement = dbconnection.prepareCall(call);
statement.registerOutParameter(1, Types.INTEGER);
statement.setString(2, "Sample.Person");
statement.setString(3, "EXTENTQUERYSPEC");
statement.registerOutParameter(4, Types.VARCHAR);
statement.registerOutParameter(5, Types.VARCHAR);
statement.registerOutParameter(6, Types.VARCHAR);
statement.executeUpdate();
int ret = statement.getInt(1);
System.out.println("ret = " + ret);
System.out.println(" description: " + statement.getString(4));
System.out.println(" type : " + statement.getString(5));
System.out.println(" default : " + statement.getString(6));
}
}
end result
ret = 0
description: null
type : null
default : Name,SSN,Home.City,Home.State
UPD:
try to change code of your procedure and add some debug like here
Class CacheQc.procgetParamDesc Extends %Library.RegisteredObject [ ClassType = "", DdlAllowed, Owner = {UnknownUser}, Not ProcedureBlock ]
{
ClassMethod getParamDesc(className As %Library.String(MAXLEN=50), methodName As %Library.String(MAXLEN=50), Output description As %Library.String(MAXLEN=8192), Output type As %Library.String(MAXLEN=50), Output defaultValue As %Library.String(MAXLEN=1024)) As %Library.Numeric(SCALE=0) [ SqlName = getParamDesc, SqlProc ]
{
set ref = className _ "||" _ methodName
set row = ##class(%Dictionary.ParameterDefinition).%OpenId(ref)
set ^debug($i(^debug))=$lb(ref,row,$system.Status.GetErrorText($g(%objlasterror)))
if (row = "") {
quit 1
}
set description = row.Description
set type = row.Type
set defaultValue = row.Default
quit 0
}
}
and after some test from java, check zw ^debug
SAMPLES>zw ^debug
^debug=4
^debug(3)=$lb("Sample.Person||EXTENTQUERYSPEC","31#%Dictionary.ParameterDefinition","ERROR #00: (no error description)")
Well, uh, I found the problem... Talk about stupid.
It happens that I had the Samples.Person class open in Studio and had made a "modification" to it; and deleted it just afterwards. Therefore the file was "as new"...
But the procedure doesn't seem to agree with this statement.
I closed the Studio where that file was, selected not to modify the "changes", reran the procedure again, and it worked...
Strangely enough, the SQL query worked even with my "fake modification". I guess it's a matter of some cache problem...

How to get a Fact creating BRL in Guvnor and querying Drools Server

I'm stuck with BRL rules in Guvnor.. I'm trying to execute rules from my application using Drools Server (this solution because in production I can use more server and maybe improve performance.. Not sure about this as it's the first time that in my company we are using Drools)..
So basically the rule is .. Given an object Route setting the property "selectedOutboundJourney" that I uploaded in guvnor in a jar, I'd like to get another object with the property "selectedReturnJourney" set.. (but Is it possible to get the same object??)
Actually I get a Route object where the selectedReturnJourney is null.
I'm not sure if using BRL is a good solution given the troubles that I'm having.. It seems easy to use for non technical people that may want to change the rules or creating new ones.
Anyway..
This is the BRL that I created in Guvnor:
rule "Selected Return for Dover - Calais"
dialect "mvel"
when
Route( selectedOutboundJourney == "DOCA" )
then
Route fact0 = new Route();
fact0.setSelectedReturnJourney( "CADO" );
insertLogical( fact0 );
end
This is the code I'm using:
final List<Command> commands = new ArrayList<Command>();
final Command insertObjectCommand = CommandFactory.newInsert(input, RESULT, true, "default");
final Command getObjectCommand = CommandFactory.newGetObjects();
final Command fireAllRulesCommand = CommandFactory.newFireAllRules();
commands.add(insertObjectCommand);
commands.add(getObjectCommand);
commands.add(fireAllRulesCommand);
final ExecutionResults executionResults = droolsHttpClient.callDroolsServer(commands);
return executionResults.getValue(RESULT);
The class DroolsHttpClient is:
public ExecutionResults callDroolsServer(final List<Command> commands) throws DroolsException
{
PostMethod postMethod = null;
try
{
final HttpClient httpClient = new HttpClient();
final String droolsServerHost = Config.getString(PoferriesrulesengineConstants.DROOLS_SERVER_HOST, "");
final int droolsServerPort = Config.getInt(PoferriesrulesengineConstants.DROOLS_SERVER_PORT, 0);
httpClient.getHostConfiguration().setHost(droolsServerHost, droolsServerPort);
final String droolsServerUrl = Config.getString(PoferriesrulesengineConstants.DROOLS_SERVER_URL, "");
postMethod = new PostMethod(droolsServerUrl);
final BatchExecutionCommand command = CommandFactory.newBatchExecution(commands, PoferriesrulesengineConstants.DROOLS_SESSION);
final XStream xStreamMarshaller = BatchExecutionHelper.newXStreamMarshaller();
final String xmlCommand = xStreamMarshaller.toXML(command);
final StringRequestEntity request = new StringRequestEntity(xmlCommand, MediaType.TEXT_PLAIN_VALUE, CharEncoding.UTF_8);
postMethod.setRequestEntity(request);
httpClient.executeMethod(postMethod);
if (postMethod.getStatusCode() != 200)
{
throw new RuntimeException("Drools Communication Error, code: " + postMethod.getStatusCode());
}
final String response = postMethod.getResponseBodyAsString();
final ExecutionResults executionResults = (ExecutionResults) xStreamMarshaller.fromXML(response);
return executionResults;
}
catch (final Exception e)
{
throw new DroolsException(e.getMessage());
}
finally
{
postMethod.releaseConnection();
}
}
If I use a DRL like below it words perfectly without using the getObjectCommand:
rule "Selected Return Routes for Dover Calais"
when
r : Route(selectedOutboundJourney == "DOCA")
then
r.setSelectedReturnJourney("CADO")
end
Can anyone help me out, please?
Assuming you only have one fact in your Knowledge Session at the start, after the execution of the following rule
rule "Selected Return for Dover - Calais"
dialect "mvel"
when
Route( selectedOutboundJourney == "DOCA" )
then
Route fact0 = new Route()
fact0.setSelectedReturnJourney( "CADO" )
insert( fact0 )
end
you will have two Route facts in your session, since you just have inserted the second one.
Route: selectedOutboundJourney = "DOCA", selectedReturnJourney=null
Route: selectedOutboundJourney = null, selectedReturnJourney="DACO"
If you want to modify the original fact use the following rule:
rule "Selected Return Routes for Dover Calais"
when
$r : Route(selectedOutboundJourney == "DOCA")
then
modify ($r) {
selectedReturnJourney = "CADO"
}
end

Drools: Having trouble with drools event processing

I am quite new to drools.
I am working on an application where my drools engine will get a series of event every second. I need to see if all the events in last 10 seconds has attribute value below 10, if the condition is true, I have to do some processing. Here is the example code which I tried, Please help me understand and resolve the issue.
My Rule file.....
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
declare Employee
#role (event)
#expires(10s)
end
// Using timer to ensure rule processing starts only after 10 secs,
//else processing starts as soon as first event comes in
rule "Test Timer"
no-loop true
10timer(int: 5s)
when
$E : Employee()
$total : Number( doubleValue < 1 )
from accumulate( Employee( Age > 10 ), count() )
then
System.out.println( $E.getName() + " is crossing the threshold of 20");
retract($E);
end
And Main class
// import classes removed from here...
public class MainClass {
/**
* #param args
*/
public static void main(String[] args){
//Create KnowledgeBase...
KnowledgeBase knowledgeBase = createKnowledgeBase();
//Create a stateful session
StatefulKnowledgeSession session = knowledgeBase.newStatefulKnowledgeSession();
// KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newConsoleLogger(session);
try {
// Using random generator to simulate the data.
int randomInt=0;
Random randomGenerator = new Random();
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = null;
while (true) {
Thread.sleep(1000);
date = new Date();
randomInt = randomGenerator.nextInt(12);
//Create Facts and insert them
Employee emp = new Employee();
emp.setName("Anurag" + randomInt);
emp.setAge(randomInt);
//LOAD THE FACT AND FIREEEEEEEEEEEEEEEEEEE............
System.out.println(dateFormat.format(date)+ " => Random no " + randomInt);
session.insert(emp);
session.fireAllRules();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
session.dispose();
}
}
/**
* Create new knowledge base
*/
private static KnowledgeBase createKnowledgeBase() {
KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder();
//Add drl file into builder
File drl = new File("D:\\eclipse\\worspace\\Research\\misc\\testforall.drl");
builder.add(ResourceFactory.newFileResource(drl), ResourceType.DRL);
if (builder.hasErrors()) {
System.out.println(builder.getErrors().toString());
//throw new RuntimeException(builder.getErrors().toString());
}
KnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
//Add to Knowledge Base packages from the builder which are actually the rules from the drl file.
knowledgeBase.addKnowledgePackages(builder.getKnowledgePackages());
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
return knowledgeBase;
}
}
public class Employee {
private String Name;
private int Age;
// getter - setters
}
did you check the Drools Fusion documentation?
First of all, Employee doesn't sounds as a good idea for an Event. Events are meaningful changes of states of something related with your domain. So, an event could be the time of arrival of an Employee to the office, or the time of departure, but the Employee itself is a domain entity (or a fact for the rule engine) more than an event.
If you are interested in using Drools fusion temporal operators I recommend you to read about sliding windows (temporal ones) which will allow you to see what happen in the last ten seconds all the time. You don't need to use timers for that.
Cheers
You forgot telling what happened when you ran it, if you did.
If your entities set is not very large, I think this problem can be solved very easily with the base Drools distribution.
I have a similar app to yours and works for me:
rule "Clear only auxiliar fact"
salience 1
when
af: AuxFact()
then
DroolsRepository.retractFact(af);
end
rule "Clear auxiliar fact and an old meaningful fact"
salience 1000
when
af: AuxFact()
mf: MeaningfulFact()
then
if(DroolsRepository.getCurrentTimeMillis() - tmf.getCreationDate().getTime() > 5000){
DroolsRepository.retractFact(af);
DroolsRepository.retractFact(mf);
// YOUR MEANINGFUL CODE
}
else{
DroolsRepository.retractFact(af);}
end
query "getAllFacts"
$result: Fact()
end
and
// Boot rules re-executing thread.
new Thread(new Runnable(){
public void run(){
do{
kSession.insert(new AuxFact());
try{
Thread.sleep(99);}
catch(InterruptedException e){
e.printStackTrace();}}
while(true);}
}).start();
A similar approach could be simpler and effective.

How to use Multiple resultsets with POSTGRES JDBC?

I am using JDBC on a PostgreSQL database.
When I query for an entity in a resultset, it returns 5 rows.
Related to that entity is another entity, for which I query while i am using a row in the above resultset.
When I execute this query, the above resultset is closed.
This means that it is allowing only 1 resultset to be active on 1 connection at a time.
Previously the same code was working perfect for Oracle DB server.
Is it that I need to ask the DB admin to configure the server to allow multiple resultsets?
Or to do some change in the code?
Or is it impossible to do it in postgre?
Here is the code for more details:
Connection conn = PTSConnection.getConnection();
Statement stmt = conn.createStatement();
ResultSet lines = stmt.executeQuery("SELECT LINEID,STARTSTOPID,ENDSTOPID FROM LINES"); **//first resultset is active**
while (lines.next()){
int lineId= lines.getInt(1);
Stop ss = StopStorage.getByID(lines.getInt(2));
Stop es = StopStorage.getByID(lines.getInt(3));
ResultSet stops = stmt.executeQuery("SELECT STOPID FROM STOPSINLINES WHERE LINEID=" + lineId); **//first resultset dies**
List<Stop> lineStops = new ArrayList<Stop>();
while(stops.next()){
Stop stop = StopStorage.getByID(stops.getInt(1));
lineStops.add(stop);
}
stops.close();
Line aLine = null;
ResultSet emergencyLine = stmt.executeQuery("SELECT CAUSE, STARTTIME, ENDTIME FROM EMERGENCYLINES WHERE LINEID =" + lineId);
if(emergencyLine.next()){
String cause = emergencyLine.getString(1);
Time startTime = emergencyLine.getTime(2);
Time endTime = emergencyLine.getTime(3);
aLine = new EmergencyLine(ss, es, cause, startTime, endTime, (Stop[]) lineStops.toArray(new Stop[lineStops.size()]));
} else {
aLine = new Line(ss, es, (Stop[]) lineStops.toArray(new Stop[lineStops.size()]));
}
emergencyLine.close();
LineRepository.getInstance().addLine(aLine);
}
lines.close();
The reason is not that you are using two resultsets on the same connection, but you are re-using the same Statement object for a new query. When you run executeQuery() on a Statement instance, any previous result will be closed (I'm surprised that your code did work with Oracle...)
Simply create a new Statement object before executing the second query:
Statement stmt = conn.createStatement();
Statement nestedStmt = conn.createStatement();
ResultSet lines = stmt.executeQuery("SELECT LINEID,STARTSTOPID,ENDSTOPID FROM LINES"); **//first resultset is active**
while (lines.next()){
...
ResultSet stops = nestedStmt.executeQuery("SELECT STOPID FROM STOPSINLINES WHERE LINEID=" + lineId); **//first resultset dies**
List lineStops = new ArrayList();
while(stops.next()){
Stop stop = StopStorage.getByID(stops.getInt(1));
lineStops.add(stop);
}
stops.close();
...
ResultSet emergencyLine = nestedStmt.executeQuery("SELECT CAUSE, STARTTIME, ENDTIME FROM EMERGENCYLINES WHERE LINEID =" + lineId);
if(emergencyLine.next()){
String cause = emergencyLine.getString(1);
....
}
emergencyLine.close();
And don't for get to properly close all Statements and ResultSets !