I'm new to Drools Expert, currently from the Sample project of the drools what I can only do is print something to the console. Now I integrate drools to a web project and It was successful, I was be able to print something to the console depending on the interaction of the user to the page.
My rules currently is like this:
rule "A test Rule"
when
m: FLTBean ( listeningScore == 1, test : listeningScore )
then
System.out.println( test );
end
So what if I want to print it out to a web page? How would I do that? Do I need to use return to return some value back to the java page and render it to the page?
In order to display something on a web page, then you need to be using the API to invoke Drools and get some output, which can then be rendered by your web application.
Therefore, you need to consider how to get output from it within your Java code. There are a few ways of doing this.
For example, when performing a simple action such as validating a request, then just operate on the request which you insert. For instance:
rule "IBAN doesn't begin with a country ISO code."
no-loop
when
$req: IbanValidationRequest($iban:iban, $country:iban.substring(0, 2))
not Country(isoCode == $country) from countryList
then
$req.reject("The IBAN does not begin with a 2-character country code. '" + $country + "' is not a country.");
update($req);
end
In that example, I'm calling a "reject" method on the fact which I inserted. That modifies the inserted fact, so that after rules execution, I have an object in my Java code, with a flag to indicate whether it was rejected or not. This method works well for stateless knowledge sessions. i.e.
Java code - Insert request fact via API
Drools rule - Modify the request fact (flag rejection, annotate, set properties, etc)
Java code - Look at the fact to see what was done to it
The following code example of how to perform this interaction is taken from the following full colass:
https://github.com/gratiartis/sctrcd-payment-validation-web/blob/master/src/main/java/com/sctrcd/payments/validation/payment/RuleBasedPaymentValidator.java
// Create a new knowledge session from an existing knowledge base
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
// Create a validation request
PaymentValidationRequest request = new PaymentValidationRequest(payment);
// A stateless session is executed with a collection of Objects, so we
// create that collection containing just our request.
List<Object> facts = new ArrayList<Object>();
facts.add(request);
// And execute the session with that request
ksession.execute(facts);
// At this point, rules such as that above should have been activated.
// The rules modify the original request fact, setting a flag to indicate
// whether it is valid and adding annotations to indicate if/why not.
// They may have added annotations to the request, which we can now read.
FxPaymentValidationResult result = new FxPaymentValidationResult();
// Get the annotations that were added to the request by the rules.
result.addAnnotations(request.getAnnotations());
return result;
An alternative in a stateful session would be that rules could insert facts into working memory. After executing the rules, you can then query the session via the API and retrieve one or more result objects. You can get all facts in the session using the getObjects() method of the KnowledgeSession. To get facts with particular properties, there is also a getObjects(ObjectFilter) method. The project linked below has examples of using these methods in the KnowledgeEnvironment and DroolsUtil classes.
Alternatively, you could insert a service as a global variable. The rules could then invoke methods on that service.
For an example of how to use Drools within a web application, I knocked up this web site recently, which provides a REST API to invoke Drools rules and get responses.
https://github.com/gratiartis/sctrcd-payment-validation-web
If you have Maven installed, you should be able to try it out pretty quickly, and play around with the code.
Related
I am trying to get the forest Data directory in MarkLogic. I used the following method to get data directory...using the Server Evaluation Call Interface running queries as admin. If not, please let me know how I can get forest data directory
ServerEvaluationCall forestDataDirCall = client.newServerEval()
.xquery("admin:forest-get-data-directory(admin:get-configuration(), admin:forest-get-id(admin:get-configuration(), \"" + forestName +"\"))");
for (EvalResult forestDataDirResult : forestDataDirCall.eval()) {
String forestDataDir = null;
forestDataDir = forestDataDirResult.getString();
System.out.println("forestDataDir is " + forestDataDir);
}
I see no reason for needing to hit the server evaluation endpoint to ask this question to the server. MarkLogic comes with a robust REST based management API including getters for almost all items of interest.
Knowing that, you can use what is documented here:
http://yourserver:8002/manage/v2/forests
Results can be in JSON, XML or HTML
It is the getter for forest configurations. Which forests you care about can be found by iterating over all forests or by reaching through the database config and then to the forests. It all depends on what you already know from the outside.
References:
Management API
Scripting Administrative Tasks
I am working in a REST service using javax.ws.rs, running under Glassfish, and I have some strange behavior differences on different servers, regarding the interpretation of empty query params.
Note, actual names of services and implementation details deemed unimportant have had their names changed or been omitted, to protect the innocent.
Some (most) servers treat a request
http://localhost/serviceRoot/orders?status=
(i.e. a query param named status is provided, but with no value after the = sign) as equivalent to
http://localhost/serviceRoot/orders
essentially letting that query param be null, but some treat it as though that query param had the value of "" (empty-string).
This is a problem in my case, because:
/* In a Resource class, I have this method defined: */
#GET
#Path("/orders")
public Response getOrders(#QueryParam("status") OrderStatus orderStatus) throws Exception {
/* code to pull orders, optionally by status, and return them in a Response */
}
/* ... and elsewhere, our enum */
public enum OrderStatus {
RECEIVED, ACKNOWLEDGED, CANCELLED
}
and when someone sends the first request above to a server which treats it as an empty string, I get an error in the form:
"java.lang.IllegalArgumentException: No enum constant com.fqcn.OrderStatus."
(because "" is not a valid value in the enum which it tries to automatically construct) whereas it would successfully retrieve a list of orders, if the request hit a different server.
In order to debug, though I was not able to make it produce a stack trace under normal execution, I was able to write an ExceptionMapper, and output the stack trace of that, explicitly, so I came up with this:
com.sun.jersey.server.impl.model.parameter.QueryParamInjectableProvider$QueryParamInjectable.getValue(QueryParamInjectableProvider.java:74),
com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:46),
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153),
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203),
com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75),
com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288),
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147),
com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108),
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147),
com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84),
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469),
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400),
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349),
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339),
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416),
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537),
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708),
javax.servlet.http.HttpServlet.service(HttpServlet.java:770),
org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550),
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281),
org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:175),
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java),
org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655),
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595),
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161),
org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331),
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231),
com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317),
com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195),
com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860),
com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757),
com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056),
com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229),
com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137),
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104),
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90),
com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79),
com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54),
com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59),
com.sun.grizzly.ContextTask.run(ContextTask.java:71),
com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532),
com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513),
java.lang.Thread.run(Thread.java:724)
My problem is: I do not know where this query-param interpreting behavior resides (what config file, or class/jar file), and I do not have control over the clients requesting this. Furthermore, the "big red button" approach of taking down the offending servers and standing up new clones from a "known good" instance is time-expensive and has to be done very carefully.
The question I would like answered is: Where, if anywhere within Glassfish or Jackson (or another layer of the service stack?), is this empty-query-param interpreting behavior configured, and how do I change it?
I am currently taking a course in app development and I am trying to use Facebooks API for GET requests on certain events. My goal is the get a JSON file containing all comments made on a certain event.
However some events return only a an "id" key with an id number such as this:
{
"id": "116445769058883"
}
That happends with this event:
https://www.facebook.com/events/116445769058883/
However other events such as (https://www.facebook.com/events/1964003870536124/) : returns only the latest comment for some reason.
I am experementing with facebook explore API:
https://developers.facebook.com/tools/explorer/
This is the following GET requests that I have been using in the explorer:
GET -> /v.10/facebook-id/?fields=comments
Any ideas? It's really tricky to understand the response since both events have the privacy set to OPEN.
Starting from v2.4 of the API, the API is now declarative which means you'll need to specify what fields you want the API to return.
For example, if you want first name and second name of the user, then you make a GET request to /me?fields=first_name,last_name else you will only get back the default fields which are id and name.
If you want to see what fields are available for a given endpoint, use metadata field. e.g. GET /me?metadata=true
In my project I'm using Neo4j's Core-API through GraphDatabaseService. In Tests we have an EmbeddedGraphDatabase where everything works as expected. I then wrote some tests to see how my implementation behaves on a RestGraphDatabase, just to find out, that most of it fails!
(The GraphDatabaseService is obtained by GraphDatabaseFactory of the Rest-API, so without an instanceof check I do not know which one it is)
Some examples:
If I use GlobalGraphOperations everything will fail, because GlopalGraphOperations are not supported by the RestGraphDatabase. (Strange enough that GlobalGraphOperations.at doesn't throw but all methods from GlobalGraphOperations).
Then I thought "ok I'll use Cypher to get the same behavior."
I tryed to implement a Method like this:
public getNodesWithLabel(String label, GraphDatabaseService graphService){
try(Transaction tx graphService.beginTx()){
ExecutionEngine ee = new ExecutionEngine(graphService);
//throws NullPOinterExeption in execute method
ExecutionResult result = ee.execute("MATCH (n:" + label + ") RETURN n");
result.columnAs("n");
//... mapping of Nodes
}
}
Searching through the API I see, that there is a RestCypherQueryEngine which is initialized via a RestAPIFascade. Problem here is, that the methods are not interchangeable, do not implement the same interface, and the return types are completeley different (i.e. ExecutionResult vs QueryResult)
So my question is: Is there a way, to get the same behavior from Neo4j where the used technology (Rest vs. Embedded) doesn't matter? Some kind of a technology independed Wrapper will suit my needs.
by the way, I'm using Neo4j in Version 2
Just don't do it. What it would do (if it worked) would be to execute every call to the database over the wire, ever read and write of nodes, rels and properties. You don't want to do that.
Use this instead.
queryEngine = new RestCypherQueryEngine(restGraphDb.getRestAPI());
queryEngine.query(query, params)
This sends the queries to the server and runs them there.
I have a template accountlist.scala.html looking like this:
#(accounts: models.domain.AccountList)
#titlebar = {<p>some html</p>}
#content = {
#for(account <- accounts) {
<p>#account.name</p>
}
}
#main(titlebar)(content)
... and another template account.scala.html like this:
#(account: models.domain.Account)
#titlebar = {<p>#account.name</p>}
#content = {
#for(transaction <- account.getTransactions()) {
<p>#transaction.detail</p>
}
}
#main(titlebar)(content)
From both of them I am invoking the template main.scala.html.
I have access to the entire Account POJO in the first view accountlist.scala.html, so really there is no need for me to invoke the server to get the details of the account when I go to the view in which I display the details. I would just like to change view on the client side. How could I call the second view account.scala.html from the view accountlist.scala.html a user clicks on an account in the list? I am ready to change the templates as needed.
I have provided a previous answer, which is still available at the end of this post. From your comments, however I understand that you are asking for something else without understanding how dangerous it is.
There are three ways of handling your use case, let's start with the worst one.
A stateful web application
If you have loaded data into a Pojo from some data source and you want to re-use the Pojo between multiple requests, what you are trying to do is to implement some kind of client-state on the server, such as a cache. Web applications have been developed in this way for long time and this was the source of major bugs and errors. What happens if the underlying account data in the database is updated between one http request and the following? Your client won't see it, because it use cached data. Additionally, what happens when the user performs a back in his browser? How do you get notified on the server side so you keep track of where the user is in his navigation flow? For these and others reasons, Play! is designed to be stateless. If you are really into web applications, you probably need to read about what is the REST architectural style.
A stateless web application
In a stateless web applications, you are not allowed to keep data between two http requests, so you have two ways to handle it:
Generate the user interface in a single shot
This is the approach which you can use when your account data is reduced. You embed all the necessary data from each account into your page and you generate the view, which you keep hidden and you show only when the user clicks. Please note that you can generate the HTML on the server side and with Javascript makes only certain part of your DOM visible, or just transfer a JSON representation of your accounts and use some kind of templating library to build the necessary UI directly on the client
Generate the user interface when required
This approach becomes necessary when the account data structure contains too many informations, and you don't want to transfer all this information for all the accounts on the client at first. For example, if you know the user is going to be interested in seeing the details only of very few accounts, you want to require the details only when the user asks for it.
For example, in your list of accounts you will have a button associated with each account, called details and you will use the account id to send a new request to the server.
#(accounts: models.domain.AccountList)
#titlebar = {<p>some html</p>}
#content = {
#for(account <- accounts) {
<p>#account.name <button class="details" href="#routes.Controllers.account(account.id)">details</button></p>
}
}
Please note that you can also generate the user interface on the client side, but you will still need to retrieve it from the server the data structures when the user clicks on the button. This will ensure that the user retrieves the last available state of the account.
Old answer
If your goal is to reuse your views, Play views are nothing else then Scala classes, so you can import them:
#import packagename._
and then you use it in another template:
#for(account <- accounts) {
#account(account)
}
The question reveals a misunderstanding of play framework templates. When compiling the play project the template code is transformed to html, css and javascript.
You can not "invoke"/link another template showing the account transactions from a href attribute of your Account row. However, you can do any of the following:
In case you have loaded all transactions from all accounts to the client in one go: extend the template to generate separate <div> sections for each account showing the transactions. Also generate javascript to 1) hide the overview div and 2) show the specific transaction div when clicking on one of the accounts in the overview. Please see the knockout library proposed by Edmondo1984 or the accordion or tabs in twitter bootstrap.
In case you only load the account overview from the server. Generate a link such as this one href="#routes.Controllers.account(account.id)" (see Edmondo1984 answer) and make another template to view this data.
Since the question concerned a case in which you got all data from the server, go by option 1.