Sending requests to the Drools Execution Server from an external source
by JeffMax
I am just posting this to share my experience setting up the Drools Execution
Server for making requests from a non-Java based service (from the
perspective of a programmer without much Spring, CXF, or Camel experience).
The Drools Execution Server is packaged as a WAR file that can be run in any
Java servlet container (Tomcat/Jetty/JBOSS.) One important thing to know
about it right now is that as of version 5.1, most tutorials out there
except on the Drools Documentation are no longer correct. It used to use a
.properties file and a URL based on the name of the knowledge engine, this
is no longer true.
I will try to explain how (with quite a bit of hand-waving and wild
guessing) how it works in this tutorial. I would welcome anyone that
understands how Camel and this integration truly works to correct or provide
more useful details on anything I mention here.
First, to get it running on tomcat:
Unzip the war file and place it in the webapps directory of Tomcat. There is
one thing you have to check (at least for Tomcat):
1) In camel-server.xml, change the line that says "address="/kservice/rest""
to just "address="/rest"". The reason for this is that in the web.xml for
the server, kservice is used as the url pattern for CXF servlet.:
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/kservice/*</url-pattern>
</servlet-mapping>
If you leave this the way it is, to get to your services, you will need to
go to kservice/kservice/, which is a little redundant.
With this being done, you should be able to go to
http://localhost:8080/drools-server/kservice/ in your browser and see a list
of services that are available.
The new version of Drools Server uses Apache CXF (a web framework that is an
implementation of JAX-RS), Spring, and Apache Camel. I do not fully
understand how it works, but the basics are that you use the Spring
Container which allows you to declaratively create your objects (or beans)
via xml configuration files (Spring is a huge framework, that was just an
over simplification of how it is being used in this context). From there
you use CXF to expose a URL which will be used as the endpoint for your
service. Camel grabs the data from this endpoint, and forwards it your
drools session, and then returns the response back out.
Lets look at how this happens in the config (camel-server.xml):
The CXF tag looks like this:
<cxf:rsServer id="rsServer"
address="/rest"
serviceClass="org.drools.jax.rs.CommandExecutorImpl">
<cxf:providers>
<bean class="org.drools.jax.rs.CommandMessageBodyReader"/>
</cxf:providers>
</cxf:rsServer>
We see here, it is exposing at /rest a web service that is serviced by the
class CommandExecuctorImpl (there is also that CommandMessageBodyReader, I
do not know exactly what it does)
A quick look into the source for CommandExecutorImpl, we see that it is
class that uses the CXF annotations (that is part of CXF, using annotations
to expose methods as web services) to expose
the execute method at /execute, to consume "text/plain" (which was the
source of some of my trouble, see below) through an HTTP POST. You can also
see that this method is not actually meant to be called because the only
thing that it does is raise an exception stating that fact.
public class CommandExecutorImpl implements CommandExecutor {
public CommandExecutorImpl() {
}
public CommandExecutorImpl(boolean restFlag) {
}
@POST()
@Path("/execute")
@Consumes("text/plain")
@Produces("text/plain")
public <T> T execute(Command<T> command) {
throw new UnsupportedOperationException( "This should never be
called, as it's handled by camel" );
}
}
I believe this is where Camel comes in. Again in the Spring configuration
(camel-server.xml) we have:
<!-- Leave this, as it's needed to make Camel "drools" aware -->
<bean id="droolsPolicy" class="org.drools.camel.component.DroolsPolicy" />
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<!--
! Routes incoming messages from end point id="rsServer".
! Example route unmarshals the messages with xstream and executes
against ksession1.
! Copy and paste this element, changing marshallers and the 'to' uri,
to target different sessions, as needed.
!-->
<route>
<from uri="cxfrs://bean://rsServer"/>
<policy ref="droolsPolicy">
<unmarshal ref="xstream" />
<to uri="drools:node1/ksession1" />
<marshal ref="xstream" />
</policy>
</route>
</camelContext>
We can see here that we are declaring a "route". Camel's job is to translate
and route data between things, and I believe here, it is somehow
intercepting the execute method, receiving the data it is supposed to
receive (the data you post to the server) and forwarding it to drools (note
the droolsPolicy bean declared right before the route). So here we are
declaring a route to take data from the CXF end point we just created, and
forward it to your drools knowledge session, which is declared in
knowledge-services.xml.
The sample that comes with the Execution Server creates a jsp that you call
from your browser that sends the command to the Execution Server (running
within the same conatainer.) The jsp uses a file called camel-client.xml to
do this. Camel-client.xml creates a bean that the jsp grabs (actually
Test.java, called from the jsp) that takes care of sending a POST to the CXF
endpoint described above.
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct://kservice"/>
<policy ref="droolsPolicy">
<to
uri="cxfrs://http://localhost:3333/drools-server/kservice/rest"/>
</policy>
</route>
</camelContext>
So test.jsp grabs this bean and passes it some xml it created and somehow
this sends a post to the CXF endpoint.
Here is the code from Test.java
public String send(String msg) {
ClassPathXmlApplicationContext springContext = new
ClassPathXmlApplicationContext("classpath:camel-client.xml");
String batch = "";
batch += "<batch-execution lookup=\"ksession1\">\n";
batch += " <insert out-identifier=\"message\">\n";
batch += " <org.test.Message>\n";
batch += " <text>" + msg + "</text>\n";
batch += " </org.test.Message>\n";
batch += " </insert>\n";
batch += "</batch-execution>\n";
Test test = new Test();
String response = test.execute( batch,
( CamelContext )
springContext.getBean( "camel" ) );
return response;
}
public String execute(String msg, CamelContext camelContext) {
String response = camelContext.createProducerTemplate().requestBody(
"direct://kservice", msg, String.class );
return response;
}
}
It basically grabs the camel context, and uses that to send the xml to the
"direct//kservice route" declared in camel-client.xml, which sends the data
to the specified URL.
This is camel-client.xml creates what is called a "Camel Endpoint"
None of this camel-client.xml really matters for my task however. You can
delete test.jsp and camel-client.xml from the code, because they are only
used for sending requests from Java to Java (or at the very least, from two
languages that support using Camel). I want to send xml requests from
another server into the drools execution server. This only uses the
knowledge-services.xml and camel-server.xml configuration. The requests that
are sent in have to be commands as described at this link:
http://downloads.jboss.com/drools/docs/5.1.1.34858.FINAL/drools-integrati...
So, if we look at the command that the test server was actually sending, it
is just:
<batch-execution lookup="ksession1"><insert
out-identifier="message"><org.test.Message><text>Hello
World</text></org.test.Message></insert></batch-execution>
This is the other place I ran into a problem. Following an online tutorial
(which as mentioned, is no longer completely accurate) at
http://www.lunatech-research.com/archives/2010/01/04/how-build-decision-s...,
I was trying to use curl to send in the request. There are two important
things that are not immediately obvious
1) Camel knows it has to append /execute to the url describing the endpoint.
2) As I pointed out, the CommandExecutorImpl states it consumes and produces
"text/plain".
By default, curl --data will send a Content-Type header of
"application/x-www-form-urlencoded". This will not work. Also by default,
curl will not show the text of HTTP errors returned by the server. You need
to use the -v flag to get that. So, to do the exact same thing that the
test.jsp servlet does, but from an external source, you would do the
following:
curl -v -H "Content-Type: text/plain" --data "<batch-execution
lookup=\"ksession1\"><insert
out-identifier=\"message\"><org.test.Message><text>HI</text></org.test.Message></insert></batch-execution>\n"
http://localhost:8080/drools-server/kservice/rest/execute
Note, you have to add /execute to the URL.
More on this later as I try to do something more complicated.
--
View this message in context: http://drools-java-rules-engine.46999.n3.nabble.com/Sending-requests-to-t...
Sent from the Drools - User mailing list archive at Nabble.com.
15 years, 5 months
How can i extract an object from a Map<String, Object> in rule
by nkumar
Hi all,
rule "FrontSuspension:FeatureCode|Sleeper:Value"
dialect "mvel"
when
b:Feature(featureClass.name=="FrontSuspension")
c:Feature(featureClass.name=="FrontAxle")
d:Feature(b.attributes.Sleeper)
e:Feature(b.attributes.LIG)
eval(b.code=="003AZG" && d.attributes.Value=="Yes" &&
e.attributes.Value=="Yes" && c.attributes.Capacity<13)
then
System.out.println("4th");
System.out.println(c.attributes.Merritor);
System.out.println(c.attributes.Handrickson);
end
i have an Object which has a Map<String,Object>. So in this Map at key
Sleeper i have saved an another object of the same class. Can you please
tell me how can i extract that object from that map because i have to get
info from that object which is in the map.
the syntax above is not working. attributes is the name of the map and at
Sleeper key i have a Class object. i want that object to perform some
conditions.
Thanks.
--
View this message in context: http://drools-java-rules-engine.46999.n3.nabble.com/How-can-i-extract-an-...
Sent from the Drools - User mailing list archive at Nabble.com.
15 years, 5 months
Any support for use of Timers / Calendars in Decision table (DURATION?)
by Uday Kodukula
Hello,
I am trying to incorporate logic within my decision table where certain
rules are activated based on the Day of the week, and also time of day.
I noticed the presence of date-effective and date-expires, however that
doesn't take the timer / cron approach that I would like. I understand that
the rules can still be evaluated to true, and all that the Calendar / Timer
would do is preventing it from firing.
Also, I couldn't find much documentation on how to use the "DURATION"
attribute. Perhaps because it is now deprecated and we should be using
Calendars / Timers? (see reference below).
That being said, how can I can i use calendars / timers from a decision
table? Is that even supported yet?
Thanks,
Uday
---
"duration
default value: no default value
type: long
The duration dictates that the rule will fire after a specified
duration, if it is still true.
5.8.2. Timers and Calendars
Rule's now suport both interval and cron based timers, which replace the now
deprecated duration attribute."
(http://hudson.jboss.org/hudson/job/drools/lastSuccessfulBuild/artifact/tr...)
--
View this message in context: http://drools-java-rules-engine.46999.n3.nabble.com/Any-support-for-use-o...
Sent from the Drools - User mailing list archive at Nabble.com.
15 years, 5 months
Drools server support serviceTask?
by sam.squire@paretopartners.com
I have tried using a serviceTask with Drools console but received an
error. I am guessing the gwt-console-server does not add a service task
handler like you would have to do if running locally. Is this true?
This message may contain confidential and privileged information and is intended solely for the use of the named addressee. Access, copying or re-use of the e-mail or any information contained therein by any other person is not authorised. If you are not the intended recipient please notify us immediately by returning the e-mail to the originator and then immediately delete this message. Although we attempt to sweep e-mail and attachments for viruses, we do not guarantee that either are virus-free and accept no liability for any damage sustained as a result of viruses.
Please refer to http://www.bnymellon.com/disclaimer/piml.html for certain disclosures.
15 years, 5 months
New project is Drools Engine suitable for it ?
by Gregory Czerwinski
Question about Drools usage ?
Hello All.
I have question about using Drools in my new project. I have this kind of
scenario to fufill with rules engine.
Scenarios.
Each user has it own set of rules that determine if he should be notified
about event,
and those are fully editable by system administrators.
There are also global rules indicating that User should be notified – common
for all users.
My question is how to use Drools engine in this concert situation, as it is
not global set of rules that can be putted once in to engine, but set of
changing per User rules ?
Thanks for help : )
--
View this message in context: http://drools-java-rules-engine.46999.n3.nabble.com/New-project-is-Drools...
Sent from the Drools - User mailing list archive at Nabble.com.
15 years, 5 months
no viable alternative at input 'or'
by chrbonte
Hi
I'm struggling with the rule syntax. I took over this drools project of a
collegue who left the company and am struggling with a bug in our
application.
The following works:
rule "cbo2"
when
(or
Patient(sex == "F")
Patient(sex == "")
)
then
...
end
What doesn't work is the following:
rule "cbo"
when
(or
(or
Patient(sex == "F")
Patient(age > 2)
)
Patient(sex == "")
)
then
...
end
AND
rule "cbo"
when
(or
(or
Patient(sex == "F")
Patient(age > 2)
)
)
then
...
end
-------------------
Can someone please point me in the right direction or explain to me why I
get "no viable alternative at input 'or' with the last 2 examples?
Regards
Christophe
--
View this message in context: http://drools-java-rules-engine.46999.n3.nabble.com/no-viable-alternative...
Sent from the Drools - User mailing list archive at Nabble.com.
15 years, 5 months
xdrl, and-constraint-connective and from
by Veit Guna
Hi.
We're using Drools 5.1.0 together with the xdrl format.
Now we encounter a problem with the <from> element.
We're using it like so:
--cut here--
<dro:and-conditional-element>
<dro:pattern object-type="EMail" identifier="fctv_17263"/>
<dro:pattern object-type="String">
<dro:field-constraint field-name="this">
<dro:literal-restriction evaluator="==" value="true"/>
</dro:field-constraint>
<dro:from>
<dro:expression>fctv_17263.getHeaderValues("X-My-Header");
</dro:expression>
</dro:from>
</dro:pattern>
</dro:and-conditional-element>
--cut here--
Now we simply added an additional field-constraint within an
and-constraint-connective (for a not null check):
--cut here--
<dro:and-conditional-element>
<dro:pattern object-type="EMail" identifier="fctv_17263"/>
<dro:pattern object-type="String">
<dro:and-constraint-connective>
<dro:field-constraint field-name="this">
<dro:literal-restriction evaluator="!=" value="null"/>
</dro:field-constraint>
<dro:field-constraint field-name="this.toLowerCase">
<dro:literal-restriction evaluator="==" value="true"/>
</dro:field-constraint>
</dro:and-constraint-connective>
<dro:from>
<dro:expression>fctv_17263.getHeaderValues("X-My-Header");
</dro:expression>
</dro:from>
</dro:pattern>
</dro:and-conditional-element>
--cut here--
But that dies with a:
java.lang.RuntimeException: org.drools.compiler.DroolsParserException:
org.xml.sax.SAXParseException: <from> is after an invalid element:
org.drools.xml.Handler
at
org.drools.compiler.PackageBuilder.addKnowledgeResource(PackageBuilder.java:545)
at
org.drools.builder.impl.KnowledgeBuilderImpl.add(KnowledgeBuilderImpl.java:28)
...
...
Caused by: org.drools.compiler.DroolsParserException:
org.xml.sax.SAXParseException: <from> is after an invalid element:
org.drools.xml.Handler
at
org.drools.compiler.PackageBuilder.addPackageFromXml(PackageBuilder.java:304)
at
org.drools.compiler.PackageBuilder.addKnowledgeResource(PackageBuilder.java:468)
... 77 more
As I'm writing this, I encountered this is related to this:
https://jira.jboss.org/browse/JBRULES-2672
I added an updated patch that worksforme to the JIRA.
Maybe someone of the Drools team can verify it?
BTW: all drools-compiler testcases seem to work (5.1.1) after applying
the patch.
Thanks
Veit
15 years, 5 months
matrix style decision tables
by kioto mitsubisi
Hi all,
I want to use decision tables of Drools in xls format. I need tables to be matrix.
C1 C2 C3
C1 T
C2 F F
C3 T T F
My decision table should similar to something like above. It will be a symmetric matrix and the action or result will be the
corresponding cell. I mean I will give the parameters say C1 and C3 and drools will tell me that it is T.
Can I do this? in RuleMatrixSheetListener javadoc, it states something like matrix style decision tables
but I didn't understand anything from it.
15 years, 5 months
Declaring events programmatically
by Samuli Saarinen
Hello,
I'm looking for a way to declare facts as events using an API. Would
anyone happen to know if such an API exists in drools?
Cheers,
Samuli
--
Remion Oy Etävalvontajärjestelmät liiketoiminnan
Samuli Saarinen tehostamiseen
gsm +358 (0)50 3560075
fax +358 (0)3 2125064 www.remion.com
15 years, 5 months